@tekmidian/pai 0.66.0 → 0.66.1
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/{chain-D4PuQ2c-.mjs → chain-CZfKIEq9.mjs} +2 -2
- package/dist/{chain-D4PuQ2c-.mjs.map → chain-CZfKIEq9.mjs.map} +1 -1
- package/dist/cli/index.mjs +5 -5
- package/dist/cli/program.mjs +5 -5
- package/dist/daemon/index.mjs +3 -3
- package/dist/{daemon-BEoVgVfJ.mjs → daemon-DXlaVCkw.mjs} +3 -3
- package/dist/{daemon-BEoVgVfJ.mjs.map → daemon-DXlaVCkw.mjs.map} +1 -1
- package/dist/{daemon-DPAYU9hp.mjs → daemon-DyORmxZu.mjs} +3 -3
- package/dist/daemon-mcp/index.mjs +6 -4
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/{fallback-B5svk75f.mjs → fallback-CIiq2Raw.mjs} +6 -4
- package/dist/fallback-CIiq2Raw.mjs.map +1 -0
- package/dist/hooks/block-sleep-poll.mjs.map +2 -2
- package/dist/hooks/load-project-context.mjs.map +2 -2
- package/dist/hooks/worker-guard.mjs +5 -0
- package/dist/hooks/worker-guard.mjs.map +2 -2
- package/dist/hooks/worker-status-line.mjs +1 -0
- package/dist/hooks/worker-status-line.mjs.map +2 -2
- package/dist/{planner-EJPZnnif.mjs → planner-Dm5Acyo1.mjs} +3 -3
- package/dist/{planner-EJPZnnif.mjs.map → planner-Dm5Acyo1.mjs.map} +1 -1
- package/dist/{program-DSETzrWg.mjs → program-JJ0TwSHI.mjs} +9 -6
- package/dist/{program-DSETzrWg.mjs.map → program-JJ0TwSHI.mjs.map} +1 -1
- package/dist/{run-Z4akoa8G.mjs → run-BCpbxqA5.mjs} +168 -6
- package/dist/run-BCpbxqA5.mjs.map +1 -0
- package/dist/{session-keepalive-BDhytXEo.mjs → session-keepalive-DxjTHGcK.mjs} +2 -2
- package/dist/{session-keepalive-BDhytXEo.mjs.map → session-keepalive-DxjTHGcK.mjs.map} +1 -1
- package/package.json +1 -1
- package/src/hooks/ts/lib/worker-guard.test.ts +12 -0
- package/src/hooks/ts/lib/worker-guard.ts +9 -0
- package/dist/fallback-B5svk75f.mjs.map +0 -1
- package/dist/run-Z4akoa8G.mjs.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import "./factory-CNpPQQ-5.mjs";
|
|
2
2
|
import "./config-BbLFD7Uf.mjs";
|
|
3
3
|
import { D as readWorkersSection } from "./run-env-DRcp7A8K.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { $ as parseRunnerArgs, A as mergeWorker, K as newWorkerId, P as appendLedger, W as loadStatus, et as shortText, k as git, n as runWorker, t as printResult } from "./run-BCpbxqA5.mjs";
|
|
5
5
|
import { h as ledgerPath, v as workersLogDir } from "./server-DgmAHyFK.mjs";
|
|
6
|
-
import { n as swapPromptArg } from "./chain-
|
|
6
|
+
import { n as swapPromptArg } from "./chain-CZfKIEq9.mjs";
|
|
7
7
|
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
8
8
|
import { join } from "node:path";
|
|
9
9
|
|
|
@@ -297,4 +297,4 @@ function printPlannerSummary(logDir, plannerId, results, merged, conflicted, fmt
|
|
|
297
297
|
|
|
298
298
|
//#endregion
|
|
299
299
|
export { runPlanner };
|
|
300
|
-
//# sourceMappingURL=planner-
|
|
300
|
+
//# sourceMappingURL=planner-Dm5Acyo1.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planner-EJPZnnif.mjs","names":[],"sources":["../src/workers/planner.ts"],"sourcesContent":["/**\n * planner.ts — the plan class: plan, spawn, integrate.\n *\n * `pai worker run --class plan -p \"<goal>\"` does not run one worker but a\n * small orchestration:\n *\n * 1. a planner worker (the plan class's provider) reads the repository and\n * writes `<logDir>/plans/<planner id>.json` — 5–50 sub-tasks, fewer only\n * when the goal itself names a smaller count, each with title, brief,\n * class, files and acceptance;\n * 2. the runner validates the plan and spawns the sub-tasks as children of\n * the planner worker (`parent` = the planner id, so `ps` shows the\n * tree), at most `workers.tree.maxChildren` at a time;\n * 3. each child that finishes delivers its structured report to the\n * planner's inbox as a `kind: \"result\"` handoff (see handoff.ts);\n * 4. the run finishes with a summary report and the branches to merge.\n *\n * The planner's prompt carries the prompt rules from the self-driving\n * codebases write-up: domain-specific instructions only, constraints over\n * step lists, explicit quantity ranges, no checkbox style.\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 { loadStatus, newWorkerId } from \"./status.js\";\nimport { parseRunnerArgs, shortText } from \"./args.js\";\nimport { swapPromptArg } from \"./chain.js\";\nimport { runWorker, printResult, type RunOptions, type StreamEvent } from \"./run.js\";\nimport { git, mergeWorker } from \"./worktree.js\";\nimport type { WorkerReport } from \"./report.js\";\n\n/** Where a planner run's plan file lives: <logDir>/plans/<planner id>.json. */\nexport function planPathFor(logDir: string, plannerId: string): string {\n return join(logDir, \"plans\", `${plannerId}.json`);\n}\n\nexport interface PlannerTask {\n title: string;\n brief: string;\n /** Task class of the child (implement, research, …); default implement. */\n class?: string;\n /** Files the sub-task likely touches. */\n files?: string[];\n /** How to tell the sub-task is done. */\n acceptance?: string[];\n}\n\nexport const MIN_TASKS = 5;\nexport const MAX_TASKS = 50;\n\n/**\n * Validate a raw plan file into its tasks. Accepts 1–MAX_TASKS tasks: the\n * prompt asks for MIN_TASKS–MAX_TASKS, but a goal may itself name a smaller\n * explicit count (\"one sub-task per file\" with three files), and that\n * explicit range wins. Everything else — missing file, damaged JSON, tasks\n * without a title or brief — throws with a message the operator can act on.\n */\nexport function validatePlan(raw: unknown): PlannerTask[] {\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n throw new Error(\"plan file must be a JSON object\");\n }\n const tasksRaw = (raw as Record<string, unknown>).tasks;\n if (!Array.isArray(tasksRaw)) throw new Error('plan file needs a \"tasks\" array');\n if (tasksRaw.length < 1) throw new Error(\"plan file has no tasks\");\n if (tasksRaw.length > MAX_TASKS) {\n throw new Error(`plan file has ${tasksRaw.length} tasks; the maximum is ${MAX_TASKS}`);\n }\n const tasks: PlannerTask[] = [];\n for (let i = 0; i < tasksRaw.length; i++) {\n const t = tasksRaw[i];\n if (typeof t !== \"object\" || t === null || Array.isArray(t)) {\n throw new Error(`task ${i + 1} must be an object`);\n }\n const o = t as Record<string, unknown>;\n const title = typeof o.title === \"string\" ? o.title.trim() : \"\";\n const brief = typeof o.brief === \"string\" ? o.brief.trim() : \"\";\n if (!title) throw new Error(`task ${i + 1} needs a non-empty \"title\"`);\n if (!brief) throw new Error(`task ${i + 1} needs a non-empty \"brief\"`);\n const strArr = (v: unknown): string[] | undefined =>\n Array.isArray(v) && v.every((x) => typeof x === \"string\") ? (v as string[]) : undefined;\n const files = strArr(o.files);\n const acceptance = strArr(o.acceptance);\n tasks.push({\n title,\n brief,\n ...(typeof o.class === \"string\" && o.class.trim() ? { class: o.class.trim() } : {}),\n ...(files?.length ? { files } : {}),\n ...(acceptance?.length ? { acceptance } : {}),\n });\n }\n return tasks;\n}\n\n/** The planner worker's instructions, goal and prompt rules included. */\nexport function plannerPrompt(goal: string, planFile: string, maxChildren: number): string {\n return [\n \"You are a PLANNER worker. Turn the goal below into a plan file and stop —\",\n \"you do not implement anything, and you do not spawn workers yourself:\",\n \"the runner executes your plan on your behalf (the sub-tasks run as your\",\n \"children and report back to you).\",\n \"\",\n `Write the plan with the Write tool to ${planFile} as one JSON object:`,\n '{\"tasks\":[{\"title\":\"…\",\"brief\":\"…\",\"class\":\"implement\",\"files\":[\"…\"],\"acceptance\":[\"…\"]}]}',\n \"\",\n \"Prompt rules for the plan itself (they are yours too):\",\n \"- Domain-specific instructions only: name real files, commands and\",\n \" constraints of this repository, never generic advice.\",\n \"- Constraints over step lists: state what must hold (and what must not\",\n \" change), not a numbered procedure to follow.\",\n \"- Explicit quantity ranges: how many, how much, how long — never\",\n ' \"several\", \"some\", \"as needed\".',\n \"- No checkbox style: no `[ ]` items, no step numbering theatre.\",\n \"\",\n `Emit between ${MIN_TASKS} and ${MAX_TASKS} sub-tasks — unless the goal itself`,\n 'names a smaller explicit count (\"one sub-task per file\" with three files',\n \"means three); an explicit count in the goal always wins.\",\n `At most ${maxChildren} of them run at a time, so independent tasks are better`,\n \"than long chains. Each task's class picks its provider: implement, draft,\",\n \"review, research, spotcheck, simple, complex, image.\",\n \"\",\n \"Read the repository first (Glob/Grep/Read) so tasks name real files.\",\n \"Every sub-task runs in its own worktree of the same repository: name files\",\n \"relative to the repository root and never an absolute path or a worktree\",\n \"directory in a title, brief, files or acceptance entry.\",\n \"\",\n \"## Goal\",\n \"\",\n goal,\n ].join(\"\\n\");\n}\n\n/** The child's prompt for one planned sub-task. */\nexport function taskPrompt(goal: string, task: PlannerTask, index: number, of: number): string {\n return [\n `You are sub-task ${index + 1} of ${of} of a planned goal. Do exactly this sub-task;`,\n \"the other sub-tasks are other workers' business.\",\n \"\",\n `# ${task.title}`,\n \"\",\n task.brief,\n ...(task.files?.length ? [\"\", \"Files likely touched: \" + task.files.join(\", \")] : []),\n ...(task.acceptance?.length\n ? [\"\", \"Done means:\", ...task.acceptance.map((a) => `- ${a}`)]\n : []),\n \"\",\n \"## The overall goal (context only — your scope is the sub-task above)\",\n \"\",\n goal,\n ].join(\"\\n\");\n}\n\nexport interface PlannerDeps {\n /** Stage runner; tests inject a mock, production uses runWorker. */\n runStage?: (opts: RunOptions) => Promise<number>;\n /** logDir override for tests. */\n logDir?: string;\n /** maxChildren override for tests. */\n maxChildren?: number;\n}\n\n/**\n * The planner orchestration; returns the process exit code. The planner id is\n * minted here and preset on the phase-1 run, so the plan file's name is known\n * before the worker starts and the prompt can name its exact path.\n */\nexport async function runPlanner(opts: RunOptions, deps: PlannerDeps = {}): Promise<number> {\n const runStage = deps.runStage ?? runWorker;\n const { workers: config } = readWorkersSection();\n const logDir = deps.logDir ?? workersLogDir(config);\n const maxChildren = deps.maxChildren ?? config.tree.maxChildren;\n const parsed = parseRunnerArgs(opts.claudeArgs);\n const goal = parsed.prompt ?? \"\";\n const plannerId = newWorkerId();\n const planFile = planPathFor(logDir, plannerId);\n mkdirSync(join(logDir, \"plans\"), { recursive: true });\n\n // --- phase 1: the planner worker writes the plan file\n process.stderr.write(`planner ${plannerId}: writing plan (${planFile})\\n`);\n const rc1 = await runStage({\n ...opts,\n id: plannerId,\n claudeArgs: swapPromptArg(opts.claudeArgs, plannerPrompt(goal, planFile, maxChildren)),\n quiet: true,\n _planner: true,\n });\n if (rc1 !== 0) return rc1;\n if (!existsSync(planFile)) {\n process.stderr.write(\n `planner ${plannerId}: no plan file at ${planFile} — the planner worker did not write one. ` +\n `Re-run, or write the plan yourself and run the tasks with pai worker run.\\n`\n );\n appendLedger(ledgerPath(logDir), \"WORKER-PLAN-END\", { planner: plannerId, rc: 1, failed: \"plan\" });\n return 1;\n }\n let tasks: PlannerTask[];\n try {\n tasks = validatePlan(JSON.parse(readFileSync(planFile, \"utf8\")));\n } catch (e) {\n process.stderr.write(`planner ${plannerId}: invalid plan file ${planFile}: ${(e as Error).message}\\n`);\n appendLedger(ledgerPath(logDir), \"WORKER-PLAN-END\", { planner: plannerId, rc: 1, failed: \"plan\" });\n return 1;\n }\n appendLedger(ledgerPath(logDir), \"WORKER-PLAN\", {\n planner: plannerId,\n tasks: tasks.length,\n plan: planFile,\n });\n\n // --- phase 2: run the sub-tasks as children, maxChildren at a time. Each\n // child is spawned in the planner's own worktree (when it got one) rather\n // than the operator's cwd, so its branch is created off the planner's own\n // HEAD and can later be merged straight into it.\n const plannerStatus = loadStatus(logDir, plannerId);\n const plannerWorktreeDir = plannerStatus?.worktreeDir ?? null;\n const results: { task: PlannerTask; rc: number; id: string }[] = [];\n for (let i = 0; i < tasks.length; i += maxChildren) {\n const wave = tasks.slice(i, i + maxChildren);\n process.stderr.write(\n `planner ${plannerId}: sub-tasks ${i + 1}–${i + wave.length} of ${tasks.length}\\n`\n );\n const waveIds: string[] = new Array(wave.length).fill(\"\");\n const rcs = await Promise.all(\n wave.map((task, w) =>\n runStage({\n className: task.class ?? \"implement\",\n providerFlag: opts.providerFlag,\n modelFlag: opts.modelFlag,\n label: shortText(task.title, 40),\n noPane: opts.noPane,\n mcpFlag: opts.mcpFlag,\n claudeArgs: swapPromptArg(opts.claudeArgs, taskPrompt(goal, task, i + w, tasks.length)),\n cwd: plannerWorktreeDir ?? opts.cwd,\n worktreeFlag: opts.worktreeFlag,\n parent: plannerId,\n quiet: true,\n onWorkerStart: (wid) => {\n waveIds[w] = wid;\n },\n })\n )\n );\n for (let w = 0; w < wave.length; w++) results.push({ task: wave[w], rc: rcs[w], id: waveIds[w] });\n }\n\n // --- phase 3: the planner merges each finished child's branch into its\n // OWN worktree branch, in spawn order — never into the operator's checkout\n // — reusing `pai worker merge`'s own logic (mergeWorker). A conflicting\n // merge is aborted cleanly so the planner's branch stays clean and the\n // next child still gets a try; the child's branch is left intact either way.\n const merged: string[] = [];\n const conflicted: { id: string; branch: string; paths: string[] }[] = [];\n if (plannerWorktreeDir) {\n for (const r of results) {\n if (r.rc !== 0 || !r.id) continue;\n const st = loadStatus(logDir, r.id);\n if (!st?.branch) continue; // ran in place, or no worktree: nothing to merge\n try {\n mergeWorker(logDir, r.id);\n merged.push(r.id);\n } catch {\n let paths: string[] = [];\n try {\n git(plannerWorktreeDir, [\"rev-parse\", \"-q\", \"--verify\", \"MERGE_HEAD\"]);\n paths = git(plannerWorktreeDir, [\"diff\", \"--name-only\", \"--diff-filter=U\"])\n .split(\"\\n\")\n .filter(Boolean);\n git(plannerWorktreeDir, [\"merge\", \"--abort\"]);\n } catch {\n // no merge was left in progress: the failure was not a conflict\n }\n conflicted.push({ id: r.id, branch: st.branch, paths });\n }\n }\n }\n\n // --- phase 4: summary from the children's statuses and inbox handoffs\n const failed = results.filter((r) => r.rc !== 0).length;\n appendLedger(ledgerPath(logDir), \"WORKER-PLAN-END\", {\n planner: plannerId,\n rc: failed || conflicted.length ? 1 : 0,\n failed,\n merged: merged.length,\n conflicted: conflicted.length,\n });\n printPlannerSummary(logDir, plannerId, results, merged, conflicted, parsed.outputFormat, opts.quiet === true);\n return failed || conflicted.length ? 1 : 0;\n}\n\n/** Compose and print the planner's summary report (text or json). */\nfunction printPlannerSummary(\n logDir: string,\n plannerId: string,\n results: { task: PlannerTask; rc: number; id: string }[],\n merged: string[],\n conflicted: { id: string; branch: string; paths: string[] }[],\n fmt: \"text\" | \"json\" | \"stream-json\",\n quiet: boolean\n): void {\n const ok = results.filter((r) => r.rc === 0).length;\n const attempted = new Set([...merged, ...conflicted.map((c) => c.id)]);\n // a branch never attempted (no planner worktree to merge into) still needs\n // the old \"go merge me by hand\" hint\n const stillOpen: { id: string; branch: string }[] = [];\n for (const r of results) {\n if (r.rc !== 0 || !r.id || attempted.has(r.id)) continue;\n const st = loadStatus(logDir, r.id);\n if (st?.branch && !st.merged) stillOpen.push({ id: r.id, branch: st.branch });\n }\n const report: WorkerReport = {\n checks: results.map((r) => ({\n name: r.task.title,\n ok: r.rc === 0,\n detail: r.rc === 0 ? shortText(r.id ? loadStatus(logDir, r.id)?.last : \"\", 80) : `rc=${r.rc}`,\n })),\n ...(merged.length || conflicted.length || stillOpen.length\n ? {\n open: [\n ...merged.map((id) => `merged: ${id}`),\n ...conflicted.map(\n (c) =>\n `conflict: pai worker merge ${c.id} (${c.branch})` +\n (c.paths.length ? ` — ${c.paths.join(\", \")}` : \"\")\n ),\n ...stillOpen.map((c) => `branch to merge: pai worker merge ${c.id} (${c.branch})`),\n ],\n }\n : {}),\n notes:\n `${ok}/${results.length} sub-tasks ok` +\n (merged.length ? `; ${merged.length} merged` : \"\") +\n (conflicted.length ? `; ${conflicted.length} conflict(s)` : \"\") +\n (stillOpen.length ? `; ${stillOpen.length} branch(es) to merge` : \"\"),\n };\n if (quiet || fmt === \"stream-json\") return;\n const allOk = ok === results.length && conflicted.length === 0;\n const resultEvent: StreamEvent = {\n type: \"result\",\n result: [\n `planner ${plannerId}: ${report.notes}`,\n ...(conflicted.length ? [\"conflicts:\"] : []),\n ...conflicted.map(\n (c) =>\n ` pai worker merge ${c.id} # ${c.branch}, conflicting: ${c.paths.join(\", \") || \"unknown\"}`\n ),\n ...(stillOpen.length ? [\"branches to merge:\"] : []),\n ...stillOpen.map((c) => ` pai worker merge ${c.id} # ${c.branch}`),\n ].join(\"\\n\"),\n is_error: !allOk,\n };\n printResult(fmt, resultEvent, allOk ? 0 : 1, logDir, plannerId, report, {\n plan: results.length,\n ...(merged.length ? { mergedBranches: merged } : {}),\n ...(conflicted.length ? { conflictedBranches: conflicted.map((c) => c.branch) } : {}),\n ...(stillOpen.length ? { branches: stillOpen.map((c) => c.branch) } : {}),\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"planner-Dm5Acyo1.mjs","names":[],"sources":["../src/workers/planner.ts"],"sourcesContent":["/**\n * planner.ts — the plan class: plan, spawn, integrate.\n *\n * `pai worker run --class plan -p \"<goal>\"` does not run one worker but a\n * small orchestration:\n *\n * 1. a planner worker (the plan class's provider) reads the repository and\n * writes `<logDir>/plans/<planner id>.json` — 5–50 sub-tasks, fewer only\n * when the goal itself names a smaller count, each with title, brief,\n * class, files and acceptance;\n * 2. the runner validates the plan and spawns the sub-tasks as children of\n * the planner worker (`parent` = the planner id, so `ps` shows the\n * tree), at most `workers.tree.maxChildren` at a time;\n * 3. each child that finishes delivers its structured report to the\n * planner's inbox as a `kind: \"result\"` handoff (see handoff.ts);\n * 4. the run finishes with a summary report and the branches to merge.\n *\n * The planner's prompt carries the prompt rules from the self-driving\n * codebases write-up: domain-specific instructions only, constraints over\n * step lists, explicit quantity ranges, no checkbox style.\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 { loadStatus, newWorkerId } from \"./status.js\";\nimport { parseRunnerArgs, shortText } from \"./args.js\";\nimport { swapPromptArg } from \"./chain.js\";\nimport { runWorker, printResult, type RunOptions, type StreamEvent } from \"./run.js\";\nimport { git, mergeWorker } from \"./worktree.js\";\nimport type { WorkerReport } from \"./report.js\";\n\n/** Where a planner run's plan file lives: <logDir>/plans/<planner id>.json. */\nexport function planPathFor(logDir: string, plannerId: string): string {\n return join(logDir, \"plans\", `${plannerId}.json`);\n}\n\nexport interface PlannerTask {\n title: string;\n brief: string;\n /** Task class of the child (implement, research, …); default implement. */\n class?: string;\n /** Files the sub-task likely touches. */\n files?: string[];\n /** How to tell the sub-task is done. */\n acceptance?: string[];\n}\n\nexport const MIN_TASKS = 5;\nexport const MAX_TASKS = 50;\n\n/**\n * Validate a raw plan file into its tasks. Accepts 1–MAX_TASKS tasks: the\n * prompt asks for MIN_TASKS–MAX_TASKS, but a goal may itself name a smaller\n * explicit count (\"one sub-task per file\" with three files), and that\n * explicit range wins. Everything else — missing file, damaged JSON, tasks\n * without a title or brief — throws with a message the operator can act on.\n */\nexport function validatePlan(raw: unknown): PlannerTask[] {\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n throw new Error(\"plan file must be a JSON object\");\n }\n const tasksRaw = (raw as Record<string, unknown>).tasks;\n if (!Array.isArray(tasksRaw)) throw new Error('plan file needs a \"tasks\" array');\n if (tasksRaw.length < 1) throw new Error(\"plan file has no tasks\");\n if (tasksRaw.length > MAX_TASKS) {\n throw new Error(`plan file has ${tasksRaw.length} tasks; the maximum is ${MAX_TASKS}`);\n }\n const tasks: PlannerTask[] = [];\n for (let i = 0; i < tasksRaw.length; i++) {\n const t = tasksRaw[i];\n if (typeof t !== \"object\" || t === null || Array.isArray(t)) {\n throw new Error(`task ${i + 1} must be an object`);\n }\n const o = t as Record<string, unknown>;\n const title = typeof o.title === \"string\" ? o.title.trim() : \"\";\n const brief = typeof o.brief === \"string\" ? o.brief.trim() : \"\";\n if (!title) throw new Error(`task ${i + 1} needs a non-empty \"title\"`);\n if (!brief) throw new Error(`task ${i + 1} needs a non-empty \"brief\"`);\n const strArr = (v: unknown): string[] | undefined =>\n Array.isArray(v) && v.every((x) => typeof x === \"string\") ? (v as string[]) : undefined;\n const files = strArr(o.files);\n const acceptance = strArr(o.acceptance);\n tasks.push({\n title,\n brief,\n ...(typeof o.class === \"string\" && o.class.trim() ? { class: o.class.trim() } : {}),\n ...(files?.length ? { files } : {}),\n ...(acceptance?.length ? { acceptance } : {}),\n });\n }\n return tasks;\n}\n\n/** The planner worker's instructions, goal and prompt rules included. */\nexport function plannerPrompt(goal: string, planFile: string, maxChildren: number): string {\n return [\n \"You are a PLANNER worker. Turn the goal below into a plan file and stop —\",\n \"you do not implement anything, and you do not spawn workers yourself:\",\n \"the runner executes your plan on your behalf (the sub-tasks run as your\",\n \"children and report back to you).\",\n \"\",\n `Write the plan with the Write tool to ${planFile} as one JSON object:`,\n '{\"tasks\":[{\"title\":\"…\",\"brief\":\"…\",\"class\":\"implement\",\"files\":[\"…\"],\"acceptance\":[\"…\"]}]}',\n \"\",\n \"Prompt rules for the plan itself (they are yours too):\",\n \"- Domain-specific instructions only: name real files, commands and\",\n \" constraints of this repository, never generic advice.\",\n \"- Constraints over step lists: state what must hold (and what must not\",\n \" change), not a numbered procedure to follow.\",\n \"- Explicit quantity ranges: how many, how much, how long — never\",\n ' \"several\", \"some\", \"as needed\".',\n \"- No checkbox style: no `[ ]` items, no step numbering theatre.\",\n \"\",\n `Emit between ${MIN_TASKS} and ${MAX_TASKS} sub-tasks — unless the goal itself`,\n 'names a smaller explicit count (\"one sub-task per file\" with three files',\n \"means three); an explicit count in the goal always wins.\",\n `At most ${maxChildren} of them run at a time, so independent tasks are better`,\n \"than long chains. Each task's class picks its provider: implement, draft,\",\n \"review, research, spotcheck, simple, complex, image.\",\n \"\",\n \"Read the repository first (Glob/Grep/Read) so tasks name real files.\",\n \"Every sub-task runs in its own worktree of the same repository: name files\",\n \"relative to the repository root and never an absolute path or a worktree\",\n \"directory in a title, brief, files or acceptance entry.\",\n \"\",\n \"## Goal\",\n \"\",\n goal,\n ].join(\"\\n\");\n}\n\n/** The child's prompt for one planned sub-task. */\nexport function taskPrompt(goal: string, task: PlannerTask, index: number, of: number): string {\n return [\n `You are sub-task ${index + 1} of ${of} of a planned goal. Do exactly this sub-task;`,\n \"the other sub-tasks are other workers' business.\",\n \"\",\n `# ${task.title}`,\n \"\",\n task.brief,\n ...(task.files?.length ? [\"\", \"Files likely touched: \" + task.files.join(\", \")] : []),\n ...(task.acceptance?.length\n ? [\"\", \"Done means:\", ...task.acceptance.map((a) => `- ${a}`)]\n : []),\n \"\",\n \"## The overall goal (context only — your scope is the sub-task above)\",\n \"\",\n goal,\n ].join(\"\\n\");\n}\n\nexport interface PlannerDeps {\n /** Stage runner; tests inject a mock, production uses runWorker. */\n runStage?: (opts: RunOptions) => Promise<number>;\n /** logDir override for tests. */\n logDir?: string;\n /** maxChildren override for tests. */\n maxChildren?: number;\n}\n\n/**\n * The planner orchestration; returns the process exit code. The planner id is\n * minted here and preset on the phase-1 run, so the plan file's name is known\n * before the worker starts and the prompt can name its exact path.\n */\nexport async function runPlanner(opts: RunOptions, deps: PlannerDeps = {}): Promise<number> {\n const runStage = deps.runStage ?? runWorker;\n const { workers: config } = readWorkersSection();\n const logDir = deps.logDir ?? workersLogDir(config);\n const maxChildren = deps.maxChildren ?? config.tree.maxChildren;\n const parsed = parseRunnerArgs(opts.claudeArgs);\n const goal = parsed.prompt ?? \"\";\n const plannerId = newWorkerId();\n const planFile = planPathFor(logDir, plannerId);\n mkdirSync(join(logDir, \"plans\"), { recursive: true });\n\n // --- phase 1: the planner worker writes the plan file\n process.stderr.write(`planner ${plannerId}: writing plan (${planFile})\\n`);\n const rc1 = await runStage({\n ...opts,\n id: plannerId,\n claudeArgs: swapPromptArg(opts.claudeArgs, plannerPrompt(goal, planFile, maxChildren)),\n quiet: true,\n _planner: true,\n });\n if (rc1 !== 0) return rc1;\n if (!existsSync(planFile)) {\n process.stderr.write(\n `planner ${plannerId}: no plan file at ${planFile} — the planner worker did not write one. ` +\n `Re-run, or write the plan yourself and run the tasks with pai worker run.\\n`\n );\n appendLedger(ledgerPath(logDir), \"WORKER-PLAN-END\", { planner: plannerId, rc: 1, failed: \"plan\" });\n return 1;\n }\n let tasks: PlannerTask[];\n try {\n tasks = validatePlan(JSON.parse(readFileSync(planFile, \"utf8\")));\n } catch (e) {\n process.stderr.write(`planner ${plannerId}: invalid plan file ${planFile}: ${(e as Error).message}\\n`);\n appendLedger(ledgerPath(logDir), \"WORKER-PLAN-END\", { planner: plannerId, rc: 1, failed: \"plan\" });\n return 1;\n }\n appendLedger(ledgerPath(logDir), \"WORKER-PLAN\", {\n planner: plannerId,\n tasks: tasks.length,\n plan: planFile,\n });\n\n // --- phase 2: run the sub-tasks as children, maxChildren at a time. Each\n // child is spawned in the planner's own worktree (when it got one) rather\n // than the operator's cwd, so its branch is created off the planner's own\n // HEAD and can later be merged straight into it.\n const plannerStatus = loadStatus(logDir, plannerId);\n const plannerWorktreeDir = plannerStatus?.worktreeDir ?? null;\n const results: { task: PlannerTask; rc: number; id: string }[] = [];\n for (let i = 0; i < tasks.length; i += maxChildren) {\n const wave = tasks.slice(i, i + maxChildren);\n process.stderr.write(\n `planner ${plannerId}: sub-tasks ${i + 1}–${i + wave.length} of ${tasks.length}\\n`\n );\n const waveIds: string[] = new Array(wave.length).fill(\"\");\n const rcs = await Promise.all(\n wave.map((task, w) =>\n runStage({\n className: task.class ?? \"implement\",\n providerFlag: opts.providerFlag,\n modelFlag: opts.modelFlag,\n label: shortText(task.title, 40),\n noPane: opts.noPane,\n mcpFlag: opts.mcpFlag,\n claudeArgs: swapPromptArg(opts.claudeArgs, taskPrompt(goal, task, i + w, tasks.length)),\n cwd: plannerWorktreeDir ?? opts.cwd,\n worktreeFlag: opts.worktreeFlag,\n parent: plannerId,\n quiet: true,\n onWorkerStart: (wid) => {\n waveIds[w] = wid;\n },\n })\n )\n );\n for (let w = 0; w < wave.length; w++) results.push({ task: wave[w], rc: rcs[w], id: waveIds[w] });\n }\n\n // --- phase 3: the planner merges each finished child's branch into its\n // OWN worktree branch, in spawn order — never into the operator's checkout\n // — reusing `pai worker merge`'s own logic (mergeWorker). A conflicting\n // merge is aborted cleanly so the planner's branch stays clean and the\n // next child still gets a try; the child's branch is left intact either way.\n const merged: string[] = [];\n const conflicted: { id: string; branch: string; paths: string[] }[] = [];\n if (plannerWorktreeDir) {\n for (const r of results) {\n if (r.rc !== 0 || !r.id) continue;\n const st = loadStatus(logDir, r.id);\n if (!st?.branch) continue; // ran in place, or no worktree: nothing to merge\n try {\n mergeWorker(logDir, r.id);\n merged.push(r.id);\n } catch {\n let paths: string[] = [];\n try {\n git(plannerWorktreeDir, [\"rev-parse\", \"-q\", \"--verify\", \"MERGE_HEAD\"]);\n paths = git(plannerWorktreeDir, [\"diff\", \"--name-only\", \"--diff-filter=U\"])\n .split(\"\\n\")\n .filter(Boolean);\n git(plannerWorktreeDir, [\"merge\", \"--abort\"]);\n } catch {\n // no merge was left in progress: the failure was not a conflict\n }\n conflicted.push({ id: r.id, branch: st.branch, paths });\n }\n }\n }\n\n // --- phase 4: summary from the children's statuses and inbox handoffs\n const failed = results.filter((r) => r.rc !== 0).length;\n appendLedger(ledgerPath(logDir), \"WORKER-PLAN-END\", {\n planner: plannerId,\n rc: failed || conflicted.length ? 1 : 0,\n failed,\n merged: merged.length,\n conflicted: conflicted.length,\n });\n printPlannerSummary(logDir, plannerId, results, merged, conflicted, parsed.outputFormat, opts.quiet === true);\n return failed || conflicted.length ? 1 : 0;\n}\n\n/** Compose and print the planner's summary report (text or json). */\nfunction printPlannerSummary(\n logDir: string,\n plannerId: string,\n results: { task: PlannerTask; rc: number; id: string }[],\n merged: string[],\n conflicted: { id: string; branch: string; paths: string[] }[],\n fmt: \"text\" | \"json\" | \"stream-json\",\n quiet: boolean\n): void {\n const ok = results.filter((r) => r.rc === 0).length;\n const attempted = new Set([...merged, ...conflicted.map((c) => c.id)]);\n // a branch never attempted (no planner worktree to merge into) still needs\n // the old \"go merge me by hand\" hint\n const stillOpen: { id: string; branch: string }[] = [];\n for (const r of results) {\n if (r.rc !== 0 || !r.id || attempted.has(r.id)) continue;\n const st = loadStatus(logDir, r.id);\n if (st?.branch && !st.merged) stillOpen.push({ id: r.id, branch: st.branch });\n }\n const report: WorkerReport = {\n checks: results.map((r) => ({\n name: r.task.title,\n ok: r.rc === 0,\n detail: r.rc === 0 ? shortText(r.id ? loadStatus(logDir, r.id)?.last : \"\", 80) : `rc=${r.rc}`,\n })),\n ...(merged.length || conflicted.length || stillOpen.length\n ? {\n open: [\n ...merged.map((id) => `merged: ${id}`),\n ...conflicted.map(\n (c) =>\n `conflict: pai worker merge ${c.id} (${c.branch})` +\n (c.paths.length ? ` — ${c.paths.join(\", \")}` : \"\")\n ),\n ...stillOpen.map((c) => `branch to merge: pai worker merge ${c.id} (${c.branch})`),\n ],\n }\n : {}),\n notes:\n `${ok}/${results.length} sub-tasks ok` +\n (merged.length ? `; ${merged.length} merged` : \"\") +\n (conflicted.length ? `; ${conflicted.length} conflict(s)` : \"\") +\n (stillOpen.length ? `; ${stillOpen.length} branch(es) to merge` : \"\"),\n };\n if (quiet || fmt === \"stream-json\") return;\n const allOk = ok === results.length && conflicted.length === 0;\n const resultEvent: StreamEvent = {\n type: \"result\",\n result: [\n `planner ${plannerId}: ${report.notes}`,\n ...(conflicted.length ? [\"conflicts:\"] : []),\n ...conflicted.map(\n (c) =>\n ` pai worker merge ${c.id} # ${c.branch}, conflicting: ${c.paths.join(\", \") || \"unknown\"}`\n ),\n ...(stillOpen.length ? [\"branches to merge:\"] : []),\n ...stillOpen.map((c) => ` pai worker merge ${c.id} # ${c.branch}`),\n ].join(\"\\n\"),\n is_error: !allOk,\n };\n printResult(fmt, resultEvent, allOk ? 0 : 1, logDir, plannerId, report, {\n plan: results.length,\n ...(merged.length ? { mergedBranches: merged } : {}),\n ...(conflicted.length ? { conflictedBranches: conflicted.map((c) => c.branch) } : {}),\n ...(stillOpen.length ? { branches: stillOpen.map((c) => c.branch) } : {}),\n });\n}\n"],"mappings":"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"}
|
|
@@ -11,19 +11,19 @@ import { a as paiHomePath, i as paiHomeDir, n as migratePaiDir, o as resolvePaiF
|
|
|
11
11
|
import { b as OWNER_LABEL_PREFIX, c as migrateConfigFile, d as readMainConfigRaw, f as writeMainConfigRaw, h as resolvedMainConfigPath, l as paiConfigFilePath, m as migrateMainConfigToYaml, n as CONFIG_FILE$2, o as expandHome, p as MainConfigError, s as loadConfig, t as CONFIG_DIR, u as paiConfigYamlFilePath, v as readJsonStrict, x as UNROUTED, y as writeJsonAtomic } from "./config-BbLFD7Uf.mjs";
|
|
12
12
|
import { a as schedulerLogPath, i as paiSocketPath, n as daemonLogPath, r as daemonPidPath } from "./runtime-paths-CHTg3ywb.mjs";
|
|
13
13
|
import { B as DEFAULT_CONTEXT_WINDOW, C as maskKey, D as readWorkersSection, F as needsWorkersYamlRelocation, H as stripModelVariant, I as parseWorkersYamlDocument, L as relocateWorkersYaml, M as initWorkersYaml, N as inlineWorkersYamlKeys, P as migrateWorkersToYaml, R as workersYamlLegacyNotice, V as contextWindowFromModelId, b as getProviderOrNative, d as MODEL_CAPABILITIES, h as WorkersConfigError, p as PROVIDER_TAGS, r as ANTHROPIC_NATIVE, t as buildRunEnv, w as nativeAnthropicProvider, x as isModelCapability, y as expandHome$1, z as workersYamlPath } from "./run-env-DRcp7A8K.mjs";
|
|
14
|
-
import { $ as
|
|
14
|
+
import { $ as parseRunnerArgs, A as mergeWorker, D as discardWorker, G as loadStatuses, H as isChatPane, I as UNLABELED, J as ownsPid, M as verifyWorker, O as gcWorktrees, P as appendLedger, Q as longInlinePromptHint, U as isLive, W as loadStatus, X as setWorkerLabel, Y as saveStatus, Z as waitForTerminalStatus, _ as callerDescription, c as handoffFromInside, f as checkPaneForWorker, g as markControlsHeld, h as clickrControlsArgv, i as usageContextTokens, it as expandMcpNames, j as uncommittedPaths, k as git, m as openPaneForWorker, n as runWorker, nt as projectLaunchConfig, o as parseWorkerReport, p as openFollowPane, r as testProvider, rt as describeMcp, tt as pinNotices, u as sayToWorker, y as requestKill } from "./run-BCpbxqA5.mjs";
|
|
15
15
|
import { t as MergeError } from "./merge-DgU9OgZy.mjs";
|
|
16
16
|
import { n as oldFederationPath, t as federationDbPath } from "./federation-db-BTyoufBh.mjs";
|
|
17
17
|
import { r as registryDbPath, t as oldRegistryPath } from "./registry-db-C7voqML9.mjs";
|
|
18
18
|
import { i as indexProjectWithBackend } from "./async-C2Bm_Lal.mjs";
|
|
19
19
|
import { t as PaiClient } from "./ipc-client-D16Xw6Uo.mjs";
|
|
20
|
-
import { A as getConfigValueOp, C as setWorkersEnabled, D as useProvider, E as updateProvider, M as setConfigValueOp, N as unsetConfigValueOp, O as MainConfigOpsError, S as setProviderModel, T as unsetClass, _ as removeProvider, a as followWorkers, b as setClass, c as statusLineOutput, d as addProvider, f as classTargetText, g as modelPrefsText, h as describeProviders, i as fallbackStatusText, j as listConfigOp, k as formatConfigGetOutput, l as readSpecPrompt, m as describeModels, n as fallbackOn, o as psOutput, p as describeCapabilities, r as fallbackStatus, s as replayOutput, t as fallbackOff, u as resolveSpecPath, v as resolveProviderName, w as unsetCapabilityPreference, x as setProviderEnabled, y as setCapabilityPreference } from "./fallback-
|
|
20
|
+
import { A as getConfigValueOp, C as setWorkersEnabled, D as useProvider, E as updateProvider, M as setConfigValueOp, N as unsetConfigValueOp, O as MainConfigOpsError, S as setProviderModel, T as unsetClass, _ as removeProvider, a as followWorkers, b as setClass, c as statusLineOutput, d as addProvider, f as classTargetText, g as modelPrefsText, h as describeProviders, i as fallbackStatusText, j as listConfigOp, k as formatConfigGetOutput, l as readSpecPrompt, m as describeModels, n as fallbackOn, o as psOutput, p as describeCapabilities, r as fallbackStatus, s as replayOutput, t as fallbackOff, u as resolveSpecPath, v as resolveProviderName, w as unsetCapabilityPreference, x as setProviderEnabled, y as setCapabilityPreference } from "./fallback-CIiq2Raw.mjs";
|
|
21
21
|
import { _ as resolveSessionByNameOrId, a as buildDeduped, c as hasConversation, d as providerResumePlan, f as restoreTopLevel, g as migrateSessionScanCache, h as fmtAge$1, l as launchInDir, m as printExitDir, o as normalizeName$2, p as resumeArgvText, s as renderDedupedSessions, t as cmdMain, u as launchPrompt, v as scanCacheFilePath, y as scanSessions } from "./main-resolver-DPPwHNtn.mjs";
|
|
22
22
|
import { n as queriesDirPath, t as migrateQueriesDir } from "./query-feedback-BIaZTTFO.mjs";
|
|
23
23
|
import { _ as statusPath, h as ledgerPath, m as eventsPath, n as ensureProxyRunning, p as ensureNoMcpConfig, r as stopProxy, t as DEFAULT_PROXY_PORT, v as workersLogDir } from "./server-DgmAHyFK.mjs";
|
|
24
24
|
import { i as sendToSession, n as fetchLiveSessions, r as revealItermSession, t as callAiBroker } from "./aibroker-client-C5Fw7DNz.mjs";
|
|
25
|
-
import { a as totalUsageTokens, i as parseSessionUsage, r as sessionKeepaliveLedgerSummary, t as loadSessionKeepaliveState } from "./session-keepalive-
|
|
26
|
-
import { t as runChain } from "./chain-
|
|
25
|
+
import { a as totalUsageTokens, i as parseSessionUsage, r as sessionKeepaliveLedgerSummary, t as loadSessionKeepaliveState } from "./session-keepalive-DxjTHGcK.mjs";
|
|
26
|
+
import { t as runChain } from "./chain-CZfKIEq9.mjs";
|
|
27
27
|
import { appendFileSync, chmodSync, closeSync, copyFileSync, cpSync, createReadStream, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
|
|
28
28
|
import { homedir, platform, tmpdir, userInfo } from "node:os";
|
|
29
29
|
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
@@ -7097,7 +7097,7 @@ function cmdLogs(opts) {
|
|
|
7097
7097
|
}
|
|
7098
7098
|
function registerDaemonCommands(daemonCmd) {
|
|
7099
7099
|
daemonCmd.command("serve").description("Start the PAI daemon in the foreground").action(async () => {
|
|
7100
|
-
const { serve } = await import("./daemon-
|
|
7100
|
+
const { serve } = await import("./daemon-DyORmxZu.mjs");
|
|
7101
7101
|
const { loadConfig: lc, ensureConfigDir } = await import("./config-YinjgXEJ.mjs");
|
|
7102
7102
|
ensureConfigDir();
|
|
7103
7103
|
await serve(lc());
|
|
@@ -19532,12 +19532,15 @@ function registerWorkerCommands(workerCmd) {
|
|
|
19532
19532
|
return;
|
|
19533
19533
|
}
|
|
19534
19534
|
try {
|
|
19535
|
+
requestKill(logDir, ledgerPath(logDir), id);
|
|
19535
19536
|
process.kill(status.pid, "SIGTERM");
|
|
19536
19537
|
if (!await waitForTerminalStatus(logDir, id)) {
|
|
19537
19538
|
const latest = loadStatus(logDir, id) ?? status;
|
|
19538
19539
|
latest.state = "killed";
|
|
19539
19540
|
latest.rc = latest.rc ?? 143;
|
|
19540
19541
|
latest.last = latest.last || "killed by signal SIGTERM";
|
|
19542
|
+
latest.endReason = "pai-worker-kill";
|
|
19543
|
+
latest.endBy = callerDescription();
|
|
19541
19544
|
saveStatus(logDir, latest);
|
|
19542
19545
|
}
|
|
19543
19546
|
console.log(`sent SIGTERM to worker ${id} (pid ${status.pid})`);
|
|
@@ -21971,4 +21974,4 @@ claude() {
|
|
|
21971
21974
|
|
|
21972
21975
|
//#endregion
|
|
21973
21976
|
export { drainStdio as n, buildProgram as t };
|
|
21974
|
-
//# sourceMappingURL=program-
|
|
21977
|
+
//# sourceMappingURL=program-JJ0TwSHI.mjs.map
|