Skip to content

Commit 803776e

Browse files
authored
Merge pull request #954 from nimobeeren/master
Add script to open Claude and submit prompt
2 parents 282b3bd + 045d7da commit 803776e

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed

commands/apps/claude/claude.js

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#!/usr/bin/env node
2+
3+
// Dependencies:
4+
// This script requires the following software to be installed:
5+
// - `node` https://nodejs.org
6+
// - `chrome-cli` https://github.com/prasmussen/chrome-cli
7+
// Install via homebrew: `brew install node chrome-cli`
8+
9+
// This script needs to run JavaScript in your browser, which requires your permission.
10+
// To do so, open Chrome and find the menu bar item:
11+
// View > Developer > Allow JavaScript from Apple Events
12+
13+
// Required parameters:
14+
// @raycast.schemaVersion 1
15+
// @raycast.title Ask Claude
16+
// @raycast.mode silent
17+
// @raycast.packageName Claude
18+
19+
// Optional parameters:
20+
// @raycast.icon ✨
21+
// @raycast.argument1 { "type": "text", "placeholder": "Prompt"}
22+
23+
// Documentation:
24+
// @raycast.description Open Claude in Chrome browser and submit a prompt
25+
// @raycast.author Nimo Beeren
26+
// @raycast.authorURL https://github.com/nimobeeren
27+
28+
const { execSync } = require("child_process");
29+
30+
const prompt = process.argv[2];
31+
32+
process.env.OUTPUT_FORMAT = "json";
33+
34+
/** Escape a string so that it can be used in JavaScript code when wrapped in double quotes. */
35+
function escapeJsString(str) {
36+
return str.replaceAll(`\\`, `\\\\`).replaceAll(`"`, `\\"`);
37+
}
38+
39+
/** Escape a string so that it can be used in a shell command when wrapped in single quotes. */
40+
function escapeShellString(str) {
41+
return str.replaceAll(`'`, `'"'"'`);
42+
}
43+
44+
try {
45+
execSync("which chrome-cli");
46+
} catch {
47+
console.error(
48+
"chrome-cli is required to run this script (https://github.com/prasmussen/chrome-cli)"
49+
);
50+
process.exit(1);
51+
}
52+
53+
// Find the Claude tab if one is already open
54+
let tabs = JSON.parse(execSync("chrome-cli list tabs")).tabs;
55+
let claudeTab = tabs.find((tab) => tab.url.startsWith("https://claude.ai/"));
56+
57+
// If there is a Claude tab open, get its info. Otherwise, open Claude in a new
58+
// window.
59+
let claudeTabInfo;
60+
if (claudeTab) {
61+
// Open a new Claude session in the existing tab and focus it
62+
execSync(`chrome-cli open 'https://claude.ai/new' -t ${claudeTab.id}`);
63+
// Get tab info
64+
claudeTabInfo = JSON.parse(execSync(`chrome-cli info -t ${claudeTab.id}`));
65+
} else {
66+
// Open a Claude session in a new tab, focus it and return the tab info
67+
claudeTabInfo = JSON.parse(
68+
execSync("chrome-cli open 'https://claude.ai/new'")
69+
);
70+
}
71+
72+
// Wait for the tab to be loaded, then execute the script
73+
let interval = setInterval(() => {
74+
if (claudeTabInfo.loading) {
75+
claudeTabInfo = JSON.parse(
76+
execSync(`chrome-cli info -t ${claudeTabInfo.id}`)
77+
);
78+
} else {
79+
clearInterval(interval);
80+
executeScript();
81+
}
82+
}, 100);
83+
84+
function executeScript() {
85+
const script = async function (prompt) {
86+
// Wait for prompt element to be on the page
87+
let promptElement;
88+
await new Promise((resolve) => {
89+
let interval = setInterval(() => {
90+
promptElement = document.querySelector(
91+
'[aria-label="Write your prompt to Claude"] > div'
92+
);
93+
if (promptElement) {
94+
clearInterval(interval);
95+
resolve();
96+
}
97+
}, 100);
98+
});
99+
100+
// Set the prompt
101+
const p = document.createElement("p");
102+
p.textContent = prompt;
103+
promptElement.replaceChildren(p);
104+
105+
// Wait for submit button to be on the page
106+
let submitButton;
107+
await new Promise((resolve) => {
108+
let interval = setInterval(() => {
109+
submitButton = document.querySelector('[aria-label="Send Message"]');
110+
if (submitButton) {
111+
clearInterval(interval);
112+
resolve();
113+
}
114+
}, 100);
115+
});
116+
117+
// Submit the prompt
118+
submitButton.click();
119+
};
120+
121+
const functionString = escapeShellString(script.toString());
122+
const promptString = escapeShellString(escapeJsString(prompt));
123+
124+
execSync(
125+
`chrome-cli execute '(${functionString})("${promptString}")' -t ${claudeTabInfo.id}`
126+
);
127+
}

0 commit comments

Comments
 (0)