@canaryai/cli 0.2.13 → 0.2.14

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.
Files changed (35) hide show
  1. package/dist/{chunk-Z3F373YR.js → chunk-4A4G5KTC.js} +2 -1
  2. package/dist/chunk-4A4G5KTC.js.map +1 -0
  3. package/dist/{chunk-IFOJT3A5.js → chunk-6IAPGYZQ.js} +38 -16
  4. package/dist/{chunk-IFOJT3A5.js.map → chunk-6IAPGYZQ.js.map} +1 -1
  5. package/dist/{chunk-SVU2XTYZ.js → chunk-ZQF72UTG.js} +2 -2
  6. package/dist/{debug-workflow-K2LL6CO4.js → debug-workflow-DIQZDFMN.js} +3 -3
  7. package/dist/{docs-SR7CW24Y.js → docs-CSVSGIGW.js} +45 -2
  8. package/dist/docs-CSVSGIGW.js.map +1 -0
  9. package/dist/index.js +8 -8
  10. package/dist/{init-KXAVWHYE.js → init-BTDX5N6P.js} +2 -2
  11. package/dist/{local-34FX3M5K.js → local-ZPVM4BXX.js} +4 -4
  12. package/dist/{local-browser-VPOSJS52.js → local-browser-WV4IH2DU.js} +3 -3
  13. package/dist/{login-MSIM2VIH.js → login-W4GXV3VA.js} +2 -2
  14. package/dist/{mcp-YBR7G254.js → mcp-YER5GQG7.js} +4 -4
  15. package/dist/{record-DXXQHPGT.js → record-KRS2PHMW.js} +2 -2
  16. package/dist/{session-XQGCLWNC.js → session-CLWAVJ2K.js} +3 -3
  17. package/dist/{src-F7LQ5PY2.js → src-WLOHOI6P.js} +2 -2
  18. package/dist/{start-ZOMUD6LW.js → start-CNNQUP5I.js} +2 -2
  19. package/dist/{workflow-5UZTKX7X.js → workflow-XXL4H5R4.js} +3 -2
  20. package/dist/workflow-XXL4H5R4.js.map +1 -0
  21. package/package.json +1 -1
  22. package/dist/chunk-Z3F373YR.js.map +0 -1
  23. package/dist/docs-SR7CW24Y.js.map +0 -1
  24. package/dist/workflow-5UZTKX7X.js.map +0 -1
  25. /package/dist/{chunk-SVU2XTYZ.js.map → chunk-ZQF72UTG.js.map} +0 -0
  26. /package/dist/{debug-workflow-K2LL6CO4.js.map → debug-workflow-DIQZDFMN.js.map} +0 -0
  27. /package/dist/{init-KXAVWHYE.js.map → init-BTDX5N6P.js.map} +0 -0
  28. /package/dist/{local-34FX3M5K.js.map → local-ZPVM4BXX.js.map} +0 -0
  29. /package/dist/{local-browser-VPOSJS52.js.map → local-browser-WV4IH2DU.js.map} +0 -0
  30. /package/dist/{login-MSIM2VIH.js.map → login-W4GXV3VA.js.map} +0 -0
  31. /package/dist/{mcp-YBR7G254.js.map → mcp-YER5GQG7.js.map} +0 -0
  32. /package/dist/{record-DXXQHPGT.js.map → record-KRS2PHMW.js.map} +0 -0
  33. /package/dist/{session-XQGCLWNC.js.map → session-CLWAVJ2K.js.map} +0 -0
  34. /package/dist/{src-F7LQ5PY2.js.map → src-WLOHOI6P.js.map} +0 -0
  35. /package/dist/{start-ZOMUD6LW.js.map → start-CNNQUP5I.js.map} +0 -0
@@ -75,6 +75,7 @@ async function spawnDaemon() {
75
75
  const match = output.match(/DAEMON_READY:(\d+)/);
76
76
  if (match) {
77
77
  clearTimeout(timeout);
78
+ child.stdout.destroy();
78
79
  resolve(parseInt(match[1], 10));
79
80
  }
80
81
  });
@@ -190,4 +191,4 @@ export {
190
191
  callTool,
191
192
  resolveTargetSession
192
193
  };
