forked from jorrit-stack/Raycast-scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnotion.js
More file actions
executable file
·141 lines (119 loc) · 5.7 KB
/
notion.js
File metadata and controls
executable file
·141 lines (119 loc) · 5.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#!/usr/bin/env node
// Raycast metadata (can also be used directly via `node notion.js ...`)
// @raycast.schemaVersion 1
// @raycast.title Ask Notion AI
// @raycast.mode silent
// @raycast.packageName Notion
// @raycast.icon 📓
// @raycast.argument1 { "type": "text", "placeholder": "Selected Text", "optional": true }
// @raycast.argument2 { "type": "text", "placeholder": "Prompt" }
// @raycast.description Open Notion (web) and submit a prompt to Notion AI with optional selected text as context
const { execSync } = require("child_process");
const fs = require("fs");
const os = require("os");
const path = require("path");
function sh(cmd, opts = {}) {
return execSync(cmd, { stdio: "pipe", encoding: "utf8", ...opts });
}
// Args: 2 = selected text, 3 = prompt, 4 = recipient name
const prompt = process.argv[3] || "";
const selectedText = process.argv[2] || "";
const recipientName = process.argv[4] || "";
// Optional Bolt support profile via env var
const useBoltSupport = process.env.BOLT_SUPPORT === "1";
// Support guidelines tailored for Notion + internal links behavior
const boltGuidelines = [
"### Core Identity & Tone",
"Role: You are a bolt.new support agent.",
"Goal: Draft clear, professional email replies focused on resolution, care, and goodwill.",
"Empathy: Acknowledge the user's situation authentically. Reassure them we are here to help.",
"No Emojis: Do not use emojis in any part of the email.",
"Punctuation: Do not use em dashes (—); use a regular hyphen (-) instead.",
"### Resolution & Goodwill Policy",
"No Compensation: We do not compensate users (refunds/credits). Focus on making things right through care and resolution.",
"Empathy Phrasing: Use terms like 'As a courtesy', 'To make things right', 'As a gesture of goodwill', or 'To help resolve this'.",
"Inconvenience Phrasing: Use terms like 'For the inconvenience', 'To acknowledge the experience', 'To help offset the inconvenience', or 'In appreciation of your patience'.",
"### Technical Guidance",
"Documentation: Prioritize answers from the official docs: https://support.bolt.new. Cite specific pages where possible.",
"Simplicity: Assume the user is non-technical. Avoid jargon and explain steps simply.",
"UI First: Prefer solutions using Bolt's interface, prompts, or built-in features over code changes.",
"Code: If code is unavoidable, provide minimal, step-by-step guidance or a direct doc link.",
"Structure: Provide short, actionable steps using bullet points for clarity. Keep it concise.",
"### Security & Internal Info",
"Internal Links: You may see internal links (Linear, Slack, Drive, etc.). These are for your context only.",
"Privacy: Never reference or link to internal tools or internal URLs in the customer-facing email.",
"External Links: The only external URL you are permitted to include is https://support.bolt.new."
].join("\n");
// Common rules applied always
const commonRules = [];
if (recipientName && recipientName.trim() !== "") {
commonRules.push(
`If the email context doesn't include a recipient name, address them by name: ${recipientName}. Start with a friendly greeting using their name (for example: "Hi ${recipientName},").`
);
} else {
commonRules.push(
'If you do not know the customer name, start with a generic friendly greeting such as "Hi there,".'
);
}
commonRules.push(
"You may end the email with a short generic closing (for example: Best, Best regards, or similar) but do not include my name in the closing, as my email client will add my signature automatically."
);
const baseBlock = commonRules.join("\n");
const mergedInstructions = (() => {
if (!useBoltSupport) {
if (prompt && prompt.trim() !== "") return [baseBlock, prompt].filter(Boolean).join("\n\n");
return baseBlock;
}
// Bolt profile
const withBolt = [baseBlock, boltGuidelines].filter(Boolean).join("\n");
if (prompt && prompt.trim() !== "") return `${withBolt}\n\nAdditional instructions from user:\n${prompt}`;
return withBolt;
})();
const finalPrompt =
selectedText && selectedText.trim() !== ""
? `Context (from email):\n\n${selectedText}\n\nInstructions:\n${mergedInstructions || ""}`
: `Instructions:\n${mergedInstructions || ""}`;
// Copy prompt to clipboard
try {
sh(`printf %s "${finalPrompt.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}" | pbcopy`);
} catch (e) {
console.error("Failed to copy to clipboard:", e.message);
}
// Ensure Chrome is running
try {
sh('open -a "Google Chrome"');
} catch (e) {
console.error("Failed to open Google Chrome:", e.message);
}
// Target Notion URL; allow override via env var
const NOTION_URL = process.env.NOTION_URL || "https://www.notion.so/";
// Open Notion in Chrome, preferring chrome-cli if available
try {
sh(`chrome-cli open "${NOTION_URL}"`);
} catch (e) {
sh(`open -a "Google Chrome" "${NOTION_URL}"`);
}
// AppleScript: activate Chrome, open Notion AI chat (Cmd+J), then paste.
// We intentionally do NOT auto-press Return so you can review/edit before sending.
const appleScript = `
tell application "Google Chrome" to activate
delay 1.2
tell application "System Events"
keystroke "j" using {command down}
delay 0.8
keystroke "v" using {command down}
end tell
`;
// Write AppleScript to a temp file to avoid shell escaping issues
const tmpScriptPath = path.join(os.tmpdir(), `notion_ai_autopaste_${Date.now()}.applescript`);
try {
fs.writeFileSync(tmpScriptPath, appleScript, { encoding: "utf8" });
execSync(`osascript "${tmpScriptPath}"`, { stdio: "inherit" });
console.log("Prompt pasted into Notion AI.");
} catch (e) {
console.warn("Auto-paste failed; prompt is in clipboard. Paste manually in Notion (Cmd+V).");
console.warn(e.message);
} finally {
try { fs.unlinkSync(tmpScriptPath); } catch (_) {}
}
process.exit(0);