@canaryai/cli 0.2.9 → 0.2.13
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/dist/{chunk-PWWQGYFG.js → chunk-ACRIE2YR.js} +5 -2
- package/dist/chunk-ACRIE2YR.js.map +1 -0
- package/dist/chunk-BOS2YLKH.js +233 -0
- package/dist/chunk-BOS2YLKH.js.map +1 -0
- package/dist/{chunk-XGO62PO2.js → chunk-IFOJT3A5.js} +1198 -262
- package/dist/chunk-IFOJT3A5.js.map +1 -0
- package/dist/{chunk-LC7ZVXPH.js → chunk-SVU2XTYZ.js} +19 -5
- package/dist/chunk-SVU2XTYZ.js.map +1 -0
- package/dist/{chunk-A44B2PEA.js → chunk-SYPQF57S.js} +40 -8
- package/dist/chunk-SYPQF57S.js.map +1 -0
- package/dist/{chunk-C2PGZRYK.js → chunk-Z3F373YR.js} +37 -11
- package/dist/chunk-Z3F373YR.js.map +1 -0
- package/dist/{debug-workflow-I3F36JBL.js → debug-workflow-K2LL6CO4.js} +10 -12
- package/dist/debug-workflow-K2LL6CO4.js.map +1 -0
- package/dist/{docs-REHST3YB.js → docs-SR7CW24Y.js} +19 -14
- package/dist/docs-SR7CW24Y.js.map +1 -0
- package/dist/{feature-flag-3HB5NTMY.js → feature-flag-BIPFVVNC.js} +3 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +83 -155
- package/dist/index.js.map +1 -1
- package/dist/init-KXAVWHYE.js +146 -0
- package/dist/init-KXAVWHYE.js.map +1 -0
- package/dist/{issues-YU57CHXS.js → issues-EWVB52CA.js} +37 -18
- package/dist/issues-EWVB52CA.js.map +1 -0
- package/dist/{knobs-QJ4IBLCT.js → knobs-VYABZESR.js} +3 -3
- package/dist/list-RCPYLS36.js +57 -0
- package/dist/list-RCPYLS36.js.map +1 -0
- package/dist/local-34FX3M5K.js +63 -0
- package/dist/local-34FX3M5K.js.map +1 -0
- package/dist/{local-browser-MKTJ36KY.js → local-browser-VPOSJS52.js} +4 -4
- package/dist/login-MSIM2VIH.js +130 -0
- package/dist/login-MSIM2VIH.js.map +1 -0
- package/dist/{mcp-ZOKM2AUE.js → mcp-YBR7G254.js} +7 -132
- package/dist/mcp-YBR7G254.js.map +1 -0
- package/dist/{psql-2YPIRMDY.js → psql-XO5BB5L5.js} +2 -2
- package/dist/{record-TNDBT3NY.js → record-DXXQHPGT.js} +10 -51
- package/dist/record-DXXQHPGT.js.map +1 -0
- package/dist/{redis-A7GWM23E.js → redis-CQTBPZ6F.js} +2 -2
- package/dist/{release-L4IXOHDF.js → release-DW7RPQSQ.js} +9 -5
- package/dist/release-DW7RPQSQ.js.map +1 -0
- package/dist/runner/preload.js +1 -1
- package/dist/{session-RNLKFS2Z.js → session-XQGCLWNC.js} +164 -75
- package/dist/session-XQGCLWNC.js.map +1 -0
- package/dist/skill-2TXI3IKP.js +424 -0
- package/dist/skill-2TXI3IKP.js.map +1 -0
- package/dist/{src-2WSMYBMJ.js → src-F7LQ5PY2.js} +8 -2
- package/dist/start-ZOMUD6LW.js +112 -0
- package/dist/start-ZOMUD6LW.js.map +1 -0
- package/dist/test.js +1 -1
- package/dist/test.js.map +1 -1
- package/dist/workflow-5UZTKX7X.js +624 -0
- package/dist/workflow-5UZTKX7X.js.map +1 -0
- package/package.json +1 -2
- package/dist/chunk-A44B2PEA.js.map +0 -1
- package/dist/chunk-C2PGZRYK.js.map +0 -1
- package/dist/chunk-DXIAHB72.js +0 -340
- package/dist/chunk-DXIAHB72.js.map +0 -1
- package/dist/chunk-LC7ZVXPH.js.map +0 -1
- package/dist/chunk-PWWQGYFG.js.map +0 -1
- package/dist/chunk-QLFSJG5O.js +0 -93
- package/dist/chunk-QLFSJG5O.js.map +0 -1
- package/dist/chunk-XGO62PO2.js.map +0 -1
- package/dist/debug-workflow-I3F36JBL.js.map +0 -1
- package/dist/docs-REHST3YB.js.map +0 -1
- package/dist/issues-YU57CHXS.js.map +0 -1
- package/dist/mcp-ZOKM2AUE.js.map +0 -1
- package/dist/record-TNDBT3NY.js.map +0 -1
- package/dist/release-L4IXOHDF.js.map +0 -1
- package/dist/session-RNLKFS2Z.js.map +0 -1
- package/dist/skill-CZ7SHI3P.js +0 -156
- package/dist/skill-CZ7SHI3P.js.map +0 -1
- /package/dist/{feature-flag-3HB5NTMY.js.map → feature-flag-BIPFVVNC.js.map} +0 -0
- /package/dist/{knobs-QJ4IBLCT.js.map → knobs-VYABZESR.js.map} +0 -0
- /package/dist/{local-browser-MKTJ36KY.js.map → local-browser-VPOSJS52.js.map} +0 -0
- /package/dist/{psql-2YPIRMDY.js.map → psql-XO5BB5L5.js.map} +0 -0
- /package/dist/{redis-A7GWM23E.js.map → redis-CQTBPZ6F.js.map} +0 -0
- /package/dist/{src-2WSMYBMJ.js.map → src-F7LQ5PY2.js.map} +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
downloadStorageState,
|
|
4
|
-
|
|
5
|
-
} from "./chunk-
|
|
4
|
+
selectCredential
|
|
5
|
+
} from "./chunk-BOS2YLKH.js";
|
|
6
6
|
import {
|
|
7
7
|
callTool,
|
|
8
8
|
createSession,
|
|
@@ -10,18 +10,19 @@ import {
|
|
|
10
10
|
deleteSession,
|
|
11
11
|
getSession,
|
|
12
12
|
listSessions,
|
|
13
|
-
resolveTargetSession
|
|
14
|
-
|
|
13
|
+
resolveTargetSession,
|
|
14
|
+
swapSessionContext
|
|
15
|
+
} from "./chunk-Z3F373YR.js";
|
|
15
16
|
import {
|
|
16
17
|
getArgValue,
|
|
17
18
|
hasFlag,
|
|
18
19
|
resolveConfig
|
|
19
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-ACRIE2YR.js";
|
|
20
21
|
import {
|
|
21
22
|
BrowserToolExecutor,
|
|
22
23
|
PlaywrightClient,
|
|
23
24
|
dispatchBrowserTool
|
|
24
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-IFOJT3A5.js";
|
|
25
26
|
import "./chunk-XAA5VQ5N.js";
|
|
26
27
|
import {
|
|
27
28
|
consoleLogger
|
|
@@ -29,57 +30,15 @@ import {
|
|
|
29
30
|
import "./chunk-VKVL7WBN.js";
|
|
30
31
|
|
|
31
32
|
// src/session/index.ts
|
|
32
|
-
import
|
|
33
|
+
import process2 from "process";
|
|
33
34
|
|
|
34
35
|
// src/session/credentials.ts
|
|
35
|
-
import process2 from "process";
|
|
36
36
|
async function resolveCredential(argv, credentialArg) {
|
|
37
37
|
const { apiUrl, token } = await resolveConfig(argv);
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
token,
|
|
41
|
-
"/org/credentials",
|
|
42
|
-
"credentials"
|
|
43
|
-
);
|
|
44
|
-
if (credentials.length === 0) {
|
|
45
|
-
console.error("No credentials found for this organization.");
|
|
38
|
+
const credential = await selectCredential(apiUrl, token, credentialArg);
|
|
39
|
+
if (!credential) {
|
|
46
40
|
return null;
|
|
47
41
|
}
|
|
48
|
-
let credential;
|
|
49
|
-
if (!credentialArg) {
|
|
50
|
-
console.log("Select a credential:");
|
|
51
|
-
for (let i = 0; i < credentials.length; i++) {
|
|
52
|
-
const c = credentials[i];
|
|
53
|
-
const propLabel = c.propertyName ? ` (${c.propertyName})` : "";
|
|
54
|
-
console.log(` ${i + 1}. ${c.name}${propLabel}`);
|
|
55
|
-
}
|
|
56
|
-
const readline = await import("readline");
|
|
57
|
-
const rl = readline.createInterface({ input: process2.stdin, output: process2.stdout });
|
|
58
|
-
const answer = await new Promise((resolve) => {
|
|
59
|
-
rl.question("> ", (ans) => {
|
|
60
|
-
rl.close();
|
|
61
|
-
resolve(ans.trim());
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
const idx = parseInt(answer, 10) - 1;
|
|
65
|
-
if (isNaN(idx) || idx < 0 || idx >= credentials.length) {
|
|
66
|
-
console.error("Invalid selection.");
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
credential = credentials[idx];
|
|
70
|
-
} else {
|
|
71
|
-
credential = credentials.find(
|
|
72
|
-
(c) => c.id === credentialArg || c.name.toLowerCase() === credentialArg.toLowerCase()
|
|
73
|
-
);
|
|
74
|
-
if (!credential) {
|
|
75
|
-
console.error(`Credential "${credentialArg}" not found.`);
|
|
76
|
-
console.error("Available credentials:");
|
|
77
|
-
for (const c of credentials) {
|
|
78
|
-
console.error(` - ${c.name} (${c.id})`);
|
|
79
|
-
}
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
42
|
console.log(`Fetching credential "${credential.name}"...`);
|
|
84
43
|
let storageStatePath;
|
|
85
44
|
if (credential.storageStateS3Key) {
|
|
@@ -188,9 +147,6 @@ async function handleCreateSession(body, res) {
|
|
|
188
147
|
browserMode: mode,
|
|
189
148
|
storageStatePath: params.storageStatePath
|
|
190
149
|
});
|
|
191
|
-
if (params.url) {
|
|
192
|
-
await client.navigate(params.url);
|
|
193
|
-
}
|
|
194
150
|
const executor = new BrowserToolExecutor(client, {
|
|
195
151
|
autoSnapshotAfterAction: true,
|
|
196
152
|
includeScreenshotWithSnapshot: true,
|
|
@@ -216,6 +172,11 @@ async function handleCreateSession(body, res) {
|
|
|
216
172
|
data: await toSessionInfo(session)
|
|
217
173
|
};
|
|
218
174
|
json(res, 201, result);
|
|
175
|
+
if (params.url) {
|
|
176
|
+
client.navigate(params.url).catch((err) => {
|
|
177
|
+
consoleLogger.warn(`Initial navigation to ${params.url} failed: ${err}`);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
219
180
|
} catch (err) {
|
|
220
181
|
const result = {
|
|
221
182
|
ok: false,
|
|
@@ -231,15 +192,24 @@ async function handleListSessions(res) {
|
|
|
231
192
|
async function handleGetSession(sessionId, res) {
|
|
232
193
|
const session = sessions.get(sessionId);
|
|
233
194
|
if (!session) {
|
|
234
|
-
json(res, 404, {
|
|
195
|
+
json(res, 404, {
|
|
196
|
+
ok: false,
|
|
197
|
+
error: `Session "${sessionId}" not found`
|
|
198
|
+
});
|
|
235
199
|
return;
|
|
236
200
|
}
|
|
237
|
-
json(res, 200, {
|
|
201
|
+
json(res, 200, {
|
|
202
|
+
ok: true,
|
|
203
|
+
data: await toSessionInfo(session)
|
|
204
|
+
});
|
|
238
205
|
}
|
|
239
206
|
async function handleDeleteSession(sessionId, res) {
|
|
240
207
|
const session = sessions.get(sessionId);
|
|
241
208
|
if (!session) {
|
|
242
|
-
json(res, 404, {
|
|
209
|
+
json(res, 404, {
|
|
210
|
+
ok: false,
|
|
211
|
+
error: `Session "${sessionId}" not found`
|
|
212
|
+
});
|
|
243
213
|
return;
|
|
244
214
|
}
|
|
245
215
|
try {
|
|
@@ -261,10 +231,60 @@ async function handleDeleteAllSessions(res) {
|
|
|
261
231
|
json(res, 200, { ok: true });
|
|
262
232
|
resetIdleTimer();
|
|
263
233
|
}
|
|
234
|
+
async function handleSwapContext(sessionId, body, res) {
|
|
235
|
+
const session = sessions.get(sessionId);
|
|
236
|
+
if (!session) {
|
|
237
|
+
json(res, 404, {
|
|
238
|
+
ok: false,
|
|
239
|
+
error: `Session "${sessionId}" not found`
|
|
240
|
+
});
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const params = parseJson(body);
|
|
244
|
+
try {
|
|
245
|
+
await session.client.swapContext({
|
|
246
|
+
storageStatePath: params.storageStatePath
|
|
247
|
+
});
|
|
248
|
+
if (params.credentialName) {
|
|
249
|
+
session.credentialName = params.credentialName;
|
|
250
|
+
}
|
|
251
|
+
json(res, 200, {
|
|
252
|
+
ok: true,
|
|
253
|
+
data: await toSessionInfo(session)
|
|
254
|
+
});
|
|
255
|
+
} catch (err) {
|
|
256
|
+
json(res, 500, {
|
|
257
|
+
ok: false,
|
|
258
|
+
error: err instanceof Error ? err.message : String(err)
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
async function handleGetStorageState(sessionId, res) {
|
|
263
|
+
const session = sessions.get(sessionId);
|
|
264
|
+
if (!session) {
|
|
265
|
+
json(res, 404, {
|
|
266
|
+
ok: false,
|
|
267
|
+
error: `Session "${sessionId}" not found`
|
|
268
|
+
});
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
const storageState = await session.client.getStorageState();
|
|
273
|
+
json(res, 200, { ok: true, data: storageState });
|
|
274
|
+
} catch (err) {
|
|
275
|
+
json(res, 500, {
|
|
276
|
+
ok: false,
|
|
277
|
+
error: err instanceof Error ? err.message : String(err)
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
264
281
|
async function handleToolCall(sessionId, toolName, body, res) {
|
|
265
282
|
const session = sessions.get(sessionId);
|
|
266
283
|
if (!session) {
|
|
267
|
-
json(res, 404, {
|
|
284
|
+
json(res, 404, {
|
|
285
|
+
ok: false,
|
|
286
|
+
error: `Session "${sessionId}" not found`
|
|
287
|
+
});
|
|
268
288
|
return;
|
|
269
289
|
}
|
|
270
290
|
const args = parseJson(body);
|
|
@@ -316,6 +336,14 @@ async function handleRequest(req, res) {
|
|
|
316
336
|
await handleDeleteSession(segments[1], res);
|
|
317
337
|
return;
|
|
318
338
|
}
|
|
339
|
+
if (method === "POST" && segments[0] === "sessions" && segments[2] === "swap-context" && segments.length === 3) {
|
|
340
|
+
await handleSwapContext(segments[1], body, res);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
if (method === "GET" && segments[0] === "sessions" && segments[2] === "storage-state" && segments.length === 3) {
|
|
344
|
+
await handleGetStorageState(segments[1], res);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
319
347
|
if (method === "POST" && segments[0] === "sessions" && segments[2] === "tools" && segments.length === 4) {
|
|
320
348
|
await handleToolCall(segments[1], segments[3], body, res);
|
|
321
349
|
return;
|
|
@@ -352,6 +380,7 @@ async function cleanup() {
|
|
|
352
380
|
}
|
|
353
381
|
async function startDaemon() {
|
|
354
382
|
const server = createServer(handleRequest);
|
|
383
|
+
server.keepAliveTimeout = 0;
|
|
355
384
|
return new Promise((resolve, reject) => {
|
|
356
385
|
server.listen(0, "127.0.0.1", async () => {
|
|
357
386
|
const addr = server.address();
|
|
@@ -426,7 +455,7 @@ function printToolResult(result, jsonMode) {
|
|
|
426
455
|
}
|
|
427
456
|
if (!result.ok) {
|
|
428
457
|
console.error(`Error: ${result.error}`);
|
|
429
|
-
|
|
458
|
+
process2.exitCode = 1;
|
|
430
459
|
return;
|
|
431
460
|
}
|
|
432
461
|
if (result.text) {
|
|
@@ -449,7 +478,7 @@ async function handleStart(argv) {
|
|
|
449
478
|
const credentialArg = nextArg && !nextArg.startsWith("--") ? nextArg : void 0;
|
|
450
479
|
resolvedCred = await resolveCredential(argv, credentialArg);
|
|
451
480
|
if (!resolvedCred) {
|
|
452
|
-
|
|
481
|
+
process2.exitCode = 1;
|
|
453
482
|
return;
|
|
454
483
|
}
|
|
455
484
|
}
|
|
@@ -466,7 +495,7 @@ async function handleStart(argv) {
|
|
|
466
495
|
}
|
|
467
496
|
if (!result.ok) {
|
|
468
497
|
console.error(`Error: ${result.error}`);
|
|
469
|
-
|
|
498
|
+
process2.exitCode = 1;
|
|
470
499
|
return;
|
|
471
500
|
}
|
|
472
501
|
const session = result.data;
|
|
@@ -474,8 +503,9 @@ async function handleStart(argv) {
|
|
|
474
503
|
if (session.credentialName) {
|
|
475
504
|
console.log(` Credential: ${session.credentialName}`);
|
|
476
505
|
}
|
|
477
|
-
|
|
478
|
-
|
|
506
|
+
const displayUrl = url ?? session.url;
|
|
507
|
+
if (displayUrl) {
|
|
508
|
+
console.log(` URL: ${displayUrl}`);
|
|
479
509
|
}
|
|
480
510
|
}
|
|
481
511
|
async function handleList(argv) {
|
|
@@ -487,13 +517,13 @@ async function handleList(argv) {
|
|
|
487
517
|
}
|
|
488
518
|
if (!result.ok) {
|
|
489
519
|
console.error(`Error: ${result.error}`);
|
|
490
|
-
|
|
520
|
+
process2.exitCode = 1;
|
|
491
521
|
return;
|
|
492
522
|
}
|
|
493
523
|
printSessionTable(result.data ?? []);
|
|
494
524
|
}
|
|
495
525
|
async function handleStatus(argv) {
|
|
496
|
-
const sessionId = argv[0] && !argv[0].startsWith("--") ? argv[0] : void 0;
|
|
526
|
+
const sessionId = getArgValue(argv, "--session") || (argv[0] && !argv[0].startsWith("--") ? argv[0] : void 0);
|
|
497
527
|
const jsonMode = hasFlag(argv, "--json");
|
|
498
528
|
try {
|
|
499
529
|
const target = await resolveTargetSession(sessionId);
|
|
@@ -504,7 +534,7 @@ async function handleStatus(argv) {
|
|
|
504
534
|
}
|
|
505
535
|
if (!result.ok || !result.data) {
|
|
506
536
|
console.error(`Error: ${result.error}`);
|
|
507
|
-
|
|
537
|
+
process2.exitCode = 1;
|
|
508
538
|
return;
|
|
509
539
|
}
|
|
510
540
|
const s = result.data;
|
|
@@ -516,7 +546,7 @@ async function handleStatus(argv) {
|
|
|
516
546
|
console.log(` Started: ${s.startedAt}`);
|
|
517
547
|
} catch (err) {
|
|
518
548
|
console.error(err instanceof Error ? err.message : String(err));
|
|
519
|
-
|
|
549
|
+
process2.exitCode = 1;
|
|
520
550
|
}
|
|
521
551
|
}
|
|
522
552
|
async function handleStop(argv) {
|
|
@@ -529,11 +559,11 @@ async function handleStop(argv) {
|
|
|
529
559
|
console.log("All sessions stopped.");
|
|
530
560
|
} else {
|
|
531
561
|
console.error(`Error: ${result.error}`);
|
|
532
|
-
|
|
562
|
+
process2.exitCode = 1;
|
|
533
563
|
}
|
|
534
564
|
return;
|
|
535
565
|
}
|
|
536
|
-
const sessionId = argv[0] && !argv[0].startsWith("--") ? argv[0] : void 0;
|
|
566
|
+
const sessionId = getArgValue(argv, "--session") || (argv[0] && !argv[0].startsWith("--") ? argv[0] : void 0);
|
|
537
567
|
try {
|
|
538
568
|
const target = await resolveTargetSession(sessionId);
|
|
539
569
|
const result = await deleteSession(target.id);
|
|
@@ -543,11 +573,62 @@ async function handleStop(argv) {
|
|
|
543
573
|
console.log(`Session "${target.id}" stopped.`);
|
|
544
574
|
} else {
|
|
545
575
|
console.error(`Error: ${result.error}`);
|
|
546
|
-
|
|
576
|
+
process2.exitCode = 1;
|
|
547
577
|
}
|
|
548
578
|
} catch (err) {
|
|
549
579
|
console.error(err instanceof Error ? err.message : String(err));
|
|
550
|
-
|
|
580
|
+
process2.exitCode = 1;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
async function handleLoadCredential(argv) {
|
|
584
|
+
const jsonMode = hasFlag(argv, "--json");
|
|
585
|
+
const sessionId = getArgValue(argv, "--session") || (argv[0] && !argv[0].startsWith("--") ? argv[0] : void 0);
|
|
586
|
+
let target;
|
|
587
|
+
try {
|
|
588
|
+
target = await resolveTargetSession(sessionId);
|
|
589
|
+
} catch (err) {
|
|
590
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
591
|
+
process2.exitCode = 1;
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
const credentialIdx = argv.indexOf("--credential");
|
|
595
|
+
const nextArg = credentialIdx !== -1 ? argv[credentialIdx + 1] : void 0;
|
|
596
|
+
const credentialArg = nextArg && !nextArg.startsWith("--") ? nextArg : void 0;
|
|
597
|
+
const storageStatePath = getArgValue(argv, "--storage-state");
|
|
598
|
+
let resolvedStorageStatePath;
|
|
599
|
+
let credentialName;
|
|
600
|
+
if (storageStatePath) {
|
|
601
|
+
resolvedStorageStatePath = storageStatePath;
|
|
602
|
+
credentialName = "(local storage state)";
|
|
603
|
+
} else {
|
|
604
|
+
const resolvedCred = await resolveCredential(argv, credentialArg);
|
|
605
|
+
if (!resolvedCred) {
|
|
606
|
+
process2.exitCode = 1;
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
resolvedStorageStatePath = resolvedCred.storageStatePath;
|
|
610
|
+
credentialName = resolvedCred.credentialName;
|
|
611
|
+
}
|
|
612
|
+
const result = await swapSessionContext(target.id, {
|
|
613
|
+
storageStatePath: resolvedStorageStatePath,
|
|
614
|
+
credentialName
|
|
615
|
+
});
|
|
616
|
+
if (jsonMode) {
|
|
617
|
+
console.log(JSON.stringify(result, null, 2));
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
if (!result.ok) {
|
|
621
|
+
console.error(`Error: ${result.error}`);
|
|
622
|
+
process2.exitCode = 1;
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
const session = result.data;
|
|
626
|
+
console.log(`Credential loaded into session "${session.id}".`);
|
|
627
|
+
if (session.credentialName) {
|
|
628
|
+
console.log(` Credential: ${session.credentialName}`);
|
|
629
|
+
}
|
|
630
|
+
if (session.url) {
|
|
631
|
+
console.log(` URL: ${session.url}`);
|
|
551
632
|
}
|
|
552
633
|
}
|
|
553
634
|
async function handleToolCommand(toolName, argv) {
|
|
@@ -560,7 +641,7 @@ async function handleToolCommand(toolName, argv) {
|
|
|
560
641
|
printToolResult(result, jsonMode);
|
|
561
642
|
} catch (err) {
|
|
562
643
|
console.error(err instanceof Error ? err.message : String(err));
|
|
563
|
-
|
|
644
|
+
process2.exitCode = 1;
|
|
564
645
|
}
|
|
565
646
|
}
|
|
566
647
|
function buildToolArgs(toolName, argv) {
|
|
@@ -604,7 +685,7 @@ function buildToolArgs(toolName, argv) {
|
|
|
604
685
|
args.fields = JSON.parse(fieldsStr);
|
|
605
686
|
} catch {
|
|
606
687
|
console.error("Error: --fields must be valid JSON");
|
|
607
|
-
|
|
688
|
+
process2.exitCode = 1;
|
|
608
689
|
}
|
|
609
690
|
}
|
|
610
691
|
break;
|
|
@@ -675,6 +756,7 @@ function printHelp() {
|
|
|
675
756
|
" list List active sessions",
|
|
676
757
|
" status [<id>] Show session details",
|
|
677
758
|
" stop [<id>] Stop a session (or --all)",
|
|
759
|
+
" load-credential Load a credential into a running session",
|
|
678
760
|
"",
|
|
679
761
|
"Browser actions:",
|
|
680
762
|
" navigate --url <url> Navigate to URL",
|
|
@@ -702,6 +784,10 @@ function printHelp() {
|
|
|
702
784
|
" --url <url> Navigate to URL after launch",
|
|
703
785
|
" --name <label> Name the session",
|
|
704
786
|
"",
|
|
787
|
+
"Load-credential options:",
|
|
788
|
+
" --credential [<name|id>] Use a credential (interactive if no value)",
|
|
789
|
+
" --storage-state <path> Use a local storage state file",
|
|
790
|
+
"",
|
|
705
791
|
"Common options:",
|
|
706
792
|
" --session <id|name> Target a specific session (when multiple)",
|
|
707
793
|
" --json Output raw JSON",
|
|
@@ -733,6 +819,9 @@ async function runSession(argv) {
|
|
|
733
819
|
case "stop":
|
|
734
820
|
await handleStop(rest);
|
|
735
821
|
break;
|
|
822
|
+
case "load-credential":
|
|
823
|
+
await handleLoadCredential(rest);
|
|
824
|
+
break;
|
|
736
825
|
default: {
|
|
737
826
|
const toolName = TOOL_ALIASES[subcommand];
|
|
738
827
|
if (toolName) {
|
|
@@ -740,7 +829,7 @@ async function runSession(argv) {
|
|
|
740
829
|
} else {
|
|
741
830
|
console.error(`Unknown session subcommand: ${subcommand}`);
|
|
742
831
|
printHelp();
|
|
743
|
-
|
|
832
|
+
process2.exitCode = 1;
|
|
744
833
|
}
|
|
745
834
|
}
|
|
746
835
|
}
|
|
@@ -748,4 +837,4 @@ async function runSession(argv) {
|
|
|
748
837
|
export {
|
|
749
838
|
runSession
|
|
750
839
|
};
|
|
751
|
-
//# sourceMappingURL=session-
|
|
840
|
+
//# sourceMappingURL=session-XQGCLWNC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/session/index.ts","../src/session/credentials.ts","../src/session/daemon.ts"],"sourcesContent":["/**\n * CLI session command — `canary session <subcommand>`.\n *\n * Flat subcommands for session lifecycle and browser tool execution.\n * All commands delegate to the session daemon via HTTP.\n *\n * @module\n */\n\nimport process from 'node:process';\nimport { getArgValue, hasFlag } from '../auth.js';\nimport {\n createSession,\n listSessions,\n getSession,\n deleteSession,\n deleteAllSessions,\n swapSessionContext,\n callTool,\n resolveTargetSession,\n} from './daemon-client.js';\nimport { resolveCredential } from './credentials.js';\nimport { runDaemon } from './daemon.js';\nimport type { SessionInfo, ToolResponse } from './types.js';\n\n/* ── Output formatting ───────────────────────────────────────────────── */\n\nfunction formatUptime(startedAt: string): string {\n const seconds = Math.floor((Date.now() - new Date(startedAt).getTime()) / 1000);\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n const secs = seconds % 60;\n if (minutes < 60) return `${minutes}m ${secs}s`;\n const hours = Math.floor(minutes / 60);\n const mins = minutes % 60;\n return `${hours}h ${mins}m`;\n}\n\nfunction printSessionTable(sessions: SessionInfo[]) {\n if (sessions.length === 0) {\n console.log('No active sessions.');\n return;\n }\n\n const header = ['ID', 'NAME', 'MODE', 'CREDENTIAL', 'URL', 'UPTIME'];\n const rows = sessions.map((s) => [\n s.id,\n s.name,\n s.mode,\n s.credentialName ?? '(none)',\n s.url ?? '(none)',\n formatUptime(s.startedAt),\n ]);\n\n // Calculate column widths\n const widths = header.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => r[i].length))\n );\n\n const pad = (str: string, width: number) => str.padEnd(width);\n console.log(header.map((h, i) => pad(h, widths[i])).join(' '));\n for (const row of rows) {\n console.log(row.map((cell, i) => pad(cell, widths[i])).join(' '));\n }\n}\n\nfunction printToolResult(result: ToolResponse, jsonMode: boolean) {\n if (jsonMode) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exitCode = 1;\n return;\n }\n\n if (result.text) {\n console.log(result.text);\n }\n\n if (result.images?.length) {\n console.log(`[${result.images.length} image(s) captured]`);\n }\n}\n\n/* ── Subcommand: start ───────────────────────────────────────────────── */\n\nasync function handleStart(argv: string[]) {\n const headless = hasFlag(argv, '--headless');\n const name = getArgValue(argv, '--name');\n const url = getArgValue(argv, '--url');\n const storageStatePath = getArgValue(argv, '--storage-state');\n const jsonMode = hasFlag(argv, '--json');\n\n // Credential handling\n const credentialIdx = argv.indexOf('--credential');\n let resolvedCred: { storageStatePath: string | undefined; credentialName: string } | null = null;\n\n if (credentialIdx !== -1) {\n // Check if next arg is a value or another flag\n const nextArg = argv[credentialIdx + 1];\n const credentialArg = nextArg && !nextArg.startsWith('--') ? nextArg : undefined;\n resolvedCred = await resolveCredential(argv, credentialArg);\n if (!resolvedCred) {\n process.exitCode = 1;\n return;\n }\n }\n\n const result = await createSession({\n headless,\n name,\n url,\n storageStatePath: resolvedCred?.storageStatePath ?? storageStatePath,\n credentialName: resolvedCred?.credentialName,\n });\n\n if (jsonMode) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exitCode = 1;\n return;\n }\n\n const session = result.data!;\n console.log(`Session \"${session.id}\" started (${session.mode})`);\n if (session.credentialName) {\n console.log(` Credential: ${session.credentialName}`);\n }\n // Show the requested URL if provided, since the daemon responds before navigation completes\n const displayUrl = url ?? session.url;\n if (displayUrl) {\n console.log(` URL: ${displayUrl}`);\n }\n}\n\n/* ── Subcommand: list ────────────────────────────────────────────────── */\n\nasync function handleList(argv: string[]) {\n const jsonMode = hasFlag(argv, '--json');\n const result = await listSessions();\n\n if (jsonMode) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exitCode = 1;\n return;\n }\n\n printSessionTable(result.data ?? []);\n}\n\n/* ── Subcommand: status ──────────────────────────────────────────────── */\n\nasync function handleStatus(argv: string[]) {\n const sessionId =\n getArgValue(argv, '--session') ||\n (argv[0] && !argv[0].startsWith('--') ? argv[0] : undefined);\n const jsonMode = hasFlag(argv, '--json');\n\n try {\n const target = await resolveTargetSession(sessionId);\n const result = await getSession(target.id);\n\n if (jsonMode) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n if (!result.ok || !result.data) {\n console.error(`Error: ${result.error}`);\n process.exitCode = 1;\n return;\n }\n\n const s = result.data;\n console.log(`Session: ${s.id} (${s.name})`);\n console.log(` Mode: ${s.mode}`);\n console.log(` Credential: ${s.credentialName ?? '(none)'}`);\n console.log(` URL: ${s.url ?? '(none)'}`);\n console.log(` Uptime: ${formatUptime(s.startedAt)}`);\n console.log(` Started: ${s.startedAt}`);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exitCode = 1;\n }\n}\n\n/* ── Subcommand: stop ────────────────────────────────────────────────── */\n\nasync function handleStop(argv: string[]) {\n const jsonMode = hasFlag(argv, '--json');\n\n if (hasFlag(argv, '--all')) {\n const result = await deleteAllSessions();\n if (jsonMode) {\n console.log(JSON.stringify(result, null, 2));\n } else if (result.ok) {\n console.log('All sessions stopped.');\n } else {\n console.error(`Error: ${result.error}`);\n process.exitCode = 1;\n }\n return;\n }\n\n const sessionId =\n getArgValue(argv, '--session') ||\n (argv[0] && !argv[0].startsWith('--') ? argv[0] : undefined);\n\n try {\n const target = await resolveTargetSession(sessionId);\n const result = await deleteSession(target.id);\n\n if (jsonMode) {\n console.log(JSON.stringify(result, null, 2));\n } else if (result.ok) {\n console.log(`Session \"${target.id}\" stopped.`);\n } else {\n console.error(`Error: ${result.error}`);\n process.exitCode = 1;\n }\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exitCode = 1;\n }\n}\n\n/* ── Subcommand: load-credential ────────────────────────────────────── */\n\nasync function handleLoadCredential(argv: string[]) {\n const jsonMode = hasFlag(argv, '--json');\n const sessionId =\n getArgValue(argv, '--session') ||\n (argv[0] && !argv[0].startsWith('--') ? argv[0] : undefined);\n\n // Resolve which session to target\n let target;\n try {\n target = await resolveTargetSession(sessionId);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exitCode = 1;\n return;\n }\n\n // Credential selection (interactive by default, or --credential <name|id>)\n const credentialIdx = argv.indexOf('--credential');\n const nextArg = credentialIdx !== -1 ? argv[credentialIdx + 1] : undefined;\n const credentialArg = nextArg && !nextArg.startsWith('--') ? nextArg : undefined;\n\n // Also support --storage-state for local files\n const storageStatePath = getArgValue(argv, '--storage-state');\n\n let resolvedStorageStatePath: string | undefined;\n let credentialName: string | undefined;\n\n if (storageStatePath) {\n resolvedStorageStatePath = storageStatePath;\n credentialName = '(local storage state)';\n } else {\n // Interactive or named credential resolution\n const resolvedCred = await resolveCredential(argv, credentialArg);\n if (!resolvedCred) {\n process.exitCode = 1;\n return;\n }\n resolvedStorageStatePath = resolvedCred.storageStatePath;\n credentialName = resolvedCred.credentialName;\n }\n\n const result = await swapSessionContext(target.id, {\n storageStatePath: resolvedStorageStatePath,\n credentialName,\n });\n\n if (jsonMode) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exitCode = 1;\n return;\n }\n\n const session = result.data!;\n console.log(`Credential loaded into session \"${session.id}\".`);\n if (session.credentialName) {\n console.log(` Credential: ${session.credentialName}`);\n }\n if (session.url) {\n console.log(` URL: ${session.url}`);\n }\n}\n\n/* ── Browser tool subcommands ────────────────────────────────────────── */\n\nasync function handleToolCommand(toolName: string, argv: string[]) {\n const sessionIdOrName = getArgValue(argv, '--session');\n const jsonMode = hasFlag(argv, '--json');\n\n try {\n const target = await resolveTargetSession(sessionIdOrName);\n const args = buildToolArgs(toolName, argv);\n const result = await callTool(target.id, toolName, args);\n printToolResult(result, jsonMode);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exitCode = 1;\n }\n}\n\nfunction buildToolArgs(toolName: string, argv: string[]): Record<string, unknown> {\n const args: Record<string, unknown> = {};\n\n switch (toolName) {\n case 'navigate':\n args.url = getArgValue(argv, '--url');\n break;\n\n case 'snapshot':\n args.search = getArgValue(argv, '--search');\n args.mode = getArgValue(argv, '--mode') ?? 'tree';\n break;\n\n case 'screenshot':\n args.fullPage = hasFlag(argv, '--full-page');\n args.label = getArgValue(argv, '--label');\n args.returnImage = true;\n break;\n\n case 'evaluate':\n args.function = getArgValue(argv, '--js');\n break;\n\n case 'click': {\n const ref = getArgValue(argv, '--ref');\n const x = getArgValue(argv, '--x');\n const y = getArgValue(argv, '--y');\n if (ref) args.ref = ref;\n if (x) args.x = parseInt(x, 10);\n if (y) args.y = parseInt(y, 10);\n args.element = getArgValue(argv, '--element') ?? '';\n break;\n }\n\n case 'type':\n args.ref = getArgValue(argv, '--ref');\n args.text = getArgValue(argv, '--text');\n args.element = getArgValue(argv, '--element') ?? '';\n args.submit = hasFlag(argv, '--submit');\n break;\n\n case 'fill_form': {\n const fieldsStr = getArgValue(argv, '--fields');\n if (fieldsStr) {\n try {\n args.fields = JSON.parse(fieldsStr);\n } catch {\n console.error('Error: --fields must be valid JSON');\n process.exitCode = 1;\n }\n }\n break;\n }\n\n case 'select_option':\n args.ref = getArgValue(argv, '--ref');\n args.value = getArgValue(argv, '--value');\n args.element = getArgValue(argv, '--element') ?? '';\n break;\n\n case 'press_key':\n args.key = getArgValue(argv, '--key');\n break;\n\n case 'scroll':\n args.direction = getArgValue(argv, '--direction') ?? 'down';\n {\n const amount = getArgValue(argv, '--amount');\n if (amount) args.amount = parseInt(amount, 10);\n }\n break;\n\n case 'hover':\n args.ref = getArgValue(argv, '--ref');\n args.element = getArgValue(argv, '--element') ?? '';\n break;\n\n case 'tabs': {\n args.action = getArgValue(argv, '--action') ?? 'list';\n const index = getArgValue(argv, '--index');\n if (index) args.index = parseInt(index, 10);\n break;\n }\n\n case 'wait_for': {\n args.text = getArgValue(argv, '--text');\n const timeout = getArgValue(argv, '--timeout');\n if (timeout) args.timeout = parseInt(timeout, 10);\n break;\n }\n\n case 'console_messages':\n args.onlyErrors = hasFlag(argv, '--only-errors');\n break;\n\n // navigate_back, network_requests, close, list_downloads, read_download\n // have no special args or use defaults\n }\n\n return args;\n}\n\n/* ── Command aliases ─────────────────────────────────────────────────── */\n\n/** Map flat CLI subcommands to browser tool names */\nconst TOOL_ALIASES: Record<string, string> = {\n navigate: 'navigate',\n back: 'navigate_back',\n snapshot: 'snapshot',\n screenshot: 'screenshot',\n evaluate: 'evaluate',\n click: 'click',\n type: 'type',\n fill: 'fill_form',\n select: 'select_option',\n press: 'press_key',\n scroll: 'scroll',\n hover: 'hover',\n drag: 'drag',\n tabs: 'tabs',\n wait: 'wait_for',\n console: 'console_messages',\n network: 'network_requests',\n};\n\n/* ── Help ────────────────────────────────────────────────────────────── */\n\nfunction printHelp() {\n console.log(\n [\n 'Usage: canary session <subcommand> [options]',\n '',\n 'Session lifecycle:',\n ' start [options] Start a new browser session',\n ' list List active sessions',\n ' status [<id>] Show session details',\n ' stop [<id>] Stop a session (or --all)',\n ' load-credential Load a credential into a running session',\n '',\n 'Browser actions:',\n ' navigate --url <url> Navigate to URL',\n ' back Navigate back',\n ' snapshot [--search <text>] [--mode tree|screenshot|both]',\n ' screenshot [--full-page] [--label <text>]',\n ' evaluate --js <expression> Evaluate JavaScript',\n ' click --ref <ref> [--element <desc>]',\n ' click --x <n> --y <n> [--element <desc>]',\n ' type --ref <ref> --text <text> [--submit]',\n ' fill --fields \\'[{\"ref\":\"e1\",\"value\":\"test\"}]\\'',\n ' select --ref <ref> --value <val> [--element <desc>]',\n ' press --key <key> Press keyboard key',\n ' scroll --direction <dir> [--amount <n>]',\n ' hover --ref <ref> [--element <desc>]',\n ' tabs [--action list|new|close|select] [--index <n>]',\n ' wait --text <text> [--timeout <ms>]',\n ' console [--only-errors] Show console messages',\n ' network Show network requests',\n '',\n 'Start options:',\n ' --credential [<name|id>] Use a credential (interactive if no value)',\n ' --storage-state <path> Use a local storage state file',\n ' --headless Run browser without visible UI',\n ' --url <url> Navigate to URL after launch',\n ' --name <label> Name the session',\n '',\n 'Load-credential options:',\n ' --credential [<name|id>] Use a credential (interactive if no value)',\n ' --storage-state <path> Use a local storage state file',\n '',\n 'Common options:',\n ' --session <id|name> Target a specific session (when multiple)',\n ' --json Output raw JSON',\n ' --env <env> Environment for credential resolution',\n ' -h, --help Show this help',\n ].join('\\n')\n );\n}\n\n/* ── Main entry ──────────────────────────────────────────────────────── */\n\nexport async function runSession(argv: string[]) {\n const [subcommand, ...rest] = argv;\n\n if (!subcommand || subcommand === 'help' || hasFlag(argv, '-h', '--help')) {\n printHelp();\n return;\n }\n\n // Internal: daemon process mode\n if (subcommand === 'daemon') {\n await runDaemon();\n return;\n }\n\n switch (subcommand) {\n case 'start':\n await handleStart(rest);\n break;\n case 'list':\n await handleList(rest);\n break;\n case 'status':\n await handleStatus(rest);\n break;\n case 'stop':\n await handleStop(rest);\n break;\n case 'load-credential':\n await handleLoadCredential(rest);\n break;\n default: {\n // Check for tool alias\n const toolName = TOOL_ALIASES[subcommand];\n if (toolName) {\n await handleToolCommand(toolName, rest);\n } else {\n console.error(`Unknown session subcommand: ${subcommand}`);\n printHelp();\n process.exitCode = 1;\n }\n }\n }\n}\n","/**\n * Credential resolution and storage state download for session commands.\n *\n * Uses shared selectCredential from cli-helpers for interactive selection,\n * then downloads the storage state for the selected credential.\n *\n * @module\n */\n\nimport { resolveConfig } from '../auth.js';\nimport { selectCredential, downloadStorageState } from '../cli-helpers.js';\n\n/**\n * Resolve a credential and download its storage state.\n *\n * @param argv - CLI arguments (for --env, --token, --api-url resolution)\n * @param credentialArg - Credential name, ID, or undefined for interactive selection\n * @returns Object with storageStatePath and credentialName, or null if no match\n */\nexport async function resolveCredential(\n argv: string[],\n credentialArg: string | undefined\n): Promise<{ storageStatePath: string | undefined; credentialName: string } | null> {\n const { apiUrl, token } = await resolveConfig(argv);\n\n const credential = await selectCredential(apiUrl, token, credentialArg);\n if (!credential) {\n return null;\n }\n\n console.log(`Fetching credential \"${credential.name}\"...`);\n\n let storageStatePath: string | undefined;\n if (credential.storageStateS3Key) {\n storageStatePath = await downloadStorageState({\n apiUrl,\n token,\n propertyId: credential.propertyId,\n credentialId: credential.id,\n prefix: 'session-ss',\n });\n\n if (storageStatePath) {\n console.log('Downloaded storage state.');\n } else {\n console.warn('Warning: Could not download storage state. Starting without auth.');\n }\n } else {\n console.log('Credential has no storage state. Starting without auth.');\n }\n\n return {\n storageStatePath,\n credentialName: credential.name,\n };\n}\n","/**\n * Session daemon — lightweight HTTP server that owns all browser sessions.\n *\n * Runs on localhost with an OS-assigned port. Both CLI and MCP delegate\n * browser lifecycle and tool execution to this daemon.\n *\n * @module\n */\n\nimport { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport os from 'node:os';\nimport {\n PlaywrightClient,\n BrowserToolExecutor,\n consoleLogger,\n dispatchBrowserTool,\n} from '@chatsdet/browser-core';\nimport type {\n DaemonState,\n SessionInfo,\n CreateSessionRequest,\n SwapContextRequest,\n DaemonResponse,\n ToolResponse,\n} from './types.js';\n\nconst PIDFILE_DIR = path.join(os.homedir(), '.config', 'canary-cli');\nconst PIDFILE_PATH = path.join(PIDFILE_DIR, 'daemon.json');\nconst IDLE_TIMEOUT_MS = 60_000;\n\ninterface ManagedSession {\n id: string;\n name: string;\n mode: 'headed' | 'headless';\n credentialName?: string;\n client: PlaywrightClient;\n executor: BrowserToolExecutor;\n startedAt: string;\n}\n\nconst sessions = new Map<string, ManagedSession>();\nlet nextId = 1;\nlet idleTimer: ReturnType<typeof setTimeout> | null = null;\n\nfunction resetIdleTimer() {\n if (idleTimer) clearTimeout(idleTimer);\n if (sessions.size === 0) {\n idleTimer = setTimeout(async () => {\n if (sessions.size === 0) {\n await removePidfile();\n process.exit(0);\n }\n }, IDLE_TIMEOUT_MS);\n }\n}\n\nfunction generateId(): string {\n return `s${nextId++}`;\n}\n\nasync function getSessionUrl(session: ManagedSession): Promise<string | undefined> {\n try {\n return await session.client.getCurrentUrl();\n } catch {\n return undefined;\n }\n}\n\nasync function toSessionInfo(s: ManagedSession): Promise<SessionInfo> {\n return {\n id: s.id,\n name: s.name,\n mode: s.mode,\n credentialName: s.credentialName,\n url: await getSessionUrl(s),\n startedAt: s.startedAt,\n };\n}\n\n/* ── Request parsing helpers ─────────────────────────────────────────── */\n\nasync function readBody(req: IncomingMessage): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);\n }\n return Buffer.concat(chunks).toString('utf-8');\n}\n\nfunction parseJson(body: string): Record<string, unknown> {\n if (!body.trim()) return {};\n try {\n return JSON.parse(body);\n } catch {\n return {};\n }\n}\n\nfunction json(res: ServerResponse, status: number, data: unknown) {\n const body = JSON.stringify(data);\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Content-Length': Buffer.byteLength(body),\n });\n res.end(body);\n}\n\nfunction parseRoute(url: string): { path: string[]; query: Record<string, string> } {\n const [pathname] = url.split('?');\n const segments = pathname.split('/').filter(Boolean);\n return { path: segments, query: {} };\n}\n\n/* ── Route handlers ──────────────────────────────────────────────────── */\n\nasync function handleHealth(res: ServerResponse) {\n json(res, 200, { ok: true, sessions: sessions.size });\n}\n\nasync function handleCreateSession(body: string, res: ServerResponse) {\n const params = parseJson(body) as CreateSessionRequest;\n const id = generateId();\n const name = params.name ?? id;\n const mode = params.headless ? 'headless' : 'headed';\n\n try {\n const client = new PlaywrightClient({ logger: consoleLogger });\n await client.connect({\n browserMode: mode,\n storageStatePath: params.storageStatePath,\n });\n\n const executor = new BrowserToolExecutor(client, {\n autoSnapshotAfterAction: true,\n includeScreenshotWithSnapshot: true,\n clickValidation: true,\n logger: consoleLogger,\n });\n\n const session: ManagedSession = {\n id,\n name,\n mode,\n credentialName: params.credentialName,\n client,\n executor,\n startedAt: new Date().toISOString(),\n };\n\n sessions.set(id, session);\n if (idleTimer) {\n clearTimeout(idleTimer);\n idleTimer = null;\n }\n\n const result: DaemonResponse<SessionInfo> = {\n ok: true,\n data: await toSessionInfo(session),\n };\n json(res, 201, result);\n\n // Navigate after responding — navigation can take 30+ seconds and the\n // CLI intentionally does not wait so callers can issue commands in parallel.\n if (params.url) {\n client.navigate(params.url).catch((err) => {\n consoleLogger.warn(`Initial navigation to ${params.url} failed: ${err}`);\n });\n }\n } catch (err) {\n const result: DaemonResponse = {\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n };\n json(res, 500, result);\n }\n}\n\nasync function handleListSessions(res: ServerResponse) {\n const list = await Promise.all(Array.from(sessions.values()).map(toSessionInfo));\n json(res, 200, { ok: true, data: list } satisfies DaemonResponse<SessionInfo[]>);\n}\n\nasync function handleGetSession(sessionId: string, res: ServerResponse) {\n const session = sessions.get(sessionId);\n if (!session) {\n json(res, 404, {\n ok: false,\n error: `Session \"${sessionId}\" not found`,\n } satisfies DaemonResponse);\n return;\n }\n json(res, 200, {\n ok: true,\n data: await toSessionInfo(session),\n } satisfies DaemonResponse<SessionInfo>);\n}\n\nasync function handleDeleteSession(sessionId: string, res: ServerResponse) {\n const session = sessions.get(sessionId);\n if (!session) {\n json(res, 404, {\n ok: false,\n error: `Session \"${sessionId}\" not found`,\n } satisfies DaemonResponse);\n return;\n }\n\n try {\n await session.client.disconnect();\n } catch {\n // Best effort\n }\n sessions.delete(sessionId);\n json(res, 200, { ok: true } satisfies DaemonResponse);\n resetIdleTimer();\n}\n\nasync function handleDeleteAllSessions(res: ServerResponse) {\n for (const session of sessions.values()) {\n try {\n await session.client.disconnect();\n } catch {\n // Best effort\n }\n }\n sessions.clear();\n json(res, 200, { ok: true } satisfies DaemonResponse);\n resetIdleTimer();\n}\n\nasync function handleSwapContext(sessionId: string, body: string, res: ServerResponse) {\n const session = sessions.get(sessionId);\n if (!session) {\n json(res, 404, {\n ok: false,\n error: `Session \"${sessionId}\" not found`,\n } satisfies DaemonResponse);\n return;\n }\n\n const params = parseJson(body) as SwapContextRequest;\n\n try {\n await session.client.swapContext({\n storageStatePath: params.storageStatePath,\n });\n\n if (params.credentialName) {\n session.credentialName = params.credentialName;\n }\n\n json(res, 200, {\n ok: true,\n data: await toSessionInfo(session),\n } satisfies DaemonResponse<SessionInfo>);\n } catch (err) {\n json(res, 500, {\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n } satisfies DaemonResponse);\n }\n}\n\nasync function handleGetStorageState(sessionId: string, res: ServerResponse) {\n const session = sessions.get(sessionId);\n if (!session) {\n json(res, 404, {\n ok: false,\n error: `Session \"${sessionId}\" not found`,\n } satisfies DaemonResponse);\n return;\n }\n\n try {\n const storageState = await session.client.getStorageState();\n json(res, 200, { ok: true, data: storageState } satisfies DaemonResponse);\n } catch (err) {\n json(res, 500, {\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n } satisfies DaemonResponse);\n }\n}\n\nasync function handleToolCall(\n sessionId: string,\n toolName: string,\n body: string,\n res: ServerResponse\n) {\n const session = sessions.get(sessionId);\n if (!session) {\n json(res, 404, {\n ok: false,\n error: `Session \"${sessionId}\" not found`,\n } satisfies DaemonResponse);\n return;\n }\n\n const args = parseJson(body);\n const fullToolName = toolName.startsWith('browser_') ? toolName : `browser_${toolName}`;\n\n try {\n const result = await dispatchBrowserTool(session.executor, fullToolName, args);\n\n if (typeof result === 'string') {\n json(res, 200, { ok: true, text: result } satisfies ToolResponse);\n } else {\n json(res, 200, {\n ok: true,\n text: result.text,\n images: result.images,\n } satisfies ToolResponse);\n }\n } catch (err) {\n json(res, 500, {\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n } satisfies ToolResponse);\n }\n}\n\n/* ── Server routing ──────────────────────────────────────────────────── */\n\nasync function handleRequest(req: IncomingMessage, res: ServerResponse) {\n const method = req.method ?? 'GET';\n const { path: segments } = parseRoute(req.url ?? '/');\n const body = method === 'POST' || method === 'DELETE' ? await readBody(req) : '';\n\n try {\n // GET /health\n if (method === 'GET' && segments[0] === 'health') {\n await handleHealth(res);\n return;\n }\n\n // POST /sessions\n if (method === 'POST' && segments[0] === 'sessions' && segments.length === 1) {\n await handleCreateSession(body, res);\n return;\n }\n\n // GET /sessions\n if (method === 'GET' && segments[0] === 'sessions' && segments.length === 1) {\n await handleListSessions(res);\n return;\n }\n\n // GET /sessions/:id\n if (method === 'GET' && segments[0] === 'sessions' && segments.length === 2) {\n await handleGetSession(segments[1], res);\n return;\n }\n\n // DELETE /sessions (all)\n if (method === 'DELETE' && segments[0] === 'sessions' && segments.length === 1) {\n await handleDeleteAllSessions(res);\n return;\n }\n\n // DELETE /sessions/:id\n if (method === 'DELETE' && segments[0] === 'sessions' && segments.length === 2) {\n await handleDeleteSession(segments[1], res);\n return;\n }\n\n // POST /sessions/:id/swap-context\n if (\n method === 'POST' &&\n segments[0] === 'sessions' &&\n segments[2] === 'swap-context' &&\n segments.length === 3\n ) {\n await handleSwapContext(segments[1], body, res);\n return;\n }\n\n // GET /sessions/:id/storage-state\n if (\n method === 'GET' &&\n segments[0] === 'sessions' &&\n segments[2] === 'storage-state' &&\n segments.length === 3\n ) {\n await handleGetStorageState(segments[1], res);\n return;\n }\n\n // POST /sessions/:id/tools/:toolName\n if (\n method === 'POST' &&\n segments[0] === 'sessions' &&\n segments[2] === 'tools' &&\n segments.length === 4\n ) {\n await handleToolCall(segments[1], segments[3], body, res);\n return;\n }\n\n json(res, 404, { ok: false, error: 'Not found' });\n } catch (err) {\n json(res, 500, { ok: false, error: err instanceof Error ? err.message : String(err) });\n }\n}\n\n/* ── Pidfile management ──────────────────────────────────────────────── */\n\nasync function writePidfile(port: number) {\n await fs.mkdir(PIDFILE_DIR, { recursive: true, mode: 0o700 });\n const state: DaemonState = {\n pid: process.pid,\n port,\n startedAt: new Date().toISOString(),\n };\n await fs.writeFile(PIDFILE_PATH, JSON.stringify(state, null, 2), { mode: 0o600 });\n}\n\nasync function removePidfile() {\n try {\n await fs.unlink(PIDFILE_PATH);\n } catch {\n // Already removed\n }\n}\n\n/* ── Cleanup ─────────────────────────────────────────────────────────── */\n\nasync function cleanup() {\n for (const session of sessions.values()) {\n try {\n await session.client.disconnect();\n } catch {\n // Best effort\n }\n }\n sessions.clear();\n await removePidfile();\n}\n\n/* ── Main entry ──────────────────────────────────────────────────────── */\n\nasync function startDaemon(): Promise<{ port: number }> {\n const server = createServer(handleRequest);\n // Disable keep-alive to prevent \"other side closed\" socket errors when\n // the client reuses a connection the server is about to close.\n server.keepAliveTimeout = 0;\n\n return new Promise((resolve, reject) => {\n server.listen(0, '127.0.0.1', async () => {\n const addr = server.address();\n if (!addr || typeof addr === 'string') {\n reject(new Error('Failed to get server address'));\n return;\n }\n\n const port = addr.port;\n await writePidfile(port);\n resetIdleTimer();\n\n // Graceful shutdown\n process.on('SIGINT', async () => {\n await cleanup();\n process.exit(0);\n });\n process.on('SIGTERM', async () => {\n await cleanup();\n process.exit(0);\n });\n process.on('exit', () => {\n removePidfile().catch(() => {});\n });\n\n resolve({ port });\n });\n\n server.on('error', reject);\n });\n}\n\n/** CLI entry point: `canary session daemon` (internal, spawned by daemon-client) */\nexport async function runDaemon() {\n const { port } = await startDaemon();\n // Write the port to stdout so the spawner can read it\n process.stdout.write(`DAEMON_READY:${port}\\n`);\n}\n"],"mappings":"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","names":["process","sessions","process"]}
|