193
- //# sourceMappingURL=chunk-Z3F373YR.js.map
194
+ //# sourceMappingURL=chunk-4A4G5KTC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/session/daemon-client.ts"],"sourcesContent":["/**\n * Daemon client — HTTP client for the session daemon.\n *\n * Handles pidfile read/write, stale PID detection, auto-start,\n * and provides typed HTTP helpers for daemon communication.\n *\n * @module\n */\n\nimport { spawn } from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport type {\n DaemonState,\n DaemonResponse,\n SessionInfo,\n CreateSessionRequest,\n SwapContextRequest,\n ToolResponse,\n StorageStateResponse,\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 HEALTH_POLL_INTERVAL_MS = 100;\nconst HEALTH_POLL_TIMEOUT_MS = 15_000;\n\n/* ── Pidfile helpers ─────────────────────────────────────────────────── */\n\nasync function readPidfile(): Promise<DaemonState | null> {\n try {\n const content = await fs.readFile(PIDFILE_PATH, 'utf-8');\n return JSON.parse(content) as DaemonState;\n } catch {\n return null;\n }\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\n/* ── HTTP helpers ────────────────────────────────────────────────────── */\n\nasync function daemonFetch(\n port: number,\n method: string,\n path: string,\n body?: unknown\n): Promise<unknown> {\n const url = `http://127.0.0.1:${port}${path}`;\n const res = await fetch(url, {\n method,\n headers: body ? { 'Content-Type': 'application/json' } : undefined,\n body: body ? JSON.stringify(body) : undefined,\n });\n return res.json();\n}\n\nasync function healthCheck(port: number): Promise<boolean> {\n try {\n const res = await fetch(`http://127.0.0.1:${port}/health`, {\n signal: AbortSignal.timeout(2000),\n });\n return res.ok;\n } catch {\n return false;\n }\n}\n\n/* ── Auto-start ──────────────────────────────────────────────────────── */\n\nasync function spawnDaemon(): Promise<number> {\n // Resolve the canary CLI entry point\n // In source: this file is src/session/daemon-client.ts → ../index.ts\n // In dist: this file is dist/chunk-*.js → ./index.js (flat)\n const dir = path.dirname(new URL(import.meta.url).pathname);\n const candidates = [\n path.resolve(dir, '..', 'index.ts'), // source layout\n path.resolve(dir, 'index.js'), // dist layout (flat)\n path.resolve(dir, '..', 'index.js'), // fallback\n ];\n const cliEntry = candidates.find((p) => existsSync(p));\n if (!cliEntry) {\n throw new Error(`Cannot find CLI entry point. Searched: ${candidates.join(', ')}`);\n }\n\n const child = spawn(process.execPath, [cliEntry, 'session', 'daemon'], {\n detached: true,\n stdio: ['ignore', 'pipe', 'ignore'],\n env: { ...process.env },\n });\n\n child.unref();\n\n // Wait for \"DAEMON_READY:<port>\" on stdout\n return new Promise<number>((resolve, reject) => {\n let output = '';\n const timeout = setTimeout(() => {\n reject(new Error('Daemon startup timed out'));\n }, HEALTH_POLL_TIMEOUT_MS);\n\n child.stdout!.on('data', (data: Buffer) => {\n output += data.toString();\n const match = output.match(/DAEMON_READY:(\\d+)/);\n if (match) {\n clearTimeout(timeout);\n child.stdout!.destroy(); // Release the pipe so the CLI process can exit\n resolve(parseInt(match[1], 10));\n }\n });\n\n child.on('error', (err) => {\n clearTimeout(timeout);\n reject(err);\n });\n\n child.on('exit', (code) => {\n clearTimeout(timeout);\n if (!output.includes('DAEMON_READY')) {\n reject(new Error(`Daemon exited with code ${code} before becoming ready`));\n }\n });\n });\n}\n\n/* ── Public API ──────────────────────────────────────────────────────── */\n\n/**\n * Ensure the daemon is running and return its port.\n * Starts the daemon if needed, cleans up stale pidfiles.\n */\nasync function ensureDaemon(): Promise<number> {\n const state = await readPidfile();\n\n if (state) {\n if (isProcessAlive(state.pid)) {\n // Verify it actually responds\n if (await healthCheck(state.port)) {\n return state.port;\n }\n }\n // Stale pidfile — clean up\n try {\n await fs.unlink(PIDFILE_PATH);\n } catch {\n // ignore\n }\n }\n\n // Spawn new daemon\n const port = await spawnDaemon();\n\n // Poll until healthy\n const deadline = Date.now() + HEALTH_POLL_TIMEOUT_MS;\n while (Date.now() < deadline) {\n if (await healthCheck(port)) return port;\n await new Promise((r) => setTimeout(r, HEALTH_POLL_INTERVAL_MS));\n }\n\n throw new Error('Daemon failed to become healthy after spawn');\n}\n\n/* ── Session operations ──────────────────────────────────────────────── */\n\nexport async function createSession(\n params: CreateSessionRequest\n): Promise<DaemonResponse<SessionInfo>> {\n const port = await ensureDaemon();\n return daemonFetch(port, 'POST', '/sessions', params) as Promise<DaemonResponse<SessionInfo>>;\n}\n\nexport async function listSessions(): Promise<DaemonResponse<SessionInfo[]>> {\n const port = await ensureDaemon();\n return daemonFetch(port, 'GET', '/sessions') as Promise<DaemonResponse<SessionInfo[]>>;\n}\n\nexport async function getSession(sessionId: string): Promise<DaemonResponse<SessionInfo>> {\n const port = await ensureDaemon();\n return daemonFetch(port, 'GET', `/sessions/${sessionId}`) as Promise<DaemonResponse<SessionInfo>>;\n}\n\nexport async function deleteSession(sessionId: string): Promise<DaemonResponse> {\n const port = await ensureDaemon();\n return daemonFetch(port, 'DELETE', `/sessions/${sessionId}`) as Promise<DaemonResponse>;\n}\n\nexport async function deleteAllSessions(): Promise<DaemonResponse> {\n const port = await ensureDaemon();\n return daemonFetch(port, 'DELETE', '/sessions') as Promise<DaemonResponse>;\n}\n\nexport async function swapSessionContext(\n sessionId: string,\n params: SwapContextRequest\n): Promise<DaemonResponse<SessionInfo>> {\n const port = await ensureDaemon();\n return daemonFetch(port, 'POST', `/sessions/${sessionId}/swap-context`, params) as Promise<\n DaemonResponse<SessionInfo>\n >;\n}\n\nexport async function getSessionStorageState(sessionId: string): Promise<StorageStateResponse> {\n const port = await ensureDaemon();\n return daemonFetch(\n port,\n 'GET',\n `/sessions/${sessionId}/storage-state`\n ) as Promise<StorageStateResponse>;\n}\n\nexport async function callTool(\n sessionId: string,\n toolName: string,\n args: Record<string, unknown>\n): Promise<ToolResponse> {\n const port = await ensureDaemon();\n return daemonFetch(\n port,\n 'POST',\n `/sessions/${sessionId}/tools/${toolName}`,\n args\n ) as Promise<ToolResponse>;\n}\n\n/**\n * Resolve the target session for a command.\n * If there's exactly one session, auto-targets it.\n * If a sessionId or name is provided, looks it up.\n */\nexport async function resolveTargetSession(sessionIdOrName?: string): Promise<SessionInfo> {\n const result = await listSessions();\n if (!result.ok || !result.data) {\n throw new Error('Failed to list sessions');\n }\n const sessions = result.data;\n\n if (sessions.length === 0) {\n throw new Error('No active sessions. Start one with: canary session start');\n }\n\n if (sessionIdOrName) {\n const match = sessions.find((s) => s.id === sessionIdOrName || s.name === sessionIdOrName);\n if (!match) {\n throw new Error(\n `Session \"${sessionIdOrName}\" not found. Active sessions: ${sessions.map((s) => s.id).join(', ')}`\n );\n }\n return match;\n }\n\n if (sessions.length === 1) {\n return sessions[0];\n }\n\n throw new Error(\n `Multiple sessions active. Specify one with --session:\\n${sessions.map((s) => ` ${s.id} (${s.name})`).join('\\n')}`\n );\n}\n"],"mappings":"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","names":["path"]}
@@ -46410,7 +46410,10 @@ var PlaywrightClient = class _PlaywrightClient {
46410
46410
  });
