hanzi-browse 2.3.0 → 2.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -79
- package/dist/agent/domain-knowledge.d.ts +20 -0
- package/dist/agent/domain-knowledge.js +33 -0
- package/dist/agent/domain-skills.json +66 -0
- package/dist/agent/loop.d.ts +12 -0
- package/dist/agent/loop.js +41 -1
- package/dist/agent/system-prompt.d.ts +1 -1
- package/dist/agent/system-prompt.js +12 -2
- package/dist/cli/json-output.d.ts +21 -0
- package/dist/cli/json-output.js +30 -0
- package/dist/cli/setup.d.ts +51 -0
- package/dist/cli/setup.js +113 -41
- package/dist/cli.js +29 -8
- package/dist/index.js +1 -567
- package/dist/managed/api.d.ts +20 -1
- package/dist/managed/api.js +181 -521
- package/dist/managed/auth.js +0 -5
- package/dist/managed/deploy.js +82 -0
- package/dist/managed/routes/api.d.ts +44 -0
- package/dist/managed/routes/api.js +220 -0
- package/dist/managed/routes/pages.d.ts +13 -0
- package/dist/managed/routes/pages.js +149 -0
- package/dist/managed/store-pg.d.ts +5 -1
- package/dist/managed/store-pg.js +12 -4
- package/dist/managed/store.d.ts +6 -1
- package/dist/managed/store.js +4 -2
- package/dist/managed/templates/pair-self.html +67 -0
- package/dist/managed/templates/pair.html +97 -0
- package/dist/mcp/tools.d.ts +20 -0
- package/dist/mcp/tools.js +263 -0
- package/dist/relay/api-proxy.d.ts +2 -0
- package/dist/relay/api-proxy.js +165 -0
- package/dist/relay/server.js +2 -112
- package/package.json +3 -3
- package/skills/competitor-monitor/SKILL.md +290 -0
- package/skills/data-extractor/SKILL.md +223 -0
- package/skills/job-applier/SKILL.md +260 -0
- package/skills/seo-checker/SKILL.md +146 -0
package/dist/cli/setup.js
CHANGED
|
@@ -65,12 +65,15 @@ const MCP_ENTRY = {
|
|
|
65
65
|
args: ['-y', 'hanzi-browse'],
|
|
66
66
|
};
|
|
67
67
|
// ── Agent registry ─────────────────────────────────────────────────────
|
|
68
|
-
function getAgentRegistry() {
|
|
69
|
-
const home = homedir();
|
|
70
|
-
const plat = platform();
|
|
68
|
+
export function getAgentRegistry(deps = {}) {
|
|
69
|
+
const home = deps.home ?? homedir();
|
|
70
|
+
const plat = deps.plat ?? platform();
|
|
71
|
+
const appData = deps.appData ?? process.env.APPDATA ?? join(home, 'AppData', 'Roaming');
|
|
72
|
+
const pathExists = deps.pathExists ?? existsSync;
|
|
73
|
+
const runCommand = deps.runCommand ?? execSync;
|
|
71
74
|
const hasCli = (bin) => {
|
|
72
75
|
try {
|
|
73
|
-
|
|
76
|
+
runCommand(`which ${bin}`, { stdio: 'ignore' });
|
|
74
77
|
return true;
|
|
75
78
|
}
|
|
76
79
|
catch {
|
|
@@ -94,7 +97,7 @@ function getAgentRegistry() {
|
|
|
94
97
|
method: 'json-merge',
|
|
95
98
|
configPath: () => join(home, '.cursor', 'mcp.json'),
|
|
96
99
|
skillsDir: () => join(home, '.cursor', 'skills'),
|
|
97
|
-
detect: () =>
|
|
100
|
+
detect: () => pathExists(join(home, '.cursor')),
|
|
98
101
|
},
|
|
99
102
|
{
|
|
100
103
|
name: 'Windsurf',
|
|
@@ -102,7 +105,7 @@ function getAgentRegistry() {
|
|
|
102
105
|
method: 'json-merge',
|
|
103
106
|
configPath: () => join(home, '.codeium', 'windsurf', 'mcp_config.json'),
|
|
104
107
|
skillsDir: () => join(home, '.codeium', 'windsurf', 'skills'),
|
|
105
|
-
detect: () =>
|
|
108
|
+
detect: () => pathExists(join(home, '.codeium', 'windsurf')),
|
|
106
109
|
},
|
|
107
110
|
{
|
|
108
111
|
name: 'VS Code',
|
|
@@ -110,7 +113,7 @@ function getAgentRegistry() {
|
|
|
110
113
|
method: 'json-merge',
|
|
111
114
|
configPath: () => join(home, '.vscode', 'mcp.json'),
|
|
112
115
|
skillsDir: () => join(home, '.vscode', 'skills'),
|
|
113
|
-
detect: () =>
|
|
116
|
+
detect: () => pathExists(join(home, '.vscode')),
|
|
114
117
|
},
|
|
115
118
|
{
|
|
116
119
|
name: 'Codex',
|
|
@@ -118,7 +121,7 @@ function getAgentRegistry() {
|
|
|
118
121
|
method: 'json-merge',
|
|
119
122
|
configPath: () => join(home, '.codex', 'mcp.json'),
|
|
120
123
|
skillsDir: () => join(home, '.agents', 'skills'),
|
|
121
|
-
detect: () =>
|
|
124
|
+
detect: () => pathExists(join(home, '.codex')) || hasCli('codex'),
|
|
122
125
|
},
|
|
123
126
|
{
|
|
124
127
|
name: 'Claude Desktop',
|
|
@@ -128,15 +131,15 @@ function getAgentRegistry() {
|
|
|
128
131
|
if (plat === 'darwin')
|
|
129
132
|
return join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
|
|
130
133
|
if (plat === 'win32')
|
|
131
|
-
return join(
|
|
134
|
+
return join(appData, 'Claude', 'claude_desktop_config.json');
|
|
132
135
|
return join(home, '.config', 'Claude', 'claude_desktop_config.json');
|
|
133
136
|
},
|
|
134
137
|
detect: () => {
|
|
135
138
|
if (plat === 'darwin')
|
|
136
|
-
return
|
|
139
|
+
return pathExists(join(home, 'Library', 'Application Support', 'Claude'));
|
|
137
140
|
if (plat === 'win32')
|
|
138
|
-
return
|
|
139
|
-
return
|
|
141
|
+
return pathExists(join(appData, 'Claude'));
|
|
142
|
+
return pathExists(join(home, '.config', 'Claude'));
|
|
140
143
|
},
|
|
141
144
|
},
|
|
142
145
|
{
|
|
@@ -145,7 +148,7 @@ function getAgentRegistry() {
|
|
|
145
148
|
method: 'json-merge',
|
|
146
149
|
configPath: () => join(home, '.gemini', 'settings.json'),
|
|
147
150
|
skillsDir: () => join(home, '.gemini', 'skills'),
|
|
148
|
-
detect: () =>
|
|
151
|
+
detect: () => pathExists(join(home, '.gemini')) || hasCli('gemini'),
|
|
149
152
|
},
|
|
150
153
|
{
|
|
151
154
|
name: 'Amp',
|
|
@@ -153,21 +156,21 @@ function getAgentRegistry() {
|
|
|
153
156
|
method: 'json-merge',
|
|
154
157
|
configPath: () => join(home, '.amp', 'mcp.json'),
|
|
155
158
|
skillsDir: () => join(home, '.amp', 'skills'),
|
|
156
|
-
detect: () =>
|
|
159
|
+
detect: () => pathExists(join(home, '.amp')),
|
|
157
160
|
},
|
|
158
161
|
{
|
|
159
162
|
name: 'Cline',
|
|
160
163
|
slug: 'cline',
|
|
161
164
|
method: 'json-merge',
|
|
162
165
|
configPath: () => join(home, '.cline', 'mcp_settings.json'),
|
|
163
|
-
detect: () =>
|
|
166
|
+
detect: () => pathExists(join(home, '.cline')),
|
|
164
167
|
},
|
|
165
168
|
{
|
|
166
169
|
name: 'Roo Code',
|
|
167
170
|
slug: 'roo-code',
|
|
168
171
|
method: 'json-merge',
|
|
169
172
|
configPath: () => join(home, '.roo-code', 'mcp_settings.json'),
|
|
170
|
-
detect: () =>
|
|
173
|
+
detect: () => pathExists(join(home, '.roo-code')),
|
|
171
174
|
},
|
|
172
175
|
];
|
|
173
176
|
}
|
|
@@ -177,16 +180,21 @@ function stripJsonComments(text) {
|
|
|
177
180
|
.replace(/\/\/.*$/gm, '')
|
|
178
181
|
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
179
182
|
}
|
|
180
|
-
function mergeJsonConfig(configPath) {
|
|
183
|
+
export function mergeJsonConfig(configPath, deps = {}) {
|
|
181
184
|
const agentName = configPath;
|
|
185
|
+
const pathExists = deps.pathExists ?? existsSync;
|
|
186
|
+
const readTextFile = deps.readTextFile ?? readFileSync;
|
|
187
|
+
const writeTextFile = deps.writeTextFile ?? writeFileSync;
|
|
188
|
+
const ensureDir = deps.ensureDir ?? mkdirSync;
|
|
189
|
+
const copyFile = deps.copyFile ?? copyFileSync;
|
|
182
190
|
try {
|
|
183
|
-
if (!
|
|
184
|
-
|
|
191
|
+
if (!pathExists(configPath)) {
|
|
192
|
+
ensureDir(join(configPath, '..'), { recursive: true });
|
|
185
193
|
const config = { mcpServers: { "hanzi-browser": MCP_ENTRY } };
|
|
186
|
-
|
|
194
|
+
writeTextFile(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
187
195
|
return { agent: agentName, status: 'configured', detail: `created ${configPath}` };
|
|
188
196
|
}
|
|
189
|
-
const raw =
|
|
197
|
+
const raw = readTextFile(configPath, 'utf-8');
|
|
190
198
|
let config;
|
|
191
199
|
try {
|
|
192
200
|
config = JSON.parse(raw);
|
|
@@ -197,9 +205,9 @@ function mergeJsonConfig(configPath) {
|
|
|
197
205
|
}
|
|
198
206
|
catch {
|
|
199
207
|
const bakPath = configPath + '.bak';
|
|
200
|
-
|
|
208
|
+
copyFile(configPath, bakPath);
|
|
201
209
|
config = { mcpServers: { "hanzi-browser": MCP_ENTRY } };
|
|
202
|
-
|
|
210
|
+
writeTextFile(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
203
211
|
return { agent: agentName, status: 'configured', detail: `backed up malformed config to ${bakPath}` };
|
|
204
212
|
}
|
|
205
213
|
}
|
|
@@ -212,7 +220,7 @@ function mergeJsonConfig(configPath) {
|
|
|
212
220
|
if (!config.mcpServers)
|
|
213
221
|
config.mcpServers = {};
|
|
214
222
|
config.mcpServers["hanzi-browser"] = MCP_ENTRY;
|
|
215
|
-
|
|
223
|
+
writeTextFile(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
216
224
|
return { agent: agentName, status: 'configured', detail: `merged into ${configPath}` };
|
|
217
225
|
}
|
|
218
226
|
catch (err) {
|
|
@@ -245,20 +253,67 @@ function runClaudeCodeSetup() {
|
|
|
245
253
|
// ── Browser detection ──────────────────────────────────────────────────
|
|
246
254
|
const EXTENSION_URL = 'https://chromewebstore.google.com/detail/hanzi-browse/iklpkemlmbhemkiojndpbhoakgikpmcd';
|
|
247
255
|
const BROWSERS = [
|
|
248
|
-
{
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
256
|
+
{
|
|
257
|
+
name: 'Google Chrome',
|
|
258
|
+
slug: 'chrome',
|
|
259
|
+
macApp: 'Google Chrome',
|
|
260
|
+
linuxBin: 'google-chrome',
|
|
261
|
+
winPaths: [
|
|
262
|
+
'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
|
|
263
|
+
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
|
|
264
|
+
],
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
name: 'Brave',
|
|
268
|
+
slug: 'brave',
|
|
269
|
+
macApp: 'Brave Browser',
|
|
270
|
+
linuxBin: 'brave-browser',
|
|
271
|
+
winPaths: [
|
|
272
|
+
'C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe',
|
|
273
|
+
'C:\\Program Files (x86)\\BraveSoftware\\Brave-Browser\\Application\\brave.exe',
|
|
274
|
+
],
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
name: 'Microsoft Edge',
|
|
278
|
+
slug: 'edge',
|
|
279
|
+
macApp: 'Microsoft Edge',
|
|
280
|
+
linuxBin: 'microsoft-edge',
|
|
281
|
+
winPaths: [
|
|
282
|
+
'C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe',
|
|
283
|
+
'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe',
|
|
284
|
+
],
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
name: 'Arc',
|
|
288
|
+
slug: 'arc',
|
|
289
|
+
macApp: 'Arc',
|
|
290
|
+
linuxBin: 'arc',
|
|
291
|
+
winPaths: [],
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
name: 'Chromium',
|
|
295
|
+
slug: 'chromium',
|
|
296
|
+
macApp: 'Chromium',
|
|
297
|
+
linuxBin: 'chromium-browser',
|
|
298
|
+
winPaths: [
|
|
299
|
+
'C:\\Program Files\\Chromium\\Application\\chrome.exe',
|
|
300
|
+
'C:\\Program Files (x86)\\Chromium\\Application\\chrome.exe',
|
|
301
|
+
],
|
|
302
|
+
},
|
|
253
303
|
];
|
|
254
|
-
function detectBrowsers() {
|
|
255
|
-
const plat = platform();
|
|
304
|
+
export function detectBrowsers(deps = {}) {
|
|
305
|
+
const plat = deps.plat ?? platform();
|
|
306
|
+
const pathExists = deps.pathExists ?? existsSync;
|
|
307
|
+
const runCommand = deps.runCommand ?? execSync;
|
|
256
308
|
return BROWSERS.filter(b => {
|
|
257
309
|
if (plat === 'darwin') {
|
|
258
|
-
return
|
|
310
|
+
return pathExists(`/Applications/${b.macApp}.app`);
|
|
311
|
+
}
|
|
312
|
+
if (plat === 'win32') {
|
|
313
|
+
return b.winPaths.some(path => pathExists(path));
|
|
259
314
|
}
|
|
260
315
|
try {
|
|
261
|
-
|
|
316
|
+
runCommand(`which ${b.linuxBin}`, { stdio: 'ignore' });
|
|
262
317
|
return true;
|
|
263
318
|
}
|
|
264
319
|
catch {
|
|
@@ -266,19 +321,36 @@ function detectBrowsers() {
|
|
|
266
321
|
}
|
|
267
322
|
});
|
|
268
323
|
}
|
|
324
|
+
export function resolveInteractiveMode(options = {}, stdinIsTTY = process.stdin.isTTY ?? false) {
|
|
325
|
+
return options.yes ? false : stdinIsTTY;
|
|
326
|
+
}
|
|
327
|
+
export function buildBrowserOpenCommand(browser, url, plat) {
|
|
328
|
+
if (plat === 'darwin') {
|
|
329
|
+
return `open -a "${browser.macApp}" "${url}"`;
|
|
330
|
+
}
|
|
331
|
+
if (plat === 'win32') {
|
|
332
|
+
const exePath = browser.winPaths.find(path => existsSync(path)) ?? browser.winPaths[0];
|
|
333
|
+
if (!exePath)
|
|
334
|
+
return `cmd /c start "" "${url}"`;
|
|
335
|
+
return `cmd /c start "" "${exePath}" "${url}"`;
|
|
336
|
+
}
|
|
337
|
+
return `${browser.linuxBin} "${url}" &`;
|
|
338
|
+
}
|
|
339
|
+
export function buildSystemOpenCommand(url, plat) {
|
|
340
|
+
if (plat === 'darwin')
|
|
341
|
+
return `open "${url}"`;
|
|
342
|
+
if (plat === 'win32')
|
|
343
|
+
return `cmd /c start "" "${url}"`;
|
|
344
|
+
return `xdg-open "${url}"`;
|
|
345
|
+
}
|
|
269
346
|
function openInBrowser(browser, url) {
|
|
270
347
|
const plat = platform();
|
|
271
348
|
try {
|
|
272
|
-
|
|
273
|
-
execSync(`open -a "${browser.macApp}" "${url}"`, { stdio: 'ignore' });
|
|
274
|
-
}
|
|
275
|
-
else {
|
|
276
|
-
execSync(`${browser.linuxBin} "${url}" &`, { stdio: 'ignore' });
|
|
277
|
-
}
|
|
349
|
+
execSync(buildBrowserOpenCommand(browser, url, plat), { stdio: 'ignore' });
|
|
278
350
|
}
|
|
279
351
|
catch {
|
|
280
352
|
// Fallback: system default
|
|
281
|
-
execSync(
|
|
353
|
+
execSync(buildSystemOpenCommand(url, plat), { stdio: 'ignore' });
|
|
282
354
|
}
|
|
283
355
|
}
|
|
284
356
|
async function ensureExtension(isInteractive) {
|
|
@@ -700,7 +772,7 @@ export async function runSetup(options = {}) {
|
|
|
700
772
|
trackEvent("setup_started");
|
|
701
773
|
const registry = getAgentRegistry();
|
|
702
774
|
const only = options.only;
|
|
703
|
-
const interactive = options
|
|
775
|
+
const interactive = resolveInteractiveMode(options);
|
|
704
776
|
// ── Banner ──
|
|
705
777
|
if (interactive) {
|
|
706
778
|
console.log(BANNER);
|
package/dist/cli.js
CHANGED
|
@@ -20,6 +20,7 @@ import { fileURLToPath } from 'url';
|
|
|
20
20
|
import { dirname } from 'path';
|
|
21
21
|
import { WebSocketClient } from './ipc/websocket-client.js';
|
|
22
22
|
import { writeSessionStatus, readSessionStatus, appendSessionLog, listSessions, deleteSessionFiles, getSessionLogPath, getSessionScreenshotPath, } from './cli/session-files.js';
|
|
23
|
+
import { buildScreenshotPayload, buildStatusPayload, buildStopPayload, buildTaskCompletePayload, buildTaskErrorPayload, } from './cli/json-output.js';
|
|
23
24
|
// Parse command line arguments
|
|
24
25
|
const args = process.argv.slice(2);
|
|
25
26
|
const command = args[0];
|
|
@@ -67,7 +68,7 @@ function handleMessage(message) {
|
|
|
67
68
|
appendSessionLog(sessionId, `[COMPLETE] ${answer}`);
|
|
68
69
|
writeSessionStatus(sessionId, { status: 'complete', result: answer });
|
|
69
70
|
if (jsonOutput) {
|
|
70
|
-
console.log(JSON.stringify(
|
|
71
|
+
console.log(JSON.stringify(buildTaskCompletePayload(sessionId, result)));
|
|
71
72
|
}
|
|
72
73
|
else {
|
|
73
74
|
console.log(`\n[CLI] Task completed: ${sessionId}`);
|
|
@@ -80,7 +81,7 @@ function handleMessage(message) {
|
|
|
80
81
|
appendSessionLog(sessionId, `[ERROR] ${data.error}`);
|
|
81
82
|
writeSessionStatus(sessionId, { status: 'error', error: data.error });
|
|
82
83
|
if (jsonOutput) {
|
|
83
|
-
console.log(JSON.stringify(
|
|
84
|
+
console.log(JSON.stringify(buildTaskErrorPayload(sessionId, data.error)));
|
|
84
85
|
}
|
|
85
86
|
else {
|
|
86
87
|
console.error(`\n[CLI] Task error: ${data.error}`);
|
|
@@ -193,12 +194,12 @@ function cmdStatus() {
|
|
|
193
194
|
console.error(`Session not found: ${sessionId}`);
|
|
194
195
|
process.exit(1);
|
|
195
196
|
}
|
|
196
|
-
console.log(JSON.stringify(status, jsonOutput ? undefined : null, jsonOutput ? undefined : 2));
|
|
197
|
+
console.log(JSON.stringify(buildStatusPayload(status), jsonOutput ? undefined : null, jsonOutput ? undefined : 2));
|
|
197
198
|
}
|
|
198
199
|
else {
|
|
199
200
|
const allSessions = listSessions();
|
|
200
201
|
if (jsonOutput) {
|
|
201
|
-
console.log(JSON.stringify(allSessions));
|
|
202
|
+
console.log(JSON.stringify(buildStatusPayload(allSessions)));
|
|
202
203
|
}
|
|
203
204
|
else if (allSessions.length === 0) {
|
|
204
205
|
console.log('No sessions found.');
|
|
@@ -267,11 +268,21 @@ async function cmdStop() {
|
|
|
267
268
|
await connection.send({ type: 'mcp_stop_task', sessionId, remove });
|
|
268
269
|
if (remove) {
|
|
269
270
|
deleteSessionFiles(sessionId);
|
|
270
|
-
|
|
271
|
+
if (jsonOutput) {
|
|
272
|
+
console.log(JSON.stringify(buildStopPayload(sessionId, true)));
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
console.log(`Session ${sessionId} stopped and removed.`);
|
|
276
|
+
}
|
|
271
277
|
}
|
|
272
278
|
else {
|
|
273
279
|
writeSessionStatus(sessionId, { status: 'stopped' });
|
|
274
|
-
|
|
280
|
+
if (jsonOutput) {
|
|
281
|
+
console.log(JSON.stringify(buildStopPayload(sessionId, false)));
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
console.log(`Session ${sessionId} stopped.`);
|
|
285
|
+
}
|
|
275
286
|
}
|
|
276
287
|
disconnectAndExit(0);
|
|
277
288
|
}
|
|
@@ -281,7 +292,9 @@ async function cmdScreenshot() {
|
|
|
281
292
|
activeSessionId = requestId;
|
|
282
293
|
await initConnection();
|
|
283
294
|
await connection.send({ type: 'mcp_screenshot', sessionId: requestId });
|
|
284
|
-
|
|
295
|
+
if (!jsonOutput) {
|
|
296
|
+
console.log(`Screenshot requested for ${requestId}. Waiting for image...\n`);
|
|
297
|
+
}
|
|
285
298
|
const data = await new Promise((resolve) => {
|
|
286
299
|
pendingScreenshotResolve = resolve;
|
|
287
300
|
setTimeout(() => {
|
|
@@ -296,7 +309,12 @@ async function cmdScreenshot() {
|
|
|
296
309
|
}
|
|
297
310
|
const screenshotPath = getSessionScreenshotPath(requestId);
|
|
298
311
|
writeFileSync(screenshotPath, Buffer.from(data, 'base64'));
|
|
299
|
-
|
|
312
|
+
if (jsonOutput) {
|
|
313
|
+
console.log(JSON.stringify(buildScreenshotPayload(requestId, screenshotPath)));
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
console.log(`[CLI] Screenshot saved: ${screenshotPath}`);
|
|
317
|
+
}
|
|
300
318
|
disconnectAndExit(0);
|
|
301
319
|
}
|
|
302
320
|
// --- Skills ---
|
|
@@ -408,6 +426,7 @@ Commands:
|
|
|
408
426
|
Each session gets its own browser window.
|
|
409
427
|
|
|
410
428
|
status [session_id] Show status of session(s)
|
|
429
|
+
--json Output machine-readable JSON
|
|
411
430
|
|
|
412
431
|
message <session_id> <msg> Send follow-up instructions to a session
|
|
413
432
|
Reuses the same browser window and page state.
|
|
@@ -417,8 +436,10 @@ Commands:
|
|
|
417
436
|
|
|
418
437
|
stop <session_id> Stop a session
|
|
419
438
|
--remove, -r Also delete session files
|
|
439
|
+
--json Output machine-readable JSON
|
|
420
440
|
|
|
421
441
|
screenshot [session_id] Take a screenshot
|
|
442
|
+
--json Output machine-readable JSON
|
|
422
443
|
|
|
423
444
|
setup Auto-detect AI agents and configure MCP
|
|
424
445
|
--only <agent> Only configure one agent (claude-code, cursor, windsurf, claude-desktop)
|