@canaryai/cli 0.2.14 → 0.2.15
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-4A4G5KTC.js → chunk-N7L7AH6L.js} +48 -23
- package/dist/chunk-N7L7AH6L.js.map +1 -0
- package/dist/{chunk-ZQF72UTG.js → chunk-W3OTKNJB.js} +2 -2
- package/dist/{chunk-BOS2YLKH.js → chunk-XSOKWWRV.js} +2 -2
- package/dist/chunk-XSOKWWRV.js.map +1 -0
- package/dist/{chunk-6IAPGYZQ.js → chunk-ZYUOJQQX.js} +298 -2
- package/dist/chunk-ZYUOJQQX.js.map +1 -0
- package/dist/{debug-workflow-DIQZDFMN.js → debug-workflow-JZKUDSVY.js} +4 -4
- package/dist/{docs-CSVSGIGW.js → docs-FORYHZVU.js} +13 -7
- package/dist/docs-FORYHZVU.js.map +1 -0
- package/dist/{feature-flag-BIPFVVNC.js → feature-flag-7BD3NT6G.js} +2 -2
- package/dist/index.js +11 -11
- package/dist/{init-BTDX5N6P.js → init-JHZ3OWKQ.js} +7 -6
- package/dist/init-JHZ3OWKQ.js.map +1 -0
- package/dist/{issues-EWVB52CA.js → issues-37LDBJU7.js} +2 -2
- package/dist/{knobs-VYABZESR.js → knobs-QUJQ4NWV.js} +2 -2
- package/dist/{list-RCPYLS36.js → list-2L2NGCSF.js} +2 -2
- package/dist/{local-ZPVM4BXX.js → local-45POWSFC.js} +5 -5
- package/dist/{local-browser-WV4IH2DU.js → local-browser-LHJHPWXU.js} +3 -3
- package/dist/{login-W4GXV3VA.js → login-ZKF6GONZ.js} +3 -3
- package/dist/{mcp-YER5GQG7.js → mcp-ETZ3OTXY.js} +4 -4
- package/dist/{record-KRS2PHMW.js → record-Y4T5FPVF.js} +3 -3
- package/dist/{session-CLWAVJ2K.js → session-UPH7SPEU.js} +33 -7
- package/dist/session-UPH7SPEU.js.map +1 -0
- package/dist/{src-WLOHOI6P.js → src-3VT7JMAG.js} +2 -2
- package/dist/{start-CNNQUP5I.js → start-QMTRNSYD.js} +3 -3
- package/dist/{workflow-XXL4H5R4.js → workflow-U2NK4YED.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-4A4G5KTC.js.map +0 -1
- package/dist/chunk-6IAPGYZQ.js.map +0 -1
- package/dist/chunk-BOS2YLKH.js.map +0 -1
- package/dist/docs-CSVSGIGW.js.map +0 -1
- package/dist/init-BTDX5N6P.js.map +0 -1
- package/dist/session-CLWAVJ2K.js.map +0 -1
- /package/dist/{chunk-ZQF72UTG.js.map → chunk-W3OTKNJB.js.map} +0 -0
- /package/dist/{debug-workflow-DIQZDFMN.js.map → debug-workflow-JZKUDSVY.js.map} +0 -0
- /package/dist/{feature-flag-BIPFVVNC.js.map → feature-flag-7BD3NT6G.js.map} +0 -0
- /package/dist/{issues-EWVB52CA.js.map → issues-37LDBJU7.js.map} +0 -0
- /package/dist/{knobs-VYABZESR.js.map → knobs-QUJQ4NWV.js.map} +0 -0
- /package/dist/{list-RCPYLS36.js.map → list-2L2NGCSF.js.map} +0 -0
- /package/dist/{local-ZPVM4BXX.js.map → local-45POWSFC.js.map} +0 -0
- /package/dist/{local-browser-WV4IH2DU.js.map → local-browser-LHJHPWXU.js.map} +0 -0
- /package/dist/{login-W4GXV3VA.js.map → login-ZKF6GONZ.js.map} +0 -0
- /package/dist/{mcp-YER5GQG7.js.map → mcp-ETZ3OTXY.js.map} +0 -0
- /package/dist/{record-KRS2PHMW.js.map → record-Y4T5FPVF.js.map} +0 -0
- /package/dist/{src-WLOHOI6P.js.map → src-3VT7JMAG.js.map} +0 -0
- /package/dist/{start-CNNQUP5I.js.map → start-QMTRNSYD.js.map} +0 -0
- /package/dist/{workflow-XXL4H5R4.js.map → workflow-U2NK4YED.js.map} +0 -0
|
@@ -26,19 +26,54 @@ function isProcessAlive(pid) {
|
|
|
26
26
|
return false;
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
var DAEMON_REQUEST_TIMEOUT_MS = 3e4;
|
|
30
|
+
var DAEMON_FETCH_MAX_RETRIES = 2;
|
|
31
|
+
function isConnectionError(err) {
|
|
32
|
+
if (err instanceof TypeError && err.message === "fetch failed") return true;
|
|
33
|
+
const cause = err?.cause;
|
|
34
|
+
if (cause?.code === "UND_ERR_SOCKET") return true;
|
|
35
|
+
if (cause?.code === "ECONNREFUSED") return true;
|
|
36
|
+
if (cause?.code === "ECONNRESET") return true;
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
async function daemonFetchOnce(port, method, path2, body) {
|
|
30
40
|
const url = `http://127.0.0.1:${port}${path2}`;
|
|
31
41
|
const res = await fetch(url, {
|
|
32
42
|
method,
|
|
33
|
-
headers:
|
|
34
|
-
|
|
43
|
+
headers: {
|
|
44
|
+
...body ? { "Content-Type": "application/json" } : void 0,
|
|
45
|
+
Connection: "close"
|
|
46
|
+
},
|
|
47
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
48
|
+
signal: AbortSignal.timeout(DAEMON_REQUEST_TIMEOUT_MS)
|
|
35
49
|
});
|
|
36
50
|
return res.json();
|
|
37
51
|
}
|
|
52
|
+
async function daemonFetchWithRetry(method, path2, body) {
|
|
53
|
+
let port = await ensureDaemon();
|
|
54
|
+
let lastError;
|
|
55
|
+
for (let attempt = 0; attempt <= DAEMON_FETCH_MAX_RETRIES; attempt++) {
|
|
56
|
+
try {
|
|
57
|
+
return await daemonFetchOnce(port, method, path2, body);
|
|
58
|
+
} catch (err) {
|
|
59
|
+
lastError = err;
|
|
60
|
+
if (!isConnectionError(err) || attempt === DAEMON_FETCH_MAX_RETRIES) {
|
|
61
|
+
throw err;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
await fs.unlink(PIDFILE_PATH);
|
|
65
|
+
} catch {
|
|
66
|
+
}
|
|
67
|
+
port = await ensureDaemon();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
throw lastError;
|
|
71
|
+
}
|
|
38
72
|
async function healthCheck(port) {
|
|
39
73
|
try {
|
|
40
74
|
const res = await fetch(`http://127.0.0.1:${port}/health`, {
|
|
41
|
-
signal: AbortSignal.timeout(2e3)
|
|
75
|
+
signal: AbortSignal.timeout(2e3),
|
|
76
|
+
headers: { Connection: "close" }
|
|
42
77
|
});
|
|
43
78
|
return res.ok;
|
|
44
79
|
} catch {
|
|
@@ -113,41 +148,31 @@ async function ensureDaemon() {
|
|
|
113
148
|
throw new Error("Daemon failed to become healthy after spawn");
|
|
114
149
|
}
|
|
115
150
|
async function createSession(params) {
|
|
116
|
-
|
|
117
|
-
return daemonFetch(port, "POST", "/sessions", params);
|
|
151
|
+
return daemonFetchWithRetry("POST", "/sessions", params);
|
|
118
152
|
}
|
|
119
153
|
async function listSessions() {
|
|
120
|
-
|
|
121
|
-
return daemonFetch(port, "GET", "/sessions");
|
|
154
|
+
return daemonFetchWithRetry("GET", "/sessions");
|
|
122
155
|
}
|
|
123
156
|
async function getSession(sessionId) {
|
|
124
|
-
|
|
125
|
-
return daemonFetch(port, "GET", `/sessions/${sessionId}`);
|
|
157
|
+
return daemonFetchWithRetry("GET", `/sessions/${sessionId}`);
|
|
126
158
|
}
|
|
127
159
|
async function deleteSession(sessionId) {
|
|
128
|
-
|
|
129
|
-
return daemonFetch(port, "DELETE", `/sessions/${sessionId}`);
|
|
160
|
+
return daemonFetchWithRetry("DELETE", `/sessions/${sessionId}`);
|
|
130
161
|
}
|
|
131
162
|
async function deleteAllSessions() {
|
|
132
|
-
|
|
133
|
-
return daemonFetch(port, "DELETE", "/sessions");
|
|
163
|
+
return daemonFetchWithRetry("DELETE", "/sessions");
|
|
134
164
|
}
|
|
135
165
|
async function swapSessionContext(sessionId, params) {
|
|
136
|
-
|
|
137
|
-
return daemonFetch(port, "POST", `/sessions/${sessionId}/swap-context`, params);
|
|
166
|
+
return daemonFetchWithRetry("POST", `/sessions/${sessionId}/swap-context`, params);
|
|
138
167
|
}
|
|
139
168
|
async function getSessionStorageState(sessionId) {
|
|
140
|
-
|
|
141
|
-
return daemonFetch(
|
|
142
|
-
port,
|
|
169
|
+
return daemonFetchWithRetry(
|
|
143
170
|
"GET",
|
|
144
171
|
`/sessions/${sessionId}/storage-state`
|
|
145
172
|
);
|
|
146
173
|
}
|
|
147
174
|
async function callTool(sessionId, toolName, args) {
|
|
148
|
-
|
|
149
|
-
return daemonFetch(
|
|
150
|
-
port,
|
|
175
|
+
return daemonFetchWithRetry(
|
|
151
176
|
"POST",
|
|
152
177
|
`/sessions/${sessionId}/tools/${toolName}`,
|
|
153
178
|
args
|
|
@@ -191,4 +216,4 @@ export {
|
|
|
191
216
|
callTool,
|
|
192
217
|
resolveTargetSession
|
|
193
218
|
};
|
|
194
|
-
//# sourceMappingURL=chunk-
|
|
219
|
+
//# sourceMappingURL=chunk-N7L7AH6L.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\nconst DAEMON_REQUEST_TIMEOUT_MS = 30_000;\nconst DAEMON_FETCH_MAX_RETRIES = 2;\n\n/* ── HTTP helpers ────────────────────────────────────────────────────── */\n\nfunction isConnectionError(err: unknown): boolean {\n if (err instanceof TypeError && err.message === 'fetch failed') return true;\n const cause = (err as { cause?: { code?: string } })?.cause;\n if (cause?.code === 'UND_ERR_SOCKET') return true;\n if (cause?.code === 'ECONNREFUSED') return true;\n if (cause?.code === 'ECONNRESET') return true;\n return false;\n}\n\nasync function daemonFetchOnce(\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: {\n ...(body ? { 'Content-Type': 'application/json' } : undefined),\n Connection: 'close',\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: AbortSignal.timeout(DAEMON_REQUEST_TIMEOUT_MS),\n });\n return res.json();\n}\n\n/**\n * Fetch from daemon with retry. On connection errors (daemon died or\n * idle-exited between ensureDaemon and the request), re-ensure the\n * daemon and retry up to DAEMON_FETCH_MAX_RETRIES times.\n */\nasync function daemonFetchWithRetry(\n method: string,\n path: string,\n body?: unknown\n): Promise<unknown> {\n let port = await ensureDaemon();\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= DAEMON_FETCH_MAX_RETRIES; attempt++) {\n try {\n return await daemonFetchOnce(port, method, path, body);\n } catch (err) {\n lastError = err;\n if (!isConnectionError(err) || attempt === DAEMON_FETCH_MAX_RETRIES) {\n throw err;\n }\n // Daemon likely died — clean up stale pidfile and re-ensure\n try {\n await fs.unlink(PIDFILE_PATH);\n } catch {\n // ignore\n }\n port = await ensureDaemon();\n }\n }\n\n throw lastError;\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 headers: { Connection: 'close' },\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 return daemonFetchWithRetry('POST', '/sessions', params) as Promise<\n DaemonResponse<SessionInfo>\n >;\n}\n\nexport async function listSessions(): Promise<DaemonResponse<SessionInfo[]>> {\n return daemonFetchWithRetry('GET', '/sessions') as Promise<DaemonResponse<SessionInfo[]>>;\n}\n\nexport async function getSession(sessionId: string): Promise<DaemonResponse<SessionInfo>> {\n return daemonFetchWithRetry('GET', `/sessions/${sessionId}`) as Promise<\n DaemonResponse<SessionInfo>\n >;\n}\n\nexport async function deleteSession(sessionId: string): Promise<DaemonResponse> {\n return daemonFetchWithRetry('DELETE', `/sessions/${sessionId}`) as Promise<DaemonResponse>;\n}\n\nexport async function deleteAllSessions(): Promise<DaemonResponse> {\n return daemonFetchWithRetry('DELETE', '/sessions') as Promise<DaemonResponse>;\n}\n\nexport async function swapSessionContext(\n sessionId: string,\n params: SwapContextRequest\n): Promise<DaemonResponse<SessionInfo>> {\n return daemonFetchWithRetry('POST', `/sessions/${sessionId}/swap-context`, params) as Promise<\n DaemonResponse<SessionInfo>\n >;\n}\n\nexport async function getSessionStorageState(sessionId: string): Promise<StorageStateResponse> {\n return daemonFetchWithRetry(\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 return daemonFetchWithRetry(\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"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
PlaywrightClient
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ZYUOJQQX.js";
|
|
5
5
|
|
|
6
6
|
// src/local-browser/host.ts
|
|
7
7
|
var HEARTBEAT_INTERVAL_MS = 3e4;
|
|
@@ -384,4 +384,4 @@ var LocalBrowserHost = class {
|
|
|
384
384
|
export {
|
|
385
385
|
LocalBrowserHost
|
|
386
386
|
};
|
|
387
|
-
//# sourceMappingURL=chunk-
|
|
387
|
+
//# sourceMappingURL=chunk-W3OTKNJB.js.map
|
|
@@ -116,7 +116,7 @@ async function selectCredential(apiUrl, token, credentialArg) {
|
|
|
116
116
|
return credentials[idx];
|
|
117
117
|
}
|
|
118
118
|
async function fetchProperties(apiUrl, token) {
|
|
119
|
-
return fetchList(apiUrl, token, "/org/properties", "
|
|
119
|
+
return fetchList(apiUrl, token, "/org/properties", "items");
|
|
120
120
|
}
|
|
121
121
|
async function selectProperty(apiUrl, token, hint) {
|
|
122
122
|
const properties = await fetchProperties(apiUrl, token);
|
|
@@ -230,4 +230,4 @@ export {
|
|
|
230
230
|
uploadStorageState,
|
|
231
231
|
fetchList
|
|
232
232
|
};
|
|
233
|
-
//# sourceMappingURL=chunk-
|
|
233
|
+
//# sourceMappingURL=chunk-XSOKWWRV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli-helpers.ts"],"sourcesContent":["/**\n * Shared CLI helpers for superadmin management commands (knobs, feature-flags).\n */\n\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport process from 'node:process';\nimport { getCanaryTmpDir } from '@chatsdet/tmp';\nimport { getArgValue } from './auth.js';\n\nexport type LifecycleStage = 'active' | 'deprecated' | 'ready_for_cleanup';\n\nexport function toLifecycleLabel(stage: LifecycleStage): string {\n switch (stage) {\n case 'deprecated':\n return 'deprecated';\n case 'ready_for_cleanup':\n return 'ready_for_cleanup';\n default:\n return 'active';\n }\n}\n\nexport function parseLifecycleStage(argv: string[]): LifecycleStage {\n const stage = getArgValue(argv, '--stage');\n if (!stage || !['active', 'deprecated', 'ready_for_cleanup'].includes(stage)) {\n console.error(\n 'Error: --stage is required and must be one of: active, deprecated, ready_for_cleanup'\n );\n process.exit(1);\n }\n return stage as LifecycleStage;\n}\n\nexport async function apiRequest<T extends { ok: boolean; error?: string }>(\n apiUrl: string,\n token: string,\n method: string,\n path: string,\n body?: Record<string, unknown>\n): Promise<T> {\n const res = await fetch(`${apiUrl}${path}`, {\n method,\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n ...(body ? { body: JSON.stringify(body) } : {}),\n });\n\n if (res.status === 401) {\n console.error('Error: Unauthorized. Your session may have expired.');\n console.error('Run: canary login');\n process.exit(1);\n }\n\n return (await res.json()) as T;\n}\n\nexport async function downloadStorageState(opts: {\n apiUrl: string;\n token: string;\n propertyId: string;\n credentialId: string;\n prefix?: string;\n}): Promise<string | undefined> {\n const tmpFile = path.join(getCanaryTmpDir(), `${opts.prefix ?? 'canary-ss'}-${Date.now()}.json`);\n try {\n const res = await fetch(\n `${opts.apiUrl}/org/properties/${opts.propertyId}/credentials/${opts.credentialId}/storage-state/download`,\n {\n headers: { Authorization: `Bearer ${opts.token}` },\n redirect: 'follow',\n }\n );\n if (res.ok) {\n const body = await res.text();\n await fs.writeFile(tmpFile, body, 'utf-8');\n return tmpFile;\n }\n } catch {\n // Caller handles missing storage state\n }\n return undefined;\n}\n\n/* ── Credential selection ─────────────────────────────────────────────── */\n\nexport interface CredentialListItem {\n id: string;\n name: string;\n propertyId: string;\n propertyName?: string;\n propertyBaseUrl?: string;\n loginUrl?: string;\n storageStateS3Key?: string | null;\n}\n\n/**\n * Fetch org credentials and let the user pick one interactively.\n *\n * @param credentialArg - Credential name or ID to auto-select, or undefined for interactive\n * @returns The selected credential, or null if none found / invalid selection\n */\nexport async function selectCredential(\n apiUrl: string,\n token: string,\n credentialArg?: string\n): Promise<CredentialListItem | null> {\n const credentials = await fetchList<CredentialListItem>(\n apiUrl,\n token,\n '/org/credentials',\n 'items'\n );\n\n if (credentials.length === 0) {\n console.error('No credentials found. Create one first in the web app.');\n return null;\n }\n\n if (credentialArg) {\n const match = credentials.find(\n (c) => c.id === credentialArg || c.name.toLowerCase() === credentialArg.toLowerCase()\n );\n if (!match) {\n console.error(`Credential \"${credentialArg}\" not found.`);\n console.error('Available credentials:');\n for (const c of credentials) {\n const baseUrl = c.propertyBaseUrl ? ` — ${c.propertyBaseUrl}` : '';\n console.error(` - ${c.name} [${c.propertyName ?? c.propertyId}${baseUrl}]`);\n }\n return null;\n }\n return match;\n }\n\n // Interactive selection\n console.log('\\nSelect a credential:\\n');\n const labels = credentials.map((c) => {\n const property = c.propertyName ?? c.propertyId;\n const baseUrl = c.propertyBaseUrl ? ` — ${c.propertyBaseUrl}` : '';\n return `${c.name} [${property}${baseUrl}]`;\n });\n\n const readline = await import('node:readline');\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n const answer = await new Promise<string>((resolve) => {\n for (let i = 0; i < labels.length; i++) {\n console.log(` ${i + 1}. ${labels[i]}`);\n }\n rl.question('\\nEnter number: ', (ans) => {\n rl.close();\n resolve(ans.trim());\n });\n });\n\n const idx = parseInt(answer, 10) - 1;\n if (isNaN(idx) || idx < 0 || idx >= credentials.length) {\n console.error('Invalid selection.');\n return null;\n }\n\n return credentials[idx];\n}\n\n/* ── Property selection ──────────────────────────────────────────────── */\n\ninterface PropertyListItem {\n id: string;\n name: string;\n baseUrl: string;\n}\n\nexport async function fetchProperties(apiUrl: string, token: string): Promise<PropertyListItem[]> {\n return fetchList<PropertyListItem>(apiUrl, token, '/org/properties', 'items');\n}\n\nexport async function selectProperty(\n apiUrl: string,\n token: string,\n hint?: string\n): Promise<PropertyListItem | null> {\n const properties = await fetchProperties(apiUrl, token);\n\n if (properties.length === 0) {\n console.error('No properties found. Create one first in the web app.');\n return null;\n }\n\n if (hint) {\n const match = properties.find(\n (p) => p.id === hint || p.name.toLowerCase() === hint.toLowerCase()\n );\n if (!match) {\n console.error(`Property \"${hint}\" not found.`);\n console.error('Available properties:');\n for (const p of properties) {\n console.error(` - ${p.name} (${p.baseUrl})`);\n }\n return null;\n }\n return match;\n }\n\n if (properties.length === 1) {\n console.log(`Auto-selected property: ${properties[0].name}`);\n return properties[0];\n }\n\n return promptChoice(\n 'Select a property:',\n properties.map((p) => ({ label: `${p.name} — ${p.baseUrl}`, value: p }))\n );\n}\n\n/* ── Interactive prompt helpers ──────────────────────────────────────── */\n\nexport async function promptInput(question: string, defaultValue?: string): Promise<string> {\n const readline = await import('node:readline');\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n const prompt = defaultValue ? `${question} [${defaultValue}]: ` : `${question}: `;\n const answer = await new Promise<string>((resolve) => {\n rl.question(prompt, (ans) => {\n rl.close();\n resolve(ans.trim());\n });\n });\n return answer || defaultValue || '';\n}\n\nexport async function promptChoice<T>(\n question: string,\n options: Array<{ label: string; value: T }>\n): Promise<T | null> {\n console.log(`\\n${question}\\n`);\n for (let i = 0; i < options.length; i++) {\n console.log(` ${i + 1}. ${options[i].label}`);\n }\n const readline = await import('node:readline');\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n const answer = await new Promise<string>((resolve) => {\n rl.question('\\nEnter number: ', (ans) => {\n rl.close();\n resolve(ans.trim());\n });\n });\n\n const idx = parseInt(answer, 10) - 1;\n if (isNaN(idx) || idx < 0 || idx >= options.length) {\n console.error('Invalid selection.');\n return null;\n }\n return options[idx].value;\n}\n\nexport async function uploadStorageState(opts: {\n apiUrl: string;\n token: string;\n propertyId: string;\n credentialId: string;\n storageState: unknown;\n}): Promise<{ ok: boolean; s3Key?: string; error?: string }> {\n const res = await fetch(\n `${opts.apiUrl}/org/properties/${opts.propertyId}/credentials/${opts.credentialId}/storage-state/upload`,\n {\n method: 'PUT',\n headers: {\n Authorization: `Bearer ${opts.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ storageState: opts.storageState }),\n }\n );\n\n if (res.status === 401) {\n console.error('Error: Unauthorized. Your session may have expired.');\n console.error('Run: canary login');\n process.exit(1);\n }\n\n return (await res.json()) as { ok: boolean; s3Key?: string; error?: string };\n}\n\nexport async function fetchList<T>(\n apiUrl: string,\n token: string,\n path: string,\n listKey: string\n): Promise<T[]> {\n const res = await fetch(`${apiUrl}${path}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (res.status === 401) {\n console.error('Error: Unauthorized. Your session may have expired.');\n console.error('Run: canary login');\n process.exit(1);\n }\n\n const json = (await res.json()) as Record<string, unknown>;\n\n if (!json.ok) {\n console.error(`Error: ${json.error}`);\n process.exit(1);\n }\n\n return (json[listKey] as T[]) ?? [];\n}\n"],"mappings":"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","names":["path"]}
|
|
@@ -39388,6 +39388,189 @@ function sortMatchesByContext(matches) {
|
|
|
39388
39388
|
});
|
|
39389
39389
|
}
|
|
39390
39390
|
|
|
39391
|
+
// ../browser-core/src/snapshot-formatter-content.ts
|
|
39392
|
+
var MAX_CONTEXT_ANNOTATIONS = 5;
|
|
39393
|
+
var MIN_CONTENT_CARD_RUN = 1;
|
|
39394
|
+
var MAX_CONTENT_CARD_CHILDREN = 6;
|
|
39395
|
+
var MIN_CONTENT_CARD_CHILDREN = 2;
|
|
39396
|
+
function isContextAnnotation(element) {
|
|
39397
|
+
if (element.role !== "paragraph" && element.role !== "generic") return false;
|
|
39398
|
+
if (isClickableByAttribute(element)) return false;
|
|
39399
|
+
if (INTERACTIVE_ROLES.has(element.role)) return false;
|
|
39400
|
+
if (hasInteractiveDescendants(element)) return false;
|
|
39401
|
+
const text = getAnnotationText(element);
|
|
39402
|
+
if (!text || text.length < 3 || text.length > 200) return false;
|
|
39403
|
+
return true;
|
|
39404
|
+
}
|
|
39405
|
+
function getAnnotationText(element) {
|
|
39406
|
+
const direct = getElementText(element);
|
|
39407
|
+
if (direct && direct.trim().length >= 3) return direct.trim();
|
|
39408
|
+
const parts = [];
|
|
39409
|
+
for (const child of element.children) {
|
|
39410
|
+
if (TEXT_CARRYING_ROLES.has(child.role)) {
|
|
39411
|
+
const childText = getElementText(child);
|
|
39412
|
+
if (childText?.trim()) {
|
|
39413
|
+
parts.push(childText.trim());
|
|
39414
|
+
}
|
|
39415
|
+
}
|
|
39416
|
+
}
|
|
39417
|
+
const composed = parts.join(" | ");
|
|
39418
|
+
return composed.length >= 3 ? composed : void 0;
|
|
39419
|
+
}
|
|
39420
|
+
function collectContextAnnotations(siblings) {
|
|
39421
|
+
const annotations = [];
|
|
39422
|
+
for (const sib of siblings) {
|
|
39423
|
+
if (annotations.length >= MAX_CONTEXT_ANNOTATIONS) break;
|
|
39424
|
+
if (extractCardTexts(sib) !== null) continue;
|
|
39425
|
+
if (isContextAnnotation(sib)) {
|
|
39426
|
+
const text = getAnnotationText(sib);
|
|
39427
|
+
if (text) {
|
|
39428
|
+
annotations.push(text);
|
|
39429
|
+
}
|
|
39430
|
+
}
|
|
39431
|
+
}
|
|
39432
|
+
return annotations;
|
|
39433
|
+
}
|
|
39434
|
+
function extractCardTexts(element) {
|
|
39435
|
+
if (isClickableByAttribute(element)) return null;
|
|
39436
|
+
if (INTERACTIVE_ROLES.has(element.role)) return null;
|
|
39437
|
+
if (hasInteractiveDescendants(element)) return null;
|
|
39438
|
+
const texts = [];
|
|
39439
|
+
collectCardTexts(element, texts, 0);
|
|
39440
|
+
if (texts.length < MIN_CONTENT_CARD_CHILDREN || texts.length > MAX_CONTENT_CARD_CHILDREN) {
|
|
39441
|
+
return null;
|
|
39442
|
+
}
|
|
39443
|
+
return texts;
|
|
39444
|
+
}
|
|
39445
|
+
function collectCardTexts(element, texts, depth) {
|
|
39446
|
+
if (depth > 2) return;
|
|
39447
|
+
for (const child of element.children) {
|
|
39448
|
+
if (TEXT_CARRYING_ROLES.has(child.role) || child.role === "listitem") {
|
|
39449
|
+
const text = getElementText(child);
|
|
39450
|
+
if (text && text.trim().length >= 2) {
|
|
39451
|
+
texts.push(text.trim());
|
|
39452
|
+
} else {
|
|
39453
|
+
collectCardTexts(child, texts, depth + 1);
|
|
39454
|
+
}
|
|
39455
|
+
}
|
|
39456
|
+
}
|
|
39457
|
+
}
|
|
39458
|
+
function detectContentCardRun(siblings, startIndex) {
|
|
39459
|
+
const cards = [];
|
|
39460
|
+
let endIndex = startIndex;
|
|
39461
|
+
for (let i = startIndex; i < siblings.length; i++) {
|
|
39462
|
+
const sib = siblings[i];
|
|
39463
|
+
const texts = extractCardTexts(sib);
|
|
39464
|
+
if (!texts) break;
|
|
39465
|
+
cards.push({ ref: sib.ref || "", texts });
|
|
39466
|
+
endIndex = i + 1;
|
|
39467
|
+
}
|
|
39468
|
+
if (cards.length < MIN_CONTENT_CARD_RUN) return null;
|
|
39469
|
+
return { cards, endIndex };
|
|
39470
|
+
}
|
|
39471
|
+
var DAY_ABBREVIATIONS = /* @__PURE__ */ new Set([
|
|
39472
|
+
"S",
|
|
39473
|
+
"M",
|
|
39474
|
+
"T",
|
|
39475
|
+
"W",
|
|
39476
|
+
"F",
|
|
39477
|
+
"Su",
|
|
39478
|
+
"Mo",
|
|
39479
|
+
"Tu",
|
|
39480
|
+
"We",
|
|
39481
|
+
"Th",
|
|
39482
|
+
"Fr",
|
|
39483
|
+
"Sa",
|
|
39484
|
+
"Sun",
|
|
39485
|
+
"Mon",
|
|
39486
|
+
"Tue",
|
|
39487
|
+
"Wed",
|
|
39488
|
+
"Thu",
|
|
39489
|
+
"Fri",
|
|
39490
|
+
"Sat"
|
|
39491
|
+
]);
|
|
39492
|
+
function detectDatepicker(element) {
|
|
39493
|
+
const kids = element.children;
|
|
39494
|
+
if (kids.length < 35) return null;
|
|
39495
|
+
let headerStart = -1;
|
|
39496
|
+
for (let i = 0; i <= kids.length - 7; i++) {
|
|
39497
|
+
if (isDayHeaderRun(kids, i)) {
|
|
39498
|
+
headerStart = i;
|
|
39499
|
+
break;
|
|
39500
|
+
}
|
|
39501
|
+
}
|
|
39502
|
+
if (headerStart === -1) return null;
|
|
39503
|
+
const dayHeaders = kids.slice(headerStart, headerStart + 7).map((k) => {
|
|
39504
|
+
const text = getElementText(k);
|
|
39505
|
+
return text?.trim() ?? "";
|
|
39506
|
+
});
|
|
39507
|
+
const dayCells = [];
|
|
39508
|
+
for (let i = headerStart + 7; i < kids.length; i++) {
|
|
39509
|
+
const child = kids[i];
|
|
39510
|
+
const text = getElementText(child)?.trim();
|
|
39511
|
+
if (!text) continue;
|
|
39512
|
+
const num = parseInt(text, 10);
|
|
39513
|
+
if (isNaN(num) || num < 1 || num > 31 || String(num) !== text) break;
|
|
39514
|
+
dayCells.push({
|
|
39515
|
+
ref: child.ref || "",
|
|
39516
|
+
dayNumber: num,
|
|
39517
|
+
isSelected: isActiveElement(child) || child.rawLine.includes("[aria-selected=true]")
|
|
39518
|
+
});
|
|
39519
|
+
}
|
|
39520
|
+
if (dayCells.length < 28 || dayCells.length > 42) return null;
|
|
39521
|
+
const weeks = [];
|
|
39522
|
+
for (let i = 0; i < dayCells.length; i += 7) {
|
|
39523
|
+
const weekDays = dayCells.slice(i, i + 7).map((cell) => ({
|
|
39524
|
+
ref: cell.ref,
|
|
39525
|
+
dayNumber: cell.dayNumber,
|
|
39526
|
+
isSelected: cell.isSelected
|
|
39527
|
+
}));
|
|
39528
|
+
weeks.push({ days: weekDays });
|
|
39529
|
+
}
|
|
39530
|
+
return {
|
|
39531
|
+
ref: element.ref || "",
|
|
39532
|
+
dayHeaders,
|
|
39533
|
+
weeks
|
|
39534
|
+
};
|
|
39535
|
+
}
|
|
39536
|
+
function isDayHeaderRun(kids, startIndex) {
|
|
39537
|
+
for (let i = startIndex; i < startIndex + 7; i++) {
|
|
39538
|
+
const child = kids[i];
|
|
39539
|
+
if (isClickableByAttribute(child)) return false;
|
|
39540
|
+
const text = getElementText(child)?.trim();
|
|
39541
|
+
if (!text || !DAY_ABBREVIATIONS.has(text)) return false;
|
|
39542
|
+
}
|
|
39543
|
+
return true;
|
|
39544
|
+
}
|
|
39545
|
+
function formatContextAnnotations(annotations, indent) {
|
|
39546
|
+
const indentStr = " ".repeat(indent + 1);
|
|
39547
|
+
return annotations.map((text) => `${indentStr}context: "${text}"`);
|
|
39548
|
+
}
|
|
39549
|
+
function formatContentCards(cards, indent) {
|
|
39550
|
+
const indentStr = " ".repeat(indent + 1);
|
|
39551
|
+
const lines = [];
|
|
39552
|
+
lines.push(`${indentStr}Content:`);
|
|
39553
|
+
for (const card of cards) {
|
|
39554
|
+
const refPart = card.ref ? `[${card.ref}] ` : "";
|
|
39555
|
+
lines.push(`${indentStr} ${refPart}${card.texts.join(" \xB7 ")}`);
|
|
39556
|
+
}
|
|
39557
|
+
return lines;
|
|
39558
|
+
}
|
|
39559
|
+
function formatDatepicker(info, indent) {
|
|
39560
|
+
const indentStr = " ".repeat(indent + 1);
|
|
39561
|
+
const lines = [];
|
|
39562
|
+
lines.push(`${indentStr}Calendar (${info.dayHeaders.join(" ")}):`);
|
|
39563
|
+
for (let wi = 0; wi < info.weeks.length; wi++) {
|
|
39564
|
+
const week = info.weeks[wi];
|
|
39565
|
+
const dayCells = week.days.map((d) => {
|
|
39566
|
+
const selected = d.isSelected ? "*" : "";
|
|
39567
|
+
return `[${d.ref}]${d.dayNumber}${selected}`;
|
|
39568
|
+
});
|
|
39569
|
+
lines.push(`${indentStr} ${dayCells.join(" ")}`);
|
|
39570
|
+
}
|
|
39571
|
+
return lines;
|
|
39572
|
+
}
|
|
39573
|
+
|
|
39391
39574
|
// ../browser-core/src/snapshot-formatter-sections.ts
|
|
39392
39575
|
var FIELD_LABEL_TEXT_ROLES = /* @__PURE__ */ new Set([
|
|
39393
39576
|
"generic",
|
|
@@ -39627,15 +39810,23 @@ function formatElement(element, options) {
|
|
|
39627
39810
|
attributes: normalizedAttributes
|
|
39628
39811
|
};
|
|
39629
39812
|
}
|
|
39813
|
+
function containsNavigation(section) {
|
|
39814
|
+
for (const sub of section.subsections) {
|
|
39815
|
+
if (sub.role === "navigation") return true;
|
|
39816
|
+
if (containsNavigation(sub)) return true;
|
|
39817
|
+
}
|
|
39818
|
+
return false;
|
|
39819
|
+
}
|
|
39630
39820
|
function shouldCollapse(section) {
|
|
39631
39821
|
if (section.containsActive) return false;
|
|
39632
39822
|
if (section.hasSearchMatch) return false;
|
|
39633
|
-
if (section.isBackground) return true;
|
|
39634
39823
|
if (section.role === "dialog" || section.role === "alertdialog") return false;
|
|
39635
39824
|
if (section.role === "navigation" || section.role === "menubar" || section.role === "menu")
|
|
39636
39825
|
return false;
|
|
39637
39826
|
if (section.role === "banner") return false;
|
|
39638
39827
|
if (section.role === "form") return false;
|
|
39828
|
+
if (containsNavigation(section)) return false;
|
|
39829
|
+
if (section.isBackground) return true;
|
|
39639
39830
|
if (section.elementCount >= MIN_ELEMENTS_TO_COLLAPSE) return true;
|
|
39640
39831
|
return false;
|
|
39641
39832
|
}
|
|
@@ -39713,6 +39904,50 @@ function collectInteractiveElements(element, elements, subsections, depth, inher
|
|
|
39713
39904
|
return;
|
|
39714
39905
|
}
|
|
39715
39906
|
const kids = element.children;
|
|
39907
|
+
const datepickerResult = detectDatepicker(element);
|
|
39908
|
+
if (datepickerResult) {
|
|
39909
|
+
const annotations = collectContextAnnotations(kids);
|
|
39910
|
+
subsections.push({
|
|
39911
|
+
heading: "Calendar",
|
|
39912
|
+
ref: datepickerResult.ref,
|
|
39913
|
+
role: "generic",
|
|
39914
|
+
level: 4,
|
|
39915
|
+
elements: [],
|
|
39916
|
+
subsections: [],
|
|
39917
|
+
collapsed: false,
|
|
39918
|
+
containsActive: false,
|
|
39919
|
+
isBackground: false,
|
|
39920
|
+
isFocused: false,
|
|
39921
|
+
elementCount: datepickerResult.weeks.reduce((sum, w) => sum + w.days.length, 0),
|
|
39922
|
+
datepickerInfo: datepickerResult,
|
|
39923
|
+
contextAnnotations: annotations.length > 0 ? annotations : void 0
|
|
39924
|
+
});
|
|
39925
|
+
return;
|
|
39926
|
+
}
|
|
39927
|
+
const cardRun = detectContentCardRun(kids, 0);
|
|
39928
|
+
if (cardRun) {
|
|
39929
|
+
const annotations = collectContextAnnotations(kids);
|
|
39930
|
+
subsections.push({
|
|
39931
|
+
heading: "Content",
|
|
39932
|
+
ref: element.ref || "",
|
|
39933
|
+
role: "generic",
|
|
39934
|
+
level: 4,
|
|
39935
|
+
elements: [],
|
|
39936
|
+
subsections: [],
|
|
39937
|
+
collapsed: false,
|
|
39938
|
+
containsActive: false,
|
|
39939
|
+
isBackground: false,
|
|
39940
|
+
isFocused: false,
|
|
39941
|
+
elementCount: cardRun.cards.length,
|
|
39942
|
+
contentCards: cardRun.cards,
|
|
39943
|
+
contextAnnotations: annotations.length > 0 ? annotations : void 0
|
|
39944
|
+
});
|
|
39945
|
+
for (let ki = cardRun.endIndex; ki < kids.length; ki++) {
|
|
39946
|
+
const child = kids[ki];
|
|
39947
|
+
collectInteractiveElements(child, elements, subsections, depth + 1, inheritedFieldLabel);
|
|
39948
|
+
}
|
|
39949
|
+
return;
|
|
39950
|
+
}
|
|
39716
39951
|
for (let ki = 0; ki < kids.length; ki++) {
|
|
39717
39952
|
const child = kids[ki];
|
|
39718
39953
|
if (isVisualHeading(child, kids, ki)) {
|
|
@@ -39771,6 +40006,44 @@ function buildSection(element, depth) {
|
|
|
39771
40006
|
if (gridInfo) {
|
|
39772
40007
|
return buildGridSection(element);
|
|
39773
40008
|
}
|
|
40009
|
+
const datepickerResult = detectDatepicker(element);
|
|
40010
|
+
if (datepickerResult) {
|
|
40011
|
+
const annotations = collectContextAnnotations(element.children);
|
|
40012
|
+
return {
|
|
40013
|
+
ref: element.ref || "",
|
|
40014
|
+
role: element.role,
|
|
40015
|
+
heading: element.text || "Calendar",
|
|
40016
|
+
level: 0,
|
|
40017
|
+
elements: [],
|
|
40018
|
+
subsections: [],
|
|
40019
|
+
containsActive: false,
|
|
40020
|
+
collapsed: false,
|
|
40021
|
+
isBackground: false,
|
|
40022
|
+
isFocused: false,
|
|
40023
|
+
elementCount: datepickerResult.weeks.reduce((sum, w) => sum + w.days.length, 0),
|
|
40024
|
+
datepickerInfo: datepickerResult,
|
|
40025
|
+
contextAnnotations: annotations.length > 0 ? annotations : void 0
|
|
40026
|
+
};
|
|
40027
|
+
}
|
|
40028
|
+
const cardRun = detectContentCardRun(element.children, 0);
|
|
40029
|
+
if (cardRun) {
|
|
40030
|
+
const annotations = collectContextAnnotations(element.children);
|
|
40031
|
+
return {
|
|
40032
|
+
ref: element.ref || "",
|
|
40033
|
+
role: element.role,
|
|
40034
|
+
heading: element.text || "Content",
|
|
40035
|
+
level: 0,
|
|
40036
|
+
elements: [],
|
|
40037
|
+
subsections: [],
|
|
40038
|
+
containsActive: false,
|
|
40039
|
+
collapsed: false,
|
|
40040
|
+
isBackground: false,
|
|
40041
|
+
isFocused: false,
|
|
40042
|
+
elementCount: cardRun.cards.length,
|
|
40043
|
+
contentCards: cardRun.cards,
|
|
40044
|
+
contextAnnotations: annotations.length > 0 ? annotations : void 0
|
|
40045
|
+
};
|
|
40046
|
+
}
|
|
39774
40047
|
const isHeading = element.role === "heading";
|
|
39775
40048
|
const isStructural = STRUCTURAL_ROLES.has(element.role);
|
|
39776
40049
|
if (isHeading && !element.text?.trim() && element.children.length === 0) {
|
|
@@ -40098,6 +40371,26 @@ function formatSectionOutput(section, indent, showCollapsed) {
|
|
|
40098
40371
|
}
|
|
40099
40372
|
const indentStr = " ".repeat(indent);
|
|
40100
40373
|
const lines = [];
|
|
40374
|
+
if (section.datepickerInfo) {
|
|
40375
|
+
const headingPrefix2 = section.level > 0 ? "#".repeat(Math.min(section.level + 2, 6)) + " " : "";
|
|
40376
|
+
const refPart2 = section.ref ? ` [${section.ref}]` : "";
|
|
40377
|
+
lines.push(`${indentStr}${headingPrefix2}${section.heading}${refPart2}`);
|
|
40378
|
+
if (section.contextAnnotations) {
|
|
40379
|
+
lines.push(...formatContextAnnotations(section.contextAnnotations, indent));
|
|
40380
|
+
}
|
|
40381
|
+
lines.push(...formatDatepicker(section.datepickerInfo, indent));
|
|
40382
|
+
return lines.join("\n");
|
|
40383
|
+
}
|
|
40384
|
+
if (section.contentCards && section.contentCards.length > 0) {
|
|
40385
|
+
const headingPrefix2 = section.level > 0 ? "#".repeat(Math.min(section.level + 2, 6)) + " " : "";
|
|
40386
|
+
const refPart2 = section.ref ? ` [${section.ref}]` : "";
|
|
40387
|
+
lines.push(`${indentStr}${headingPrefix2}${section.heading}${refPart2}`);
|
|
40388
|
+
if (section.contextAnnotations) {
|
|
40389
|
+
lines.push(...formatContextAnnotations(section.contextAnnotations, indent));
|
|
40390
|
+
}
|
|
40391
|
+
lines.push(...formatContentCards(section.contentCards, indent));
|
|
40392
|
+
return lines.join("\n");
|
|
40393
|
+
}
|
|
40101
40394
|
const headingPrefix = section.level > 0 ? "#".repeat(Math.min(section.level + 2, 6)) + " " : "";
|
|
40102
40395
|
const refPart = section.ref ? ` [${section.ref}]` : "";
|
|
40103
40396
|
const focusedPart = section.isFocused ? " [FOCUSED]" : "";
|
|
@@ -40106,6 +40399,9 @@ function formatSectionOutput(section, indent, showCollapsed) {
|
|
|
40106
40399
|
lines.push(
|
|
40107
40400
|
`${indentStr}${headingPrefix}${section.heading}${refPart}${focusedPart}${backgroundPart}${activePart}`
|
|
40108
40401
|
);
|
|
40402
|
+
if (section.contextAnnotations) {
|
|
40403
|
+
lines.push(...formatContextAnnotations(section.contextAnnotations, indent));
|
|
40404
|
+
}
|
|
40109
40405
|
if (section.collapsed && !showCollapsed) {
|
|
40110
40406
|
if (section.isBackground) {
|
|
40111
40407
|
if (section.ref) {
|
|
@@ -49243,4 +49539,4 @@ playwright-extra/dist/index.esm.js:
|
|
|
49243
49539
|
* @license MIT
|
|
49244
49540
|
*)
|
|
49245
49541
|
*/
|
|
49246
|
-
//# sourceMappingURL=chunk-
|
|
49542
|
+
//# sourceMappingURL=chunk-ZYUOJQQX.js.map
|