46411
46411
  this.lastKnownUrl = url;
46412
46412
  await this.stabilize("navigation");
46413
- const [snapshotYaml, title] = await Promise.all([this.captureSnapshotInternal(), page.title()]);
46413
+ const [snapshotYaml, title] = await Promise.all([
46414
+ this.captureSnapshotInternal(),
46415
+ this.getPage().then((p) => p.title())
46416
+ ]);
46414
46417
  return this.formatMCPResponse(
46415
46418
  `Navigated to ${url}`,
46416
46419
  snapshotYaml,
@@ -46426,7 +46429,10 @@ var PlaywrightClient = class _PlaywrightClient {
46426
46429
  this.logger.debug("[DirectPlaywright] Navigating back");
46427
46430
  await page.goBack({ timeout: opts?.timeoutMs ?? TIMEOUTS.NAVIGATE });
46428
46431
  await this.stabilize("navigation");
46429
- const [snapshotYaml, title] = await Promise.all([this.captureSnapshotInternal(), page.title()]);
46432
+ const [snapshotYaml, title] = await Promise.all([
46433
+ this.captureSnapshotInternal(),
46434
+ this.getPage().then((p) => p.title())
46435
+ ]);
46430
46436
  return this.formatMCPResponse("Navigated back", snapshotYaml, "await page.goBack();", title);
46431
46437
  }
46432
46438
  // ================ PAGE INSPECTION ================
@@ -46472,7 +46478,7 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
46472
46478
  }
