@selesai/code 0.13.12 → 0.13.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/dist/extensions/pi-subagents/CHANGELOG.md +77 -1
- package/dist/extensions/pi-subagents/VISION.md +12 -1
- package/dist/extensions/pi-subagents/docs/agents.md +13 -6
- package/dist/extensions/pi-subagents/docs/configuration.md +35 -9
- package/dist/extensions/pi-subagents/docs/extension-api.md +1 -1
- package/dist/extensions/pi-subagents/docs/missions.md +1 -1
- package/dist/extensions/pi-subagents/docs/models.md +6 -6
- package/dist/extensions/pi-subagents/docs/observability.md +6 -3
- package/dist/extensions/pi-subagents/docs/tool-reference.md +3 -3
- package/dist/extensions/pi-subagents/docs/watchdog.md +92 -114
- package/dist/extensions/pi-subagents/docs/workflows.md +1 -1
- package/dist/extensions/pi-subagents/install.mjs +1 -2
- package/dist/extensions/pi-subagents/package.json +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +6 -6
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/multi-lane-orchestration.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +4 -4
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/review-and-validation.md +1 -1
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +41 -4
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +3 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +120 -124
- package/dist/extensions/pi-subagents/src/agents/runtime-agent-registry.ts +5 -1
- package/dist/extensions/pi-subagents/src/api/preflight.ts +4 -0
- package/dist/extensions/pi-subagents/src/api/shared-types.ts +3 -0
- package/dist/extensions/pi-subagents/src/extension/config.ts +20 -0
- package/dist/extensions/pi-subagents/src/extension/public-execution.ts +1 -0
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +6 -2
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +1 -1
- package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +19 -13
- package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +26 -8
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +103 -23
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +6 -2
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -2
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +54 -3
- package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +16 -0
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +22 -2
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +63 -6
- package/dist/extensions/pi-subagents/src/runs/background/steering.ts +4 -1
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +69 -12
- package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +13 -0
- package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +3 -1
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +21 -8
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +59 -6
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +95 -18
- package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +11 -43
- package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +1 -0
- package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/lane-metadata.ts +24 -3
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +4 -0
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +2 -6
- package/dist/extensions/pi-subagents/src/runs/shared/permissions.ts +1 -0
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +33 -18
- package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +73 -37
- package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +33 -6
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +4 -2
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +20 -3
- package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +21 -7
- package/dist/extensions/pi-subagents/src/runs/shared/tool-timeout.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +467 -63
- package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +3 -1
- package/dist/extensions/pi-subagents/src/shared/fork-context.ts +0 -12
- package/dist/extensions/pi-subagents/src/shared/fork-session-cwd.ts +27 -0
- package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +3 -0
- package/dist/extensions/pi-subagents/src/shared/types.ts +42 -4
- package/dist/extensions/pi-subagents/src/shared/utils.ts +18 -7
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +1 -1
- package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +26 -12
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +61 -2
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +12 -7
- package/dist/extensions/pi-subagents/src/tui/render.ts +227 -14
- package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +56 -34
- package/dist/extensions/pi-subagents/src/watchdog/diff-tool.ts +77 -0
- package/dist/extensions/pi-subagents/src/watchdog/emission-guard.ts +5 -3
- package/dist/extensions/pi-subagents/src/watchdog/guidance.ts +20 -0
- package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +16 -13
- package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +10 -9
- package/dist/extensions/pi-subagents/src/watchdog/render.ts +4 -5
- package/dist/extensions/pi-subagents/src/watchdog/review.ts +15 -4
- package/dist/extensions/pi-subagents/src/watchdog/rules.ts +70 -0
- package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +75 -92
- package/dist/extensions/pi-subagents/src/watchdog/scope.ts +2 -1
- package/dist/extensions/pi-subagents/src/watchdog/settings.ts +48 -104
- package/dist/extensions/pi-subagents/src/watchdog/types.ts +18 -32
- package/dist/extensions/pi-subagents/src/watchdog/warning-format.ts +0 -1
- package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +3 -2
- package/dist/extensions/pi-subagents/src/workflows/workflow-checklist.ts +439 -0
- package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +28 -1
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +335 -21
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +4 -1
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +22 -18
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +0 -1
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +21 -18
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +307 -22
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/support/helpers.ts +25 -0
- package/dist/extensions/pi-subagents/test/support/isolated-temp-root.mjs +15 -4
- package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +17 -2
- package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +96 -15
- package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +53 -5
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +20 -0
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +221 -8
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +45 -24
- package/dist/extensions/pi-subagents/test/unit/agent-scan-dirs.test.ts +133 -0
- package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +28 -2
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +2 -0
- package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +4 -1
- package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +18 -4
- package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +16 -0
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +38 -0
- package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +21 -0
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +19 -6
- package/dist/extensions/pi-subagents/test/unit/get-final-output.test.ts +26 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +22 -1
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +2 -6
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +66 -1
- package/dist/extensions/pi-subagents/test/unit/pi-args-permission-system.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +116 -10
- package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +136 -18
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +20 -0
- package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +22 -0
- package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/unit/project-panes-public-api.test.ts +8 -0
- package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +127 -48
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +68 -0
- package/dist/extensions/pi-subagents/test/unit/runtime-agent-registration.test.ts +17 -0
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +88 -0
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +4 -2
- package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +9 -9
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/steering.test.ts +9 -3
- package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +22 -9
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +91 -8
- package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/unit/temp-paths.test.ts +50 -0
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +0 -1
- package/dist/extensions/pi-subagents/test/unit/tool-timeout.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +1 -2
- package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +73 -13
- package/dist/extensions/pi-subagents/test/unit/watchdog-diff-tool.test.ts +79 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-permission-arbiter.test.ts +2 -4
- package/dist/extensions/pi-subagents/test/unit/watchdog-render.test.ts +7 -8
- package/dist/extensions/pi-subagents/test/unit/watchdog-review.test.ts +48 -3
- package/dist/extensions/pi-subagents/test/unit/watchdog-rules.test.ts +37 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +36 -118
- package/dist/extensions/pi-subagents/test/unit/watchdog-scope.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +37 -14
- package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +45 -26
- package/dist/extensions/pi-subagents/test/unit/workflow-checklist.test.ts +223 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +50 -1
- package/dist/extensions/pi-subagents/test/unit/workflow-preflight.test.ts +22 -0
- package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +136 -4
- package/dist/extensions/pi-zentui/README.md +19 -5
- package/dist/extensions/pi-zentui/docs/configuration.md +37 -9
- package/dist/extensions/pi-zentui/extensions/zentui/config.ts +29 -0
- package/dist/extensions/pi-zentui/extensions/zentui/index.ts +31 -2
- package/dist/extensions/pi-zentui/extensions/zentui/prototype-patch-registry.ts +55 -11
- package/dist/extensions/pi-zentui/extensions/zentui/settings-command.ts +115 -3
- package/dist/extensions/pi-zentui/extensions/zentui/settings-previews.ts +119 -2
- package/dist/extensions/pi-zentui/extensions/zentui/thinking-experimental.ts +1768 -0
- package/dist/extensions/pi-zentui/extensions/zentui/thinking-status.ts +69 -0
- package/dist/extensions/pi-zentui/extensions/zentui/thinking-steps.ts +155 -0
- package/dist/extensions/pi-zentui/extensions/zentui/ui.ts +2 -1
- package/dist/extensions/pi-zentui/extensions/zentui/user-message-osc.ts +16 -2
- package/dist/extensions/pi-zentui/extensions/zentui/user-message-styles.ts +1 -1
- package/dist/extensions/pi-zentui/test/config-load-lifecycle.test.ts +124 -0
- package/dist/extensions/pi-zentui/test/config.test.ts +82 -2
- package/dist/extensions/pi-zentui/test/editor-viewport-indicators.test.ts +19 -4
- package/dist/extensions/pi-zentui/test/extension-compliance.test.ts +58 -9
- package/dist/extensions/pi-zentui/test/package-contents.mjs +33 -0
- package/dist/extensions/pi-zentui/test/prototype-patch-registry.test.ts +131 -0
- package/dist/extensions/pi-zentui/test/responsive-dependencies.test.ts +4 -4
- package/dist/extensions/pi-zentui/test/settings-command.test.ts +289 -7
- package/dist/extensions/pi-zentui/test/settings-previews.test.ts +106 -0
- package/dist/extensions/pi-zentui/test/thinking-experimental-docs.test.ts +51 -0
- package/dist/extensions/pi-zentui/test/thinking-experimental-loader-diagnostics.mjs +54 -0
- package/dist/extensions/pi-zentui/test/thinking-experimental-missing-export.test.ts +44 -0
- package/dist/extensions/pi-zentui/test/thinking-experimental-rows.test.ts +297 -0
- package/dist/extensions/pi-zentui/test/thinking-experimental-tui.mjs +2329 -0
- package/dist/extensions/pi-zentui/test/thinking-experimental.test.ts +1668 -0
- package/dist/extensions/pi-zentui/test/thinking-status.test.ts +85 -0
- package/dist/extensions/pi-zentui/test/thinking-steps.test.ts +122 -0
- package/dist/extensions/pi-zentui/test/user-message-osc.test.ts +58 -0
- package/dist/skills/brandkit/SKILL.md +0 -2
- package/dist/skills/{industrial-brutalist-ui → brutalist}/SKILL.md +1 -3
- package/dist/skills/gpt-taste/SKILL.md +0 -2
- package/dist/skills/image-to-code/SKILL.md +0 -2
- package/dist/skills/imagegen-frontend-mobile/SKILL.md +0 -2
- package/dist/skills/imagegen-frontend-web/SKILL.md +0 -2
- package/dist/skills/{minimalist-ui → minimalist}/SKILL.md +1 -3
- package/dist/skills/{full-output-enforcement → output}/SKILL.md +1 -3
- package/dist/skills/{redesign-existing-projects → redesign}/SKILL.md +1 -3
- package/dist/skills/{high-end-visual-design → soft}/SKILL.md +1 -3
- package/dist/skills/stitch/DESIGN.md +121 -0
- package/dist/skills/{stitch-design-taste → stitch}/SKILL.md +1 -3
- package/dist/skills/{design-taste-frontend → taste}/SKILL.md +1 -3
- package/dist/skills/{design-taste-frontend-v1 → taste-v1}/SKILL.md +2 -4
- package/package.json +1 -1
|
@@ -41,7 +41,8 @@ export function formatInspectorDashboard(input: { status: AsyncStatus; asyncDir:
|
|
|
41
41
|
lines.push("");
|
|
42
42
|
}
|
|
43
43
|
lines.push(formatAsyncRunTranscript(status, asyncDir, { index: input.index, lines: 60, sessionRoots: input.sessionRoots }));
|
|
44
|
-
const
|
|
44
|
+
const acceptsPlainGuidance = input.index !== undefined || status.mode === "single";
|
|
45
|
+
const controls = [input.allowSteer === false || !acceptsPlainGuidance ? undefined : "type guidance", input.allowSteer === false ? undefined : "steer <message>", input.allowStop === false ? undefined : "stop", "status"].filter(Boolean);
|
|
45
46
|
lines.push("", `Controls: ${controls.join(" | ")}`, "Supervisor replies remain in the parent Pi session (subagent_supervisor/intercom).");
|
|
46
47
|
return lines.join("\n");
|
|
47
48
|
}
|
|
@@ -81,6 +82,20 @@ function isTerminal(status: AsyncStatus): boolean {
|
|
|
81
82
|
return status.state !== "queued" && status.state !== "running";
|
|
82
83
|
}
|
|
83
84
|
|
|
85
|
+
function queueInspectorSteer(options: RunnerOptions, status: AsyncStatus, message: string): string {
|
|
86
|
+
if (options.allowSteer === false) throw new Error("Authority policy does not allow steer from this inspector.");
|
|
87
|
+
if (isTerminal(status)) throw new Error(`Run '${options.runId}' is ${status.state} and cannot be steered.`);
|
|
88
|
+
const runningIndexes = (status.steps ?? []).map((step, index) => step.status === "running" ? index : undefined).filter((index): index is number => index !== undefined);
|
|
89
|
+
const targetIndex = options.index ?? (status.mode === "single" ? 0 : undefined);
|
|
90
|
+
if (targetIndex === undefined && runningIndexes.length === 0) throw new Error("No running child is available to steer. Open a child-specific inspector for a pending child.");
|
|
91
|
+
requestAsyncSteer(options.asyncDir, {
|
|
92
|
+
message,
|
|
93
|
+
...(targetIndex !== undefined ? { targetIndex } : { targetIndexes: runningIndexes }),
|
|
94
|
+
source: "herdr-inspector",
|
|
95
|
+
});
|
|
96
|
+
return steeringReceipt(message, `Steering queued for run ${options.runId}.`);
|
|
97
|
+
}
|
|
98
|
+
|
|
84
99
|
export function submitInspectorControl(options: RunnerOptions, line: string): string {
|
|
85
100
|
const command = line.trim();
|
|
86
101
|
if (!command || command === "status") return "Status refreshed.";
|
|
@@ -93,22 +108,13 @@ export function submitInspectorControl(options: RunnerOptions, line: string): st
|
|
|
93
108
|
return `Stop requested for run ${options.runId}.`;
|
|
94
109
|
}
|
|
95
110
|
if (command.startsWith("steer ")) {
|
|
96
|
-
if (options.allowSteer === false) throw new Error("Authority policy does not allow steer from this inspector.");
|
|
97
111
|
const message = command.slice("steer ".length).trim();
|
|
98
112
|
if (!message) throw new Error("steer requires a message.");
|
|
99
|
-
|
|
100
|
-
const runningIndexes = (status.steps ?? []).map((step, index) => step.status === "running" ? index : undefined).filter((index): index is number => index !== undefined);
|
|
101
|
-
const targetIndex = options.index ?? (status.mode === "single" ? 0 : undefined);
|
|
102
|
-
if (targetIndex === undefined && runningIndexes.length === 0) throw new Error("No running child is available to steer. Open a child-specific inspector for a pending child.");
|
|
103
|
-
requestAsyncSteer(options.asyncDir, {
|
|
104
|
-
message,
|
|
105
|
-
...(targetIndex !== undefined ? { targetIndex } : { targetIndexes: runningIndexes }),
|
|
106
|
-
source: "herdr-inspector",
|
|
107
|
-
});
|
|
108
|
-
return steeringReceipt(message, `Steering queued for run ${options.runId}.`);
|
|
113
|
+
return queueInspectorSteer(options, status, message);
|
|
109
114
|
}
|
|
110
115
|
if (command.startsWith("reply ")) throw new Error("Supervisor replies are owned by the parent Pi session; use subagent_supervisor/intercom there.");
|
|
111
|
-
throw new Error("
|
|
116
|
+
if (options.index === undefined && status.mode !== "single") throw new Error("Plain guidance requires a child-specific inspector. Use steer <message> to target all running children from the aggregate inspector.");
|
|
117
|
+
return queueInspectorSteer(options, status, command);
|
|
112
118
|
}
|
|
113
119
|
|
|
114
120
|
export function runInspector(argv = process.argv.slice(2)): void {
|
|
@@ -33,6 +33,7 @@ export interface ActiveAsyncCapacityHandle {
|
|
|
33
33
|
markStarted(runnerProcessInstanceId: string): void;
|
|
34
34
|
markWorkflowStarted(): void;
|
|
35
35
|
rollback(): boolean;
|
|
36
|
+
rollbackBeforeRunnerProceed(runnerProcessInstanceId: string): boolean;
|
|
36
37
|
reconcile(liveWorkflowRunIds?: ReadonlySet<string>): ActiveAsyncCapacitySnapshot;
|
|
37
38
|
}
|
|
38
39
|
|
|
@@ -43,6 +44,7 @@ interface CapacityOptions {
|
|
|
43
44
|
abandonedSlotReleaseAfterMs?: number | false;
|
|
44
45
|
pidLiveness?: (pid: number) => PidLiveness;
|
|
45
46
|
afterSlotRename?: (releasedDir: string) => void;
|
|
47
|
+
writeOwner?: (filePath: string, owner: ActiveAsyncCapacityOwnerV1) => void;
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
export interface ActiveAsyncCapacityReleaseEvidence {
|
|
@@ -269,7 +271,6 @@ function workflowReleaseVerdict(owner: ActiveAsyncCapacityOwnerV1, status: Async
|
|
|
269
271
|
if (liveWorkflowRunIds.has(owner.runId)) return { state: "retained", reason: "workflow controller is still live" };
|
|
270
272
|
for (const step of status.steps ?? []) {
|
|
271
273
|
const label = step.workflowKey ?? step.agent;
|
|
272
|
-
if (step.status === "pending" || step.status === "running" || step.status === "paused") return { state: "retained", reason: `workflow child ${label} is still ${step.status}` };
|
|
273
274
|
if (typeof step.async !== "boolean") return { state: "retained", reason: `workflow child ${label} is missing async classification` };
|
|
274
275
|
if (!step.async) continue;
|
|
275
276
|
if (!step.runId) return { state: "retained", reason: `async workflow child ${label} is missing run id` };
|
|
@@ -380,6 +381,7 @@ function createSlot(poolDir: string, owner: ActiveAsyncCapacityOwnerV1): boolean
|
|
|
380
381
|
|
|
381
382
|
function handleFor(owner: ActiveAsyncCapacityOwnerV1, limit: number, options: CapacityOptions, rollbackOwner?: ActiveAsyncCapacityOwnerV1): ActiveAsyncCapacityHandle {
|
|
382
383
|
const rootDir = options.rootDir ?? ACTIVE_ASYNC_CAPACITY_DIR;
|
|
384
|
+
const writeOwner = options.writeOwner ?? writePrivateAtomicJson;
|
|
383
385
|
const dir = slotDir(sessionDir(owner.ownerSessionId, rootDir), owner.slot);
|
|
384
386
|
return {
|
|
385
387
|
owner,
|
|
@@ -388,14 +390,10 @@ function handleFor(owner: ActiveAsyncCapacityOwnerV1, limit: number, options: Ca
|
|
|
388
390
|
const current = matchingOwner(dir, owner);
|
|
389
391
|
if (!current) return false;
|
|
390
392
|
const next = { ...current, runnerProcessInstanceId, runnerStartedAt: options.now?.() ?? Date.now() };
|
|
391
|
-
// Mark memory first
|
|
392
|
-
//
|
|
393
|
+
// Mark memory first so pre-proceed cleanup can distinguish a failed durable
|
|
394
|
+
// bind from an unrelated unstarted reservation.
|
|
393
395
|
Object.assign(owner, next);
|
|
394
|
-
|
|
395
|
-
writePrivateAtomicJson(path.join(dir, "owner.json"), next);
|
|
396
|
-
} catch (error) {
|
|
397
|
-
console.error(`Failed to bind active async capacity to runner '${runnerProcessInstanceId}'; capacity will remain occupied:`, error);
|
|
398
|
-
}
|
|
396
|
+
writeOwner(path.join(dir, "owner.json"), next);
|
|
399
397
|
return true;
|
|
400
398
|
});
|
|
401
399
|
if (!claimed.acquired || !claimed.value) throw new Error(`Active async capacity ownership changed for run '${owner.runId}'.`);
|
|
@@ -427,6 +425,26 @@ function handleFor(owner: ActiveAsyncCapacityOwnerV1, limit: number, options: Ca
|
|
|
427
425
|
});
|
|
428
426
|
return claimed.acquired && claimed.value;
|
|
429
427
|
},
|
|
428
|
+
rollbackBeforeRunnerProceed(runnerProcessInstanceId) {
|
|
429
|
+
const claimed = withSlotClaim(dir, () => {
|
|
430
|
+
const current = matchingOwner(dir, owner);
|
|
431
|
+
if (!current) return false;
|
|
432
|
+
const boundToRunner = current.runnerProcessInstanceId === runnerProcessInstanceId;
|
|
433
|
+
const bindingFailedBeforeProceed = current.runnerProcessInstanceId === undefined && current.runnerStartedAt === undefined && owner.runnerProcessInstanceId === runnerProcessInstanceId;
|
|
434
|
+
if (!boundToRunner && !bindingFailedBeforeProceed) return false;
|
|
435
|
+
if (rollbackOwner) {
|
|
436
|
+
writePrivateAtomicJson(path.join(dir, "owner.json"), rollbackOwner);
|
|
437
|
+
Object.assign(owner, rollbackOwner);
|
|
438
|
+
return true;
|
|
439
|
+
}
|
|
440
|
+
const releasedDir = path.join(path.dirname(dir), `.${path.basename(dir)}.released-${randomUUID()}`);
|
|
441
|
+
fs.renameSync(dir, releasedDir);
|
|
442
|
+
options.afterSlotRename?.(releasedDir);
|
|
443
|
+
fs.rmSync(releasedDir, { recursive: true, force: true });
|
|
444
|
+
return true;
|
|
445
|
+
});
|
|
446
|
+
return claimed.acquired && claimed.value;
|
|
447
|
+
},
|
|
430
448
|
reconcile(liveWorkflowRunIds) {
|
|
431
449
|
return reconcileActiveAsyncCapacity(owner.ownerSessionId, limit, { ...options, rootDir, liveWorkflowRunIds });
|
|
432
450
|
},
|
|
@@ -11,15 +11,16 @@ import { createRequire } from "node:module";
|
|
|
11
11
|
import type { ExtensionAPI } from "@selesai/code";
|
|
12
12
|
import { discoverAgents, formatUnknownAgentError, unknownAgentDiagnosticContext, type AgentConfig, type UnknownAgentDiagnosticContext } from "../../agents/agents.ts";
|
|
13
13
|
import { appendAgentRefinementOverlay } from "../../agents/agent-refinements.ts";
|
|
14
|
-
import { writePrivateAtomicJson } from "../../shared/atomic-json.ts";
|
|
14
|
+
import { createAtomicJsonWriter, writePrivateAtomicJson } from "../../shared/atomic-json.ts";
|
|
15
15
|
import { currentCompletionOwnerId } from "../../shared/completion-owner.ts";
|
|
16
16
|
import { planChildLaunch, resolveStepBehavior, suppressProgressForReadOnlyTask, type ResolvedStepBehavior } from "../shared/child-launch-plan.ts";
|
|
17
17
|
import { applyThinkingSuffix, projectLaunchResolvedChildExtensions, resolvePiLaunchToolPlan } from "../shared/pi-args.ts";
|
|
18
18
|
import { injectOutputPathSystemPrompt, injectSingleOutputInstruction, normalizeSingleOutputOverride, resolveSingleOutputPath, validateFileOnlyOutputMode } from "../shared/single-output.ts";
|
|
19
|
-
import {
|
|
19
|
+
import { applyWatchdogLaunchRules, sendRuleViolationWarning } from "../../watchdog/rules.ts";
|
|
20
|
+
import { buildChainInstructions, isDynamicParallelStep, isParallelStep, resolveExistingReadInstructionPaths, resolveExistingReadPaths, writeInitialProgressFile, type ChainStep, type SequentialStep, type StepOverrides } from "../../shared/settings.ts";
|
|
20
21
|
import type { RunnerStep } from "../shared/parallel-utils.ts";
|
|
21
22
|
import type { ContextMode } from "../shared/context-mode.ts";
|
|
22
|
-
import { resolvePiPackageRoot } from "../shared/pi-spawn.ts";
|
|
23
|
+
import { resolveInstalledPiPackageRoot, resolvePiPackageRoot } from "../shared/pi-spawn.ts";
|
|
23
24
|
import { backgroundProcessOptions } from "../shared/background-process-options.ts";
|
|
24
25
|
import { preflightLaunchCwd } from "../shared/launch-cwd.ts";
|
|
25
26
|
import { resolveNodeExecutable } from "../../shared/node-executable.ts";
|
|
@@ -31,11 +32,11 @@ import { resolveToolTimeoutMs, toolTimeoutFromEnv } from "../shared/tool-timeout
|
|
|
31
32
|
import { resolveModelScopesForAgent, type ModelScopeConfig } from "../shared/model-scope.ts";
|
|
32
33
|
import { findModelInfo, resolveEffectiveThinking } from "../../shared/model-info.ts";
|
|
33
34
|
import { assertThinkingWithinCeiling, decodeThinkingCeiling, intersectThinkingCeilings, SUBAGENT_THINKING_CEILING_ENV, type ThinkingLevel } from "../../shared/thinking-ceiling.ts";
|
|
34
|
-
import { resolveExpectedWorktreeAgentCwd } from "../shared/worktree.ts";
|
|
35
|
+
import { resolveExpectedWorktreeAgentCwd, resolveWorktreeProvider, shouldDeferWorktreeCwd, WORKTREE_AGENT_CWD_PLACEHOLDER } from "../shared/worktree.ts";
|
|
35
36
|
import { buildWorkflowGraphSnapshot } from "../shared/workflow-graph.ts";
|
|
36
37
|
import { ChainOutputValidationError, validateChainOutputBindings } from "../shared/chain-outputs.ts";
|
|
37
38
|
import { createStructuredOutputRuntime } from "../shared/structured-output.ts";
|
|
38
|
-
import { resolveEffectiveAcceptance, validateAcceptanceInput, validateExecutionAcceptance } from "../shared/acceptance.ts";
|
|
39
|
+
import { resolveAcceptanceReportMode, resolveEffectiveAcceptance, validateAcceptanceInput, validateExecutionAcceptance } from "../shared/acceptance.ts";
|
|
39
40
|
import { createRunFanoutBudget, writeRunFanoutBudgetDescriptor } from "../shared/run-fanout-budget.ts";
|
|
40
41
|
import { validateImplementationToolContract } from "../shared/completion-guard.ts";
|
|
41
42
|
import {
|
|
@@ -70,7 +71,7 @@ import { validateToolBudgetConfig } from "../shared/tool-budget.ts";
|
|
|
70
71
|
import { usageBudgetState } from "../shared/usage-budget.ts";
|
|
71
72
|
import type { ImportedAsyncRoot } from "./chain-root-attachment.ts";
|
|
72
73
|
import type { SessionLeaseRequest } from "../shared/session-lease.ts";
|
|
73
|
-
import { finalizeProcessTerminal, readProcessTerminal } from "./process-terminal.ts";
|
|
74
|
+
import { finalizeProcessTerminal, initializeProcessTerminal, readProcessTerminal } from "./process-terminal.ts";
|
|
74
75
|
import type { ActiveAsyncCapacityHandle } from "./active-async-capacity.ts";
|
|
75
76
|
import { statusStepDescription } from "./chain-append.ts";
|
|
76
77
|
import { SUBAGENT_PROCESS_TERMINAL_EVENT } from "../../shared/types.ts";
|
|
@@ -81,7 +82,7 @@ import { normalizeExtensionBindings, omitExtensionBindingsEnv, type ExtensionBin
|
|
|
81
82
|
import { assertWorkflowLaneKey, normalizeWorkflowLaneMetadata } from "../shared/lane-metadata.ts";
|
|
82
83
|
|
|
83
84
|
const require = createRequire(import.meta.url);
|
|
84
|
-
const piPackageRoot = resolvePiPackageRoot();
|
|
85
|
+
const piPackageRoot = resolvePiPackageRoot() ?? resolveInstalledPiPackageRoot();
|
|
85
86
|
|
|
86
87
|
function resolveJitiCliFromPackageJson(packageJsonPath: string): string | undefined {
|
|
87
88
|
if (!fs.existsSync(packageJsonPath)) return undefined;
|
|
@@ -178,6 +179,8 @@ interface AsyncChainParams {
|
|
|
178
179
|
worktreeSetupHook?: string;
|
|
179
180
|
worktreeSetupHookTimeoutMs?: number;
|
|
180
181
|
worktreeBaseDir?: string;
|
|
182
|
+
worktreeProvider?: import("../../shared/types.ts").WorktreeProvider;
|
|
183
|
+
worktreeBranchPrefix?: string;
|
|
181
184
|
controlConfig?: ResolvedControlConfig;
|
|
182
185
|
controlIntercomTarget?: string;
|
|
183
186
|
childIntercomTarget?: (agent: string, index: number) => string | undefined;
|
|
@@ -245,6 +248,8 @@ interface AsyncSingleParams {
|
|
|
245
248
|
worktreeSetupHook?: string;
|
|
246
249
|
worktreeSetupHookTimeoutMs?: number;
|
|
247
250
|
worktreeBaseDir?: string;
|
|
251
|
+
worktreeProvider?: import("../../shared/types.ts").WorktreeProvider;
|
|
252
|
+
worktreeBranchPrefix?: string;
|
|
248
253
|
worktree?: boolean;
|
|
249
254
|
controlConfig?: ResolvedControlConfig;
|
|
250
255
|
intercomBridge?: IntercomBridgeConfig;
|
|
@@ -310,6 +315,8 @@ export interface AsyncRunnerStepBuildParams {
|
|
|
310
315
|
waitToolEnabled?: boolean;
|
|
311
316
|
waitToolDefaultTimeoutMs?: number;
|
|
312
317
|
worktreeBaseDir?: string;
|
|
318
|
+
worktreeProvider?: import("../../shared/types.ts").WorktreeProvider;
|
|
319
|
+
worktreeBranchPrefix?: string;
|
|
313
320
|
asyncDir: string;
|
|
314
321
|
outputBaseDir?: string;
|
|
315
322
|
validateOutputBindings?: boolean;
|
|
@@ -432,13 +439,15 @@ function waitForRunnerStartup(startupPath: string, expectedState: RunnerStartupS
|
|
|
432
439
|
return { ok: false, error: `Timed out after ${timeoutMs}ms waiting for the async runner startup state '${expectedState}'.`, startupDidNotProceed: true };
|
|
433
440
|
}
|
|
434
441
|
|
|
442
|
+
const writePrivateStartupControlJson = createAtomicJsonWriter({ mode: 0o600, ignoreCleanupErrorAfterSuccess: true });
|
|
443
|
+
|
|
435
444
|
function writeRunnerStartupControl(filePath: string, payload: { action: "ack" | "proceed"; token: string }): void {
|
|
436
445
|
// Delegate to the shared atomic JSON writer (temp file + rename, retrying
|
|
437
446
|
// transient Windows EPERM/EBUSY/EACCES locks and cleaning up the temp file
|
|
438
447
|
// on failure), so the startup handshake gets the same locking resilience as
|
|
439
448
|
// every other async control/result file. This is exercised by
|
|
440
449
|
// test/unit/atomic-json.test.ts.
|
|
441
|
-
|
|
450
|
+
writePrivateStartupControlJson(filePath, payload);
|
|
442
451
|
}
|
|
443
452
|
|
|
444
453
|
function runnerIsAlive(pid: number): boolean {
|
|
@@ -520,7 +529,7 @@ export function emitProcessTerminalEvent(ctx: AsyncExecutionContext, proof: unkn
|
|
|
520
529
|
}
|
|
521
530
|
}
|
|
522
531
|
|
|
523
|
-
function spawnRunner(cfg: object, suffix: string, cwd: string, initialStatus: Omit<AsyncStatus, "pid" | "processTerminal">, initialStatusPath: string, onProcessTerminal?: (proof: unknown) => void, requestedCwd = cwd): SpawnRunnerResult {
|
|
532
|
+
function spawnRunner(cfg: object, suffix: string, cwd: string, initialStatus: Omit<AsyncStatus, "pid" | "processTerminal">, initialStatusPath: string, onProcessTerminal?: (proof: unknown) => void, onBeforeProceed?: (runnerProcessInstanceId: string) => void, requestedCwd = cwd): SpawnRunnerResult {
|
|
524
533
|
const cwdError = preflightLaunchCwd(requestedCwd, cwd);
|
|
525
534
|
if (cwdError) return { error: cwdError };
|
|
526
535
|
|
|
@@ -637,6 +646,24 @@ function spawnRunner(cfg: object, suffix: string, cwd: string, initialStatus: Om
|
|
|
637
646
|
});
|
|
638
647
|
} catch (error) {
|
|
639
648
|
const message = `Failed to persist initial async status: ${error instanceof Error ? error.message : String(error)}`;
|
|
649
|
+
if (launchAsyncDir) persistPreProceedStartupFailure(launchAsyncDir, launchRunId, runnerProcessInstanceId, launchSessionId, launchCompletionOwnerId, message);
|
|
650
|
+
const terminationObserved = terminateRunnerBeforeProceed(proc.pid);
|
|
651
|
+
return { pid: proc.pid, runnerProcessInstanceId, error: message, terminationObserved, startupDidNotProceed: true };
|
|
652
|
+
}
|
|
653
|
+
try {
|
|
654
|
+
if (!launchAsyncDir) throw new Error("Async runner is missing its lifecycle directory.");
|
|
655
|
+
initializeProcessTerminal(launchAsyncDir, launchRunId, runnerProcessInstanceId);
|
|
656
|
+
} catch (error) {
|
|
657
|
+
const message = `Failed to establish async runner lifecycle sidecar: ${error instanceof Error ? error.message : String(error)}`;
|
|
658
|
+
if (launchAsyncDir) persistPreProceedStartupFailure(launchAsyncDir, launchRunId, runnerProcessInstanceId, launchSessionId, launchCompletionOwnerId, message);
|
|
659
|
+
const terminationObserved = terminateRunnerBeforeProceed(proc.pid);
|
|
660
|
+
return { pid: proc.pid, runnerProcessInstanceId, error: message, terminationObserved, startupDidNotProceed: true };
|
|
661
|
+
}
|
|
662
|
+
try {
|
|
663
|
+
onBeforeProceed?.(runnerProcessInstanceId);
|
|
664
|
+
} catch (error) {
|
|
665
|
+
const message = `Failed to establish async runner capacity ownership: ${error instanceof Error ? error.message : String(error)}`;
|
|
666
|
+
if (launchAsyncDir) persistPreProceedStartupFailure(launchAsyncDir, launchRunId, runnerProcessInstanceId, launchSessionId, launchCompletionOwnerId, message);
|
|
640
667
|
const terminationObserved = terminateRunnerBeforeProceed(proc.pid);
|
|
641
668
|
return { pid: proc.pid, runnerProcessInstanceId, error: message, terminationObserved, startupDidNotProceed: true };
|
|
642
669
|
}
|
|
@@ -720,6 +747,8 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
720
747
|
thinkingOverridesByFlatIndex,
|
|
721
748
|
maxSubagentDepth,
|
|
722
749
|
worktreeBaseDir,
|
|
750
|
+
worktreeProvider,
|
|
751
|
+
worktreeBranchPrefix,
|
|
723
752
|
asyncDir,
|
|
724
753
|
} = params;
|
|
725
754
|
const outputBaseDir = params.outputBaseDir;
|
|
@@ -727,6 +756,15 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
727
756
|
const chainSkills = params.chainSkills ?? [];
|
|
728
757
|
const availableModels = params.availableModels;
|
|
729
758
|
const runnerCwd = resolveChildCwd(ctx.cwd, cwd);
|
|
759
|
+
let managedWorktreeProvider: "native" | "worktrunk" | undefined;
|
|
760
|
+
try {
|
|
761
|
+
if (chain.some((step) => "worktree" in step && step.worktree === true)) {
|
|
762
|
+
const resolved = resolveWorktreeProvider(worktreeProvider, worktreeBaseDir);
|
|
763
|
+
managedWorktreeProvider = shouldDeferWorktreeCwd(worktreeProvider, worktreeBaseDir) ? "worktrunk" : resolved;
|
|
764
|
+
}
|
|
765
|
+
} catch (error) {
|
|
766
|
+
return { error: error instanceof Error ? error.message : String(error) };
|
|
767
|
+
}
|
|
730
768
|
const progressDir = params.progressDir ?? runnerCwd;
|
|
731
769
|
const graphChain: ChainStep[] = params.attachRoot
|
|
732
770
|
? [{
|
|
@@ -853,7 +891,7 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
853
891
|
if (validationError) throw new AsyncStartValidationError(validationError);
|
|
854
892
|
let taskTemplate = s.task ?? "{previous}";
|
|
855
893
|
taskTemplate = taskTemplate.replace(/\{task\}/g, originalTask ?? "");
|
|
856
|
-
taskTemplate = taskTemplate.replace(/\{chain_dir\}/g, runnerCwd);
|
|
894
|
+
taskTemplate = taskTemplate.replace(/\{chain_dir\}/g, behaviorCwd ?? runnerCwd);
|
|
857
895
|
const taskText = `${readInstructions.prefix}${taskTemplate}${progressInstructions.suffix}`;
|
|
858
896
|
const task = namespaceOutputPath ? taskText : injectSingleOutputInstruction(taskText, outputPath, a);
|
|
859
897
|
|
|
@@ -902,9 +940,12 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
902
940
|
throw new AsyncStartValidationError(error instanceof Error ? error.message : String(error));
|
|
903
941
|
}
|
|
904
942
|
}
|
|
943
|
+
const launchRuleError = applyWatchdogLaunchRules({ cwd: stepCwd, agent: a.name, model: modelCandidates[0] ?? model, warn: (violation) => sendRuleViolationWarning(ctx.pi, violation) });
|
|
944
|
+
if (launchRuleError) throw new AsyncStartValidationError(launchRuleError);
|
|
905
945
|
const fast = s.fast ?? params.fast ?? a.fast;
|
|
906
946
|
const toolPlan = resolvePiLaunchToolPlan({
|
|
907
947
|
tools: a.tools,
|
|
948
|
+
excludeTools: a.excludeTools,
|
|
908
949
|
allowNestedSubagents: a.allowNestedSubagents,
|
|
909
950
|
extensions: a.extensions,
|
|
910
951
|
subagentOnlyExtensions: a.subagentOnlyExtensions,
|
|
@@ -967,6 +1008,7 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
967
1008
|
...(primaryModelFromParent ? { skipPrimaryModelVerification: true } : {}),
|
|
968
1009
|
...(availableModels && availableModels.length > 0 ? { modelVerificationRegistry: availableModels } : {}),
|
|
969
1010
|
tools: a.tools,
|
|
1011
|
+
excludeTools: a.excludeTools,
|
|
970
1012
|
allowNestedSubagents: a.allowNestedSubagents,
|
|
971
1013
|
extensions: a.extensions,
|
|
972
1014
|
subagentOnlyExtensions: a.subagentOnlyExtensions,
|
|
@@ -1002,7 +1044,7 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
1002
1044
|
acceptanceRole: a.acceptanceRole,
|
|
1003
1045
|
...(s.gateOn ? { gateOn: s.gateOn } : {}),
|
|
1004
1046
|
...(s.outputSchema ? { structuredOutputSchema: s.outputSchema } : {}),
|
|
1005
|
-
...(s.outputSchema ? { structuredOutput: createStructuredOutputRuntime(s.outputSchema, path.join(asyncDir, "structured-output"), {
|
|
1047
|
+
...(s.outputSchema ? { structuredOutput: createStructuredOutputRuntime(s.outputSchema, path.join(asyncDir, "structured-output"), { acceptanceReport: resolveAcceptanceReportMode(s.acceptance) }) } : {}),
|
|
1006
1048
|
...(resolvedToolBudget.budget ? { toolBudget: resolvedToolBudget.budget } : {}),
|
|
1007
1049
|
...(s.worktree ? { worktree: true } : {}),
|
|
1008
1050
|
};
|
|
@@ -1036,7 +1078,9 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
1036
1078
|
return {
|
|
1037
1079
|
parallel: s.parallel.map((t, taskIndex) => {
|
|
1038
1080
|
let behaviorCwd: string | undefined;
|
|
1039
|
-
if (s.worktree) {
|
|
1081
|
+
if (s.worktree && managedWorktreeProvider === "worktrunk") {
|
|
1082
|
+
behaviorCwd = WORKTREE_AGENT_CWD_PLACEHOLDER;
|
|
1083
|
+
} else if (s.worktree && managedWorktreeProvider === "native") {
|
|
1040
1084
|
try {
|
|
1041
1085
|
behaviorCwd = resolveExpectedWorktreeAgentCwd(runnerCwd, `${id}-s${stepIndex}`, taskIndex, worktreeBaseDir);
|
|
1042
1086
|
} catch {
|
|
@@ -1091,7 +1135,9 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
1091
1135
|
}
|
|
1092
1136
|
const sequential = s as SequentialStep;
|
|
1093
1137
|
let behaviorCwd: string | undefined;
|
|
1094
|
-
if (sequential.worktree) {
|
|
1138
|
+
if (sequential.worktree && managedWorktreeProvider === "worktrunk") {
|
|
1139
|
+
behaviorCwd = WORKTREE_AGENT_CWD_PLACEHOLDER;
|
|
1140
|
+
} else if (sequential.worktree && managedWorktreeProvider === "native") {
|
|
1095
1141
|
try {
|
|
1096
1142
|
behaviorCwd = resolveExpectedWorktreeAgentCwd(runnerCwd, `${id}-s${stepIndex}`, 0, worktreeBaseDir);
|
|
1097
1143
|
} catch {
|
|
@@ -1161,6 +1207,8 @@ export function executeAsyncChain(
|
|
|
1161
1207
|
worktreeSetupHook,
|
|
1162
1208
|
worktreeSetupHookTimeoutMs,
|
|
1163
1209
|
worktreeBaseDir,
|
|
1210
|
+
worktreeProvider,
|
|
1211
|
+
worktreeBranchPrefix,
|
|
1164
1212
|
controlConfig,
|
|
1165
1213
|
controlIntercomTarget,
|
|
1166
1214
|
childIntercomTarget,
|
|
@@ -1171,7 +1219,7 @@ export function executeAsyncChain(
|
|
|
1171
1219
|
chain: chain.map((step) => {
|
|
1172
1220
|
if (isParallelStep(step)) return { parallel: step.parallel };
|
|
1173
1221
|
if (isDynamicParallelStep(step)) return { acceptance: step.acceptance, parallel: step.parallel };
|
|
1174
|
-
return { acceptance: step.acceptance };
|
|
1222
|
+
return { acceptance: step.acceptance, outputSchema: step.outputSchema };
|
|
1175
1223
|
}),
|
|
1176
1224
|
});
|
|
1177
1225
|
if (acceptanceErrors.length > 0) return formatAsyncStartError(resultMode, acceptanceErrors.join(" "));
|
|
@@ -1217,6 +1265,8 @@ export function executeAsyncChain(
|
|
|
1217
1265
|
waitToolEnabled: params.waitToolEnabled,
|
|
1218
1266
|
waitToolDefaultTimeoutMs: params.waitToolDefaultTimeoutMs,
|
|
1219
1267
|
worktreeBaseDir,
|
|
1268
|
+
worktreeProvider,
|
|
1269
|
+
worktreeBranchPrefix,
|
|
1220
1270
|
asyncDir,
|
|
1221
1271
|
fast: params.fast,
|
|
1222
1272
|
toolBudget: params.toolBudget,
|
|
@@ -1292,6 +1342,8 @@ export function executeAsyncChain(
|
|
|
1292
1342
|
worktreeSetupHook,
|
|
1293
1343
|
worktreeSetupHookTimeoutMs,
|
|
1294
1344
|
worktreeBaseDir,
|
|
1345
|
+
worktreeProvider,
|
|
1346
|
+
worktreeBranchPrefix,
|
|
1295
1347
|
controlConfig,
|
|
1296
1348
|
toolBudget: params.toolBudget,
|
|
1297
1349
|
usageBudget: params.usageBudget,
|
|
@@ -1332,6 +1384,7 @@ export function executeAsyncChain(
|
|
|
1332
1384
|
},
|
|
1333
1385
|
path.join(asyncDir, "status.json"),
|
|
1334
1386
|
(proof) => emitProcessTerminalEvent(ctx, proof),
|
|
1387
|
+
(runnerProcessInstanceId) => params.activeAsyncCapacity?.markStarted(runnerProcessInstanceId),
|
|
1335
1388
|
);
|
|
1336
1389
|
} catch (error) {
|
|
1337
1390
|
params.activeAsyncCapacity?.rollback();
|
|
@@ -1340,7 +1393,10 @@ export function executeAsyncChain(
|
|
|
1340
1393
|
}
|
|
1341
1394
|
|
|
1342
1395
|
if (spawnResult.error) {
|
|
1343
|
-
if (
|
|
1396
|
+
if (spawnResult.startupDidNotProceed) {
|
|
1397
|
+
if (!spawnResult.runnerProcessInstanceId || params.activeAsyncCapacity?.rollbackBeforeRunnerProceed(spawnResult.runnerProcessInstanceId) !== true) params.activeAsyncCapacity?.rollback();
|
|
1398
|
+
}
|
|
1399
|
+
else if (!spawnResult.pid || !spawnResult.runnerProcessInstanceId) params.activeAsyncCapacity?.rollback();
|
|
1344
1400
|
else params.activeAsyncCapacity?.markStarted(spawnResult.runnerProcessInstanceId);
|
|
1345
1401
|
return formatAsyncStartError(resultMode, `Failed to start async ${resultMode} '${id}': ${spawnResult.error}`);
|
|
1346
1402
|
}
|
|
@@ -1348,8 +1404,6 @@ export function executeAsyncChain(
|
|
|
1348
1404
|
params.activeAsyncCapacity?.rollback();
|
|
1349
1405
|
return formatAsyncStartError(resultMode, `Failed to start async ${resultMode} '${id}': runner identity unavailable`);
|
|
1350
1406
|
}
|
|
1351
|
-
params.activeAsyncCapacity?.markStarted(spawnResult.runnerProcessInstanceId);
|
|
1352
|
-
|
|
1353
1407
|
if (spawnResult.pid) {
|
|
1354
1408
|
const eventFirstStep = eventChain[0];
|
|
1355
1409
|
if (!eventFirstStep) {
|
|
@@ -1487,6 +1541,8 @@ export function executeAsyncSingle(
|
|
|
1487
1541
|
worktreeSetupHook,
|
|
1488
1542
|
worktreeSetupHookTimeoutMs,
|
|
1489
1543
|
worktreeBaseDir,
|
|
1544
|
+
worktreeProvider,
|
|
1545
|
+
worktreeBranchPrefix,
|
|
1490
1546
|
controlConfig,
|
|
1491
1547
|
controlIntercomTarget,
|
|
1492
1548
|
childIntercomTarget,
|
|
@@ -1532,7 +1588,18 @@ export function executeAsyncSingle(
|
|
|
1532
1588
|
return formatAsyncStartError("single", error instanceof Error ? error.message : String(error));
|
|
1533
1589
|
}
|
|
1534
1590
|
const runnerCwd = resolveChildCwd(ctx.cwd, cwd);
|
|
1535
|
-
|
|
1591
|
+
let managedWorktreeProvider: "native" | "worktrunk" | undefined;
|
|
1592
|
+
if (params.worktree === true) {
|
|
1593
|
+
try {
|
|
1594
|
+
const resolved = resolveWorktreeProvider(params.worktreeProvider, worktreeBaseDir);
|
|
1595
|
+
managedWorktreeProvider = shouldDeferWorktreeCwd(params.worktreeProvider, worktreeBaseDir) ? "worktrunk" : resolved;
|
|
1596
|
+
} catch (error) {
|
|
1597
|
+
return formatAsyncStartError("single", error instanceof Error ? error.message : String(error));
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
const instructionCwd = params.worktree === true && managedWorktreeProvider === "worktrunk"
|
|
1601
|
+
? WORKTREE_AGENT_CWD_PLACEHOLDER
|
|
1602
|
+
: params.worktree === true && managedWorktreeProvider === "native"
|
|
1536
1603
|
? resolveExpectedWorktreeAgentCwd(runnerCwd, `${id}-s0`, 0, worktreeBaseDir)
|
|
1537
1604
|
: runnerCwd;
|
|
1538
1605
|
const readExistenceCwd = params.worktree === true ? runnerCwd : instructionCwd;
|
|
@@ -1586,7 +1653,11 @@ export function executeAsyncSingle(
|
|
|
1586
1653
|
// Reads: caller override > agent defaultReads > none. `~`/`~/` expand to home;
|
|
1587
1654
|
// absolute paths pass through; relative paths resolve against the child cwd.
|
|
1588
1655
|
const reads = params.reads !== undefined ? params.reads : agentConfig.defaultReads ?? false;
|
|
1589
|
-
const readPaths = Array.isArray(reads)
|
|
1656
|
+
const readPaths = Array.isArray(reads)
|
|
1657
|
+
? managedWorktreeProvider === "worktrunk"
|
|
1658
|
+
? resolveExistingReadInstructionPaths(reads, instructionCwd, readExistenceCwd)
|
|
1659
|
+
: resolveExistingReadPaths(reads, readExistenceCwd)
|
|
1660
|
+
: [];
|
|
1590
1661
|
const readsInstruction = readPaths.length > 0
|
|
1591
1662
|
? `[Read from: ${readPaths.join(", ")}]\n\n`
|
|
1592
1663
|
: "";
|
|
@@ -1647,7 +1718,7 @@ export function executeAsyncSingle(
|
|
|
1647
1718
|
const initialUsageBudget = usageBudgetState(params.usageBudget, undefined);
|
|
1648
1719
|
const resolvedSessionDir = params.sessionDir ?? (sessionRoot ? path.join(sessionRoot, `async-${id}`) : undefined);
|
|
1649
1720
|
const structuredOutput = params.structuredOutputSchema
|
|
1650
|
-
? createStructuredOutputRuntime(params.structuredOutputSchema, path.join(asyncDir, "structured-output"), {
|
|
1721
|
+
? createStructuredOutputRuntime(params.structuredOutputSchema, path.join(asyncDir, "structured-output"), { acceptanceReport: resolveAcceptanceReportMode(params.acceptance) })
|
|
1651
1722
|
: undefined;
|
|
1652
1723
|
let modelCandidates: string[] = [];
|
|
1653
1724
|
if (!externalRunner) {
|
|
@@ -1667,6 +1738,7 @@ export function executeAsyncSingle(
|
|
|
1667
1738
|
}
|
|
1668
1739
|
const toolPlan = resolvePiLaunchToolPlan({
|
|
1669
1740
|
tools: agentConfig.tools,
|
|
1741
|
+
excludeTools: agentConfig.excludeTools,
|
|
1670
1742
|
allowNestedSubagents: agentConfig.allowNestedSubagents,
|
|
1671
1743
|
extensions: agentConfig.extensions,
|
|
1672
1744
|
subagentOnlyExtensions: agentConfig.subagentOnlyExtensions,
|
|
@@ -1713,6 +1785,7 @@ export function executeAsyncSingle(
|
|
|
1713
1785
|
inheritSkills: agentConfig.inheritSkills,
|
|
1714
1786
|
skills: resolvedSkills.map((skill) => skill.name),
|
|
1715
1787
|
tools: toolPlan.effectiveToolAllowlist,
|
|
1788
|
+
...(toolPlan.excludeTools.length > 0 ? { excludeTools: toolPlan.excludeTools } : {}),
|
|
1716
1789
|
extensions: toolPlan.extensionArgs,
|
|
1717
1790
|
mcpDirectTools: toolPlan.effectiveMcpTools,
|
|
1718
1791
|
...(outputPath ? { outputPath } : {}),
|
|
@@ -1751,6 +1824,7 @@ export function executeAsyncSingle(
|
|
|
1751
1824
|
...(effectiveThinking ? { thinking: resolveEffectiveThinking(model, effectiveThinking) } : {}),
|
|
1752
1825
|
...(thinkingCeiling ? { thinkingCeiling } : {}),
|
|
1753
1826
|
...(recoveryAgentConfig.tools ? { tools: [...recoveryAgentConfig.tools] } : {}),
|
|
1827
|
+
...(recoveryAgentConfig.excludeTools ? { excludeTools: [...recoveryAgentConfig.excludeTools] } : {}),
|
|
1754
1828
|
...(recoveryAgentConfig.allowNestedSubagents !== undefined ? { allowNestedSubagents: recoveryAgentConfig.allowNestedSubagents } : {}),
|
|
1755
1829
|
...(recoveryAgentConfig.extensions ? { extensions: [...recoveryAgentConfig.extensions] } : {}),
|
|
1756
1830
|
...(recoveryAgentConfig.subagentOnlyExtensions ? { subagentOnlyExtensions: [...recoveryAgentConfig.subagentOnlyExtensions] } : {}),
|
|
@@ -1818,6 +1892,7 @@ export function executeAsyncSingle(
|
|
|
1818
1892
|
...(modelOrigin === "inherited" ? { skipPrimaryModelVerification: true } : {}),
|
|
1819
1893
|
...(availableModels && availableModels.length > 0 ? { modelVerificationRegistry: availableModels } : {}),
|
|
1820
1894
|
tools: agentConfig.tools,
|
|
1895
|
+
excludeTools: agentConfig.excludeTools,
|
|
1821
1896
|
allowNestedSubagents: agentConfig.allowNestedSubagents,
|
|
1822
1897
|
extensions: agentConfig.extensions,
|
|
1823
1898
|
subagentOnlyExtensions: agentConfig.subagentOnlyExtensions,
|
|
@@ -1846,6 +1921,7 @@ export function executeAsyncSingle(
|
|
|
1846
1921
|
...(extensionBindings ? { extensionBindings } : {}),
|
|
1847
1922
|
launchResolvedExtensions,
|
|
1848
1923
|
effectiveAcceptance: resolvedAcceptance,
|
|
1924
|
+
acceptanceInput: params.acceptance,
|
|
1849
1925
|
...(structuredOutput ? { structuredOutput } : {}),
|
|
1850
1926
|
...(params.structuredOutputSchema ? { structuredOutputSchema: params.structuredOutputSchema } : {}),
|
|
1851
1927
|
...(resolvedToolBudget.budget ? { toolBudget: resolvedToolBudget.budget } : {}),
|
|
@@ -1872,6 +1948,8 @@ export function executeAsyncSingle(
|
|
|
1872
1948
|
worktreeSetupHook,
|
|
1873
1949
|
worktreeSetupHookTimeoutMs,
|
|
1874
1950
|
worktreeBaseDir,
|
|
1951
|
+
worktreeProvider,
|
|
1952
|
+
worktreeBranchPrefix,
|
|
1875
1953
|
controlConfig,
|
|
1876
1954
|
timeoutMs,
|
|
1877
1955
|
deadlineAt,
|
|
@@ -1914,6 +1992,7 @@ export function executeAsyncSingle(
|
|
|
1914
1992
|
},
|
|
1915
1993
|
path.join(asyncDir, "status.json"),
|
|
1916
1994
|
(proof) => emitProcessTerminalEvent(ctx, proof),
|
|
1995
|
+
(runnerProcessInstanceId) => params.activeAsyncCapacity?.markStarted(runnerProcessInstanceId),
|
|
1917
1996
|
params.requestedCwd ?? runnerCwd,
|
|
1918
1997
|
);
|
|
1919
1998
|
} catch (error) {
|
|
@@ -1923,7 +2002,10 @@ export function executeAsyncSingle(
|
|
|
1923
2002
|
}
|
|
1924
2003
|
|
|
1925
2004
|
if (spawnResult.error) {
|
|
1926
|
-
if (
|
|
2005
|
+
if (spawnResult.startupDidNotProceed) {
|
|
2006
|
+
if (!spawnResult.runnerProcessInstanceId || params.activeAsyncCapacity?.rollbackBeforeRunnerProceed(spawnResult.runnerProcessInstanceId) !== true) params.activeAsyncCapacity?.rollback();
|
|
2007
|
+
}
|
|
2008
|
+
else if (!spawnResult.pid || !spawnResult.runnerProcessInstanceId) params.activeAsyncCapacity?.rollback();
|
|
1927
2009
|
else params.activeAsyncCapacity?.markStarted(spawnResult.runnerProcessInstanceId);
|
|
1928
2010
|
return formatAsyncStartError("single", `Failed to start async run '${id}': ${spawnResult.error}`);
|
|
1929
2011
|
}
|
|
@@ -1931,8 +2013,6 @@ export function executeAsyncSingle(
|
|
|
1931
2013
|
params.activeAsyncCapacity?.rollback();
|
|
1932
2014
|
return formatAsyncStartError("single", `Failed to start async run '${id}': runner identity unavailable`);
|
|
1933
2015
|
}
|
|
1934
|
-
params.activeAsyncCapacity?.markStarted(spawnResult.runnerProcessInstanceId);
|
|
1935
|
-
|
|
1936
2016
|
if (spawnResult.pid) {
|
|
1937
2017
|
if (inheritedNestedRoute && nestedAddress) {
|
|
1938
2018
|
const now = Date.now();
|
|
@@ -45,6 +45,8 @@ export type AsyncResumeTarget = {
|
|
|
45
45
|
sessionName?: string;
|
|
46
46
|
index: number;
|
|
47
47
|
cwd?: string;
|
|
48
|
+
/** True when cwd is the retained managed worktree recorded by the handoff. */
|
|
49
|
+
managedWorktree?: boolean;
|
|
48
50
|
sessionFile?: string;
|
|
49
51
|
model?: string;
|
|
50
52
|
thinking?: string;
|
|
@@ -315,7 +317,7 @@ export function readAsyncRecoveryDescriptor(asyncDir: string | undefined): Steer
|
|
|
315
317
|
const parsed = value as Record<string, unknown>;
|
|
316
318
|
const allowedFields = new Set([
|
|
317
319
|
"version", "launchContractDigest", "sourceRunId", "agentContract", "agent", "sessionFile", "cwd", "model", "modelProvider", "modelOverrideFromParent", "modelOrigin", "fallbackModels", "thinking", "thinkingCeiling", "tools", "allowNestedSubagents", "extensions",
|
|
318
|
-
"subagentOnlyExtensions", "mcpDirectTools", "mutationTools", "systemPrompt", "systemPromptMode", "inheritProjectContext", "inheritGlobalContext", "inheritSkills", "skills",
|
|
320
|
+
"subagentOnlyExtensions", "mcpDirectTools", "excludeTools", "mutationTools", "systemPrompt", "systemPromptMode", "inheritProjectContext", "inheritGlobalContext", "inheritSkills", "skills",
|
|
319
321
|
"skillPath", "agentFilePath", "completionGuard", "memory", "outputPath", "outputMode", "structuredOutputSchema", "acceptance", "sessionDir", "artifactConfig",
|
|
320
322
|
"artifactsDir", "maxOutput", "controlConfig", "context", "intercomBridge", "absoluteDeadlineAt", "initialTurnBudget", "initialToolBudget", "maxSubagentDepth", "share", "capabilityCeiling",
|
|
321
323
|
"launchResolvedExtensions", "runFanoutBudget", "lane",
|
|
@@ -356,7 +358,7 @@ export function readAsyncRecoveryDescriptor(asyncDir: string | undefined): Steer
|
|
|
356
358
|
else if (typeof parsed.inheritGlobalContext !== "boolean") throw new Error(`Invalid async recovery descriptor '${descriptorPath}': inheritGlobalContext must be a boolean.`);
|
|
357
359
|
if (parsed.allowNestedSubagents !== undefined && typeof parsed.allowNestedSubagents !== "boolean") throw new Error(`Invalid async recovery descriptor '${descriptorPath}': allowNestedSubagents must be a boolean.`);
|
|
358
360
|
if (!Number.isInteger(parsed.maxSubagentDepth) || (parsed.maxSubagentDepth as number) < 0) throw new Error(`Invalid async recovery descriptor '${descriptorPath}': maxSubagentDepth must be a non-negative integer.`);
|
|
359
|
-
for (const field of ["fallbackModels", "tools", "extensions", "subagentOnlyExtensions", "mcpDirectTools", "mutationTools", "skills", "skillPath"] as const) {
|
|
361
|
+
for (const field of ["fallbackModels", "tools", "excludeTools", "extensions", "subagentOnlyExtensions", "mcpDirectTools", "mutationTools", "skills", "skillPath"] as const) {
|
|
360
362
|
const item = parsed[field];
|
|
361
363
|
if (item !== undefined && (!Array.isArray(item) || item.some((entry) => typeof entry !== "string" || !entry.trim()))) throw new Error(`Invalid async recovery descriptor '${descriptorPath}': ${field} must contain non-empty strings.`);
|
|
362
364
|
}
|
|
@@ -569,6 +571,7 @@ export function resolveAsyncResumeTarget(params: AsyncResumeParams, deps: AsyncR
|
|
|
569
571
|
...(statusSteps[index]?.sessionName ?? resultSteps[index]?.sessionName ? { sessionName: statusSteps[index]?.sessionName ?? resultSteps[index]?.sessionName } : {}),
|
|
570
572
|
index,
|
|
571
573
|
...(resumeCwd ? { cwd: resumeCwd } : {}),
|
|
574
|
+
...(managedWorktreeCwd ? { managedWorktree: true } : {}),
|
|
572
575
|
...(resolvedSessionFile ? { sessionFile: resolvedSessionFile } : {}),
|
|
573
576
|
...(stepModel ? { model: stepModel } : {}),
|
|
574
577
|
...(stepThinking ? { thinking: stepThinking } : {}),
|
|
@@ -590,6 +593,7 @@ export function applySteeringRecoveryAgentConfig(agentConfig: AgentConfig, descr
|
|
|
590
593
|
thinking: descriptor.thinking,
|
|
591
594
|
maxThinking: intersectThinkingCeilings(descriptor.thinkingCeiling, agentConfig.maxThinking),
|
|
592
595
|
tools: descriptor.tools ? [...descriptor.tools] : undefined,
|
|
596
|
+
excludeTools: descriptor.excludeTools ? [...descriptor.excludeTools] : undefined,
|
|
593
597
|
allowNestedSubagents: descriptor.allowNestedSubagents,
|
|
594
598
|
extensions: descriptor.extensions ? [...descriptor.extensions] : undefined,
|
|
595
599
|
subagentOnlyExtensions: descriptor.subagentOnlyExtensions ? [...descriptor.subagentOnlyExtensions] : undefined,
|
|
@@ -3,7 +3,7 @@ import * as path from "node:path";
|
|
|
3
3
|
import { formatDuration, formatModelThinking, formatTokens, shortenPath } from "../../shared/formatters.ts";
|
|
4
4
|
import { previewDisplayText } from "../../shared/display-text.ts";
|
|
5
5
|
import { formatActivityLabel, formatParallelOutcome } from "../../shared/status-format.ts";
|
|
6
|
-
import { type ActivityState, type AsyncJobStep, type AsyncParallelGroupStatus, type AsyncStatus, type CostSummary, type Details, type HostStepNodeV1, type HostStepState, type LaunchResolvedChildExtensionsV1, type RuntimeAcknowledgedChildExtensionsV1, type NestedRunSummary, type SteeringStatus, type SubagentRunMode, type TimeoutRecoveryProjection, type TokenUsage, type TurnBudgetState, type UsageBudgetState, type WorkflowPreflightV1, type WorkflowGraphSnapshot } from "../../shared/types.ts";
|
|
6
|
+
import { type ActivityState, type AsyncJobStep, type AsyncParallelGroupStatus, type AsyncStatus, type CostSummary, type Details, type HostStepNodeV1, type HostStepState, type LaunchResolvedChildExtensionsV1, type RuntimeAcknowledgedChildExtensionsV1, type NestedRunSummary, type SteeringStatus, type SubagentRunMode, type TimeoutRecoveryProjection, type TokenUsage, type TurnBudgetState, type UsageBudgetState, type WorktreeNaming, type WorkflowPreflightV1, type WorkflowGraphSnapshot } from "../../shared/types.ts";
|
|
7
7
|
import type { ResolvedSubagentCapabilityCeiling, SubagentCapabilityAudit } from "../shared/capability-ceiling.ts";
|
|
8
8
|
import { readStatus } from "../../shared/utils.ts";
|
|
9
9
|
import { attachRootChildrenToSteps, buildNestedRouteIndex, findNestedRouteForRootId, type NestedRoute, projectNestedEvents } from "../shared/nested-events.ts";
|
|
@@ -24,6 +24,7 @@ import { validateAsyncStatusLaneMetadata } from "../shared/lane-metadata.ts";
|
|
|
24
24
|
import { formatWorkflowPreflightPlanSummary, formatWorkflowPreflightWarningSummary } from "../../workflows/workflow-preflight.ts";
|
|
25
25
|
import { workflowGraphStageNodes } from "../shared/workflow-graph.ts";
|
|
26
26
|
import { formatTimeoutRecoveryLines, projectTimeoutRecovery } from "../shared/mutation-evidence.ts";
|
|
27
|
+
import { formatWorkflowChecklistText, projectWorkflowChecklist } from "../../workflows/workflow-checklist.ts";
|
|
27
28
|
|
|
28
29
|
interface AsyncRunStepSummary {
|
|
29
30
|
index: number;
|
|
@@ -39,6 +40,8 @@ interface AsyncRunStepSummary {
|
|
|
39
40
|
lane?: AsyncJobStep["lane"];
|
|
40
41
|
worktreePath?: string;
|
|
41
42
|
branch?: string;
|
|
43
|
+
provider?: "native" | "worktrunk";
|
|
44
|
+
naming?: WorktreeNaming;
|
|
42
45
|
runId?: string;
|
|
43
46
|
outputName?: string;
|
|
44
47
|
structured?: boolean;
|
|
@@ -337,6 +340,8 @@ function statusToSummary(asyncDir: string, status: AsyncStatus & { cwd?: string
|
|
|
337
340
|
...(step.lane ? { lane: step.lane } : {}),
|
|
338
341
|
...(step.worktreePath ? { worktreePath: step.worktreePath } : {}),
|
|
339
342
|
...(step.branch ? { branch: step.branch } : {}),
|
|
343
|
+
...(step.provider ? { provider: step.provider } : {}),
|
|
344
|
+
...(step.naming ? { naming: step.naming } : {}),
|
|
340
345
|
...(step.runId ? { runId: step.runId } : {}),
|
|
341
346
|
...(step.outputName ? { outputName: step.outputName } : {}),
|
|
342
347
|
...(step.structured ? { structured: step.structured } : {}),
|
|
@@ -623,7 +628,7 @@ function formatStepLine(step: AsyncRunStepSummary): string {
|
|
|
623
628
|
if (step.durationMs !== undefined) parts.push(formatDuration(step.durationMs));
|
|
624
629
|
if (step.tokens) parts.push(`${formatTokens(step.tokens.total)} tok`);
|
|
625
630
|
if (step.lane) parts.push(`lane ${step.lane.key}`);
|
|
626
|
-
if (step.worktreePath) parts.push(`worktree ${shortenPath(step.worktreePath)} · branch ${step.branch ?? "unknown"}`);
|
|
631
|
+
if (step.worktreePath) parts.push(`worktree ${shortenPath(step.worktreePath)} · branch ${step.branch ?? "unknown"}${step.provider ? ` · provider ${step.provider}` : ""}`);
|
|
627
632
|
return parts.join(" | ");
|
|
628
633
|
}
|
|
629
634
|
|
|
@@ -716,6 +721,17 @@ export function formatAsyncRunList(runs: AsyncRunSummary[], heading = "Active as
|
|
|
716
721
|
if (run.preflight) lines.push(formatWorkflowPreflightPlanSummary(run.preflight, { indent: " " }));
|
|
717
722
|
const preflightWarning = formatWorkflowPreflightWarningSummary(run.workflow?.preflightWarnings, { indent: " " });
|
|
718
723
|
if (preflightWarning) lines.push(preflightWarning);
|
|
724
|
+
if (run.mode === "workflow") {
|
|
725
|
+
const checklist = projectWorkflowChecklist({
|
|
726
|
+
graph: run.workflowGraph,
|
|
727
|
+
steps: run.steps,
|
|
728
|
+
hostSteps: run.hostSteps,
|
|
729
|
+
preflight: run.preflight,
|
|
730
|
+
trace: run.workflow?.trace,
|
|
731
|
+
now: run.lastUpdate ?? run.endedAt ?? Date.now(),
|
|
732
|
+
});
|
|
733
|
+
lines.push(...formatWorkflowChecklistText(checklist, " ", { includeItems: false }));
|
|
734
|
+
}
|
|
719
735
|
for (const step of run.steps) {
|
|
720
736
|
lines.push(` ${formatStepLine(step)}`);
|
|
721
737
|
lines.push(...formatTimeoutRecoveryLines(step.timeoutRecovery, " "));
|