@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
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { discoverAgentSnapshot, findBlockingAgentDiagnostic, formatUnknownAgentError, resolveAgentName, unknownAgentDiagnosticContext } from "../agents/agents.js";
|
|
5
|
+
import { resolveExecutionAgentScope } from "../agents/agent-scope.js";
|
|
6
|
+
import { buildSkillInjection, normalizeSkillInput, resolveSkillsWithFallback } from "../agents/skills.js";
|
|
7
|
+
import { buildAgentMemoryInjection } from "../agents/agent-memory.js";
|
|
8
|
+
import { buildModelCandidates, inheritsParentModel, resolveEffectiveSubagentModel } from "../runs/shared/model-fallback.js";
|
|
9
|
+
import { resolveModelScopesForAgent } from "../runs/shared/model-scope.js";
|
|
10
|
+
import { applyThinkingSuffix, resolvePiLaunchToolPlan } from "../runs/shared/dm-args.js";
|
|
11
|
+
import { injectOutputPathSystemPrompt, normalizeSingleOutputOverride, resolveSingleOutputPath } from "../runs/shared/single-output.js";
|
|
12
|
+
import { getArtifactPaths, getArtifactsDir } from "../shared/artifacts.js";
|
|
13
|
+
import { resolveEffectiveThinking } from "../shared/model-info.js";
|
|
14
|
+
import { assertThinkingWithinCeiling, decodeThinkingCeiling, intersectThinkingCeilings, SUBAGENT_THINKING_CEILING_ENV } from "../shared/thinking-ceiling.js";
|
|
15
|
+
import { SUBAGENT_LIFECYCLE_ARTIFACT_VERSION } from "../shared/types.js";
|
|
16
|
+
import { capabilityCeilingAgentRestrictionMessage, intersectSubagentCapabilityCeilings } from "../runs/shared/capability-ceiling.js";
|
|
17
|
+
import { resolvePermissionRules } from "../runs/shared/permissions.js";
|
|
18
|
+
import { resolveStepBehavior } from "../shared/settings.js";
|
|
19
|
+
import { canPreferForkFromSnapshot, resolveSubagentLaunchContext } from "../shared/fork-context.js";
|
|
20
|
+
import { loadConfig } from "../extension/config.js";
|
|
21
|
+
import { agentDefinitionDigest, AGENT_DEFINITION_PROJECTION_VERSION, launchBindingDigest, stableJsonDigest } from "../shared/launch-contract.js";
|
|
22
|
+
import { DIRS, TEMP_ROOT_DIR } from "../shared/types.js";
|
|
23
|
+
import { processTerminalCandidatePath, processTerminalPath } from "../runs/background/process-terminal.js";
|
|
24
|
+
import { resultFilePath } from "../runs/background/result-files.js";
|
|
25
|
+
import { nestedResultsPath } from "../runs/shared/nested-events.js";
|
|
26
|
+
import { normalizeExtensionBindings } from "../runs/shared/extension-bindings.js";
|
|
27
|
+
export const SUBAGENT_LAUNCH_CONTRACT_VERSION = 2;
|
|
28
|
+
function packageVersion() {
|
|
29
|
+
const packagePath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "package.json");
|
|
30
|
+
const parsed = JSON.parse(fs.readFileSync(packagePath, "utf-8"));
|
|
31
|
+
if (typeof parsed.version !== "string" || !parsed.version.trim()) {
|
|
32
|
+
throw new Error(`Invalid package version in '${packagePath}'.`);
|
|
33
|
+
}
|
|
34
|
+
return parsed.version;
|
|
35
|
+
}
|
|
36
|
+
function digestContract(contract) {
|
|
37
|
+
return stableJsonDigest(contract);
|
|
38
|
+
}
|
|
39
|
+
function normalizeAvailableModels(models) {
|
|
40
|
+
return (models ?? []).map((model) => ({ ...model, fullId: model.fullId ?? `${model.provider}/${model.id}` }));
|
|
41
|
+
}
|
|
42
|
+
function resolveLaunchContractContext(input, agent) {
|
|
43
|
+
return resolveSubagentLaunchContext({
|
|
44
|
+
explicitContext: input.context,
|
|
45
|
+
agentDefaultContext: agent.defaultContext,
|
|
46
|
+
defaultSubagentContext: loadConfig().defaultSubagentContext,
|
|
47
|
+
canUseImplicitFork: canPreferForkFromSnapshot({
|
|
48
|
+
parentSessionFile: input.parentSessionFile,
|
|
49
|
+
leafId: input.parentLeafId
|
|
50
|
+
})
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function taskWorkspaceScopeAuthorityDiagnostic(task) {
|
|
54
|
+
if (!task)
|
|
55
|
+
return;
|
|
56
|
+
const text = task.replace(/\s+/g, " ").trim();
|
|
57
|
+
if (!text)
|
|
58
|
+
return;
|
|
59
|
+
const createsWorkspacePackage = /\b(?:add|create|introduce|make|set up)\b.{0,80}\b(?:new\s+)?(?:workspace\s+)?package\b/i.test(text) || /\b(?:new\s+)?package\b.{0,80}\b(?:workspace|monorepo)\b/i.test(text);
|
|
60
|
+
if (!createsWorkspacePackage)
|
|
61
|
+
return;
|
|
62
|
+
const packageOnlyAuthority = /\b(?:only|solely)\b.{0,40}\b(?:edit|change|modify|touch|write(?:\s+to)?)\b.{0,80}\b(?:package(?:\s+directory)?|packages\/[\w.-]+)\b/i.test(text) || /\b(?:do not|don't|must not)\b.{0,40}\b(?:edit|change|modify|touch|write(?:\s+to)?)\b.{0,80}\b(?:root|workspace|lockfile|metadata)\b/i.test(text) || /\bwithout\b.{0,40}\b(?:root|workspace|lockfile|metadata)\b.{0,40}\b(?:edit|change|modification|write)s?\b/i.test(text);
|
|
63
|
+
if (!packageOnlyAuthority)
|
|
64
|
+
return;
|
|
65
|
+
return {
|
|
66
|
+
code: "workspace_scope_authority",
|
|
67
|
+
severity: "warning",
|
|
68
|
+
message: "Task asks for a workspace package change while limiting authority to package-scope edits. New workspace packages often need root workspace metadata or lockfile changes, so confirm that authority before launch."
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function candidateList(inputAgent, selected, all) {
|
|
72
|
+
return [...all.builtin, ...all.package, ...all.user, ...all.project].filter((agent) => Boolean(resolveAgentName(inputAgent, [agent]).agent)).map((agent) => ({
|
|
73
|
+
name: agent.name,
|
|
74
|
+
...agent.localName ? { localName: agent.localName } : {},
|
|
75
|
+
...agent.packageName ? { packageName: agent.packageName } : {},
|
|
76
|
+
source: agent.source,
|
|
77
|
+
filePath: agent.filePath,
|
|
78
|
+
...agent.disabled === true ? { disabled: true } : {},
|
|
79
|
+
selected: Boolean(selected && agent.filePath === selected.filePath && agent.name === selected.name)
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
export async function resolveSubagentLaunchContract(input) {
|
|
83
|
+
const diagnostics = [];
|
|
84
|
+
const authorityDiagnostic = taskWorkspaceScopeAuthorityDiagnostic(input.task);
|
|
85
|
+
if (authorityDiagnostic)
|
|
86
|
+
diagnostics.push(authorityDiagnostic);
|
|
87
|
+
const effectiveCwd = path.resolve(input.cwd);
|
|
88
|
+
try {
|
|
89
|
+
if (!fs.statSync(effectiveCwd).isDirectory()) {
|
|
90
|
+
return { ok: false, code: "invalid_cwd", message: `cwd '${effectiveCwd}' is not a directory.`, diagnostics };
|
|
91
|
+
}
|
|
92
|
+
} catch (error) {
|
|
93
|
+
const detail = error instanceof Error ? ` ${error.message}` : "";
|
|
94
|
+
return { ok: false, code: "invalid_cwd", message: `cwd '${effectiveCwd}' is not a directory.${detail}`, diagnostics };
|
|
95
|
+
}
|
|
96
|
+
if (input.context !== undefined && input.context !== "fresh" && input.context !== "fork") {
|
|
97
|
+
return { ok: false, code: "unsupported_mode", message: `Unsupported context '${String(input.context)}'; expected 'fresh' or 'fork'.`, diagnostics };
|
|
98
|
+
}
|
|
99
|
+
if (input.artifactDir !== undefined && input.artifactDir !== "project" && input.artifactDir !== "session" && input.artifactDir !== "temp") {
|
|
100
|
+
return { ok: false, code: "invalid_artifact_dir", message: `Unsupported artifactDir '${String(input.artifactDir)}'; expected 'project', 'session', or 'temp'.`, diagnostics };
|
|
101
|
+
}
|
|
102
|
+
const scope = resolveExecutionAgentScope(input.agentScope);
|
|
103
|
+
const parentProvider = input.preferredProvider ?? input.parentModel?.provider;
|
|
104
|
+
const discovery = discoverAgentSnapshot(effectiveCwd, scope, parentProvider, { includeChains: false });
|
|
105
|
+
const discovered = discovery.effective;
|
|
106
|
+
const resolvedAgent = resolveAgentName(input.agent, discovered.agents);
|
|
107
|
+
const ambiguousCandidates = resolvedAgent.error ? discovered.agents.filter((agent) => resolveAgentName(input.agent, [agent]).agent) : resolvedAgent.agent;
|
|
108
|
+
const invalidAgent = findBlockingAgentDiagnostic(input.agent, ambiguousCandidates, discovered.agentDiagnostics);
|
|
109
|
+
if (invalidAgent) {
|
|
110
|
+
const message = `Agent '${input.agent}' has invalid configuration: ${invalidAgent.error}`;
|
|
111
|
+
return { ok: false, code: "missing_agent", message, diagnostics: [{ code: "missing_agent", severity: "error", message }] };
|
|
112
|
+
}
|
|
113
|
+
if (resolvedAgent.error) {
|
|
114
|
+
return { ok: false, code: "ambiguous_agent", message: resolvedAgent.error, diagnostics };
|
|
115
|
+
}
|
|
116
|
+
if (!resolvedAgent.agent) {
|
|
117
|
+
return { ok: false, code: "missing_agent", message: formatUnknownAgentError(input.agent, unknownAgentDiagnosticContext(discovered)), diagnostics };
|
|
118
|
+
}
|
|
119
|
+
const agent = resolvedAgent.agent;
|
|
120
|
+
let extensionBindings;
|
|
121
|
+
try {
|
|
122
|
+
extensionBindings = normalizeExtensionBindings(input.extensionBindings)?.value;
|
|
123
|
+
} catch (error) {
|
|
124
|
+
return { ok: false, code: "invalid_extension_bindings", message: error instanceof Error ? error.message : String(error), diagnostics };
|
|
125
|
+
}
|
|
126
|
+
if (extensionBindings !== undefined && (agent.runner?.type === "external-cli" || agent.runner?.type === "external-job")) {
|
|
127
|
+
return { ok: false, code: "unsupported_mode", message: `extensionBindings is not supported for runner.type='${agent.runner.type}'.`, diagnostics };
|
|
128
|
+
}
|
|
129
|
+
const context = resolveLaunchContractContext(input, agent);
|
|
130
|
+
if (context === "fork") {
|
|
131
|
+
diagnostics.push({ code: "host_required", severity: "host-required", message: "Exact fork session branching and fork-thinking downgrade checks require DM host session and model-registry snapshots." });
|
|
132
|
+
}
|
|
133
|
+
const effectiveCapabilityCeiling = intersectSubagentCapabilityCeilings(input.capabilityCeiling, input.inheritedCapabilityCeiling);
|
|
134
|
+
const restrictionMessage = capabilityCeilingAgentRestrictionMessage(agent.name, effectiveCapabilityCeiling);
|
|
135
|
+
if (restrictionMessage)
|
|
136
|
+
return { ok: false, code: "restricted_agent", message: restrictionMessage, diagnostics };
|
|
137
|
+
const runId = input.runId ?? "preflight";
|
|
138
|
+
const skillInput = normalizeSkillInput(input.skill);
|
|
139
|
+
const outputOverride = normalizeSingleOutputOverride(input.output, agent.output);
|
|
140
|
+
const behavior = resolveStepBehavior(agent, {
|
|
141
|
+
...outputOverride !== undefined ? { output: outputOverride } : {},
|
|
142
|
+
...input.outputMode !== undefined ? { outputMode: input.outputMode } : {},
|
|
143
|
+
...skillInput !== undefined ? { skills: skillInput } : {},
|
|
144
|
+
...input.model !== undefined ? { model: input.model } : {}
|
|
145
|
+
});
|
|
146
|
+
const requestedSkills = behavior.skills === false ? [] : behavior.skills;
|
|
147
|
+
const resolvedSkills = resolveSkillsWithFallback(requestedSkills, effectiveCwd, effectiveCwd, agent.skillPath, agent.filePath ? path.dirname(agent.filePath) : effectiveCwd);
|
|
148
|
+
if (resolvedSkills.missing.includes("dm-subagents")) {
|
|
149
|
+
return { ok: false, code: "missing_skill", message: "The dm-subagents orchestration skill is not child-injectable.", diagnostics };
|
|
150
|
+
}
|
|
151
|
+
if (resolvedSkills.missing.length > 0)
|
|
152
|
+
diagnostics.push({ code: "missing_skill", severity: "error", message: `Missing skills: ${resolvedSkills.missing.join(", ")}` });
|
|
153
|
+
const externalRunner = agent.runner?.type === "external-cli" || agent.runner?.type === "external-job";
|
|
154
|
+
const availableModels = normalizeAvailableModels(input.availableModels);
|
|
155
|
+
const preferredProvider = agent.modelProvider ?? input.preferredProvider ?? input.parentModel?.provider;
|
|
156
|
+
const modelScopes = resolveModelScopesForAgent(discovered.modelScope, agent.name, input.parentModel);
|
|
157
|
+
const primaryModel = externalRunner ? undefined : resolveEffectiveSubagentModel(input.model, agent.model, input.parentModel, availableModels, preferredProvider, { scope: modelScopes });
|
|
158
|
+
const effectiveThinkingConfig = input.thinking !== undefined ? input.thinking : agent.thinking;
|
|
159
|
+
const thinkingCeiling = externalRunner ? undefined : intersectThinkingCeilings(discovered.maxThinking, input.thinkingCeiling, input.inheritedThinkingCeiling, decodeThinkingCeiling(process.env[SUBAGENT_THINKING_CEILING_ENV]));
|
|
160
|
+
const model = externalRunner ? undefined : applyThinkingSuffix(primaryModel, effectiveThinkingConfig, input.thinking !== undefined);
|
|
161
|
+
const modelCandidates = externalRunner ? [] : buildModelCandidates(primaryModel, agent.fallbackModels, availableModels, preferredProvider, {
|
|
162
|
+
scope: modelScopes,
|
|
163
|
+
primaryModelFromParent: inheritsParentModel(input.model, agent.model, input.parentModel)
|
|
164
|
+
}).map((candidate) => applyThinkingSuffix(candidate, effectiveThinkingConfig, input.thinking !== undefined) ?? candidate);
|
|
165
|
+
if (!externalRunner) {
|
|
166
|
+
try {
|
|
167
|
+
assertThinkingWithinCeiling({ model, configThinking: effectiveThinkingConfig, ceiling: thinkingCeiling, agent: agent.name, runId });
|
|
168
|
+
for (const candidate of modelCandidates)
|
|
169
|
+
assertThinkingWithinCeiling({ model: candidate, configThinking: effectiveThinkingConfig, ceiling: thinkingCeiling, agent: agent.name, runId });
|
|
170
|
+
} catch (error) {
|
|
171
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
172
|
+
diagnostics.push({ code: "thinking_ceiling", severity: "error", message });
|
|
173
|
+
return { ok: false, code: "thinking_ceiling", message, diagnostics };
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
let toolPlan;
|
|
177
|
+
const permissionRules = resolvePermissionRules(loadConfig().permissions, agent.permissions);
|
|
178
|
+
const fast = input.fast ?? agent.fast;
|
|
179
|
+
try {
|
|
180
|
+
toolPlan = resolvePiLaunchToolPlan({
|
|
181
|
+
tools: agent.tools,
|
|
182
|
+
allowNestedSubagents: agent.allowNestedSubagents,
|
|
183
|
+
extensions: agent.extensions,
|
|
184
|
+
subagentOnlyExtensions: agent.subagentOnlyExtensions,
|
|
185
|
+
mcpDirectTools: agent.mcpDirectTools,
|
|
186
|
+
cwd: effectiveCwd,
|
|
187
|
+
requireReadTool: resolvedSkills.resolved.length > 0,
|
|
188
|
+
structuredOutput: Boolean(input.outputSchema),
|
|
189
|
+
fast,
|
|
190
|
+
model,
|
|
191
|
+
modelCandidates,
|
|
192
|
+
capabilityCeiling: effectiveCapabilityCeiling,
|
|
193
|
+
agentName: agent.name,
|
|
194
|
+
permissionRules
|
|
195
|
+
});
|
|
196
|
+
} catch (error) {
|
|
197
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
198
|
+
diagnostics.push({ code: "denied_required_tool", severity: "error", message });
|
|
199
|
+
return { ok: false, code: "denied_required_tool", message, diagnostics };
|
|
200
|
+
}
|
|
201
|
+
const artifactsEnabled = input.artifacts !== false;
|
|
202
|
+
const artifactsDir = artifactsEnabled ? getArtifactsDir(input.parentSessionFile ?? null, effectiveCwd, input.artifactDir) : undefined;
|
|
203
|
+
const artifactPaths = artifactsDir ? getArtifactPaths(artifactsDir, runId, agent.name, 0) : undefined;
|
|
204
|
+
const outputPath = resolveSingleOutputPath(behavior.output, effectiveCwd, effectiveCwd, artifactsDir ? path.join(artifactsDir, "outputs", runId) : undefined);
|
|
205
|
+
const sessionRoot = input.sessionDir ? path.resolve(input.sessionDir) : input.sessionRoot ? path.join(path.resolve(input.sessionRoot), runId) : undefined;
|
|
206
|
+
const sessionDir = sessionRoot ? path.join(sessionRoot, "run-0") : undefined;
|
|
207
|
+
const lifecycleAsyncDir = input.nestedRootRunId ? path.join(TEMP_ROOT_DIR, "nested-subagent-runs", input.nestedRootRunId, runId) : path.join(DIRS.async, runId);
|
|
208
|
+
const lifecycleResultPath = input.nestedRootRunId ? nestedResultsPath(input.nestedRootRunId, runId) : resultFilePath(DIRS.results, runId);
|
|
209
|
+
if (!sessionDir)
|
|
210
|
+
diagnostics.push({ code: "host_required", severity: "host-required", message: "No sessionRoot/sessionDir was supplied; exact child session paths require the DM host session-root policy." });
|
|
211
|
+
if (!externalRunner && input.availableModels === undefined && (input.model || agent.model || input.parentModel)) {
|
|
212
|
+
diagnostics.push({ code: "host_required", severity: "host-required", message: "No availableModels snapshot was supplied; model resolution may differ from the active DM host registry." });
|
|
213
|
+
}
|
|
214
|
+
if (resolvedSkills.missing.length > 0) {
|
|
215
|
+
return { ok: false, code: "missing_skill", message: `Missing skills: ${resolvedSkills.missing.join(", ")}`, diagnostics };
|
|
216
|
+
}
|
|
217
|
+
let effectiveSystemPrompt = agent.systemPrompt?.trim() ?? "";
|
|
218
|
+
if (resolvedSkills.resolved.length > 0) {
|
|
219
|
+
const skillInjection = buildSkillInjection(resolvedSkills.resolved);
|
|
220
|
+
effectiveSystemPrompt = effectiveSystemPrompt ? `${effectiveSystemPrompt}
|
|
221
|
+
|
|
222
|
+
${skillInjection}` : skillInjection;
|
|
223
|
+
}
|
|
224
|
+
const memoryInjection = buildAgentMemoryInjection(agent, effectiveCwd);
|
|
225
|
+
if (memoryInjection)
|
|
226
|
+
effectiveSystemPrompt = effectiveSystemPrompt ? `${effectiveSystemPrompt}
|
|
227
|
+
|
|
228
|
+
${memoryInjection}` : memoryInjection;
|
|
229
|
+
effectiveSystemPrompt = injectOutputPathSystemPrompt(effectiveSystemPrompt, outputPath, agent);
|
|
230
|
+
const candidates = candidateList(input.agent, agent, discovery.all);
|
|
231
|
+
const shadowedCandidates = candidates.filter((candidate) => !candidate.selected);
|
|
232
|
+
const definitionDigest = agentDefinitionDigest(agent);
|
|
233
|
+
const contractBase = {
|
|
234
|
+
version: SUBAGENT_LAUNCH_CONTRACT_VERSION,
|
|
235
|
+
runId,
|
|
236
|
+
agent: {
|
|
237
|
+
name: agent.name,
|
|
238
|
+
...agent.localName ? { localName: agent.localName } : {},
|
|
239
|
+
...agent.packageName ? { packageName: agent.packageName } : {},
|
|
240
|
+
source: agent.source,
|
|
241
|
+
filePath: agent.filePath,
|
|
242
|
+
definitionProjectionVersion: AGENT_DEFINITION_PROJECTION_VERSION,
|
|
243
|
+
definitionDigest,
|
|
244
|
+
shadowedCandidates
|
|
245
|
+
},
|
|
246
|
+
context,
|
|
247
|
+
...model ? { model } : {},
|
|
248
|
+
modelCandidates,
|
|
249
|
+
...resolveEffectiveThinking(model, effectiveThinkingConfig) ? { thinking: resolveEffectiveThinking(model, effectiveThinkingConfig) } : {},
|
|
250
|
+
...thinkingCeiling ? { thinkingCeiling } : {},
|
|
251
|
+
systemPromptMode: agent.systemPromptMode,
|
|
252
|
+
inheritProjectContext: agent.inheritProjectContext,
|
|
253
|
+
inheritGlobalContext: agent.inheritGlobalContext,
|
|
254
|
+
inheritSkills: agent.inheritSkills,
|
|
255
|
+
skills: {
|
|
256
|
+
requested: requestedSkills,
|
|
257
|
+
resolved: resolvedSkills.resolved.map((skill) => ({ name: skill.name, path: skill.path, source: skill.source })),
|
|
258
|
+
missing: resolvedSkills.missing
|
|
259
|
+
},
|
|
260
|
+
tools: {
|
|
261
|
+
requestedBuiltin: toolPlan.requestedBuiltinTools,
|
|
262
|
+
declaredBuiltin: toolPlan.declaredBuiltinTools,
|
|
263
|
+
effectiveAllowlist: toolPlan.effectiveToolAllowlist,
|
|
264
|
+
explicitAllowlist: toolPlan.explicitToolAllowlist,
|
|
265
|
+
requiredChildTools: toolPlan.requiredChildTools,
|
|
266
|
+
internalTools: toolPlan.internalTools,
|
|
267
|
+
mcp: toolPlan.effectiveMcpSelections,
|
|
268
|
+
effectiveMcpTools: toolPlan.effectiveMcpTools,
|
|
269
|
+
toolExtensionPaths: toolPlan.toolExtensionPaths,
|
|
270
|
+
runtimeExtensions: toolPlan.runtimeExtensions,
|
|
271
|
+
configuredExtensions: toolPlan.configuredExtensions,
|
|
272
|
+
extensionArgs: toolPlan.extensionArgs,
|
|
273
|
+
disableAmbientExtensions: toolPlan.disableAmbientExtensions,
|
|
274
|
+
fanoutAuthorized: toolPlan.fanoutAuthorized,
|
|
275
|
+
...toolPlan.capabilityCeiling ? { capabilityCeiling: toolPlan.capabilityCeiling } : {},
|
|
276
|
+
...toolPlan.capabilityAudit ? { capabilityAudit: toolPlan.capabilityAudit } : {}
|
|
277
|
+
},
|
|
278
|
+
roots: {
|
|
279
|
+
cwd: effectiveCwd,
|
|
280
|
+
...sessionRoot ? { sessionRoot } : {},
|
|
281
|
+
...sessionDir ? { sessionDir, sessionFile: path.join(sessionDir, "session.jsonl") } : {},
|
|
282
|
+
...artifactsDir ? { artifactsDir } : {},
|
|
283
|
+
...artifactPaths ? { artifactPaths } : {},
|
|
284
|
+
...outputPath ? { outputPath } : {},
|
|
285
|
+
lifecycle: {
|
|
286
|
+
asyncDir: lifecycleAsyncDir,
|
|
287
|
+
resultPath: lifecycleResultPath,
|
|
288
|
+
statusPath: path.join(lifecycleAsyncDir, "status.json"),
|
|
289
|
+
eventsPath: path.join(lifecycleAsyncDir, "events.jsonl"),
|
|
290
|
+
processTerminalPath: processTerminalPath(lifecycleAsyncDir),
|
|
291
|
+
processTerminalCandidatePath: processTerminalCandidatePath(lifecycleAsyncDir)
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
protocol: {
|
|
295
|
+
lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
|
|
296
|
+
packageVersion: packageVersion()
|
|
297
|
+
},
|
|
298
|
+
diagnostics,
|
|
299
|
+
launchContractDigest: launchBindingDigest({
|
|
300
|
+
task: input.task ?? "",
|
|
301
|
+
definitionDigest,
|
|
302
|
+
...model ? { model } : {},
|
|
303
|
+
modelCandidates,
|
|
304
|
+
...fast !== undefined ? { fast } : {},
|
|
305
|
+
...resolveEffectiveThinking(model, effectiveThinkingConfig) ? { thinking: resolveEffectiveThinking(model, effectiveThinkingConfig) } : {},
|
|
306
|
+
systemPrompt: effectiveSystemPrompt,
|
|
307
|
+
systemPromptMode: agent.systemPromptMode,
|
|
308
|
+
inheritProjectContext: agent.inheritProjectContext,
|
|
309
|
+
inheritGlobalContext: agent.inheritGlobalContext,
|
|
310
|
+
inheritSkills: agent.inheritSkills,
|
|
311
|
+
skills: requestedSkills,
|
|
312
|
+
tools: toolPlan.effectiveToolAllowlist,
|
|
313
|
+
extensions: toolPlan.extensionArgs,
|
|
314
|
+
mcpDirectTools: toolPlan.effectiveMcpTools,
|
|
315
|
+
...outputPath ? { outputPath } : {},
|
|
316
|
+
outputMode: behavior.outputMode,
|
|
317
|
+
...input.outputSchema ? { structuredOutputSchema: input.outputSchema } : {},
|
|
318
|
+
...extensionBindings ? { extensionBindings } : {}
|
|
319
|
+
})
|
|
320
|
+
};
|
|
321
|
+
return { ok: true, contract: { ...contractBase, digest: digestContract(contractBase) } };
|
|
322
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export {
|
|
2
|
+
PROJECT_PANES_API_VERSION,
|
|
3
|
+
PROJECT_PANE_TRUST_STATUS,
|
|
4
|
+
createProjectPaneManager,
|
|
5
|
+
openProjectPane,
|
|
6
|
+
getProjectPaneStatus,
|
|
7
|
+
focusProjectPane,
|
|
8
|
+
closeProjectPane,
|
|
9
|
+
readProjectPaneBinding,
|
|
10
|
+
projectPaneBindingPath
|
|
11
|
+
} from "../inspectors/herdr/project-panes.js";
|
|
@@ -1,6 +1,168 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
+
import * as os from "node:os";
|
|
2
3
|
import * as path from "node:path";
|
|
4
|
+
import { Key } from "@duckmind/dm-tui";
|
|
5
|
+
import { FLEET_KEYBINDING_ACTIONS } from "../shared/types.js";
|
|
6
|
+
import { validateMissionStoreConfig } from "../missions/store.js";
|
|
7
|
+
import { validateAuthorityPolicy } from "../policy/authority.js";
|
|
3
8
|
import { getAgentDir } from "../shared/utils.js";
|
|
9
|
+
import { DEFAULT_MODEL_EXCLUSION_TTL_MS, MAX_MODEL_EXCLUSION_TTL_MS, setDefaultTTL } from "../runs/shared/model-exclusions.js";
|
|
10
|
+
import { validatePermissionConfig } from "../runs/shared/permissions.js";
|
|
11
|
+
import { MAX_ABANDONED_SLOT_RELEASE_AFTER_MS, MIN_ABANDONED_SLOT_RELEASE_AFTER_MS } from "../runs/background/active-async-capacity.js";
|
|
12
|
+
const ARTIFACT_DIR_PREFERENCES = new Set(["project", "session", "temp"]);
|
|
13
|
+
const FLEET_KEYBINDING_ACTION_SET = new Set(FLEET_KEYBINDING_ACTIONS);
|
|
14
|
+
const KEY_MODIFIERS = new Set(["ctrl", "shift", "alt", "super"]);
|
|
15
|
+
const BASE_KEY_IDS = new Set([
|
|
16
|
+
..."abcdefghijklmnopqrstuvwxyz0123456789",
|
|
17
|
+
...Object.values(Key).flatMap((value) => typeof value === "string" ? [value.toLowerCase()] : [])
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
class PrunedForkConfigError extends Error {
|
|
21
|
+
}
|
|
22
|
+
function validateForkContextConfig(value) {
|
|
23
|
+
if (value === undefined)
|
|
24
|
+
return;
|
|
25
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
26
|
+
throw new Error("config.forkContext must be a JSON object");
|
|
27
|
+
const config = value;
|
|
28
|
+
if (config.mode !== undefined && config.mode !== "full" && config.mode !== "pruned") {
|
|
29
|
+
throw new Error('config.forkContext.mode must be "full" or "pruned"');
|
|
30
|
+
}
|
|
31
|
+
if (config.model !== undefined && (typeof config.model !== "string" || !config.model.trim())) {
|
|
32
|
+
throw new PrunedForkConfigError("config.forkContext.model must be a non-empty string");
|
|
33
|
+
}
|
|
34
|
+
if (config.mode === "pruned" && config.model === undefined) {
|
|
35
|
+
throw new PrunedForkConfigError('config.forkContext.model is required when config.forkContext.mode is "pruned"');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function isValidKeyId(value) {
|
|
39
|
+
if (value !== value.trim())
|
|
40
|
+
return false;
|
|
41
|
+
const parts = value.toLowerCase().split("+");
|
|
42
|
+
const base = parts.pop();
|
|
43
|
+
if (!base || !BASE_KEY_IDS.has(base))
|
|
44
|
+
return false;
|
|
45
|
+
return parts.length <= KEY_MODIFIERS.size && new Set(parts).size === parts.length && parts.every((modifier) => KEY_MODIFIERS.has(modifier));
|
|
46
|
+
}
|
|
47
|
+
export function resolveScheduledStoreRoot(value) {
|
|
48
|
+
const expanded = value.startsWith("~/") ? path.join(os.homedir(), value.slice(2)) : value;
|
|
49
|
+
if (!path.isAbsolute(expanded))
|
|
50
|
+
throw new Error(`config.scheduledRuns.storeRoot must be an absolute path or "~/...", got ${JSON.stringify(value)}`);
|
|
51
|
+
return path.normalize(expanded);
|
|
52
|
+
}
|
|
53
|
+
function validateScheduledRunsConfig(value) {
|
|
54
|
+
if (value === undefined)
|
|
55
|
+
return;
|
|
56
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
57
|
+
throw new Error("config.scheduledRuns must be a JSON object");
|
|
58
|
+
const storeRoot = value.storeRoot;
|
|
59
|
+
if (storeRoot === undefined)
|
|
60
|
+
return;
|
|
61
|
+
if (typeof storeRoot !== "string" || !storeRoot.trim())
|
|
62
|
+
throw new Error("config.scheduledRuns.storeRoot must be a non-empty string");
|
|
63
|
+
resolveScheduledStoreRoot(storeRoot);
|
|
64
|
+
}
|
|
65
|
+
function validateFleetKeybindingsConfig(value) {
|
|
66
|
+
if (value === undefined)
|
|
67
|
+
return;
|
|
68
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
69
|
+
throw new Error("config.fleetKeybindings must be a JSON object");
|
|
70
|
+
for (const [action, bindings] of Object.entries(value)) {
|
|
71
|
+
if (!FLEET_KEYBINDING_ACTION_SET.has(action))
|
|
72
|
+
throw new Error(`config.fleetKeybindings.${action} is not a supported Fleet action`);
|
|
73
|
+
if (!Array.isArray(bindings) || bindings.length === 0)
|
|
74
|
+
throw new Error(`config.fleetKeybindings.${action} must be a non-empty array of strings`);
|
|
75
|
+
for (const binding of bindings) {
|
|
76
|
+
if (typeof binding !== "string" || !binding.trim())
|
|
77
|
+
throw new Error(`config.fleetKeybindings.${action} entries must be non-empty strings`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function validateArtifactConfig(value) {
|
|
82
|
+
if (value === undefined)
|
|
83
|
+
return;
|
|
84
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
85
|
+
throw new Error("config.artifactConfig must be a JSON object");
|
|
86
|
+
const cleanupDays = value.cleanupDays;
|
|
87
|
+
if (cleanupDays !== undefined && (typeof cleanupDays !== "number" || !Number.isInteger(cleanupDays) || cleanupDays < 0)) {
|
|
88
|
+
throw new Error("config.artifactConfig.cleanupDays must be a non-negative integer");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function validateCapacityConfig(value) {
|
|
92
|
+
if (value === undefined)
|
|
93
|
+
return;
|
|
94
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
95
|
+
throw new Error("config.capacity must be a JSON object");
|
|
96
|
+
const abandonedSlotReleaseAfterMs = value.abandonedSlotReleaseAfterMs;
|
|
97
|
+
if (abandonedSlotReleaseAfterMs !== undefined && abandonedSlotReleaseAfterMs !== false && (typeof abandonedSlotReleaseAfterMs !== "number" || !Number.isInteger(abandonedSlotReleaseAfterMs) || abandonedSlotReleaseAfterMs < MIN_ABANDONED_SLOT_RELEASE_AFTER_MS || abandonedSlotReleaseAfterMs > MAX_ABANDONED_SLOT_RELEASE_AFTER_MS)) {
|
|
98
|
+
throw new Error(`config.capacity.abandonedSlotReleaseAfterMs must be false or an integer from ${MIN_ABANDONED_SLOT_RELEASE_AFTER_MS} to ${MAX_ABANDONED_SLOT_RELEASE_AFTER_MS}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function validateModelExclusionsConfig(value) {
|
|
102
|
+
if (value === undefined)
|
|
103
|
+
return;
|
|
104
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
105
|
+
throw new Error("config.modelExclusions must be a JSON object");
|
|
106
|
+
const defaultTtlMs = value.defaultTtlMs;
|
|
107
|
+
if (defaultTtlMs !== undefined && (typeof defaultTtlMs !== "number" || !Number.isFinite(defaultTtlMs) || defaultTtlMs <= 0 || defaultTtlMs > MAX_MODEL_EXCLUSION_TTL_MS)) {
|
|
108
|
+
throw new Error(`config.modelExclusions.defaultTtlMs must be a finite positive number no greater than ${MAX_MODEL_EXCLUSION_TTL_MS}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function validateOrcaProgressTabsConfig(value) {
|
|
112
|
+
if (value === undefined)
|
|
113
|
+
return;
|
|
114
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
115
|
+
throw new Error("config.orcaProgressTabs must be a JSON object");
|
|
116
|
+
const config = value;
|
|
117
|
+
for (const key of Object.keys(config)) {
|
|
118
|
+
if (key !== "enabled")
|
|
119
|
+
throw new Error(`config.orcaProgressTabs.${key} is not supported`);
|
|
120
|
+
}
|
|
121
|
+
if (config.enabled !== undefined && typeof config.enabled !== "boolean") {
|
|
122
|
+
throw new Error("config.orcaProgressTabs.enabled must be a boolean");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function validateMainWindowRendererConfig(value) {
|
|
126
|
+
if (value === undefined)
|
|
127
|
+
return;
|
|
128
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
129
|
+
throw new Error("config.mainWindowRenderer must be a JSON object");
|
|
130
|
+
const rendererConfig = value;
|
|
131
|
+
if (rendererConfig.horizontalSpacing !== undefined && (typeof rendererConfig.horizontalSpacing !== "number" || !Number.isInteger(rendererConfig.horizontalSpacing) || rendererConfig.horizontalSpacing < 0 || rendererConfig.horizontalSpacing > 4)) {
|
|
132
|
+
throw new Error("config.mainWindowRenderer.horizontalSpacing must be an integer from 0 to 4");
|
|
133
|
+
}
|
|
134
|
+
if (rendererConfig.compactResultMaxLines !== undefined && (typeof rendererConfig.compactResultMaxLines !== "number" || !Number.isInteger(rendererConfig.compactResultMaxLines) || rendererConfig.compactResultMaxLines < 1)) {
|
|
135
|
+
throw new Error("config.mainWindowRenderer.compactResultMaxLines must be a positive integer");
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function validateConfig(config) {
|
|
139
|
+
if (config.defaultSubagentContext !== undefined && config.defaultSubagentContext !== "fresh" && config.defaultSubagentContext !== "fork") {
|
|
140
|
+
throw new Error('config.defaultSubagentContext must be "fresh" or "fork"');
|
|
141
|
+
}
|
|
142
|
+
validateForkContextConfig(config.forkContext);
|
|
143
|
+
if (config.foregroundDetachShortcut !== undefined && (typeof config.foregroundDetachShortcut !== "string" || !isValidKeyId(config.foregroundDetachShortcut))) {
|
|
144
|
+
throw new Error('config.foregroundDetachShortcut must be a valid keybinding string such as "ctrl+b"');
|
|
145
|
+
}
|
|
146
|
+
if (config.artifactDir !== undefined && !ARTIFACT_DIR_PREFERENCES.has(config.artifactDir)) {
|
|
147
|
+
throw new Error(`config.artifactDir must be "project", "session", or "temp"`);
|
|
148
|
+
}
|
|
149
|
+
if (config.maxActiveAsyncRunsPerSession !== undefined && (typeof config.maxActiveAsyncRunsPerSession !== "number" || !Number.isInteger(config.maxActiveAsyncRunsPerSession) || config.maxActiveAsyncRunsPerSession < 0)) {
|
|
150
|
+
throw new Error("config.maxActiveAsyncRunsPerSession must be a non-negative integer");
|
|
151
|
+
}
|
|
152
|
+
if (config.resultScanLogging !== undefined && config.resultScanLogging !== "all" && config.resultScanLogging !== "activity" && config.resultScanLogging !== "off") {
|
|
153
|
+
throw new Error('config.resultScanLogging must be "all", "activity", or "off"');
|
|
154
|
+
}
|
|
155
|
+
validateMissionStoreConfig(config.missions);
|
|
156
|
+
validateAuthorityPolicy(config.authorityPolicy);
|
|
157
|
+
validatePermissionConfig(config.permissions);
|
|
158
|
+
validateScheduledRunsConfig(config.scheduledRuns);
|
|
159
|
+
validateFleetKeybindingsConfig(config.fleetKeybindings);
|
|
160
|
+
validateArtifactConfig(config.artifactConfig);
|
|
161
|
+
validateCapacityConfig(config.capacity);
|
|
162
|
+
validateModelExclusionsConfig(config.modelExclusions);
|
|
163
|
+
validateMainWindowRendererConfig(config.mainWindowRenderer);
|
|
164
|
+
validateOrcaProgressTabsConfig(config.orcaProgressTabs);
|
|
165
|
+
}
|
|
4
166
|
export function getConfigPath() {
|
|
5
167
|
return path.join(getAgentDir(), "extensions", "subagent", "config.json");
|
|
6
168
|
}
|
|
@@ -11,6 +173,7 @@ function readConfigForUpdate(configPath = getConfigPath()) {
|
|
|
11
173
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
12
174
|
throw new Error(`Subagent config at '${configPath}' must be a JSON object`);
|
|
13
175
|
}
|
|
176
|
+
validateConfig(parsed);
|
|
14
177
|
return parsed;
|
|
15
178
|
}
|
|
16
179
|
export function saveConfig(config, configPath = getConfigPath()) {
|
|
@@ -21,14 +184,26 @@ export function saveConfig(config, configPath = getConfigPath()) {
|
|
|
21
184
|
export function updateConfig(updater) {
|
|
22
185
|
const configPath = getConfigPath();
|
|
23
186
|
const next = updater(readConfigForUpdate(configPath));
|
|
187
|
+
validateConfig(next);
|
|
24
188
|
saveConfig(next, configPath);
|
|
25
189
|
return next;
|
|
26
190
|
}
|
|
191
|
+
export function resolveModelExclusionTTL(config) {
|
|
192
|
+
return config.modelExclusions?.defaultTtlMs ?? DEFAULT_MODEL_EXCLUSION_TTL_MS;
|
|
193
|
+
}
|
|
194
|
+
export function applyModelExclusionsConfig(config) {
|
|
195
|
+
setDefaultTTL(resolveModelExclusionTTL(config), { shortenExisting: config.modelExclusions?.defaultTtlMs !== undefined });
|
|
196
|
+
}
|
|
197
|
+
export function resolveAsyncByDefault(config) {
|
|
198
|
+
return config.asyncByDefault !== false;
|
|
199
|
+
}
|
|
27
200
|
export function loadConfig() {
|
|
28
201
|
const configPath = getConfigPath();
|
|
29
202
|
try {
|
|
30
203
|
return readConfigForUpdate(configPath);
|
|
31
204
|
} catch (error) {
|
|
205
|
+
if (error instanceof PrunedForkConfigError)
|
|
206
|
+
throw error;
|
|
32
207
|
console.error(`Failed to load subagent config from '${configPath}':`, error);
|
|
33
208
|
}
|
|
34
209
|
return {};
|
|
@@ -6,21 +6,6 @@ export function controlNoticeTarget(details) {
|
|
|
6
6
|
export function formatSubagentControlNotice(details, content) {
|
|
7
7
|
return details.noticeText ?? content ?? formatControlNoticeMessage(details.event, controlNoticeTarget(details));
|
|
8
8
|
}
|
|
9
|
-
function noticeTimerKey(details) {
|
|
10
|
-
const childIntercomTarget = controlNoticeTarget(details);
|
|
11
|
-
return `${details.event.runId}:${controlNotificationKey(details.event, childIntercomTarget)}`;
|
|
12
|
-
}
|
|
13
|
-
export function clearPendingForegroundControlNotices(state, runId) {
|
|
14
|
-
const pending = state.pendingForegroundControlNotices;
|
|
15
|
-
if (!pending)
|
|
16
|
-
return;
|
|
17
|
-
for (const [key, timer] of pending) {
|
|
18
|
-
if (runId !== undefined && !key.startsWith(`${runId}:`))
|
|
19
|
-
continue;
|
|
20
|
-
clearTimeout(timer);
|
|
21
|
-
pending.delete(key);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
9
|
function deliverControlNotice(input) {
|
|
25
10
|
const childIntercomTarget = controlNoticeTarget(input.details);
|
|
26
11
|
const key = controlNotificationKey(input.details.event, childIntercomTarget);
|
|
@@ -28,42 +13,18 @@ function deliverControlNotice(input) {
|
|
|
28
13
|
return;
|
|
29
14
|
input.visibleControlNotices.add(key);
|
|
30
15
|
const noticeText = input.details.noticeText ?? formatControlNoticeMessage(input.details.event, childIntercomTarget);
|
|
31
|
-
input.
|
|
16
|
+
input.dm.sendMessage({
|
|
32
17
|
customType: SUBAGENT_CONTROL_MESSAGE_TYPE,
|
|
33
18
|
content: noticeText,
|
|
34
19
|
display: true,
|
|
35
20
|
details: { ...input.details, childIntercomTarget, noticeText }
|
|
36
|
-
}, { triggerTurn: input.details.source
|
|
37
|
-
}
|
|
38
|
-
function isForegroundNoticeStillActionable(state, details) {
|
|
39
|
-
const control = state.foregroundControls.get(details.event.runId);
|
|
40
|
-
if (!control)
|
|
41
|
-
return false;
|
|
42
|
-
if (control.currentAgent && control.currentAgent !== details.event.agent)
|
|
43
|
-
return false;
|
|
44
|
-
if (details.event.index !== undefined && control.currentIndex !== details.event.index)
|
|
45
|
-
return false;
|
|
46
|
-
return control.currentActivityState === "needs_attention";
|
|
21
|
+
}, { triggerTurn: input.details.source === "async" });
|
|
47
22
|
}
|
|
48
23
|
export function handleSubagentControlNotice(input) {
|
|
49
24
|
if (!input.details?.event || input.details.event.type === "active_long_running")
|
|
50
25
|
return;
|
|
51
|
-
if (input.details.source
|
|
52
|
-
deliverControlNotice(input);
|
|
26
|
+
if (input.details.source === "foreground") {
|
|
53
27
|
return;
|
|
54
28
|
}
|
|
55
|
-
|
|
56
|
-
input.state.pendingForegroundControlNotices = pending;
|
|
57
|
-
const timerKey = noticeTimerKey(input.details);
|
|
58
|
-
const existing = pending.get(timerKey);
|
|
59
|
-
if (existing)
|
|
60
|
-
clearTimeout(existing);
|
|
61
|
-
const timer = setTimeout(() => {
|
|
62
|
-
pending.delete(timerKey);
|
|
63
|
-
if (!isForegroundNoticeStillActionable(input.state, input.details))
|
|
64
|
-
return;
|
|
65
|
-
deliverControlNotice(input);
|
|
66
|
-
}, input.foregroundDelayMs ?? 1000);
|
|
67
|
-
timer.unref?.();
|
|
68
|
-
pending.set(timerKey, timer);
|
|
29
|
+
deliverControlNotice(input);
|
|
69
30
|
}
|