46473
46479
  const [rawSnapshotYaml, title] = await Promise.all([
46474
46480
  this.captureSnapshotInternal(),
46475
- page.title()
46481
+ this.getPage().then((p) => p.title())
46476
46482
  ]);
46477
46483
  const snapshotYaml = this.filterSnapshot(
46478
46484
  rawSnapshotYaml,
@@ -48449,21 +48455,37 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
48449
48455
  }
48450
48456
  };
48451
48457
  if (this.extensionsEnabled && this.context) {
48452
- this.logger.warn("[DirectPlaywright] Restoring page in existing persistent context", {
48453
- reason
48454
- });
48455
- await this.createPageWithListeners(this.context, reason);
48456
- await this.restoreUrlAfterRecovery(urlToRestore, crashType);
48457
- await restartScreencastIfNeeded();
48458
- return;
48458
+ try {
48459
+ this.logger.warn("[DirectPlaywright] Restoring page in existing persistent context", {
48460
+ reason
48461
+ });
48462
+ await this.createPageWithListeners(this.context, reason);
48463
+ await this.restoreUrlAfterRecovery(urlToRestore, crashType);
48464
+ await restartScreencastIfNeeded();
48465
+ return;
48466
+ } catch (err) {
48467
+ this.logger.warn(
48468
+ "[DirectPlaywright] Persistent context unusable, falling through to full recreation",
48469
+ { reason, error: err instanceof Error ? err.message : String(err) }
48470
+ );
48471
+ this.context = null;
48472
+ }
48459
48473
  }
48460
48474
  const reuseContext = this.browser?.isConnected() && this.context;
48461
48475
  if (reuseContext) {
48462
- this.logger.warn("[DirectPlaywright] Restoring page in existing context", { reason });
48463
- await this.createPageWithListeners(this.context, reason);
48464
- await this.restoreUrlAfterRecovery(urlToRestore, crashType);
48465
- await restartScreencastIfNeeded();
48466
- return;
48476
+ try {
48477
+ this.logger.warn("[DirectPlaywright] Restoring page in existing context", { reason });
48478
+ await this.createPageWithListeners(this.context, reason);
48479
+ await this.restoreUrlAfterRecovery(urlToRestore, crashType);
48480
+ await restartScreencastIfNeeded();
48481
+ return;
48482
+ } catch (err) {
48483
+ this.logger.warn(
48484
+ "[DirectPlaywright] Context unusable despite connected browser, falling through",
48485
+ { reason, error: err instanceof Error ? err.message : String(err) }
48486
+ );
48487
+ this.context = null;
48488
+ }
48467
48489
  }
48468
48490
  if (this.browserLease) {
48469
48491
  this.logger.warn("[DirectPlaywright] Recovering via pool lease", {
@@ -49221,4 +49243,4 @@ playwright-extra/dist/index.esm.js:
49221
49243
  * @license MIT
49222
49244
  *)
49223
49245
  */
49224
- //# sourceMappingURL=chunk-IFOJT3A5.js.map
49246
+ //# sourceMappingURL=chunk-6IAPGYZQ.js.map