@tekmidian/pai 0.48.0 → 0.50.0
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/{aibroker-client-D5NT0S1N.mjs → aibroker-client-Bu72yPKj.mjs} +1 -1
- package/dist/{aibroker-client-Bn9SnGMa.mjs → aibroker-client-CDIXmq-e.mjs} +1 -1
- package/dist/{aibroker-client-Bn9SnGMa.mjs.map → aibroker-client-CDIXmq-e.mjs.map} +1 -1
- package/dist/{chain-CNSa0A3G.mjs → chain-BBbVbWVv.mjs} +4 -4
- package/dist/{chain-CNSa0A3G.mjs.map → chain-BBbVbWVv.mjs.map} +1 -1
- package/dist/cli/index.mjs +14 -14
- package/dist/cli/program.mjs +14 -14
- package/dist/config-Bn9jpblO.mjs +653 -0
- package/dist/config-Bn9jpblO.mjs.map +1 -0
- package/dist/{config-DxMZjpvY.mjs → config-DYXARgk8.mjs} +180 -151
- package/dist/config-DYXARgk8.mjs.map +1 -0
- package/dist/config-RjeVGJ7K.mjs +3 -0
- package/dist/{context-handover-cache-B9NKSjwR.mjs → context-handover-cache-yOuK9RIk.mjs} +5 -5
- package/dist/{context-handover-cache-B9NKSjwR.mjs.map → context-handover-cache-yOuK9RIk.mjs.map} +1 -1
- package/dist/daemon/index.mjs +13 -12
- package/dist/daemon/index.mjs.map +1 -1
- package/dist/{daemon-DZ4Q0jrs.mjs → daemon-CBTQYtHF.mjs} +49 -30
- package/dist/daemon-CBTQYtHF.mjs.map +1 -0
- package/dist/daemon-Vf7pHnjR.mjs +25 -0
- package/dist/daemon-mcp/index.mjs +186 -23
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/factory-Ba8j9K7q.mjs +3 -0
- package/dist/{factory-DNYAqjH0.mjs → factory-Bt7TWQje.mjs} +3 -3
- package/dist/{factory-DNYAqjH0.mjs.map → factory-Bt7TWQje.mjs.map} +1 -1
- package/dist/{fallback-IeR2FrFn.mjs → fallback-CIGspCSi.mjs} +260 -10
- package/dist/fallback-CIGspCSi.mjs.map +1 -0
- package/dist/hooks/capture-all-events.mjs +80 -8
- package/dist/hooks/capture-all-events.mjs.map +4 -4
- package/dist/hooks/context-compression-hook.mjs +54 -39
- package/dist/hooks/context-compression-hook.mjs.map +4 -4
- package/dist/hooks/post-compact-inject.mjs +54 -39
- package/dist/hooks/post-compact-inject.mjs.map +4 -4
- package/dist/hooks/route-agents-to-worker.mjs +204 -109
- package/dist/hooks/route-agents-to-worker.mjs.map +4 -4
- package/dist/hooks/whisper-rules.mjs +7613 -9
- package/dist/hooks/whisper-rules.mjs.map +4 -4
- package/dist/hooks/worker-proxy.mjs +204 -109
- package/dist/hooks/worker-proxy.mjs.map +4 -4
- package/dist/hooks/worker-status-line.mjs +211 -116
- package/dist/hooks/worker-status-line.mjs.map +4 -4
- package/dist/hooks/worker-supervision.mjs +208 -113
- package/dist/hooks/worker-supervision.mjs.map +4 -4
- package/dist/{kg-entity-BSjM5xZh.mjs → kg-entity-BSW7ra8i.mjs} +1 -1
- package/dist/{kg-entity-BSjM5xZh.mjs.map → kg-entity-BSW7ra8i.mjs.map} +1 -1
- package/dist/main-resolver-BTastpp4.mjs +7 -0
- package/dist/{main-resolver-DvYu9jbl.mjs → main-resolver-BmZPCmgj.mjs} +3 -3
- package/dist/{main-resolver-DvYu9jbl.mjs.map → main-resolver-BmZPCmgj.mjs.map} +1 -1
- package/dist/{planner-Cn8HmT7l.mjs → planner-BiH9msqq.mjs} +6 -6
- package/dist/{planner-Cn8HmT7l.mjs.map → planner-BiH9msqq.mjs.map} +1 -1
- package/dist/{program-Bgv1lFFA.mjs → program-BX67-4I2.mjs} +536 -260
- package/dist/program-BX67-4I2.mjs.map +1 -0
- package/dist/query-feedback-Bm6XvCmg.mjs +3 -0
- package/dist/{query-feedback-CYyOGi3y.mjs → query-feedback-CTs_jx6i.mjs} +1 -1
- package/dist/{query-feedback-CYyOGi3y.mjs.map → query-feedback-CTs_jx6i.mjs.map} +1 -1
- package/dist/{run-Cls0YGgV.mjs → run-TChOnMO_.mjs} +1388 -1183
- package/dist/run-TChOnMO_.mjs.map +1 -0
- package/dist/{server-Ch99xt5K.mjs → server-R9UkCn3v.mjs} +42 -3
- package/dist/server-R9UkCn3v.mjs.map +1 -0
- package/dist/session-keepalive-BuG3wvik.mjs +579 -0
- package/dist/session-keepalive-BuG3wvik.mjs.map +1 -0
- package/dist/skills/VaultContext/SKILL.md +1 -1
- package/dist/{state-DnYGRmS7.mjs → state-Ca0ltLgI.mjs} +1 -1
- package/dist/{state-PJrgfDLW.mjs → state-DwrsOoMi.mjs} +1 -1
- package/dist/{state-PJrgfDLW.mjs.map → state-DwrsOoMi.mjs.map} +1 -1
- package/dist/{tools-B77WHeVZ.mjs → tools-BEqiJt_j.mjs} +13 -13
- package/dist/{tools-B77WHeVZ.mjs.map → tools-BEqiJt_j.mjs.map} +1 -1
- package/dist/{tools-NnR_n-Ja.mjs → tools-BwsOTmjh.mjs} +2 -2
- package/dist/{wakeup-UrhiW-KU.mjs → wakeup-Yk5lQ0jb.mjs} +1 -1
- package/dist/{wakeup-UrhiW-KU.mjs.map → wakeup-Yk5lQ0jb.mjs.map} +1 -1
- package/dist/{work-queue-worker-BA5IDBwQ.mjs → work-queue-worker-B9zVWImP.mjs} +3 -3
- package/dist/{work-queue-worker-BA5IDBwQ.mjs.map → work-queue-worker-B9zVWImP.mjs.map} +1 -1
- package/dist/work-queue-worker-D-DnQ7oh.mjs +14 -0
- package/dist/{zettelkasten-BBjA7GcP.mjs → zettelkasten-DezbXghl.mjs} +2 -2
- package/dist/{zettelkasten-BBjA7GcP.mjs.map → zettelkasten-DezbXghl.mjs.map} +1 -1
- package/docs/cache-keepalive.md +138 -0
- package/docs/commands/README.md +7 -0
- package/docs/commands/audit.md +1 -0
- package/docs/commands/config.md +84 -0
- package/docs/commands/daemon.md +6 -0
- package/docs/commands/worker.md +37 -2
- package/docs/config.md +171 -0
- package/docs/model-catalogue.md +502 -0
- package/docs/provider-independence-details.md +1 -1
- package/docs/task-bus.md +1 -1
- package/docs/worker.md +33 -5
- package/docs/workers-config.md +105 -12
- package/package.json +1 -1
- package/src/hooks/ts/capture-all-events.test.ts +71 -0
- package/src/hooks/ts/capture-all-events.ts +10 -3
- package/src/hooks/ts/user-prompt/whisper-rules.test.ts +56 -1
- package/src/hooks/ts/user-prompt/whisper-rules.ts +24 -0
- package/statusline-command.sh +81 -6
- package/dist/config-DCu8THKi.mjs +0 -228
- package/dist/config-DCu8THKi.mjs.map +0 -1
- package/dist/config-DeqFqa1N.mjs +0 -3
- package/dist/config-DxMZjpvY.mjs.map +0 -1
- package/dist/daemon-CYpVy_Dw.mjs +0 -24
- package/dist/daemon-DZ4Q0jrs.mjs.map +0 -1
- package/dist/factory-47Qf_df7.mjs +0 -3
- package/dist/fallback-IeR2FrFn.mjs.map +0 -1
- package/dist/indexer-C5Le7XE7.mjs +0 -1
- package/dist/main-resolver-CnfnWa8C.mjs +0 -7
- package/dist/program-Bgv1lFFA.mjs.map +0 -1
- package/dist/query-feedback-C7rSfiXU.mjs +0 -3
- package/dist/run-Cls0YGgV.mjs.map +0 -1
- package/dist/server-Ch99xt5K.mjs.map +0 -1
- package/dist/work-queue-worker-DLM2wlqM.mjs +0 -14
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as switchToSession, i as sendToSession, n as fetchLiveSessions, r as revealItermSession, t as callAiBroker } from "./aibroker-client-
|
|
1
|
+
import { a as switchToSession, i as sendToSession, n as fetchLiveSessions, r as revealItermSession, t as callAiBroker } from "./aibroker-client-CDIXmq-e.mjs";
|
|
2
2
|
|
|
3
3
|
export { sendToSession };
|
|
@@ -212,4 +212,4 @@ end tell`;
|
|
|
212
212
|
|
|
213
213
|
//#endregion
|
|
214
214
|
export { switchToSession as a, sendToSession as i, fetchLiveSessions as n, revealItermSession as r, callAiBroker as t };
|
|
215
|
-
//# sourceMappingURL=aibroker-client-
|
|
215
|
+
//# sourceMappingURL=aibroker-client-CDIXmq-e.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aibroker-client-Bn9SnGMa.mjs","names":[],"sources":["../src/cli/lib/aibroker-client.ts"],"sourcesContent":["/**\n * aibroker-client.ts — Lightweight IPC client for AIBroker daemon.\n *\n * Connects to the AIBroker Unix Domain Socket, sends a JSON-RPC request,\n * and reads a single newline-terminated JSON response. No class needed —\n * just a thin async function matching the WatcherClient protocol.\n *\n * Socket path: /tmp/aibroker.sock (default; override via AIBROKER_SOCKET env).\n */\n\nimport { connect } from \"node:net\";\nimport { randomUUID } from \"node:crypto\";\nimport { spawnSync } from \"node:child_process\";\nimport { aibrokerSocketPath } from \"../../runtime-paths.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Lightweight session metadata returned by the AIBroker `sessions` IPC method.\n * Does NOT include scrollback content — use `session_content` for that.\n */\nexport interface AiBrokerSessionMeta {\n index: number;\n sessionId: string;\n /** iTerm2 tab title or profile name */\n name: string;\n /** PAI session name set via /Name; null for bare shells */\n paiName: string | null;\n atPrompt: boolean;\n /** \"claude\" for Claude Code panes, \"shell\" for bare terminals */\n kind: \"claude\" | \"shell\";\n /** Whether this is the currently focused pane */\n active: boolean;\n /** Last user prompt seen in scrollback (only populated by fetchLiveSessionsWithPrompts) */\n lastPrompt?: string;\n}\n\ninterface AiBrokerSessionsResult {\n sessions: AiBrokerSessionMeta[];\n}\n\n// ---------------------------------------------------------------------------\n// Core call\n// ---------------------------------------------------------------------------\n\n// AIBROKER_SOCKET stays first: it is AIBroker's own variable and a user who has\n// set it means it. The fallback goes through runtime-paths so the test guard\n// can redirect it — writing to a live socket from a test is the same hazard as\n// writing to live user state, and this one is not even ours.\nconst DEFAULT_SOCKET = process.env.AIBROKER_SOCKET ?? aibrokerSocketPath();\n\n/**\n * How long to wait for `send_to_session`, which must exceed the server's own\n * ack window or the caller gives up while the callee is still working.\n *\n * AIBroker waits up to SEND_ACK_TIMEOUT_MS (15s) for the submit confirmation —\n * the text leaving the input line — before answering. The generic client\n * timeout is 8s. So every send needing 8-15s to confirm reported\n * \"AIBroker IPC call timed out\" while succeeding, and the handler's eventual\n * `delivered: true` was written into a socket nobody was reading any more.\n *\n * Measured on `pai pause all` across 15 sessions: 9 reported failed, 8 of them\n * verifiably paused. A caller's deadline shorter than the callee's is not a\n * tuning question, it is a guaranteed false negative on every slow success.\n */\nconst SEND_TIMEOUT_MS = 30_000;\n\n/**\n * Call an AIBroker IPC method and return the result.\n *\n * Resolves with the `result` field of a successful response.\n * Rejects if the socket is not available, the call times out, or the\n * daemon returns an error.\n *\n * @param method IPC method name (e.g. \"session_content\", \"send_to_session\")\n * @param params Method parameters object\n * @param timeoutMs Connection + response timeout in milliseconds (default: 8 000)\n */\nexport function callAiBroker(\n method: string,\n params: Record<string, unknown> = {},\n timeoutMs = 8_000\n): Promise<Record<string, unknown>> {\n return new Promise((resolve, reject) => {\n const socketPath = DEFAULT_SOCKET;\n let done = false;\n let buffer = \"\";\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n function finish(err: Error | null, value?: Record<string, unknown>): void {\n if (done) return;\n done = true;\n if (timer !== null) {\n clearTimeout(timer);\n timer = null;\n }\n try {\n socket.destroy();\n } catch {\n /* ignore */\n }\n if (err) reject(err);\n else resolve(value!);\n }\n\n const socket = connect(socketPath, () => {\n const request = {\n id: randomUUID(),\n sessionId: process.env.TERM_SESSION_ID ?? \"pai-cli\",\n method,\n params,\n };\n const itermId = process.env.ITERM_SESSION_ID;\n if (itermId) Object.assign(request, { itermSessionId: itermId });\n socket.write(JSON.stringify(request) + \"\\n\");\n });\n\n socket.on(\"data\", (chunk: Buffer) => {\n buffer += chunk.toString(\"utf8\");\n const nl = buffer.indexOf(\"\\n\");\n if (nl === -1) return;\n const line = buffer.slice(0, nl);\n\n let response: { ok: boolean; result?: Record<string, unknown>; error?: string };\n try {\n response = JSON.parse(line);\n } catch {\n finish(new Error(`AIBroker IPC parse error: ${line.slice(0, 120)}`));\n return;\n }\n\n if (!response.ok) {\n finish(new Error(response.error ?? \"AIBroker IPC call failed\"));\n } else {\n finish(null, response.result ?? {});\n }\n });\n\n socket.on(\"error\", (e: NodeJS.ErrnoException) => {\n if (e.code === \"ENOENT\" || e.code === \"ECONNREFUSED\") {\n finish(new Error(\"AIBroker not running (socket not found).\"));\n } else {\n finish(e);\n }\n });\n\n socket.on(\"end\", () => {\n if (!done) finish(new Error(\"AIBroker IPC connection closed before response.\"));\n });\n\n timer = setTimeout(\n () => finish(new Error(\"AIBroker IPC call timed out.\")),\n timeoutMs\n );\n });\n}\n\n// ---------------------------------------------------------------------------\n// Typed helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Fetch all live iTerm2 session metadata from AIBroker via the `sessions` method.\n * Returns an empty array if AIBroker is not running.\n *\n * This is metadata-only (no scrollback). It is faster than `session_content`\n * and the correct source for listing/routing purposes.\n */\nexport async function fetchLiveSessions(): Promise<AiBrokerSessionMeta[]> {\n try {\n const result = await callAiBroker(\"sessions\", {});\n const sessions = (result as unknown as AiBrokerSessionsResult).sessions;\n if (!Array.isArray(sessions)) return [];\n return sessions;\n } catch {\n return [];\n }\n}\n\n/**\n * Fetch live sessions WITH the last user prompt extracted from terminal scrollback.\n *\n * Heavier than `fetchLiveSessions` (one IPC call returning full content for\n * every session), but yields a `lastPrompt` field useful for the unified\n * listing.\n */\nexport async function fetchLiveSessionsWithPrompts(): Promise<\n (AiBrokerSessionMeta & { lastPrompt?: string })[]\n> {\n // Get the basic metadata first (always works, fast).\n const metas = await fetchLiveSessions();\n if (metas.length === 0) return [];\n\n // Then enrich with last prompts via session_content (single call, all sessions).\n try {\n const contentResult = (await callAiBroker(\"session_content\", { lines: 60 })) as {\n sessions?: Array<{ sessionId: string; content?: string }>;\n };\n const contentMap = new Map<string, string>();\n for (const s of contentResult.sessions ?? []) {\n if (s.sessionId && typeof s.content === \"string\") {\n contentMap.set(s.sessionId, s.content);\n }\n }\n return metas.map((m) => {\n const content = contentMap.get(m.sessionId);\n const lastPrompt = content ? extractLastUserPrompt(content) : undefined;\n return { ...m, lastPrompt };\n });\n } catch {\n return metas.map((m) => ({ ...m }));\n }\n}\n\n/**\n * Extract the most-recent user prompt from a terminal scrollback string.\n *\n * Claude Code's TUI shows user input lines prefixed with `❯ `. We scan from\n * the bottom up, skipping the active input box (between the two horizontal\n * rule lines) and the statusline footer.\n */\nfunction extractLastUserPrompt(content: string): string | undefined {\n const lines = content.split(\"\\n\");\n // Walk bottom-up looking for the most recent user-typed line.\n // Claude Code marks user prompts with one of these prefixes:\n // ❯ <text> (current/recent prompt in the input box or scrollback)\n // > <text> (older variant)\n // The line MUST have non-empty content after the prompt symbol.\n // Skip the active input box (often empty `❯`) and statusline (👋 PAI CC...).\n for (let i = lines.length - 1; i >= 0; i--) {\n const line = lines[i].trim();\n // Match ❯ or > (followed by space) then content\n const m = line.match(/^[❯>]\\s+(.+?)\\s*$/);\n if (!m) continue;\n let text = m[1].trim();\n if (!text) continue;\n // Skip lines that are just box-drawing or known UI noise\n if (/^[─━═]+/.test(text)) continue;\n if (text.startsWith(\"👋\")) continue;\n // Strip ANSI escape sequences that may leak in\n text = text.replace(/\\x1B\\[[0-9;]*[A-Za-z]/g, \"\").trim();\n if (text) return text;\n }\n return undefined;\n}\n\n/**\n * Send text to a specific AIBroker session by its iTerm2 sessionId.\n *\n * The wire keys are `target` and `message`, and neither is negotiable — the\n * handler rejects anything else with \"target is required\" before it looks at\n * the rest. This was written as `{ target: sessionId, message: text }`, which is the shape of\n * THIS function's own parameters rather than the shape of the IPC, so every\n * call failed identically. `pai pause all` was the only caller, so the live\n * path had never once executed: its --dry-run branch returns before sending,\n * and that was the only branch anyone had exercised.\n *\n * The caller must NOT terminate `text` with a newline. The transport sends with\n * `enter: true` and appends the Enter itself, so a trailing \\n submits twice —\n * once for the text and once for an empty prompt.\n */\nexport async function sendToSession(\n sessionId: string,\n text: string,\n timeoutMs = SEND_TIMEOUT_MS\n): Promise<{ ok: boolean; error?: string; timedOut?: boolean }> {\n try {\n await callAiBroker(\"send_to_session\", { target: sessionId, message: text }, timeoutMs);\n return { ok: true };\n } catch (e) {\n const error = String(e);\n // A timeout is NOT a delivery failure, and conflating the two is expensive.\n // The handler deposits into the target's mailbox BEFORE it waits for the\n // submit ack, so a send that times out has still been delivered — only the\n // confirmation is missing. Reported as a plain failure, the natural response\n // is to send again, which is how `pai pause all` produced nested\n // \"carried forward\" blocks in checkpoints that had already been written.\n return { ok: false, error, timedOut: /timed out/i.test(error) };\n }\n}\n\n/**\n * Switch iTerm2 focus to the session identified by `target`.\n *\n * `target` can be a sessionId, paiName, or tab index number (as string).\n * After switching, activates the iTerm2 application itself so the window\n * comes to the foreground.\n *\n * Returns { ok: true } if AIBroker confirmed the switch, or\n * { ok: false, error } if AIBroker is not running or the session was not found.\n */\nexport async function switchToSession(target: string): Promise<{ ok: boolean; error?: string }> {\n try {\n await callAiBroker(\"switch\", { target });\n // Bring iTerm2 itself to the foreground (the IPC only selects the tab)\n const { spawnSync } = await import(\"node:child_process\");\n spawnSync(\"osascript\", [\"-e\", 'tell application \"iTerm\" to activate'], {\n stdio: \"ignore\",\n });\n return { ok: true };\n } catch (e) {\n return { ok: false, error: String(e) };\n }\n}\n\n/**\n * Bring the iTerm2 tab containing a specific session to the front.\n *\n * This is the mechanism AIBroker's screenshot path uses: match the session by\n * its iTerm2 session id (the `sessionId` returned by `fetchLiveSessions`, which\n * is iTerm's own `id of session`), then `select` its window, tab, and session.\n * Unlike the `switch` IPC (which only flips an internal index and never touches\n * iTerm), this actually reveals the tab.\n */\nexport function revealItermSession(itermSessionId: string): { ok: boolean; error?: string } {\n // Strip any \"iterm:\" style prefix, matching AIBroker's stripItermPrefix.\n const id = itermSessionId.replace(/^iterm:/i, \"\").trim();\n const script = `tell application \"iTerm2\"\n activate\n repeat with w in windows\n repeat with t in tabs of w\n repeat with s in sessions of t\n if id of s is \"${id}\" then\n select w\n select t\n select s\n return \"ok\"\n end if\n end repeat\n end repeat\n end repeat\n return \"not-found\"\nend tell`;\n try {\n const r = spawnSync(\"osascript\", [\"-e\", script], { encoding: \"utf8\" });\n if (r.status !== 0) {\n return { ok: false, error: (r.stderr || \"osascript failed\").trim() };\n }\n if ((r.stdout ?? \"\").trim() === \"ok\") return { ok: true };\n return { ok: false, error: \"session not found in any iTerm2 window\" };\n } catch (e) {\n return { ok: false, error: String(e) };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"aibroker-client-CDIXmq-e.mjs","names":[],"sources":["../src/cli/lib/aibroker-client.ts"],"sourcesContent":["/**\n * aibroker-client.ts — Lightweight IPC client for AIBroker daemon.\n *\n * Connects to the AIBroker Unix Domain Socket, sends a JSON-RPC request,\n * and reads a single newline-terminated JSON response. No class needed —\n * just a thin async function matching the WatcherClient protocol.\n *\n * Socket path: /tmp/aibroker.sock (default; override via AIBROKER_SOCKET env).\n */\n\nimport { connect } from \"node:net\";\nimport { randomUUID } from \"node:crypto\";\nimport { spawnSync } from \"node:child_process\";\nimport { aibrokerSocketPath } from \"../../runtime-paths.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Lightweight session metadata returned by the AIBroker `sessions` IPC method.\n * Does NOT include scrollback content — use `session_content` for that.\n */\nexport interface AiBrokerSessionMeta {\n index: number;\n sessionId: string;\n /** iTerm2 tab title or profile name */\n name: string;\n /** PAI session name set via /Name; null for bare shells */\n paiName: string | null;\n atPrompt: boolean;\n /** \"claude\" for Claude Code panes, \"shell\" for bare terminals */\n kind: \"claude\" | \"shell\";\n /** Whether this is the currently focused pane */\n active: boolean;\n /** Last user prompt seen in scrollback (only populated by fetchLiveSessionsWithPrompts) */\n lastPrompt?: string;\n}\n\ninterface AiBrokerSessionsResult {\n sessions: AiBrokerSessionMeta[];\n}\n\n// ---------------------------------------------------------------------------\n// Core call\n// ---------------------------------------------------------------------------\n\n// AIBROKER_SOCKET stays first: it is AIBroker's own variable and a user who has\n// set it means it. The fallback goes through runtime-paths so the test guard\n// can redirect it — writing to a live socket from a test is the same hazard as\n// writing to live user state, and this one is not even ours.\nconst DEFAULT_SOCKET = process.env.AIBROKER_SOCKET ?? aibrokerSocketPath();\n\n/**\n * How long to wait for `send_to_session`, which must exceed the server's own\n * ack window or the caller gives up while the callee is still working.\n *\n * AIBroker waits up to SEND_ACK_TIMEOUT_MS (15s) for the submit confirmation —\n * the text leaving the input line — before answering. The generic client\n * timeout is 8s. So every send needing 8-15s to confirm reported\n * \"AIBroker IPC call timed out\" while succeeding, and the handler's eventual\n * `delivered: true` was written into a socket nobody was reading any more.\n *\n * Measured on `pai pause all` across 15 sessions: 9 reported failed, 8 of them\n * verifiably paused. A caller's deadline shorter than the callee's is not a\n * tuning question, it is a guaranteed false negative on every slow success.\n */\nconst SEND_TIMEOUT_MS = 30_000;\n\n/**\n * Call an AIBroker IPC method and return the result.\n *\n * Resolves with the `result` field of a successful response.\n * Rejects if the socket is not available, the call times out, or the\n * daemon returns an error.\n *\n * @param method IPC method name (e.g. \"session_content\", \"send_to_session\")\n * @param params Method parameters object\n * @param timeoutMs Connection + response timeout in milliseconds (default: 8 000)\n */\nexport function callAiBroker(\n method: string,\n params: Record<string, unknown> = {},\n timeoutMs = 8_000\n): Promise<Record<string, unknown>> {\n return new Promise((resolve, reject) => {\n const socketPath = DEFAULT_SOCKET;\n let done = false;\n let buffer = \"\";\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n function finish(err: Error | null, value?: Record<string, unknown>): void {\n if (done) return;\n done = true;\n if (timer !== null) {\n clearTimeout(timer);\n timer = null;\n }\n try {\n socket.destroy();\n } catch {\n /* ignore */\n }\n if (err) reject(err);\n else resolve(value!);\n }\n\n const socket = connect(socketPath, () => {\n const request = {\n id: randomUUID(),\n sessionId: process.env.TERM_SESSION_ID ?? \"pai-cli\",\n method,\n params,\n };\n const itermId = process.env.ITERM_SESSION_ID;\n if (itermId) Object.assign(request, { itermSessionId: itermId });\n socket.write(JSON.stringify(request) + \"\\n\");\n });\n\n socket.on(\"data\", (chunk: Buffer) => {\n buffer += chunk.toString(\"utf8\");\n const nl = buffer.indexOf(\"\\n\");\n if (nl === -1) return;\n const line = buffer.slice(0, nl);\n\n let response: { ok: boolean; result?: Record<string, unknown>; error?: string };\n try {\n response = JSON.parse(line);\n } catch {\n finish(new Error(`AIBroker IPC parse error: ${line.slice(0, 120)}`));\n return;\n }\n\n if (!response.ok) {\n finish(new Error(response.error ?? \"AIBroker IPC call failed\"));\n } else {\n finish(null, response.result ?? {});\n }\n });\n\n socket.on(\"error\", (e: NodeJS.ErrnoException) => {\n if (e.code === \"ENOENT\" || e.code === \"ECONNREFUSED\") {\n finish(new Error(\"AIBroker not running (socket not found).\"));\n } else {\n finish(e);\n }\n });\n\n socket.on(\"end\", () => {\n if (!done) finish(new Error(\"AIBroker IPC connection closed before response.\"));\n });\n\n timer = setTimeout(\n () => finish(new Error(\"AIBroker IPC call timed out.\")),\n timeoutMs\n );\n });\n}\n\n// ---------------------------------------------------------------------------\n// Typed helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Fetch all live iTerm2 session metadata from AIBroker via the `sessions` method.\n * Returns an empty array if AIBroker is not running.\n *\n * This is metadata-only (no scrollback). It is faster than `session_content`\n * and the correct source for listing/routing purposes.\n */\nexport async function fetchLiveSessions(): Promise<AiBrokerSessionMeta[]> {\n try {\n const result = await callAiBroker(\"sessions\", {});\n const sessions = (result as unknown as AiBrokerSessionsResult).sessions;\n if (!Array.isArray(sessions)) return [];\n return sessions;\n } catch {\n return [];\n }\n}\n\n/**\n * Fetch live sessions WITH the last user prompt extracted from terminal scrollback.\n *\n * Heavier than `fetchLiveSessions` (one IPC call returning full content for\n * every session), but yields a `lastPrompt` field useful for the unified\n * listing.\n */\nexport async function fetchLiveSessionsWithPrompts(): Promise<\n (AiBrokerSessionMeta & { lastPrompt?: string })[]\n> {\n // Get the basic metadata first (always works, fast).\n const metas = await fetchLiveSessions();\n if (metas.length === 0) return [];\n\n // Then enrich with last prompts via session_content (single call, all sessions).\n try {\n const contentResult = (await callAiBroker(\"session_content\", { lines: 60 })) as {\n sessions?: Array<{ sessionId: string; content?: string }>;\n };\n const contentMap = new Map<string, string>();\n for (const s of contentResult.sessions ?? []) {\n if (s.sessionId && typeof s.content === \"string\") {\n contentMap.set(s.sessionId, s.content);\n }\n }\n return metas.map((m) => {\n const content = contentMap.get(m.sessionId);\n const lastPrompt = content ? extractLastUserPrompt(content) : undefined;\n return { ...m, lastPrompt };\n });\n } catch {\n return metas.map((m) => ({ ...m }));\n }\n}\n\n/**\n * Extract the most-recent user prompt from a terminal scrollback string.\n *\n * Claude Code's TUI shows user input lines prefixed with `❯ `. We scan from\n * the bottom up, skipping the active input box (between the two horizontal\n * rule lines) and the statusline footer.\n */\nfunction extractLastUserPrompt(content: string): string | undefined {\n const lines = content.split(\"\\n\");\n // Walk bottom-up looking for the most recent user-typed line.\n // Claude Code marks user prompts with one of these prefixes:\n // ❯ <text> (current/recent prompt in the input box or scrollback)\n // > <text> (older variant)\n // The line MUST have non-empty content after the prompt symbol.\n // Skip the active input box (often empty `❯`) and statusline (👋 PAI CC...).\n for (let i = lines.length - 1; i >= 0; i--) {\n const line = lines[i].trim();\n // Match ❯ or > (followed by space) then content\n const m = line.match(/^[❯>]\\s+(.+?)\\s*$/);\n if (!m) continue;\n let text = m[1].trim();\n if (!text) continue;\n // Skip lines that are just box-drawing or known UI noise\n if (/^[─━═]+/.test(text)) continue;\n if (text.startsWith(\"👋\")) continue;\n // Strip ANSI escape sequences that may leak in\n text = text.replace(/\\x1B\\[[0-9;]*[A-Za-z]/g, \"\").trim();\n if (text) return text;\n }\n return undefined;\n}\n\n/**\n * Send text to a specific AIBroker session by its iTerm2 sessionId.\n *\n * The wire keys are `target` and `message`, and neither is negotiable — the\n * handler rejects anything else with \"target is required\" before it looks at\n * the rest. This was written as `{ target: sessionId, message: text }`, which is the shape of\n * THIS function's own parameters rather than the shape of the IPC, so every\n * call failed identically. `pai pause all` was the only caller, so the live\n * path had never once executed: its --dry-run branch returns before sending,\n * and that was the only branch anyone had exercised.\n *\n * The caller must NOT terminate `text` with a newline. The transport sends with\n * `enter: true` and appends the Enter itself, so a trailing \\n submits twice —\n * once for the text and once for an empty prompt.\n */\nexport async function sendToSession(\n sessionId: string,\n text: string,\n timeoutMs = SEND_TIMEOUT_MS\n): Promise<{ ok: boolean; error?: string; timedOut?: boolean }> {\n try {\n await callAiBroker(\"send_to_session\", { target: sessionId, message: text }, timeoutMs);\n return { ok: true };\n } catch (e) {\n const error = String(e);\n // A timeout is NOT a delivery failure, and conflating the two is expensive.\n // The handler deposits into the target's mailbox BEFORE it waits for the\n // submit ack, so a send that times out has still been delivered — only the\n // confirmation is missing. Reported as a plain failure, the natural response\n // is to send again, which is how `pai pause all` produced nested\n // \"carried forward\" blocks in checkpoints that had already been written.\n return { ok: false, error, timedOut: /timed out/i.test(error) };\n }\n}\n\n/**\n * Switch iTerm2 focus to the session identified by `target`.\n *\n * `target` can be a sessionId, paiName, or tab index number (as string).\n * After switching, activates the iTerm2 application itself so the window\n * comes to the foreground.\n *\n * Returns { ok: true } if AIBroker confirmed the switch, or\n * { ok: false, error } if AIBroker is not running or the session was not found.\n */\nexport async function switchToSession(target: string): Promise<{ ok: boolean; error?: string }> {\n try {\n await callAiBroker(\"switch\", { target });\n // Bring iTerm2 itself to the foreground (the IPC only selects the tab)\n const { spawnSync } = await import(\"node:child_process\");\n spawnSync(\"osascript\", [\"-e\", 'tell application \"iTerm\" to activate'], {\n stdio: \"ignore\",\n });\n return { ok: true };\n } catch (e) {\n return { ok: false, error: String(e) };\n }\n}\n\n/**\n * Bring the iTerm2 tab containing a specific session to the front.\n *\n * This is the mechanism AIBroker's screenshot path uses: match the session by\n * its iTerm2 session id (the `sessionId` returned by `fetchLiveSessions`, which\n * is iTerm's own `id of session`), then `select` its window, tab, and session.\n * Unlike the `switch` IPC (which only flips an internal index and never touches\n * iTerm), this actually reveals the tab.\n */\nexport function revealItermSession(itermSessionId: string): { ok: boolean; error?: string } {\n // Strip any \"iterm:\" style prefix, matching AIBroker's stripItermPrefix.\n const id = itermSessionId.replace(/^iterm:/i, \"\").trim();\n const script = `tell application \"iTerm2\"\n activate\n repeat with w in windows\n repeat with t in tabs of w\n repeat with s in sessions of t\n if id of s is \"${id}\" then\n select w\n select t\n select s\n return \"ok\"\n end if\n end repeat\n end repeat\n end repeat\n return \"not-found\"\nend tell`;\n try {\n const r = spawnSync(\"osascript\", [\"-e\", script], { encoding: \"utf8\" });\n if (r.status !== 0) {\n return { ok: false, error: (r.stderr || \"osascript failed\").trim() };\n }\n if ((r.stdout ?? \"\").trim() === \"ok\") return { ok: true };\n return { ok: false, error: \"session not found in any iTerm2 window\" };\n } catch (e) {\n return { ok: false, error: String(e) };\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { C as readWorkersSection } from "./config-DYXARgk8.mjs";
|
|
2
|
+
import { I as newWorkerId, T as appendLedger, W as shortText, n as runWorker } from "./run-TChOnMO_.mjs";
|
|
3
|
+
import { g as ledgerPath, y as workersLogDir } from "./server-R9UkCn3v.mjs";
|
|
4
4
|
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
|
|
@@ -162,4 +162,4 @@ async function runChain(opts, deps = {}) {
|
|
|
162
162
|
|
|
163
163
|
//#endregion
|
|
164
164
|
export { swapPromptArg as n, runChain as t };
|
|
165
|
-
//# sourceMappingURL=chain-
|
|
165
|
+
//# sourceMappingURL=chain-BBbVbWVv.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chain-CNSa0A3G.mjs","names":[],"sources":["../src/workers/chain.ts"],"sourcesContent":["/**\n * chain.ts — draft-then-implement chains: `--chain draft,implement[,review]`.\n *\n * The chain runs each stage as its own worker (own id, own pane, `parent` set\n * to the chain id), so `ps` shows the chain as a tree and every stage can be\n * followed, replayed and said to like any other worker:\n *\n * - draft turns the operator's brief into a full spec file under\n * <logDir>/specs/<chain id>.md (goal, constraints, files likely\n * touched, acceptance checks, verification commands);\n * - any other stage (implement, plan, …) runs with that spec as its prompt\n * and the original brief attached;\n * - review reads the spec and the working-tree diff and produces the\n * structured report.\n *\n * A stage that fails (or a draft that produces no spec file) stops the chain;\n * the caller then writes the spec itself and re-runs without the draft stage.\n */\n\nimport { existsSync, mkdirSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { readWorkersSection } from \"./config.js\";\nimport { appendLedger } from \"./ledger.js\";\nimport { ledgerPath, workersLogDir } from \"./paths.js\";\nimport { newWorkerId } from \"./status.js\";\nimport { shortText } from \"./args.js\";\nimport { runWorker, type RunOptions } from \"./run.js\";\n\n/** Where a chain's spec file lives: <logDir>/specs/<chain id>.md. */\nexport function specPathFor(logDir: string, chainId: string): string {\n return join(logDir, \"specs\", `${chainId}.md`);\n}\n\n/**\n * Replace the caller's -p value with `prompt`, dropping every existing\n * -p/--print pair first (two -p flags on one claude command line are an error,\n * so the chain must never leave the brief in place when swapping prompts).\n */\nexport function swapPromptArg(claudeArgs: string[], prompt: string): string[] {\n const out: string[] = [];\n for (let i = 0; i < claudeArgs.length; i++) {\n const a = claudeArgs[i];\n if (a === \"-p\" || a === \"--print\") {\n if (i + 1 < claudeArgs.length && !claudeArgs[i + 1].startsWith(\"-\")) i += 1;\n continue;\n }\n out.push(a);\n }\n out.push(\"-p\", prompt);\n return out;\n}\n\nexport function draftPrompt(brief: string, specPath: string): string {\n return [\n \"You are the DRAFT stage of a worker chain. Turn the operator's brief below into a full implementation spec and write it to\",\n specPath,\n \"with the Write tool.\",\n \"\",\n \"Use exactly these five sections as Markdown headings:\",\n \"# Goal\",\n \"# Constraints\",\n \"# Files likely touched\",\n \"# Acceptance checks\",\n \"# Verification commands\",\n \"\",\n \"Read the repository first (Glob/Grep/Read) so the spec names real files and real commands. Do not implement anything.\",\n \"\",\n \"## Operator brief\",\n \"\",\n brief,\n ].join(\"\\n\");\n}\n\nexport function implementPrompt(brief: string, specPath: string | null, spec: string | null): string {\n const head = spec\n ? [\n \"You are the IMPLEMENT stage of a worker chain. The draft stage wrote the spec below (also at \" +\n specPath +\n \"). Implement it exactly, then run the spec's verification commands before finishing.\",\n \"\",\n \"## Spec\",\n \"\",\n spec,\n ]\n : [\"Implement the operator's brief below.\"];\n return [...head, \"\", \"## Operator brief\", \"\", brief].join(\"\\n\");\n}\n\nexport function reviewPrompt(brief: string, specPath: string | null, spec: string | null): string {\n const specPart = spec\n ? [\n \"\",\n \"## Spec (also at \" + specPath + \")\",\n \"\",\n spec,\n ]\n : [];\n return [\n \"You are the REVIEW stage of a worker chain. The implement stage just ran. Read the repository's diff (run `git diff` and `git status`; use `git diff --stat` for the overview) and check it against the spec's acceptance checks and verification commands — run the checks when they are cheap. Do not fix anything you find; report it.\",\n ...specPart,\n \"\",\n \"## Operator brief\",\n \"\",\n brief,\n ].join(\"\\n\");\n}\n\nexport interface ChainOptions {\n /** Class names, run in order: e.g. [\"draft\", \"implement\", \"review\"]. */\n stages: string[];\n /** Overrides the class of every stage when given (--class with --chain). */\n className?: string;\n providerFlag?: string;\n modelFlag?: string;\n label?: string;\n noPane?: boolean;\n mcpFlag?: string;\n /** --spec value, resolved for display/recording (\"-\" for stdin). */\n specPath?: string;\n /** The operator's brief — the -p value of the run. */\n brief: string;\n /** The caller's claude args (allowedTools etc.); the -p value is swapped. */\n claudeArgs: string[];\n cwd?: string;\n /** Internal: notified with the chain id once it exists (worker_run uses it). */\n onChainStart?: (chainId: string) => void;\n /** Internal: suppress result printing (the MCP shim's stdout is the RPC channel). */\n quiet?: boolean;\n}\n\nexport interface ChainDeps {\n /** Stage runner; tests inject a mock, production uses runWorker. */\n runStage?: (opts: RunOptions) => Promise<number>;\n /** logDir override for tests; default: the configured workers logDir. */\n logDir?: string;\n}\n\n/** Run a chain of stages; returns the exit code of the first failed stage, 0 when all pass. */\nexport async function runChain(opts: ChainOptions, deps: ChainDeps = {}): Promise<number> {\n const stages = opts.stages.map((s) => s.trim()).filter(Boolean);\n if (!stages.length) throw new Error(\"--chain needs at least one class, e.g. --chain draft,implement\");\n const runStage = deps.runStage ?? runWorker;\n const logDir = deps.logDir ?? workersLogDir(readWorkersSection().workers);\n const chainId = newWorkerId();\n const specPath = specPathFor(logDir, chainId);\n mkdirSync(join(logDir, \"specs\"), { recursive: true }); // the draft stage writes into it\n const baseLabel = opts.label ?? shortText(opts.brief, 40);\n\n appendLedger(ledgerPath(logDir), \"WORKER-CHAIN\", {\n chain: chainId,\n stages: stages.join(\",\"),\n label: baseLabel,\n });\n opts.onChainStart?.(chainId);\n\n let spec: string | null = null;\n for (let i = 0; i < stages.length; i++) {\n const stage = stages[i];\n if (stage === \"draft\") {\n spec = null; // a chain may legally start over; the draft rewrites it\n } else if (spec === null && existsSync(specPath)) {\n spec = readFileSync(specPath, \"utf8\");\n }\n const prompt =\n stage === \"draft\"\n ? draftPrompt(opts.brief, specPath)\n : stage === \"review\"\n ? reviewPrompt(opts.brief, spec ? specPath : null, spec)\n : implementPrompt(opts.brief, spec ? specPath : null, spec);\n process.stderr.write(\n `chain ${chainId}: stage ${i + 1}/${stages.length} ${stage} (spec: ${specPath})\\n`\n );\n const rc = await runStage({\n className: opts.className ?? stage,\n providerFlag: opts.providerFlag,\n modelFlag: opts.modelFlag,\n label: `${baseLabel} · ${stage}`,\n noPane: opts.noPane,\n mcpFlag: opts.mcpFlag,\n specPath: opts.specPath,\n claudeArgs: swapPromptArg(opts.claudeArgs, prompt),\n cwd: opts.cwd,\n parent: chainId,\n stage,\n quiet: opts.quiet,\n });\n if (stage === \"draft\") {\n if (!existsSync(specPath)) {\n process.stderr.write(\n `chain ${chainId}: draft stage produced no spec at ${specPath} — stopping. ` +\n `Write the spec yourself and re-run without the draft stage.\\n`\n );\n appendLedger(ledgerPath(logDir), \"WORKER-CHAIN-END\", {\n chain: chainId,\n rc: rc !== 0 ? rc : 1,\n failed: \"draft\",\n });\n return rc !== 0 ? rc : 1;\n }\n spec = readFileSync(specPath, \"utf8\");\n }\n if (rc !== 0) {\n appendLedger(ledgerPath(logDir), \"WORKER-CHAIN-END\", {\n chain: chainId,\n rc,\n failed: stage,\n });\n return rc;\n }\n }\n appendLedger(ledgerPath(logDir), \"WORKER-CHAIN-END\", { chain: chainId, rc: 0 });\n return 0;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chain-BBbVbWVv.mjs","names":[],"sources":["../src/workers/chain.ts"],"sourcesContent":["/**\n * chain.ts — draft-then-implement chains: `--chain draft,implement[,review]`.\n *\n * The chain runs each stage as its own worker (own id, own pane, `parent` set\n * to the chain id), so `ps` shows the chain as a tree and every stage can be\n * followed, replayed and said to like any other worker:\n *\n * - draft turns the operator's brief into a full spec file under\n * <logDir>/specs/<chain id>.md (goal, constraints, files likely\n * touched, acceptance checks, verification commands);\n * - any other stage (implement, plan, …) runs with that spec as its prompt\n * and the original brief attached;\n * - review reads the spec and the working-tree diff and produces the\n * structured report.\n *\n * A stage that fails (or a draft that produces no spec file) stops the chain;\n * the caller then writes the spec itself and re-runs without the draft stage.\n */\n\nimport { existsSync, mkdirSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { readWorkersSection } from \"./config.js\";\nimport { appendLedger } from \"./ledger.js\";\nimport { ledgerPath, workersLogDir } from \"./paths.js\";\nimport { newWorkerId } from \"./status.js\";\nimport { shortText } from \"./args.js\";\nimport { runWorker, type RunOptions } from \"./run.js\";\n\n/** Where a chain's spec file lives: <logDir>/specs/<chain id>.md. */\nexport function specPathFor(logDir: string, chainId: string): string {\n return join(logDir, \"specs\", `${chainId}.md`);\n}\n\n/**\n * Replace the caller's -p value with `prompt`, dropping every existing\n * -p/--print pair first (two -p flags on one claude command line are an error,\n * so the chain must never leave the brief in place when swapping prompts).\n */\nexport function swapPromptArg(claudeArgs: string[], prompt: string): string[] {\n const out: string[] = [];\n for (let i = 0; i < claudeArgs.length; i++) {\n const a = claudeArgs[i];\n if (a === \"-p\" || a === \"--print\") {\n if (i + 1 < claudeArgs.length && !claudeArgs[i + 1].startsWith(\"-\")) i += 1;\n continue;\n }\n out.push(a);\n }\n out.push(\"-p\", prompt);\n return out;\n}\n\nexport function draftPrompt(brief: string, specPath: string): string {\n return [\n \"You are the DRAFT stage of a worker chain. Turn the operator's brief below into a full implementation spec and write it to\",\n specPath,\n \"with the Write tool.\",\n \"\",\n \"Use exactly these five sections as Markdown headings:\",\n \"# Goal\",\n \"# Constraints\",\n \"# Files likely touched\",\n \"# Acceptance checks\",\n \"# Verification commands\",\n \"\",\n \"Read the repository first (Glob/Grep/Read) so the spec names real files and real commands. Do not implement anything.\",\n \"\",\n \"## Operator brief\",\n \"\",\n brief,\n ].join(\"\\n\");\n}\n\nexport function implementPrompt(brief: string, specPath: string | null, spec: string | null): string {\n const head = spec\n ? [\n \"You are the IMPLEMENT stage of a worker chain. The draft stage wrote the spec below (also at \" +\n specPath +\n \"). Implement it exactly, then run the spec's verification commands before finishing.\",\n \"\",\n \"## Spec\",\n \"\",\n spec,\n ]\n : [\"Implement the operator's brief below.\"];\n return [...head, \"\", \"## Operator brief\", \"\", brief].join(\"\\n\");\n}\n\nexport function reviewPrompt(brief: string, specPath: string | null, spec: string | null): string {\n const specPart = spec\n ? [\n \"\",\n \"## Spec (also at \" + specPath + \")\",\n \"\",\n spec,\n ]\n : [];\n return [\n \"You are the REVIEW stage of a worker chain. The implement stage just ran. Read the repository's diff (run `git diff` and `git status`; use `git diff --stat` for the overview) and check it against the spec's acceptance checks and verification commands — run the checks when they are cheap. Do not fix anything you find; report it.\",\n ...specPart,\n \"\",\n \"## Operator brief\",\n \"\",\n brief,\n ].join(\"\\n\");\n}\n\nexport interface ChainOptions {\n /** Class names, run in order: e.g. [\"draft\", \"implement\", \"review\"]. */\n stages: string[];\n /** Overrides the class of every stage when given (--class with --chain). */\n className?: string;\n providerFlag?: string;\n modelFlag?: string;\n label?: string;\n noPane?: boolean;\n mcpFlag?: string;\n /** --spec value, resolved for display/recording (\"-\" for stdin). */\n specPath?: string;\n /** The operator's brief — the -p value of the run. */\n brief: string;\n /** The caller's claude args (allowedTools etc.); the -p value is swapped. */\n claudeArgs: string[];\n cwd?: string;\n /** Internal: notified with the chain id once it exists (worker_run uses it). */\n onChainStart?: (chainId: string) => void;\n /** Internal: suppress result printing (the MCP shim's stdout is the RPC channel). */\n quiet?: boolean;\n}\n\nexport interface ChainDeps {\n /** Stage runner; tests inject a mock, production uses runWorker. */\n runStage?: (opts: RunOptions) => Promise<number>;\n /** logDir override for tests; default: the configured workers logDir. */\n logDir?: string;\n}\n\n/** Run a chain of stages; returns the exit code of the first failed stage, 0 when all pass. */\nexport async function runChain(opts: ChainOptions, deps: ChainDeps = {}): Promise<number> {\n const stages = opts.stages.map((s) => s.trim()).filter(Boolean);\n if (!stages.length) throw new Error(\"--chain needs at least one class, e.g. --chain draft,implement\");\n const runStage = deps.runStage ?? runWorker;\n const logDir = deps.logDir ?? workersLogDir(readWorkersSection().workers);\n const chainId = newWorkerId();\n const specPath = specPathFor(logDir, chainId);\n mkdirSync(join(logDir, \"specs\"), { recursive: true }); // the draft stage writes into it\n const baseLabel = opts.label ?? shortText(opts.brief, 40);\n\n appendLedger(ledgerPath(logDir), \"WORKER-CHAIN\", {\n chain: chainId,\n stages: stages.join(\",\"),\n label: baseLabel,\n });\n opts.onChainStart?.(chainId);\n\n let spec: string | null = null;\n for (let i = 0; i < stages.length; i++) {\n const stage = stages[i];\n if (stage === \"draft\") {\n spec = null; // a chain may legally start over; the draft rewrites it\n } else if (spec === null && existsSync(specPath)) {\n spec = readFileSync(specPath, \"utf8\");\n }\n const prompt =\n stage === \"draft\"\n ? draftPrompt(opts.brief, specPath)\n : stage === \"review\"\n ? reviewPrompt(opts.brief, spec ? specPath : null, spec)\n : implementPrompt(opts.brief, spec ? specPath : null, spec);\n process.stderr.write(\n `chain ${chainId}: stage ${i + 1}/${stages.length} ${stage} (spec: ${specPath})\\n`\n );\n const rc = await runStage({\n className: opts.className ?? stage,\n providerFlag: opts.providerFlag,\n modelFlag: opts.modelFlag,\n label: `${baseLabel} · ${stage}`,\n noPane: opts.noPane,\n mcpFlag: opts.mcpFlag,\n specPath: opts.specPath,\n claudeArgs: swapPromptArg(opts.claudeArgs, prompt),\n cwd: opts.cwd,\n parent: chainId,\n stage,\n quiet: opts.quiet,\n });\n if (stage === \"draft\") {\n if (!existsSync(specPath)) {\n process.stderr.write(\n `chain ${chainId}: draft stage produced no spec at ${specPath} — stopping. ` +\n `Write the spec yourself and re-run without the draft stage.\\n`\n );\n appendLedger(ledgerPath(logDir), \"WORKER-CHAIN-END\", {\n chain: chainId,\n rc: rc !== 0 ? rc : 1,\n failed: \"draft\",\n });\n return rc !== 0 ? rc : 1;\n }\n spec = readFileSync(specPath, \"utf8\");\n }\n if (rc !== 0) {\n appendLedger(ledgerPath(logDir), \"WORKER-CHAIN-END\", {\n chain: chainId,\n rc,\n failed: stage,\n });\n return rc;\n }\n }\n appendLedger(ledgerPath(logDir), \"WORKER-CHAIN-END\", { chain: chainId, rc: 0 });\n return 0;\n}\n"],"mappings":"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"}
|
package/dist/cli/index.mjs
CHANGED
|
@@ -7,21 +7,21 @@ import "../helpers-crDEr6S2.mjs";
|
|
|
7
7
|
import "../sync-Btcb6xA4.mjs";
|
|
8
8
|
import "../embeddings-DvRKcQyt.mjs";
|
|
9
9
|
import "../search-B69cQwDB.mjs";
|
|
10
|
-
import { n as drainStdio, t as buildProgram } from "../program-
|
|
11
|
-
import "../context-handover-cache-
|
|
12
|
-
import "../config-
|
|
13
|
-
import "../config-
|
|
14
|
-
import "../run-
|
|
15
|
-
import "../
|
|
10
|
+
import { n as drainStdio, t as buildProgram } from "../program-BX67-4I2.mjs";
|
|
11
|
+
import "../context-handover-cache-yOuK9RIk.mjs";
|
|
12
|
+
import "../config-Bn9jpblO.mjs";
|
|
13
|
+
import "../config-DYXARgk8.mjs";
|
|
14
|
+
import "../run-TChOnMO_.mjs";
|
|
15
|
+
import "../session-keepalive-BuG3wvik.mjs";
|
|
16
16
|
import "../ipc-client-C6NryMMb.mjs";
|
|
17
|
-
import "../factory-
|
|
18
|
-
import "../
|
|
19
|
-
import "../
|
|
20
|
-
import "../
|
|
21
|
-
import "../
|
|
22
|
-
import "../
|
|
23
|
-
import "../
|
|
24
|
-
import "../
|
|
17
|
+
import "../factory-Bt7TWQje.mjs";
|
|
18
|
+
import "../fallback-CIGspCSi.mjs";
|
|
19
|
+
import "../wakeup-Yk5lQ0jb.mjs";
|
|
20
|
+
import "../main-resolver-BmZPCmgj.mjs";
|
|
21
|
+
import "../server-R9UkCn3v.mjs";
|
|
22
|
+
import "../state-DwrsOoMi.mjs";
|
|
23
|
+
import "../aibroker-client-CDIXmq-e.mjs";
|
|
24
|
+
import "../chain-BBbVbWVv.mjs";
|
|
25
25
|
import { CommanderError } from "commander";
|
|
26
26
|
|
|
27
27
|
//#region src/cli/index.ts
|
package/dist/cli/program.mjs
CHANGED
|
@@ -6,20 +6,20 @@ import "../helpers-crDEr6S2.mjs";
|
|
|
6
6
|
import "../sync-Btcb6xA4.mjs";
|
|
7
7
|
import "../embeddings-DvRKcQyt.mjs";
|
|
8
8
|
import "../search-B69cQwDB.mjs";
|
|
9
|
-
import { t as buildProgram } from "../program-
|
|
10
|
-
import "../context-handover-cache-
|
|
11
|
-
import "../config-
|
|
12
|
-
import "../config-
|
|
13
|
-
import "../run-
|
|
14
|
-
import "../
|
|
9
|
+
import { t as buildProgram } from "../program-BX67-4I2.mjs";
|
|
10
|
+
import "../context-handover-cache-yOuK9RIk.mjs";
|
|
11
|
+
import "../config-Bn9jpblO.mjs";
|
|
12
|
+
import "../config-DYXARgk8.mjs";
|
|
13
|
+
import "../run-TChOnMO_.mjs";
|
|
14
|
+
import "../session-keepalive-BuG3wvik.mjs";
|
|
15
15
|
import "../ipc-client-C6NryMMb.mjs";
|
|
16
|
-
import "../factory-
|
|
17
|
-
import "../
|
|
18
|
-
import "../
|
|
19
|
-
import "../
|
|
20
|
-
import "../
|
|
21
|
-
import "../
|
|
22
|
-
import "../
|
|
23
|
-
import "../
|
|
16
|
+
import "../factory-Bt7TWQje.mjs";
|
|
17
|
+
import "../fallback-CIGspCSi.mjs";
|
|
18
|
+
import "../wakeup-Yk5lQ0jb.mjs";
|
|
19
|
+
import "../main-resolver-BmZPCmgj.mjs";
|
|
20
|
+
import "../server-R9UkCn3v.mjs";
|
|
21
|
+
import "../state-DwrsOoMi.mjs";
|
|
22
|
+
import "../aibroker-client-CDIXmq-e.mjs";
|
|
23
|
+
import "../chain-BBbVbWVv.mjs";
|
|
24
24
|
|
|
25
25
|
export { buildProgram };
|