@duckmind/dm-windows-x64 0.61.4 → 0.61.9
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/dm.exe +0 -0
- package/extensions/.dm-extensions.json +211 -67
- package/extensions/dm-subagents/agents/claude-code-writer.md +15 -0
- package/extensions/dm-subagents/agents/claude-code.md +15 -0
- package/extensions/dm-subagents/agents/codex-exec-writer.md +15 -0
- package/extensions/dm-subagents/agents/codex-exec.md +15 -0
- package/extensions/dm-subagents/agents/cursor-agent-writer.md +14 -0
- package/extensions/dm-subagents/agents/cursor-agent.md +14 -0
- package/extensions/dm-subagents/agents/delegate.md +3 -2
- package/extensions/dm-subagents/agents/oracle.md +10 -5
- package/extensions/dm-subagents/agents/researcher.md +2 -2
- package/extensions/dm-subagents/agents/reviewer.md +17 -7
- package/extensions/dm-subagents/agents/scout.md +5 -5
- package/extensions/dm-subagents/agents/worker.md +6 -2
- package/extensions/dm-subagents/async-retention-discovery-worker.mjs +167 -0
- package/extensions/dm-subagents/index.js +4 -0
- package/extensions/dm-subagents/inspector-runner.mjs +10 -0
- package/extensions/dm-subagents/install.mjs +3 -2
- package/extensions/dm-subagents/package.json +2 -2
- package/extensions/dm-subagents/prompts/council.md +60 -0
- package/extensions/dm-subagents/prompts/parallel-review.md +5 -1
- package/extensions/dm-subagents/prompts/review-loop.md +13 -7
- package/extensions/dm-subagents/skills/council-mode/SKILL.md +59 -0
- package/extensions/dm-subagents/skills/council-mode/references/pass-contracts.md +150 -0
- package/extensions/dm-subagents/skills/dm-subagents/SKILL.md +96 -911
- package/extensions/dm-subagents/skills/dm-subagents/references/constraints-and-recipes.md +70 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/execution-controls.md +539 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/management-authoring-rpc.md +161 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/multi-lane-orchestration.md +51 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/prompting-and-roles.md +295 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/review-and-validation.md +73 -0
- package/extensions/dm-subagents/src/agents/agent-management.js +716 -484
- package/extensions/dm-subagents/src/agents/agent-refinements.js +563 -0
- package/extensions/dm-subagents/src/agents/agent-serializer.js +70 -5
- package/extensions/dm-subagents/src/agents/agents.js +1447 -299
- package/extensions/dm-subagents/src/agents/builtin-names.js +15 -0
- package/extensions/dm-subagents/src/agents/chain-serializer.js +12 -7
- package/extensions/dm-subagents/src/agents/frontmatter.js +64 -14
- package/extensions/dm-subagents/src/agents/identity.js +1 -1
- package/extensions/dm-subagents/src/agents/proactive-skills.js +14 -11
- package/extensions/dm-subagents/src/agents/runtime-agent-events.js +49 -0
- package/extensions/dm-subagents/src/agents/runtime-agent-registry.js +412 -0
- package/extensions/dm-subagents/src/agents/skills.js +52 -35
- package/extensions/dm-subagents/src/api/agents.js +6 -0
- package/extensions/dm-subagents/src/api/background-work.js +151 -0
- package/extensions/dm-subagents/src/api/capability-ceiling.js +12 -0
- package/extensions/dm-subagents/src/api/control-channel.js +3 -0
- package/extensions/dm-subagents/src/api/delegation.js +5 -0
- package/extensions/dm-subagents/src/api/dm-args.js +3 -0
- package/extensions/dm-subagents/src/api/external-job-provider.js +137 -0
- package/extensions/dm-subagents/src/api/external-runs.js +233 -0
- package/extensions/dm-subagents/src/api/intercom-bridge.js +3 -0
- package/extensions/dm-subagents/src/api/preflight.js +322 -0
- package/extensions/dm-subagents/src/api/project-panes.js +11 -0
- package/extensions/dm-subagents/src/api/shared-types.js +4 -0
- package/extensions/dm-subagents/src/extension/config.js +175 -0
- package/extensions/dm-subagents/src/extension/control-notices.js +4 -43
- package/extensions/dm-subagents/src/extension/doctor.js +71 -17
- package/extensions/dm-subagents/src/extension/fanout-child.js +49 -32
- package/extensions/dm-subagents/src/extension/index.js +711 -265
- package/extensions/dm-subagents/src/extension/public-execution.js +114 -0
- package/extensions/dm-subagents/src/extension/rpc.js +427 -22
- package/extensions/dm-subagents/src/extension/schemas.js +158 -65
- package/extensions/dm-subagents/src/extension/steering-notices.js +23 -0
- package/extensions/dm-subagents/src/extension/subagent-guide.js +31 -0
- package/extensions/dm-subagents/src/extension/tool-description.js +92 -74
- package/extensions/dm-subagents/src/extension/tool-result.js +7 -0
- package/extensions/dm-subagents/src/inspectors/herdr/actions.js +218 -0
- package/extensions/dm-subagents/src/inspectors/herdr/client.js +123 -0
- package/extensions/dm-subagents/src/inspectors/herdr/focus.js +47 -0
- package/extensions/dm-subagents/src/inspectors/herdr/inspector-runner.js +160 -0
- package/extensions/dm-subagents/src/inspectors/herdr/project-panes.js +618 -0
- package/extensions/dm-subagents/src/inspectors/herdr/session-roots-codec.js +21 -0
- package/extensions/dm-subagents/src/inspectors/herdr/shell-command.js +15 -0
- package/extensions/dm-subagents/src/integrations/herdr-status.js +377 -0
- package/extensions/dm-subagents/src/intercom/intercom-bridge.js +17 -13
- package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +371 -79
- package/extensions/dm-subagents/src/intercom/result-intercom.js +47 -7
- package/extensions/dm-subagents/src/missions/actions.js +394 -0
- package/extensions/dm-subagents/src/missions/goal-driver.js +149 -0
- package/extensions/dm-subagents/src/missions/lifecycle.js +331 -0
- package/extensions/dm-subagents/src/missions/store.js +548 -0
- package/extensions/dm-subagents/src/missions/types.js +9 -0
- package/extensions/dm-subagents/src/missions/workflow-state.js +245 -0
- package/extensions/dm-subagents/src/policy/authority.js +37 -0
- package/extensions/dm-subagents/src/profiles/profiles.js +36 -18
- package/extensions/dm-subagents/src/runs/background/active-async-capacity.js +427 -0
- package/extensions/dm-subagents/src/runs/background/active-run-index.js +122 -0
- package/extensions/dm-subagents/src/runs/background/async-execution.js +925 -137
- package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +515 -148
- package/extensions/dm-subagents/src/runs/background/async-resume.js +378 -51
- package/extensions/dm-subagents/src/runs/background/async-retention.js +828 -0
- package/extensions/dm-subagents/src/runs/background/async-status-snapshot.js +31 -0
- package/extensions/dm-subagents/src/runs/background/async-status.js +259 -22
- package/extensions/dm-subagents/src/runs/background/auto-drain.js +46 -0
- package/extensions/dm-subagents/src/runs/background/chain-append.js +50 -15
- package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +67 -12
- package/extensions/dm-subagents/src/runs/background/completion-batcher.js +5 -1
- package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +3 -11
- package/extensions/dm-subagents/src/runs/background/completion-replay.js +245 -0
- package/extensions/dm-subagents/src/runs/background/control-channel.js +423 -36
- package/extensions/dm-subagents/src/runs/background/fleet-view.js +132 -59
- package/extensions/dm-subagents/src/runs/background/index-segment.js +38 -0
- package/extensions/dm-subagents/src/runs/background/inspect-rpc.js +373 -0
- package/extensions/dm-subagents/src/runs/background/notify.js +357 -57
- package/extensions/dm-subagents/src/runs/background/owned-process-tree.js +86 -0
- package/extensions/dm-subagents/src/runs/background/process-terminal.js +269 -0
- package/extensions/dm-subagents/src/runs/background/result-delivery-ownership.js +34 -0
- package/extensions/dm-subagents/src/runs/background/result-files.js +469 -0
- package/extensions/dm-subagents/src/runs/background/result-watcher.js +540 -75
- package/extensions/dm-subagents/src/runs/background/resume-guidance.js +44 -0
- package/extensions/dm-subagents/src/runs/background/retained-children.js +119 -0
- package/extensions/dm-subagents/src/runs/background/run-id-query.js +5 -0
- package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +93 -9
- package/extensions/dm-subagents/src/runs/background/run-status.js +303 -32
- package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +784 -376
- package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +75 -34
- package/extensions/dm-subagents/src/runs/background/steering.js +221 -0
- package/extensions/dm-subagents/src/runs/background/subagent-runner.js +3106 -844
- package/extensions/dm-subagents/src/runs/background/subagent-wait.js +529 -0
- package/extensions/dm-subagents/src/runs/background/terminal-run-index.js +106 -0
- package/extensions/dm-subagents/src/runs/background/top-level-async.js +1 -1
- package/extensions/dm-subagents/src/runs/background/wait-completions.js +155 -0
- package/extensions/dm-subagents/src/runs/background/wait-config.js +46 -0
- package/extensions/dm-subagents/src/runs/background/wait-subscriptions.js +278 -0
- package/extensions/dm-subagents/src/runs/background/wait-tool.js +47 -0
- package/extensions/dm-subagents/src/runs/foreground/async-dismiss-action.js +81 -0
- package/extensions/dm-subagents/src/runs/foreground/async-steering-action.js +245 -0
- package/extensions/dm-subagents/src/runs/foreground/async-stop-action.js +74 -0
- package/extensions/dm-subagents/src/runs/foreground/execution.js +1401 -342
- package/extensions/dm-subagents/src/runs/foreground/foreground-control.js +133 -0
- package/extensions/dm-subagents/src/runs/foreground/foreground-history.js +148 -0
- package/extensions/dm-subagents/src/runs/foreground/prompt-audit.js +139 -0
- package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +4278 -1441
- package/extensions/dm-subagents/src/runs/foreground/workflow-detach-reconcile.js +278 -0
- package/extensions/dm-subagents/src/runs/foreground/workflow-foreground-steering.js +155 -0
- package/extensions/dm-subagents/src/runs/shared/abort-recovery.js +97 -0
- package/extensions/dm-subagents/src/runs/shared/acceptance.js +597 -148
- package/extensions/dm-subagents/src/runs/shared/agent-contract.js +35 -0
- package/extensions/dm-subagents/src/runs/shared/async-status-projection.js +472 -0
- package/extensions/dm-subagents/src/runs/shared/background-process-options.js +6 -0
- package/extensions/dm-subagents/src/runs/shared/capability-ceiling.js +175 -0
- package/extensions/dm-subagents/src/runs/shared/child-identity.js +32 -0
- package/extensions/dm-subagents/src/runs/shared/child-launch-plan.js +65 -0
- package/extensions/dm-subagents/src/runs/shared/child-protocol.js +447 -0
- package/extensions/dm-subagents/src/runs/shared/claude-code-adapter.js +120 -0
- package/extensions/dm-subagents/src/runs/shared/codex-exec-adapter.js +129 -0
- package/extensions/dm-subagents/src/runs/shared/completion-evidence.js +40 -0
- package/extensions/dm-subagents/src/runs/shared/completion-guard.js +140 -83
- package/extensions/dm-subagents/src/runs/shared/context-mode.js +38 -0
- package/extensions/dm-subagents/src/runs/shared/cursor-agent-adapter.js +101 -0
- package/extensions/dm-subagents/src/runs/shared/dm-args.js +445 -72
- package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +27 -16
- package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +19 -6
- package/extensions/dm-subagents/src/runs/shared/extension-bindings.js +81 -0
- package/extensions/dm-subagents/src/runs/shared/external-cli-contract.js +134 -0
- package/extensions/dm-subagents/src/runs/shared/external-cli-preflight.js +98 -0
- package/extensions/dm-subagents/src/runs/shared/external-cli-runner.js +419 -0
- package/extensions/dm-subagents/src/runs/shared/external-job-bridge.js +404 -0
- package/extensions/dm-subagents/src/runs/shared/external-job-runner.js +334 -0
- package/extensions/dm-subagents/src/runs/shared/fast-mode-extension.js +8 -0
- package/extensions/dm-subagents/src/runs/shared/host-step-status.js +228 -0
- package/extensions/dm-subagents/src/runs/shared/lane-metadata.js +104 -0
- package/extensions/dm-subagents/src/runs/shared/launch-cwd.js +17 -0
- package/extensions/dm-subagents/src/runs/shared/llm-intent-arbiter.js +190 -0
- package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +48 -3
- package/extensions/dm-subagents/src/runs/shared/mcp-config-sources.js +387 -0
- package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +212 -137
- package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-grant.js +131 -0
- package/extensions/dm-subagents/src/runs/shared/model-exclusions.js +207 -0
- package/extensions/dm-subagents/src/runs/shared/model-fallback.js +225 -55
- package/extensions/dm-subagents/src/runs/shared/model-scope.js +85 -28
- package/extensions/dm-subagents/src/runs/shared/mutation-evidence.js +182 -0
- package/extensions/dm-subagents/src/runs/shared/nested-events.js +264 -102
- package/extensions/dm-subagents/src/runs/shared/nested-render.js +15 -5
- package/extensions/dm-subagents/src/runs/shared/orca-progress-tabs.js +505 -0
- package/extensions/dm-subagents/src/runs/shared/parallel-handoff.js +653 -0
- package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +29 -12
- package/extensions/dm-subagents/src/runs/shared/permissions.js +108 -0
- package/extensions/dm-subagents/src/runs/shared/process-signal.js +13 -0
- package/extensions/dm-subagents/src/runs/shared/run-fanout-budget.js +257 -0
- package/extensions/dm-subagents/src/runs/shared/run-history.js +133 -13
- package/extensions/dm-subagents/src/runs/shared/runtime-acknowledged-extensions.js +62 -0
- package/extensions/dm-subagents/src/runs/shared/session-lease.js +225 -0
- package/extensions/dm-subagents/src/runs/shared/single-output.js +129 -27
- package/extensions/dm-subagents/src/runs/shared/spawn-budget.js +95 -0
- package/extensions/dm-subagents/src/runs/shared/structured-output.js +129 -10
- package/extensions/dm-subagents/src/runs/shared/subagent-control.js +66 -11
- package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +548 -70
- package/extensions/dm-subagents/src/runs/shared/subagent-startup-retry.js +50 -0
- package/extensions/dm-subagents/src/runs/shared/task-intent.js +130 -0
- package/extensions/dm-subagents/src/runs/shared/tool-availability.js +59 -0
- package/extensions/dm-subagents/src/runs/shared/tool-budget.js +7 -5
- package/extensions/dm-subagents/src/runs/shared/tool-timeout.js +64 -0
- package/extensions/dm-subagents/src/runs/shared/usage-budget.js +74 -0
- package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +22 -0
- package/extensions/dm-subagents/src/runs/shared/worktree-cleanup-plan.js +721 -0
- package/extensions/dm-subagents/src/runs/shared/worktree.js +168 -19
- package/extensions/dm-subagents/src/shared/accessible-dir.js +35 -0
- package/extensions/dm-subagents/src/shared/agent-stream-options.js +3 -0
- package/extensions/dm-subagents/src/shared/artifacts.js +170 -11
- package/extensions/dm-subagents/src/shared/atomic-json.js +36 -38
- package/extensions/dm-subagents/src/shared/capacity-resilient-json.js +77 -0
- package/extensions/dm-subagents/src/shared/child-session-name.js +15 -0
- package/extensions/dm-subagents/src/shared/child-transcript.js +57 -2
- package/extensions/dm-subagents/src/shared/completion-owner.js +7 -0
- package/extensions/dm-subagents/src/shared/display-text.js +142 -0
- package/extensions/dm-subagents/src/shared/extension-context.js +17 -0
- package/extensions/dm-subagents/src/shared/file-coalescer.js +9 -0
- package/extensions/dm-subagents/src/shared/file-system-retry.js +56 -0
- package/extensions/dm-subagents/src/shared/fork-context.js +96 -33
- package/extensions/dm-subagents/src/shared/formatters.js +21 -7
- package/extensions/dm-subagents/src/shared/launch-contract.js +94 -0
- package/extensions/dm-subagents/src/shared/model-info.js +10 -5
- package/extensions/dm-subagents/src/shared/node-executable.js +19 -0
- package/extensions/dm-subagents/src/shared/prompt-resources.js +10 -0
- package/extensions/dm-subagents/src/shared/pruned-fork.js +427 -0
- package/extensions/dm-subagents/src/shared/session-file-trust.js +19 -0
- package/extensions/dm-subagents/src/shared/session-tokens.js +14 -3
- package/extensions/dm-subagents/src/shared/settings.js +39 -47
- package/extensions/dm-subagents/src/shared/shortcuts.js +16 -0
- package/extensions/dm-subagents/src/shared/status-format.js +9 -2
- package/extensions/dm-subagents/src/shared/thinking-ceiling.js +41 -0
- package/extensions/dm-subagents/src/shared/types.js +47 -7
- package/extensions/dm-subagents/src/shared/utf8.js +12 -0
- package/extensions/dm-subagents/src/shared/utils.js +151 -131
- package/extensions/dm-subagents/src/shared/watch-strategy.js +3 -0
- package/extensions/dm-subagents/src/shared/workflow-child-permit.js +84 -0
- package/extensions/dm-subagents/src/slash/delegation-adapters.js +274 -0
- package/extensions/dm-subagents/src/slash/delegation-json.js +113 -0
- package/extensions/dm-subagents/src/slash/delegation-request.js +152 -0
- package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +294 -243
- package/extensions/dm-subagents/src/slash/prompt-workflows.js +35 -73
- package/extensions/dm-subagents/src/slash/selector.js +101 -0
- package/extensions/dm-subagents/src/slash/slash-bridge.js +17 -1
- package/extensions/dm-subagents/src/slash/slash-commands.js +722 -732
- package/extensions/dm-subagents/src/slash/slash-live-state.js +37 -19
- package/extensions/dm-subagents/src/slash/subagents-admin.js +410 -0
- package/extensions/dm-subagents/src/tui/fleet-status.js +824 -0
- package/extensions/dm-subagents/src/tui/fleet-transcript.js +479 -0
- package/extensions/dm-subagents/src/tui/fleet.js +1326 -0
- package/extensions/dm-subagents/src/tui/render-helpers.js +22 -0
- package/extensions/dm-subagents/src/tui/render.js +1511 -261
- package/extensions/dm-subagents/src/watchdog/change-signature.js +220 -0
- package/extensions/dm-subagents/src/watchdog/child-status.js +151 -0
- package/extensions/dm-subagents/src/watchdog/emission-guard.js +90 -0
- package/extensions/dm-subagents/src/watchdog/lsp-diagnostics.js +484 -0
- package/extensions/dm-subagents/src/watchdog/model-selection.js +154 -0
- package/extensions/dm-subagents/src/watchdog/permission-arbiter.js +138 -0
- package/extensions/dm-subagents/src/watchdog/register-child.js +112 -0
- package/extensions/dm-subagents/src/watchdog/register-main.js +419 -0
- package/extensions/dm-subagents/src/watchdog/render.js +54 -0
- package/extensions/dm-subagents/src/watchdog/review.js +251 -0
- package/extensions/dm-subagents/src/watchdog/runtime.js +803 -0
- package/extensions/dm-subagents/src/watchdog/scope.js +56 -0
- package/extensions/dm-subagents/src/watchdog/settings.js +515 -0
- package/extensions/dm-subagents/src/watchdog/tool-actions.js +151 -0
- package/extensions/dm-subagents/src/watchdog/turn-delta.js +169 -0
- package/extensions/dm-subagents/src/watchdog/types.js +29 -0
- package/extensions/dm-subagents/src/watchdog/warning-format.js +58 -0
- package/extensions/dm-subagents/src/workflows/chat-progress.js +116 -0
- package/extensions/dm-subagents/src/workflows/host-command.js +227 -0
- package/extensions/dm-subagents/src/workflows/scripted-workflow.js +2011 -0
- package/extensions/dm-subagents/src/workflows/workflow-child-summary.js +116 -0
- package/extensions/dm-subagents/src/workflows/workflow-preflight.js +243 -0
- package/extensions/dm-subagents/src/workflows/workflow-receipt.js +387 -0
- package/extensions/dm-subagents/src/workflows/workflow-settlement.js +189 -0
- package/package.json +4 -3
- package/extensions/dm-fff/package.json +0 -21
- package/extensions/dm-fff/src/index.js +0 -691
- package/extensions/dm-fff/src/query.js +0 -60
- package/extensions/dm-subagents/agents/context-builder.md +0 -46
- package/extensions/dm-subagents/agents/planner.md +0 -55
- package/extensions/dm-subagents/prompts/parallel-context-build.md +0 -55
- package/extensions/dm-subagents/prompts/parallel-handoff-plan.md +0 -61
- package/extensions/dm-subagents/src/runs/background/wait.js +0 -206
- package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +0 -1013
- package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +0 -981
- package/extensions/dm-subagents/src/runs/shared/turn-budget.js +0 -50
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
|
+
import { isUnexplainedProcessSignal } from "../runs/shared/process-signal.js";
|
|
3
4
|
import {
|
|
4
5
|
SUBAGENT_RESULT_INTERCOM_DELIVERY_EVENT,
|
|
5
6
|
SUBAGENT_RESULT_INTERCOM_EVENT
|
|
@@ -7,10 +8,16 @@ import {
|
|
|
7
8
|
export function resolveSubagentResultStatus(input) {
|
|
8
9
|
if (input.detached)
|
|
9
10
|
return "detached";
|
|
11
|
+
if (input.stopped || input.state === "stopped")
|
|
12
|
+
return "stopped";
|
|
10
13
|
if (input.interrupted || input.state === "paused")
|
|
11
14
|
return "paused";
|
|
12
|
-
if (
|
|
13
|
-
return
|
|
15
|
+
if (input.success === true)
|
|
16
|
+
return "completed";
|
|
17
|
+
if (isUnexplainedProcessSignal(input) && input.exitCode !== 0)
|
|
18
|
+
return "stopped";
|
|
19
|
+
if (input.success === false)
|
|
20
|
+
return "failed";
|
|
14
21
|
if (input.state === "complete")
|
|
15
22
|
return "completed";
|
|
16
23
|
if (input.state === "failed")
|
|
@@ -24,6 +31,7 @@ function countStatuses(children) {
|
|
|
24
31
|
completed: 0,
|
|
25
32
|
failed: 0,
|
|
26
33
|
paused: 0,
|
|
34
|
+
stopped: 0,
|
|
27
35
|
detached: 0
|
|
28
36
|
};
|
|
29
37
|
for (const child of children) {
|
|
@@ -35,15 +43,32 @@ function formatStatusCounts(counts) {
|
|
|
35
43
|
const parts = [
|
|
36
44
|
counts.completed ? `${counts.completed} completed` : undefined,
|
|
37
45
|
counts.failed ? `${counts.failed} failed` : undefined,
|
|
46
|
+
counts.stopped ? `${counts.stopped} stopped` : undefined,
|
|
38
47
|
counts.paused ? `${counts.paused} paused` : undefined,
|
|
39
48
|
counts.detached ? `${counts.detached} detached` : undefined
|
|
40
49
|
].filter((part) => Boolean(part));
|
|
41
50
|
return parts.length ? parts.join(", ") : "0 results";
|
|
42
51
|
}
|
|
52
|
+
function countOutputStates(children) {
|
|
53
|
+
const counts = { present: 0, absent: 0, unknown: 0 };
|
|
54
|
+
for (const child of children)
|
|
55
|
+
counts[child.outputState ?? "unknown"] += 1;
|
|
56
|
+
return counts;
|
|
57
|
+
}
|
|
58
|
+
function formatOutputCounts(counts) {
|
|
59
|
+
const parts = [
|
|
60
|
+
counts.present ? `${counts.present} present` : undefined,
|
|
61
|
+
counts.absent ? `${counts.absent} absent` : undefined,
|
|
62
|
+
counts.unknown ? `${counts.unknown} unknown` : undefined
|
|
63
|
+
].filter((part) => Boolean(part));
|
|
64
|
+
return parts.length ? parts.join(", ") : "0 outputs";
|
|
65
|
+
}
|
|
43
66
|
function resolveGroupedStatus(children) {
|
|
44
67
|
const counts = countStatuses(children);
|
|
45
68
|
if (counts.failed > 0)
|
|
46
69
|
return "failed";
|
|
70
|
+
if (counts.stopped > 0)
|
|
71
|
+
return "stopped";
|
|
47
72
|
if (counts.paused > 0)
|
|
48
73
|
return "paused";
|
|
49
74
|
if (counts.completed > 0)
|
|
@@ -66,6 +91,7 @@ function compactNestedRun(run, depth = 0) {
|
|
|
66
91
|
})),
|
|
67
92
|
...run.asyncDir ? { asyncDir: run.asyncDir } : {},
|
|
68
93
|
...run.sessionId ? { sessionId: run.sessionId } : {},
|
|
94
|
+
...run.sessionName ? { sessionName: run.sessionName } : {},
|
|
69
95
|
...run.sessionFile ? { sessionFile: run.sessionFile } : {},
|
|
70
96
|
...run.intercomTarget ? { intercomTarget: run.intercomTarget } : {},
|
|
71
97
|
...run.ownerIntercomTarget ? { ownerIntercomTarget: run.ownerIntercomTarget } : {},
|
|
@@ -75,6 +101,8 @@ function compactNestedRun(run, depth = 0) {
|
|
|
75
101
|
state: run.state,
|
|
76
102
|
...run.agent ? { agent: run.agent } : {},
|
|
77
103
|
...run.agents?.length ? { agents: run.agents.slice(0, 12) } : {},
|
|
104
|
+
...run.model ? { model: run.model } : {},
|
|
105
|
+
...run.thinking ? { thinking: run.thinking } : {},
|
|
78
106
|
...run.currentStep !== undefined ? { currentStep: run.currentStep } : {},
|
|
79
107
|
...run.chainStepCount !== undefined ? { chainStepCount: run.chainStepCount } : {},
|
|
80
108
|
...run.parallelGroups?.length ? { parallelGroups: run.parallelGroups.slice(0, 8) } : {},
|
|
@@ -92,7 +120,10 @@ function compactNestedRun(run, depth = 0) {
|
|
|
92
120
|
...run.error ? { error: run.error } : {},
|
|
93
121
|
...run.steps?.length ? { steps: run.steps.slice(0, 12).map((step) => ({
|
|
94
122
|
agent: step.agent,
|
|
123
|
+
...step.sessionName ? { sessionName: step.sessionName } : {},
|
|
95
124
|
status: step.status,
|
|
125
|
+
...step.model ? { model: step.model } : {},
|
|
126
|
+
...step.thinking ? { thinking: step.thinking } : {},
|
|
96
127
|
...step.sessionFile ? { sessionFile: step.sessionFile } : {},
|
|
97
128
|
...step.activityState ? { activityState: step.activityState } : {},
|
|
98
129
|
...step.lastActivityAt !== undefined ? { lastActivityAt: step.lastActivityAt } : {},
|
|
@@ -166,14 +197,19 @@ function asyncResumeGuidance(input) {
|
|
|
166
197
|
}
|
|
167
198
|
function formatSubagentResultIntercomMessage(input) {
|
|
168
199
|
const counts = countStatuses(input.children);
|
|
200
|
+
const outputCounts = countOutputStates(input.children);
|
|
169
201
|
const lines = [
|
|
170
202
|
"subagent results",
|
|
171
203
|
"",
|
|
172
204
|
`Run: ${input.runId}`,
|
|
173
205
|
`Mode: ${input.mode}`,
|
|
174
|
-
`
|
|
175
|
-
`Children: ${formatStatusCounts(counts)}
|
|
206
|
+
`Process status: ${input.status}`,
|
|
207
|
+
`Children: ${formatStatusCounts(counts)}`,
|
|
208
|
+
`Outputs: ${formatOutputCounts(outputCounts)} (semantic adequacy unassessed)`
|
|
176
209
|
];
|
|
210
|
+
if (input.children.some((child) => child.status === "failed" && child.outputState === "present")) {
|
|
211
|
+
lines.push("Recovery: At least one failed process produced output. Inspect that output before retrying; output presence does not establish task completion.");
|
|
212
|
+
}
|
|
177
213
|
if (input.mode === "chain" && typeof input.chainSteps === "number") {
|
|
178
214
|
lines.push(`Chain steps: ${input.chainSteps}`);
|
|
179
215
|
}
|
|
@@ -181,6 +217,8 @@ function formatSubagentResultIntercomMessage(input) {
|
|
|
181
217
|
lines.push(`Async id: ${input.asyncId}`);
|
|
182
218
|
if (input.asyncDir)
|
|
183
219
|
lines.push(`Async dir: ${input.asyncDir}`);
|
|
220
|
+
if (input.parallelHandoff)
|
|
221
|
+
lines.push(`Parallel handoff: ${input.parallelHandoff.path}`);
|
|
184
222
|
const resumeGuidance = asyncResumeGuidance(input);
|
|
185
223
|
if (resumeGuidance)
|
|
186
224
|
lines.push(resumeGuidance);
|
|
@@ -191,7 +229,7 @@ function formatSubagentResultIntercomMessage(input) {
|
|
|
191
229
|
for (let index = 0;index < input.children.length; index++) {
|
|
192
230
|
const child = input.children[index];
|
|
193
231
|
lines.push("");
|
|
194
|
-
lines.push(`${index + 1}. ${child.agent} — ${child.status}`);
|
|
232
|
+
lines.push(`${index + 1}. ${child.agent} — process ${child.status} · output ${child.outputState ?? "unknown"}`);
|
|
195
233
|
if (child.intercomTarget)
|
|
196
234
|
lines.push(`${input.source === "async" ? "Previous intercom target" : "Run intercom target"}: ${child.intercomTarget}`);
|
|
197
235
|
if (child.artifactPath)
|
|
@@ -208,6 +246,7 @@ function formatSubagentResultIntercomMessage(input) {
|
|
|
208
246
|
export function buildSubagentResultIntercomPayload(input) {
|
|
209
247
|
const children = input.children.map((child) => ({
|
|
210
248
|
...child,
|
|
249
|
+
outputState: child.outputState ?? "unknown",
|
|
211
250
|
summary: child.summary.trim() || "(no output)",
|
|
212
251
|
children: compactNestedResultChildren(child.children)
|
|
213
252
|
}));
|
|
@@ -225,6 +264,7 @@ export function buildSubagentResultIntercomPayload(input) {
|
|
|
225
264
|
...input.asyncId ? { asyncId: input.asyncId } : {},
|
|
226
265
|
...input.asyncDir ? { asyncDir: input.asyncDir } : {},
|
|
227
266
|
...typeof input.chainSteps === "number" ? { chainSteps: input.chainSteps } : {},
|
|
267
|
+
...input.parallelHandoff ? { parallelHandoff: input.parallelHandoff } : {},
|
|
228
268
|
...firstChild?.agent ? { agent: firstChild.agent } : {},
|
|
229
269
|
...firstChild?.index !== undefined ? { index: firstChild.index } : {},
|
|
230
270
|
...firstChild?.artifactPath ? { artifactPath: firstChild.artifactPath } : {},
|
|
@@ -240,8 +280,6 @@ export async function deliverSubagentResultIntercomEvent(events, payload, timeou
|
|
|
240
280
|
export async function deliverSubagentIntercomMessageEvent(events, to, message, timeoutMs = 500, extra = {}) {
|
|
241
281
|
if (typeof events.on !== "function" || typeof events.emit !== "function")
|
|
242
282
|
return false;
|
|
243
|
-
if (events.listenerCount?.(SUBAGENT_RESULT_INTERCOM_EVENT) === 0)
|
|
244
|
-
return true;
|
|
245
283
|
const requestId = typeof extra.requestId === "string" ? extra.requestId : randomUUID();
|
|
246
284
|
return new Promise((resolve) => {
|
|
247
285
|
let settled = false;
|
|
@@ -294,6 +332,8 @@ export function formatSubagentResultReceipt(input) {
|
|
|
294
332
|
`Run: ${input.runId}`,
|
|
295
333
|
`Children: ${formatStatusCounts(counts)}`
|
|
296
334
|
];
|
|
335
|
+
if (input.payload.parallelHandoff)
|
|
336
|
+
lines.push(`Parallel handoff: ${input.payload.parallelHandoff.path}`);
|
|
297
337
|
const artifacts = input.payload.children.filter((child) => typeof child.artifactPath === "string");
|
|
298
338
|
if (artifacts.length > 0) {
|
|
299
339
|
lines.push("Artifacts:");
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
MISSION_STATUSES
|
|
5
|
+
} from "./types.js";
|
|
6
|
+
import { missionStatePath } from "./workflow-state.js";
|
|
7
|
+
import {
|
|
8
|
+
createMission,
|
|
9
|
+
listGlobalMissions,
|
|
10
|
+
listMissions,
|
|
11
|
+
missionRecordPath,
|
|
12
|
+
readMission,
|
|
13
|
+
resolveMissionStoreLocation,
|
|
14
|
+
updateMission,
|
|
15
|
+
validateMissionId
|
|
16
|
+
} from "./store.js";
|
|
17
|
+
export const MISSION_ACTIONS = [
|
|
18
|
+
"mission.create",
|
|
19
|
+
"mission.list",
|
|
20
|
+
"mission.show",
|
|
21
|
+
"mission.update",
|
|
22
|
+
"mission.resolve-decision",
|
|
23
|
+
"mission.attach-run",
|
|
24
|
+
"mission.close"
|
|
25
|
+
];
|
|
26
|
+
function textResult(text, details) {
|
|
27
|
+
return { content: [{ type: "text", text }], details };
|
|
28
|
+
}
|
|
29
|
+
function requireMissionId(params) {
|
|
30
|
+
return validateMissionId(params.missionId, "missionId");
|
|
31
|
+
}
|
|
32
|
+
function validateStatus(value, label) {
|
|
33
|
+
if (typeof value !== "string" || !MISSION_STATUSES.includes(value)) {
|
|
34
|
+
throw new Error(`${label} must be one of ${MISSION_STATUSES.join(", ")}`);
|
|
35
|
+
}
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
export function validateMissionLaunch(value) {
|
|
39
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
40
|
+
throw new Error("mission must be an object");
|
|
41
|
+
const input = value;
|
|
42
|
+
for (const key of Object.keys(input)) {
|
|
43
|
+
if (key !== "title" && key !== "summary" && key !== "objective" && key !== "goal" && key !== "budget" && key !== "labels")
|
|
44
|
+
throw new Error(`mission.${key} is unknown`);
|
|
45
|
+
}
|
|
46
|
+
if (input.title !== undefined && input.summary !== undefined)
|
|
47
|
+
throw new Error("mission.title and mission.summary cannot both be set");
|
|
48
|
+
const title = input.title ?? input.summary;
|
|
49
|
+
if (typeof title !== "string" || !title.trim())
|
|
50
|
+
throw new Error("mission.title or mission.summary must be a non-empty string");
|
|
51
|
+
if (input.objective !== undefined && (typeof input.objective !== "string" || !input.objective.trim()))
|
|
52
|
+
throw new Error("mission.objective must be a non-empty string");
|
|
53
|
+
if (input.goal !== undefined && input.goal !== true)
|
|
54
|
+
throw new Error("mission.goal must be true when supplied");
|
|
55
|
+
const budget = input.budget;
|
|
56
|
+
if (budget !== undefined && (!budget || typeof budget !== "object" || Array.isArray(budget) || !Number.isSafeInteger(budget.tokens) || budget.tokens < 1)) {
|
|
57
|
+
throw new Error("mission.budget.tokens must be a positive integer");
|
|
58
|
+
}
|
|
59
|
+
if (input.goal === true && budget === undefined)
|
|
60
|
+
throw new Error("mission.budget is required when mission.goal is true");
|
|
61
|
+
if (input.labels !== undefined && (!Array.isArray(input.labels) || input.labels.some((label) => typeof label !== "string" || !label.trim()))) {
|
|
62
|
+
throw new Error("mission.labels must contain only non-empty strings");
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
title: title.trim(),
|
|
66
|
+
...typeof input.objective === "string" ? { objective: input.objective.trim() } : {},
|
|
67
|
+
...input.goal === true ? { goal: true } : {},
|
|
68
|
+
...budget !== undefined ? { budget: { tokens: budget.tokens } } : {},
|
|
69
|
+
...input.labels !== undefined ? { labels: input.labels.map((label) => label.trim()) } : {}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function validateArtifact(value, index) {
|
|
73
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
74
|
+
throw new Error(`missionUpdate.artifacts[${index}] must be an object`);
|
|
75
|
+
const input = value;
|
|
76
|
+
const kinds = ["status", "output", "patch", "manifest", "review", "note", "other"];
|
|
77
|
+
if (typeof input.kind !== "string" || !kinds.includes(input.kind))
|
|
78
|
+
throw new Error(`missionUpdate.artifacts[${index}].kind is invalid`);
|
|
79
|
+
if (typeof input.path !== "string" || !input.path.trim())
|
|
80
|
+
throw new Error(`missionUpdate.artifacts[${index}].path must be a non-empty string`);
|
|
81
|
+
if (input.description !== undefined && (typeof input.description !== "string" || !input.description.trim()))
|
|
82
|
+
throw new Error(`missionUpdate.artifacts[${index}].description must be a non-empty string`);
|
|
83
|
+
return {
|
|
84
|
+
kind: input.kind,
|
|
85
|
+
path: input.path,
|
|
86
|
+
...typeof input.description === "string" ? { description: input.description } : {}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function validateReceipt(value, index) {
|
|
90
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
91
|
+
throw new Error(`missionUpdate.receipts[${index}] must be an object`);
|
|
92
|
+
const input = value;
|
|
93
|
+
for (const key of Object.keys(input)) {
|
|
94
|
+
if (!["kind", "status", "title", "url", "description"].includes(key))
|
|
95
|
+
throw new Error(`missionUpdate.receipts[${index}].${key} is unknown`);
|
|
96
|
+
}
|
|
97
|
+
const kinds = ["pull_request", "ci", "deployment", "release"];
|
|
98
|
+
const statuses = ["pending", "ready", "succeeded", "failed"];
|
|
99
|
+
if (typeof input.kind !== "string" || !kinds.includes(input.kind))
|
|
100
|
+
throw new Error(`missionUpdate.receipts[${index}].kind is invalid`);
|
|
101
|
+
if (typeof input.status !== "string" || !statuses.includes(input.status))
|
|
102
|
+
throw new Error(`missionUpdate.receipts[${index}].status is invalid`);
|
|
103
|
+
for (const field of ["title", "url"]) {
|
|
104
|
+
if (typeof input[field] !== "string" || !input[field].trim())
|
|
105
|
+
throw new Error(`missionUpdate.receipts[${index}].${field} must be a non-empty string`);
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
new URL(input.url);
|
|
109
|
+
} catch {
|
|
110
|
+
throw new Error(`missionUpdate.receipts[${index}].url must be an absolute URL`);
|
|
111
|
+
}
|
|
112
|
+
if (input.description !== undefined && (typeof input.description !== "string" || !input.description.trim()))
|
|
113
|
+
throw new Error(`missionUpdate.receipts[${index}].description must be a non-empty string`);
|
|
114
|
+
return {
|
|
115
|
+
kind: input.kind,
|
|
116
|
+
status: input.status,
|
|
117
|
+
title: input.title.trim(),
|
|
118
|
+
url: input.url.trim(),
|
|
119
|
+
...typeof input.description === "string" ? { description: input.description.trim() } : {}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function validateMissionUpdate(value) {
|
|
123
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
124
|
+
throw new Error("missionUpdate must be an object");
|
|
125
|
+
const input = value;
|
|
126
|
+
for (const key of Object.keys(input)) {
|
|
127
|
+
if (!["title", "objective", "goal", "budget", "status", "summary", "labels", "artifacts", "receipts", "decisions"].includes(key))
|
|
128
|
+
throw new Error(`missionUpdate.${key} is unknown`);
|
|
129
|
+
}
|
|
130
|
+
const update = {};
|
|
131
|
+
for (const field of ["title", "objective", "summary"]) {
|
|
132
|
+
const candidate = input[field];
|
|
133
|
+
if (candidate === undefined)
|
|
134
|
+
continue;
|
|
135
|
+
if (typeof candidate !== "string" || !candidate.trim())
|
|
136
|
+
throw new Error(`missionUpdate.${field} must be a non-empty string`);
|
|
137
|
+
update[field] = candidate.trim();
|
|
138
|
+
}
|
|
139
|
+
if (input.goal !== undefined) {
|
|
140
|
+
if (typeof input.goal === "boolean")
|
|
141
|
+
update.goal = input.goal ? { status: "active" } : false;
|
|
142
|
+
else {
|
|
143
|
+
if (!input.goal || typeof input.goal !== "object" || Array.isArray(input.goal) || typeof input.goal.paused !== "boolean" || Object.keys(input.goal).some((key) => key !== "paused")) {
|
|
144
|
+
throw new Error("missionUpdate.goal must be boolean or { paused: boolean }");
|
|
145
|
+
}
|
|
146
|
+
update.goal = { status: input.goal.paused ? "paused" : "active" };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (input.budget !== undefined) {
|
|
150
|
+
if (!input.budget || typeof input.budget !== "object" || Array.isArray(input.budget) || !Number.isSafeInteger(input.budget.tokens) || input.budget.tokens < 1) {
|
|
151
|
+
throw new Error("missionUpdate.budget.tokens must be a positive integer");
|
|
152
|
+
}
|
|
153
|
+
update.budget = { tokens: input.budget.tokens };
|
|
154
|
+
}
|
|
155
|
+
if (input.status !== undefined)
|
|
156
|
+
update.status = validateStatus(input.status, "missionUpdate.status");
|
|
157
|
+
if (input.labels !== undefined) {
|
|
158
|
+
if (!Array.isArray(input.labels) || input.labels.some((label) => typeof label !== "string" || !label.trim()))
|
|
159
|
+
throw new Error("missionUpdate.labels must contain only non-empty strings");
|
|
160
|
+
update.labels = input.labels;
|
|
161
|
+
}
|
|
162
|
+
if (input.artifacts !== undefined) {
|
|
163
|
+
if (!Array.isArray(input.artifacts))
|
|
164
|
+
throw new Error("missionUpdate.artifacts must be an array");
|
|
165
|
+
update.addArtifacts = input.artifacts.map(validateArtifact);
|
|
166
|
+
}
|
|
167
|
+
if (input.receipts !== undefined) {
|
|
168
|
+
if (!Array.isArray(input.receipts))
|
|
169
|
+
throw new Error("missionUpdate.receipts must be an array");
|
|
170
|
+
update.addReceipts = input.receipts.map(validateReceipt);
|
|
171
|
+
}
|
|
172
|
+
if (input.decisions !== undefined) {
|
|
173
|
+
if (!Array.isArray(input.decisions))
|
|
174
|
+
throw new Error("missionUpdate.decisions must be an array");
|
|
175
|
+
update.addDecisions = input.decisions.map((value, index) => {
|
|
176
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
177
|
+
throw new Error(`missionUpdate.decisions[${index}] must be an object`);
|
|
178
|
+
const decision = value;
|
|
179
|
+
if (typeof decision.title !== "string" || !decision.title.trim())
|
|
180
|
+
throw new Error(`missionUpdate.decisions[${index}].title must be a non-empty string`);
|
|
181
|
+
if (decision.options !== undefined && (!Array.isArray(decision.options) || decision.options.some((option) => typeof option !== "string" || !option.trim())))
|
|
182
|
+
throw new Error(`missionUpdate.decisions[${index}].options must contain only non-empty strings`);
|
|
183
|
+
return {
|
|
184
|
+
title: decision.title.trim(),
|
|
185
|
+
...typeof decision.prompt === "string" && decision.prompt.trim() ? { prompt: decision.prompt } : {},
|
|
186
|
+
...Array.isArray(decision.options) ? { options: decision.options } : {},
|
|
187
|
+
...typeof decision.recommendation === "string" && decision.recommendation.trim() ? { recommendation: decision.recommendation } : {}
|
|
188
|
+
};
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
if (Object.keys(update).length === 0)
|
|
192
|
+
throw new Error("missionUpdate must include at least one supported field");
|
|
193
|
+
return update;
|
|
194
|
+
}
|
|
195
|
+
function refreshLinkedRunStatus(location, record) {
|
|
196
|
+
const warnings = [];
|
|
197
|
+
const updates = record.runs.flatMap((run) => {
|
|
198
|
+
if (!run.asyncDir)
|
|
199
|
+
return [];
|
|
200
|
+
const statusPath = path.join(run.asyncDir, "status.json");
|
|
201
|
+
if (!fs.existsSync(statusPath))
|
|
202
|
+
return [];
|
|
203
|
+
let status;
|
|
204
|
+
try {
|
|
205
|
+
status = JSON.parse(fs.readFileSync(statusPath, "utf-8"));
|
|
206
|
+
} catch (error) {
|
|
207
|
+
warnings.push(`Failed to read linked run status '${statusPath}': ${error instanceof Error ? error.message : String(error)}`);
|
|
208
|
+
return [];
|
|
209
|
+
}
|
|
210
|
+
if (!status || typeof status !== "object" || Array.isArray(status)) {
|
|
211
|
+
warnings.push(`Linked run status '${statusPath}' must be an object`);
|
|
212
|
+
return [];
|
|
213
|
+
}
|
|
214
|
+
const state = status.state;
|
|
215
|
+
if (typeof state !== "string" || !state.trim()) {
|
|
216
|
+
warnings.push(`Linked run status '${statusPath}' is missing state`);
|
|
217
|
+
return [];
|
|
218
|
+
}
|
|
219
|
+
if (state === run.status)
|
|
220
|
+
return [];
|
|
221
|
+
return [{
|
|
222
|
+
...run,
|
|
223
|
+
status: state,
|
|
224
|
+
...!["queued", "running"].includes(state) && !run.completedAt ? { completedAt: new Date().toISOString() } : {}
|
|
225
|
+
}];
|
|
226
|
+
});
|
|
227
|
+
if (updates.length === 0)
|
|
228
|
+
return { record, warnings };
|
|
229
|
+
const merged = record.runs.map((run) => updates.find((update) => update.runId === run.runId && update.childIndex === run.childIndex) ?? run);
|
|
230
|
+
const states = merged.map((run) => run.status);
|
|
231
|
+
const status = record.status === "completed" || record.status === "failed" || record.status === "cancelled" ? record.status : record.goal && !states.some((state) => state === "queued" || state === "running" || state === "active") ? "active" : states.some((state) => state === "queued" || state === "running" || state === "active") ? "active" : states.some((state) => state === "paused") ? "waiting" : states.some((state) => state === "failed") ? "failed" : states.some((state) => state === "stopped" || state === "rejected" || state === "cancelled") ? "cancelled" : states.length > 0 && states.every((state) => state === "complete" || state === "completed") ? "completed" : record.status;
|
|
232
|
+
return { record: updateMission(location, record.id, { status, addRuns: updates }), warnings };
|
|
233
|
+
}
|
|
234
|
+
function formatMission(record) {
|
|
235
|
+
const lines = [
|
|
236
|
+
`Mission: ${record.id}`,
|
|
237
|
+
`Title: ${record.title}`,
|
|
238
|
+
`Status: ${record.status}`,
|
|
239
|
+
`Objective: ${record.objective}`,
|
|
240
|
+
`Updated: ${record.updatedAt}`
|
|
241
|
+
];
|
|
242
|
+
if (record.goal && record.budget)
|
|
243
|
+
lines.push(`Goal mode: ${record.goal.status}`, `Budget: ${record.usage?.tokens ?? 0}/${record.budget.tokens} tokens`);
|
|
244
|
+
if (record.summary)
|
|
245
|
+
lines.push(`Summary: ${record.summary}`);
|
|
246
|
+
if (record.labels?.length)
|
|
247
|
+
lines.push(`Labels: ${record.labels.join(", ")}`);
|
|
248
|
+
if (record.runs.length) {
|
|
249
|
+
lines.push("Runs:");
|
|
250
|
+
for (const run of record.runs)
|
|
251
|
+
lines.push(` ${run.runId} (${run.mode}${run.status ? `, ${run.status}` : ""})${run.asyncDir ? ` — ${run.asyncDir}` : ""}`);
|
|
252
|
+
}
|
|
253
|
+
if (record.workflowChildren.length) {
|
|
254
|
+
lines.push("Workflow children:");
|
|
255
|
+
for (const child of record.workflowChildren) {
|
|
256
|
+
const identity = child.runId ? `${child.key} (${child.runId})` : child.key;
|
|
257
|
+
const heartbeat = child.heartbeat ? `; heartbeat ${child.heartbeat.status ?? child.status}${child.heartbeat.phase ? `/${child.heartbeat.phase}` : ""} at ${child.heartbeat.updatedAt}` : "";
|
|
258
|
+
const recovery = child.sessionPath ? `; session ${child.sessionPath}` : child.artifactPaths.length ? `; artifacts ${child.artifactPaths.length}` : "";
|
|
259
|
+
lines.push(` ${identity}: ${child.status}${child.agent ? ` — ${child.agent}` : ""}${child.phase ? ` [${child.phase}]` : ""}; updated ${child.updatedAt}${heartbeat}${recovery}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (record.decisions.length) {
|
|
263
|
+
lines.push("Decisions:");
|
|
264
|
+
for (const decision of record.decisions) {
|
|
265
|
+
lines.push(` ${decision.id}: ${decision.status} — ${decision.title}${decision.resolution ? `; resolution: ${decision.resolution}` : ""}`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (record.artifacts.length) {
|
|
269
|
+
lines.push("Artifacts:");
|
|
270
|
+
for (const artifact of record.artifacts)
|
|
271
|
+
lines.push(` ${artifact.kind}: ${artifact.path}`);
|
|
272
|
+
}
|
|
273
|
+
if (record.receipts.length) {
|
|
274
|
+
lines.push("Delivery receipts:");
|
|
275
|
+
for (const receipt of record.receipts)
|
|
276
|
+
lines.push(` ${receipt.kind} (${receipt.status}): ${receipt.title} — ${receipt.url}`);
|
|
277
|
+
}
|
|
278
|
+
return lines.join(`
|
|
279
|
+
`);
|
|
280
|
+
}
|
|
281
|
+
export function handleMissionAction(action, params, ctx) {
|
|
282
|
+
const location = resolveMissionStoreLocation({
|
|
283
|
+
projectRoot: ctx.cwd,
|
|
284
|
+
...ctx.config ? { config: ctx.config } : {},
|
|
285
|
+
...ctx.agentDir ? { agentDir: ctx.agentDir } : {}
|
|
286
|
+
});
|
|
287
|
+
if (action === "mission.create") {
|
|
288
|
+
const mission = validateMissionLaunch(params.mission);
|
|
289
|
+
const record = createMission(location, {
|
|
290
|
+
title: mission.title,
|
|
291
|
+
objective: mission.objective ?? mission.title,
|
|
292
|
+
...mission.goal === true ? { goal: true } : {},
|
|
293
|
+
...mission.budget ? { budget: mission.budget } : {},
|
|
294
|
+
status: params.missionStatus ? validateStatus(params.missionStatus, "missionStatus") : "planned",
|
|
295
|
+
...mission.labels ? { labels: mission.labels } : {},
|
|
296
|
+
...ctx.currentSessionId ? { ownerSessionId: ctx.currentSessionId } : {}
|
|
297
|
+
}, new Date, ctx.config?.retainTerminal);
|
|
298
|
+
return textResult(`Created mission ${record.id}: ${record.title}`, { mode: "management", results: [], missionId: record.id, missionPath: pathFor(record.id), mission: record });
|
|
299
|
+
}
|
|
300
|
+
if (action === "mission.list") {
|
|
301
|
+
if (params.missionScope !== undefined && params.missionScope !== "project" && params.missionScope !== "global") {
|
|
302
|
+
throw new Error('missionScope must be "project" or "global"');
|
|
303
|
+
}
|
|
304
|
+
if (params.missionScope === "global") {
|
|
305
|
+
const listed = listGlobalMissions(location.globalIndexDir);
|
|
306
|
+
const lines = listed.entries.length === 0 ? ["No indexed missions."] : listed.entries.map((entry) => `${entry.missionId} ${entry.status}${entry.stale ? " [stale]" : ""} ${entry.title} ${entry.projectRoot}`);
|
|
307
|
+
if (listed.warnings.length)
|
|
308
|
+
lines.push("", ...listed.warnings.map((warning) => `Warning: ${warning}`));
|
|
309
|
+
return textResult(lines.join(`
|
|
310
|
+
`), { mode: "management", results: [], missions: { globalEntries: listed.entries, warnings: listed.warnings } });
|
|
311
|
+
}
|
|
312
|
+
const listed = listMissions(location);
|
|
313
|
+
const lines = listed.records.length === 0 ? ["No project missions."] : listed.records.map((record) => {
|
|
314
|
+
const open = record.decisions.filter((decision) => decision.status === "open").length;
|
|
315
|
+
const resolved = record.decisions.length - open;
|
|
316
|
+
return `${record.id} ${record.status} ${record.title} ${record.updatedAt}${record.decisions.length ? ` decisions: ${open} open, ${resolved} resolved` : ""}`;
|
|
317
|
+
});
|
|
318
|
+
if (listed.warnings.length)
|
|
319
|
+
lines.push("", ...listed.warnings.map((warning) => `Warning: ${warning}`));
|
|
320
|
+
return textResult(lines.join(`
|
|
321
|
+
`), { mode: "management", results: [], missions: { records: listed.records, warnings: listed.warnings } });
|
|
322
|
+
}
|
|
323
|
+
if (action === "mission.show") {
|
|
324
|
+
const refreshed = refreshLinkedRunStatus(location, readMission(location, requireMissionId(params)));
|
|
325
|
+
const lines = [formatMission(refreshed.record), `State: ${missionStatePath(location, refreshed.record.id)}`];
|
|
326
|
+
if (refreshed.warnings.length)
|
|
327
|
+
lines.push("", ...refreshed.warnings.map((warning) => `Warning: ${warning}`));
|
|
328
|
+
return textResult(lines.join(`
|
|
329
|
+
`), {
|
|
330
|
+
mode: "management",
|
|
331
|
+
results: [],
|
|
332
|
+
missionId: refreshed.record.id,
|
|
333
|
+
missionPath: pathFor(refreshed.record.id),
|
|
334
|
+
mission: refreshed.record,
|
|
335
|
+
missions: { warnings: refreshed.warnings }
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
if (action === "mission.update") {
|
|
339
|
+
const record = updateMission(location, requireMissionId(params), validateMissionUpdate(params.missionUpdate));
|
|
340
|
+
return textResult(`Updated mission ${record.id}.
|
|
341
|
+
|
|
342
|
+
${formatMission(record)}`, { mode: "management", results: [], missionId: record.id, missionPath: pathFor(record.id), mission: record });
|
|
343
|
+
}
|
|
344
|
+
if (action === "mission.resolve-decision") {
|
|
345
|
+
const missionId = requireMissionId(params);
|
|
346
|
+
const decisionId = validateMissionId(params.id, "id");
|
|
347
|
+
if (typeof params.summary !== "string" || !params.summary.trim())
|
|
348
|
+
throw new Error("mission.resolve-decision requires a non-empty summary");
|
|
349
|
+
const record = updateMission(location, missionId, { resolveDecision: { id: decisionId, resolution: params.summary.trim() } });
|
|
350
|
+
return textResult(`Resolved decision ${decisionId} for mission ${record.id}.
|
|
351
|
+
|
|
352
|
+
${formatMission(record)}`, { mode: "management", results: [], missionId: record.id, missionPath: pathFor(record.id), mission: record });
|
|
353
|
+
}
|
|
354
|
+
if (action === "mission.attach-run") {
|
|
355
|
+
const missionId = requireMissionId(params);
|
|
356
|
+
const runId = params.runId ?? params.id;
|
|
357
|
+
if (typeof runId !== "string" || !runId.trim())
|
|
358
|
+
throw new Error("mission.attach-run requires runId or id");
|
|
359
|
+
const rawMode = params.runMode ?? "external";
|
|
360
|
+
if (!["single", "parallel", "chain", "workflow", "scheduled", "external"].includes(rawMode))
|
|
361
|
+
throw new Error("runMode is invalid");
|
|
362
|
+
const mode = rawMode;
|
|
363
|
+
if (params.dir !== undefined && !params.dir.trim())
|
|
364
|
+
throw new Error("dir must be a non-empty string");
|
|
365
|
+
if (params.runStatus !== undefined && !params.runStatus.trim())
|
|
366
|
+
throw new Error("runStatus must be a non-empty string");
|
|
367
|
+
const record = updateMission(location, missionId, {
|
|
368
|
+
status: "active",
|
|
369
|
+
addRuns: [{
|
|
370
|
+
runId: runId.trim(),
|
|
371
|
+
mode,
|
|
372
|
+
...params.dir ? { asyncDir: params.dir } : {},
|
|
373
|
+
...params.agent ? { agent: params.agent } : {},
|
|
374
|
+
...params.runStatus ? { status: params.runStatus } : {},
|
|
375
|
+
startedAt: new Date().toISOString()
|
|
376
|
+
}]
|
|
377
|
+
});
|
|
378
|
+
return textResult(`Attached run ${runId} to mission ${record.id}.`, { mode: "management", results: [], missionId: record.id, missionPath: pathFor(record.id), mission: record });
|
|
379
|
+
}
|
|
380
|
+
const missionId = requireMissionId(params);
|
|
381
|
+
const status = params.missionStatus ?? "completed";
|
|
382
|
+
if (status !== "completed" && status !== "failed" && status !== "cancelled")
|
|
383
|
+
throw new Error("mission.close missionStatus must be completed, failed, or cancelled");
|
|
384
|
+
if (params.summary !== undefined && !params.summary.trim())
|
|
385
|
+
throw new Error("summary must be a non-empty string");
|
|
386
|
+
const record = updateMission(location, missionId, {
|
|
387
|
+
status,
|
|
388
|
+
...params.summary !== undefined ? { summary: params.summary.trim() } : {}
|
|
389
|
+
});
|
|
390
|
+
return textResult(`Closed mission ${record.id} as ${record.status}.`, { mode: "management", results: [], missionId: record.id, missionPath: pathFor(record.id), mission: record });
|
|
391
|
+
function pathFor(missionId) {
|
|
392
|
+
return missionRecordPath(location, missionId);
|
|
393
|
+
}
|
|
394
|
+
}
|