@duckmind/dm-windows-x64 0.61.5 → 0.62.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dm.exe +0 -0
- package/extensions/.dm-extensions.json +215 -71
- package/extensions/dm-cua/bin/browser-cua.mjs +6 -1
- package/extensions/dm-cua/index.js +3 -2
- package/extensions/dm-cua/src/browser-cua-lib.mjs +69 -13
- 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/extensions/greedysearch-dm/bin/cdp.mjs +28 -3
- package/extensions/greedysearch-dm/bin/launch.mjs +2 -3
- package/extensions/greedysearch-dm/src/search/constants.mjs +5 -2
- 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
|
@@ -7,25 +7,40 @@ import {
|
|
|
7
7
|
defaultSystemPromptMode,
|
|
8
8
|
discoverAgentsAll,
|
|
9
9
|
buildRuntimeName,
|
|
10
|
+
findBlockingAgentDiagnostic,
|
|
10
11
|
frontmatterNameForConfig,
|
|
11
12
|
parsePackageName,
|
|
12
13
|
mergeBuiltinAgentOverride,
|
|
13
14
|
removeBuiltinAgentOverride,
|
|
14
|
-
removeBuiltinAgentOverrideFields
|
|
15
|
+
removeBuiltinAgentOverrideFields,
|
|
16
|
+
resolveAgentName
|
|
15
17
|
} from "./agents.js";
|
|
16
18
|
import { serializeAgent } from "./agent-serializer.js";
|
|
17
|
-
import {
|
|
18
|
-
import { discoverAvailableSkills } from "./skills.js";
|
|
19
|
+
import { mergeAgentsForScope } from "./agent-selection.js";
|
|
20
|
+
import { discoverAvailableSkills, resolveSkills } from "./skills.js";
|
|
19
21
|
import {
|
|
20
22
|
buildProactiveSkillSubagentRecommendationLines
|
|
21
23
|
} from "./proactive-skills.js";
|
|
22
|
-
import { parseFrontmatter } from "./frontmatter.js";
|
|
24
|
+
import { parseFrontmatter, parseFrontmatterList } from "./frontmatter.js";
|
|
23
25
|
import { toModelInfo } from "../shared/model-info.js";
|
|
24
26
|
import { resolveSubagentModelOverride } from "../runs/shared/model-fallback.js";
|
|
25
27
|
import { validateToolBudgetConfig } from "../runs/shared/tool-budget.js";
|
|
28
|
+
import { validateAcceptanceInput } from "../runs/shared/acceptance.js";
|
|
29
|
+
import { CODE_OWNED_EXTERNAL_CLI_ADAPTER_LABEL, isCodeOwnedExternalCliAdapterId, resolveExternalCliRunnerStatus, validateCodeOwnedProfileRunner } from "../runs/shared/external-cli-contract.js";
|
|
26
30
|
import { getProjectConfigDir } from "../shared/utils.js";
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
import { previewDisplayText } from "../shared/display-text.js";
|
|
32
|
+
import { capabilityCeilingAgentRestrictionSources, isAgentAllowedByCapabilityCeiling, resolveCurrentSubagentCapabilityCeiling } from "../runs/shared/capability-ceiling.js";
|
|
33
|
+
import { listRuntimeAgentConfigs, mergeRuntimeAgents } from "./runtime-agent-registry.js";
|
|
34
|
+
import { listExternalJobProviders } from "../api/external-job-provider.js";
|
|
35
|
+
function result(text, isError = false, details) {
|
|
36
|
+
return { content: [{ type: "text", text }], isError, details: { mode: "management", results: [], ...details } };
|
|
37
|
+
}
|
|
38
|
+
function jsonDetails(value) {
|
|
39
|
+
return JSON.parse(JSON.stringify(value));
|
|
40
|
+
}
|
|
41
|
+
function presentDetails(value) {
|
|
42
|
+
const cleaned = jsonDetails(value);
|
|
43
|
+
return Object.keys(cleaned).length > 0 ? cleaned : undefined;
|
|
29
44
|
}
|
|
30
45
|
function parseCsv(value) {
|
|
31
46
|
return [...new Set(value.split(",").map((v) => v.trim()).filter(Boolean))];
|
|
@@ -37,16 +52,27 @@ function configObject(config) {
|
|
|
37
52
|
val = JSON.parse(val);
|
|
38
53
|
} catch (error) {
|
|
39
54
|
const message = error instanceof Error ? error.message : String(error);
|
|
40
|
-
return { error: `config must be valid JSON: ${message}` };
|
|
55
|
+
return { status: "error", message: `config must be valid JSON: ${message}` };
|
|
41
56
|
}
|
|
42
57
|
}
|
|
43
58
|
if (!val || typeof val !== "object" || Array.isArray(val))
|
|
44
|
-
return {};
|
|
45
|
-
return { value: val };
|
|
59
|
+
return { status: "missing" };
|
|
60
|
+
return { status: "ok", value: val };
|
|
46
61
|
}
|
|
47
62
|
function hasKey(obj, key) {
|
|
48
63
|
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
49
64
|
}
|
|
65
|
+
function isJsonSerializable(value) {
|
|
66
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
67
|
+
return true;
|
|
68
|
+
if (typeof value === "number")
|
|
69
|
+
return Number.isFinite(value);
|
|
70
|
+
if (Array.isArray(value))
|
|
71
|
+
return value.every(isJsonSerializable);
|
|
72
|
+
if (value && typeof value === "object")
|
|
73
|
+
return Object.values(value).every(isJsonSerializable);
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
50
76
|
function asDisambiguationScope(scope) {
|
|
51
77
|
if (scope === "user" || scope === "project")
|
|
52
78
|
return scope;
|
|
@@ -74,30 +100,48 @@ function parsePackageConfig(value) {
|
|
|
74
100
|
function allAgents(d) {
|
|
75
101
|
return [...d.builtin, ...d.package, ...d.user, ...d.project];
|
|
76
102
|
}
|
|
77
|
-
function
|
|
78
|
-
|
|
79
|
-
const items = kind === "agent" ? allAgents(d) : d.chains;
|
|
80
|
-
return [...new Set(items.map((x) => x.name))].sort((a, b) => a.localeCompare(b));
|
|
103
|
+
function availableAgentNamesFromDiscovery(d) {
|
|
104
|
+
return [...new Set(allAgents(d).map((agent) => agent.name))].sort((a, b) => a.localeCompare(b));
|
|
81
105
|
}
|
|
82
|
-
function
|
|
83
|
-
|
|
84
|
-
const raw = name.trim();
|
|
85
|
-
const sanitized = sanitizeName(raw);
|
|
86
|
-
return allAgents(d).filter((a) => (scope === "both" || a.source === scope) && (a.name === raw || a.name === sanitized)).sort((a, b) => a.source.localeCompare(b.source));
|
|
106
|
+
function availableAgentNames(cwd) {
|
|
107
|
+
return availableAgentNamesFromDiscovery(discoverAgentsAll(cwd));
|
|
87
108
|
}
|
|
88
|
-
function
|
|
109
|
+
function findAgentsInDiscovery(name, d, scope = "both") {
|
|
89
110
|
const raw = name.trim();
|
|
90
111
|
const sanitized = sanitizeName(raw);
|
|
91
|
-
|
|
112
|
+
const scoped = mergeAgentsForScope(scope, d.user, d.project, d.builtin, d.package);
|
|
113
|
+
let resolved = resolveAgentName(raw, scoped);
|
|
114
|
+
if (!resolved.agent && !resolved.error && sanitized !== raw)
|
|
115
|
+
resolved = resolveAgentName(sanitized, scoped);
|
|
116
|
+
if (resolved.agent)
|
|
117
|
+
return scoped.filter((agent) => agent.name === resolved.agent.name).sort((a, b) => a.source.localeCompare(b.source));
|
|
118
|
+
return scoped.filter((agent) => Boolean(resolveAgentName(raw, [agent]).agent) || sanitized !== raw && Boolean(resolveAgentName(sanitized, [agent]).agent)).sort((a, b) => a.source.localeCompare(b.source));
|
|
119
|
+
}
|
|
120
|
+
function findAgents(name, cwd, scope = "both") {
|
|
121
|
+
return findAgentsInDiscovery(name, discoverAgentsAll(cwd), scope);
|
|
122
|
+
}
|
|
123
|
+
function diagnosticsForScope(diagnostics, scope) {
|
|
124
|
+
if (scope === "both")
|
|
125
|
+
return diagnostics;
|
|
126
|
+
const excludedSource = scope === "user" ? "project" : "user";
|
|
127
|
+
return diagnostics?.filter((diagnostic) => diagnostic.source !== excludedSource);
|
|
92
128
|
}
|
|
93
|
-
const AGENT_SOURCE_PRECEDENCE = { builtin: 0, package: 1, user: 2, project: 3 };
|
|
94
|
-
function
|
|
129
|
+
const AGENT_SOURCE_PRECEDENCE = { builtin: 0, package: 1, user: 2, project: 3, runtime: 4 };
|
|
130
|
+
function resolveEffectiveAgent(d, name) {
|
|
95
131
|
const raw = name.trim();
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
if (
|
|
99
|
-
|
|
100
|
-
|
|
132
|
+
const candidates = allAgents(d);
|
|
133
|
+
let resolved = resolveAgentName(raw, candidates);
|
|
134
|
+
if (!resolved.agent && !resolved.error) {
|
|
135
|
+
const sanitized = sanitizeName(raw);
|
|
136
|
+
if (sanitized !== raw)
|
|
137
|
+
resolved = resolveAgentName(sanitized, candidates);
|
|
138
|
+
}
|
|
139
|
+
if (resolved.error)
|
|
140
|
+
return { error: resolved.error };
|
|
141
|
+
if (!resolved.agent)
|
|
142
|
+
return {};
|
|
143
|
+
const matches = candidates.filter((agent) => agent.name === resolved.agent.name);
|
|
144
|
+
return { agent: matches.reduce((best, agent) => AGENT_SOURCE_PRECEDENCE[agent.source] > AGENT_SOURCE_PRECEDENCE[best.source] ? agent : best) };
|
|
101
145
|
}
|
|
102
146
|
function nameExistsInScope(cwd, scope, name, excludePath) {
|
|
103
147
|
const d = discoverAgentsAll(cwd);
|
|
@@ -105,43 +149,18 @@ function nameExistsInScope(cwd, scope, name, excludePath) {
|
|
|
105
149
|
if (a.name === name && a.filePath !== excludePath)
|
|
106
150
|
return true;
|
|
107
151
|
}
|
|
108
|
-
for (const c of d.chains) {
|
|
109
|
-
if (c.source === scope && c.name === name && c.filePath !== excludePath)
|
|
110
|
-
return true;
|
|
111
|
-
}
|
|
112
152
|
return false;
|
|
113
153
|
}
|
|
114
154
|
function isMutableSource(source) {
|
|
115
155
|
return source === "user" || source === "project";
|
|
116
156
|
}
|
|
117
|
-
function unknownChainAgents(cwd, steps) {
|
|
118
|
-
const d = discoverAgentsAll(cwd);
|
|
119
|
-
const known = new Set(allAgents(d).map((a) => a.name));
|
|
120
|
-
return [...new Set(steps.map((s) => s.agent).filter((a) => !known.has(a)))].sort((a, b) => a.localeCompare(b));
|
|
121
|
-
}
|
|
122
|
-
function chainStepWarnings(ctx, steps) {
|
|
123
|
-
const warnings = [];
|
|
124
|
-
const available = new Set(discoverAvailableSkills(ctx.cwd).map((s) => s.name));
|
|
125
|
-
for (let i = 0;i < steps.length; i++) {
|
|
126
|
-
const s = steps[i];
|
|
127
|
-
if (s.model) {
|
|
128
|
-
const found = ctx.modelRegistry.getAvailable().some((m) => `${m.provider}/${m.id}` === s.model || m.id === s.model);
|
|
129
|
-
if (!found)
|
|
130
|
-
warnings.push(`Warning: step ${i + 1} (${s.agent}): model '${s.model}' is not in the current model registry.`);
|
|
131
|
-
}
|
|
132
|
-
if (Array.isArray(s.skills) && s.skills.length > 0) {
|
|
133
|
-
const missing = s.skills.filter((sk) => !available.has(sk));
|
|
134
|
-
if (missing.length)
|
|
135
|
-
warnings.push(`Warning: step ${i + 1} (${s.agent}): skills not found: ${missing.join(", ")}.`);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
return warnings;
|
|
139
|
-
}
|
|
140
157
|
function modelWarning(ctx, model) {
|
|
141
158
|
if (!model)
|
|
142
159
|
return;
|
|
143
160
|
const found = ctx.modelRegistry.getAvailable().some((m) => `${m.provider}/${m.id}` === model || m.id === model);
|
|
144
|
-
|
|
161
|
+
if (found)
|
|
162
|
+
return;
|
|
163
|
+
return `Warning: model '${model}' is not in the current model registry. Run subagent({ action: "models" }) to list valid provider/id selectors, then use the exact provider/id form (bare ids resolve only when unique).`;
|
|
145
164
|
}
|
|
146
165
|
function fallbackModelsWarning(ctx, fallbackModels) {
|
|
147
166
|
if (!fallbackModels || fallbackModels.length === 0)
|
|
@@ -150,35 +169,80 @@ function fallbackModelsWarning(ctx, fallbackModels) {
|
|
|
150
169
|
const missing = fallbackModels.filter((model) => !available.has(model));
|
|
151
170
|
return missing.length ? `Warning: fallback models not in the current model registry: ${missing.join(", ")}.` : undefined;
|
|
152
171
|
}
|
|
153
|
-
function skillsWarning(cwd,
|
|
154
|
-
if (!skills
|
|
172
|
+
function skillsWarning(cwd, agent) {
|
|
173
|
+
if (!agent.skills?.length)
|
|
155
174
|
return;
|
|
156
|
-
const
|
|
157
|
-
const missing = skills.filter((s) => !available.has(s));
|
|
175
|
+
const { missing } = resolveSkills(agent.skills, cwd, agent.skillPath, agent.filePath ? path.dirname(agent.filePath) : cwd);
|
|
158
176
|
return missing.length ? `Warning: skills not found: ${missing.join(", ")}.` : undefined;
|
|
159
177
|
}
|
|
160
|
-
function
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
return { ...agent };
|
|
178
|
+
function withDeclaredExtensionPaths(config, filePath) {
|
|
179
|
+
const { frontmatter } = parseFrontmatter(fs.readFileSync(filePath, "utf-8"));
|
|
180
|
+
const { extensions: _extensions, subagentOnlyExtensions: _subagentOnlyExtensions, ...withoutResolvedExtensions } = config;
|
|
164
181
|
return {
|
|
165
|
-
...
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
182
|
+
...withoutResolvedExtensions,
|
|
183
|
+
...frontmatter.extensions !== undefined ? { extensions: parseFrontmatterList(frontmatter.extensions) } : {},
|
|
184
|
+
...frontmatter.subagentOnlyExtensions !== undefined ? { subagentOnlyExtensions: parseFrontmatterList(frontmatter.subagentOnlyExtensions) } : {}
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
export function editableAgentConfig(agent) {
|
|
188
|
+
const { extensions: _extensions, ...withoutExtensions } = agent;
|
|
189
|
+
const base = agent.override?.base;
|
|
190
|
+
const {
|
|
191
|
+
override: _override,
|
|
192
|
+
output: _output,
|
|
193
|
+
outputMode: _outputMode,
|
|
194
|
+
defaultReads: _defaultReads,
|
|
195
|
+
model: _model,
|
|
196
|
+
fallbackModels: _fallbackModels,
|
|
197
|
+
thinking: _thinking,
|
|
198
|
+
systemPromptMode: _systemPromptMode,
|
|
199
|
+
inheritProjectContext: _inheritProjectContext,
|
|
200
|
+
inheritGlobalContext: _inheritGlobalContext,
|
|
201
|
+
inheritSkills: _inheritSkills,
|
|
202
|
+
defaultContext: _defaultContext,
|
|
203
|
+
acceptanceRole: _acceptanceRole,
|
|
204
|
+
disabled: _disabled,
|
|
205
|
+
systemPrompt: _systemPrompt,
|
|
206
|
+
skills: _skills,
|
|
207
|
+
skillPath: _skillPath,
|
|
208
|
+
tools: _tools,
|
|
209
|
+
mcpDirectTools: _mcpDirectTools,
|
|
210
|
+
subagentOnlyExtensions: _subagentOnlyExtensions,
|
|
211
|
+
mutationTools: _mutationTools,
|
|
212
|
+
completionGuard: _completionGuard,
|
|
213
|
+
...editable
|
|
214
|
+
} = withoutExtensions;
|
|
215
|
+
if (!base) {
|
|
216
|
+
return withDeclaredExtensionPaths({
|
|
217
|
+
...withoutExtensions,
|
|
218
|
+
...agent.extensionsFromDefault ? {} : agent.extensions !== undefined ? { extensions: [...agent.extensions] } : {}
|
|
219
|
+
}, agent.filePath);
|
|
220
|
+
}
|
|
221
|
+
return withDeclaredExtensionPaths({
|
|
222
|
+
...editable,
|
|
223
|
+
...base.output !== undefined ? { output: base.output } : {},
|
|
224
|
+
...base.outputMode !== undefined ? { outputMode: base.outputMode } : {},
|
|
225
|
+
...base.defaultReads !== undefined ? { defaultReads: [...base.defaultReads] } : {},
|
|
226
|
+
...base.model !== undefined ? { model: base.model } : {},
|
|
227
|
+
...base.fallbackModels !== undefined ? { fallbackModels: [...base.fallbackModels] } : {},
|
|
228
|
+
...base.thinking !== undefined ? { thinking: base.thinking } : {},
|
|
169
229
|
systemPromptMode: base.systemPromptMode,
|
|
170
230
|
inheritProjectContext: base.inheritProjectContext,
|
|
231
|
+
inheritGlobalContext: base.inheritGlobalContext,
|
|
171
232
|
inheritSkills: base.inheritSkills,
|
|
172
|
-
defaultContext: base.defaultContext,
|
|
173
|
-
|
|
233
|
+
...base.defaultContext !== undefined ? { defaultContext: base.defaultContext } : {},
|
|
234
|
+
...base.acceptanceRole !== undefined ? { acceptanceRole: base.acceptanceRole } : {},
|
|
235
|
+
...base.disabled !== undefined ? { disabled: base.disabled } : {},
|
|
174
236
|
systemPrompt: base.systemPrompt,
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
237
|
+
...base.skills !== undefined ? { skills: [...base.skills] } : {},
|
|
238
|
+
...base.skillPath !== undefined ? { skillPath: [...base.skillPath] } : {},
|
|
239
|
+
...base.tools !== undefined ? { tools: [...base.tools] } : {},
|
|
240
|
+
...base.mcpDirectTools !== undefined ? { mcpDirectTools: [...base.mcpDirectTools] } : {},
|
|
241
|
+
...base.extensions !== undefined ? { extensions: [...base.extensions] } : {},
|
|
242
|
+
...base.subagentOnlyExtensions !== undefined ? { subagentOnlyExtensions: [...base.subagentOnlyExtensions] } : {},
|
|
243
|
+
...base.mutationTools !== undefined ? { mutationTools: [...base.mutationTools] } : {},
|
|
244
|
+
...base.completionGuard !== undefined ? { completionGuard: base.completionGuard } : {}
|
|
245
|
+
}, agent.filePath);
|
|
182
246
|
}
|
|
183
247
|
function readAgentFrontmatterFields(filePath) {
|
|
184
248
|
try {
|
|
@@ -188,7 +252,7 @@ function readAgentFrontmatterFields(filePath) {
|
|
|
188
252
|
return new Set;
|
|
189
253
|
}
|
|
190
254
|
}
|
|
191
|
-
function preservedAgentFrontmatterFields(agent, cfg) {
|
|
255
|
+
export function preservedAgentFrontmatterFields(agent, cfg) {
|
|
192
256
|
const fields = readAgentFrontmatterFields(agent.filePath);
|
|
193
257
|
const changed = (...names) => {
|
|
194
258
|
for (const name of names)
|
|
@@ -200,8 +264,12 @@ function preservedAgentFrontmatterFields(agent, cfg) {
|
|
|
200
264
|
changed("package");
|
|
201
265
|
if (hasKey(cfg, "description"))
|
|
202
266
|
changed("description");
|
|
267
|
+
if (hasKey(cfg, "aliases"))
|
|
268
|
+
changed("alias", "aliases");
|
|
203
269
|
if (hasKey(cfg, "systemPrompt"))
|
|
204
270
|
changed("systemPrompt");
|
|
271
|
+
if (hasKey(cfg, "runner"))
|
|
272
|
+
changed("runner");
|
|
205
273
|
if (hasKey(cfg, "model"))
|
|
206
274
|
changed("model");
|
|
207
275
|
if (hasKey(cfg, "fallbackModels"))
|
|
@@ -210,10 +278,14 @@ function preservedAgentFrontmatterFields(agent, cfg) {
|
|
|
210
278
|
changed("tools");
|
|
211
279
|
if (hasKey(cfg, "skills"))
|
|
212
280
|
changed("skill", "skills");
|
|
281
|
+
if (hasKey(cfg, "skillPath"))
|
|
282
|
+
changed("skillPath");
|
|
213
283
|
if (hasKey(cfg, "extensions"))
|
|
214
284
|
changed("extensions");
|
|
215
285
|
if (hasKey(cfg, "subagentOnlyExtensions"))
|
|
216
286
|
changed("subagentOnlyExtensions");
|
|
287
|
+
if (hasKey(cfg, "mutationTools"))
|
|
288
|
+
changed("mutationTools");
|
|
217
289
|
if (hasKey(cfg, "thinking")) {
|
|
218
290
|
changed("thinking");
|
|
219
291
|
if (cfg.thinking === "off")
|
|
@@ -227,14 +299,28 @@ function preservedAgentFrontmatterFields(agent, cfg) {
|
|
|
227
299
|
changed("inheritProjectContext");
|
|
228
300
|
fields.add("inheritProjectContext");
|
|
229
301
|
}
|
|
302
|
+
if (hasKey(cfg, "inheritGlobalContext")) {
|
|
303
|
+
changed("inheritGlobalContext");
|
|
304
|
+
fields.add("inheritGlobalContext");
|
|
305
|
+
}
|
|
230
306
|
if (hasKey(cfg, "inheritSkills")) {
|
|
231
307
|
changed("inheritSkills");
|
|
232
308
|
fields.add("inheritSkills");
|
|
233
309
|
}
|
|
234
310
|
if (hasKey(cfg, "defaultContext"))
|
|
235
311
|
changed("defaultContext");
|
|
312
|
+
if (hasKey(cfg, "async"))
|
|
313
|
+
changed("async");
|
|
314
|
+
if (hasKey(cfg, "timeoutMs"))
|
|
315
|
+
changed("timeoutMs");
|
|
316
|
+
if (hasKey(cfg, "acceptance"))
|
|
317
|
+
changed("acceptance");
|
|
318
|
+
if (hasKey(cfg, "acceptanceRole"))
|
|
319
|
+
changed("acceptanceRole");
|
|
236
320
|
if (hasKey(cfg, "output"))
|
|
237
321
|
changed("output");
|
|
322
|
+
if (hasKey(cfg, "outputMode"))
|
|
323
|
+
changed("outputMode");
|
|
238
324
|
if (hasKey(cfg, "reads"))
|
|
239
325
|
changed("defaultReads");
|
|
240
326
|
if (hasKey(cfg, "progress"))
|
|
@@ -250,96 +336,6 @@ function preservedAgentFrontmatterFields(agent, cfg) {
|
|
|
250
336
|
changed("toolBudget");
|
|
251
337
|
return fields;
|
|
252
338
|
}
|
|
253
|
-
function parseStepList(raw) {
|
|
254
|
-
if (!Array.isArray(raw))
|
|
255
|
-
return { error: "config.steps must be an array." };
|
|
256
|
-
if (raw.length === 0)
|
|
257
|
-
return { error: "config.steps must include at least one step." };
|
|
258
|
-
const steps = [];
|
|
259
|
-
for (let i = 0;i < raw.length; i++) {
|
|
260
|
-
const item = raw[i];
|
|
261
|
-
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
262
|
-
return { error: `config.steps[${i}] must be an object.` };
|
|
263
|
-
const s = item;
|
|
264
|
-
if (typeof s.agent !== "string" || !s.agent.trim())
|
|
265
|
-
return { error: `config.steps[${i}].agent must be a non-empty string.` };
|
|
266
|
-
const step = { agent: s.agent.trim(), task: typeof s.task === "string" ? s.task : "" };
|
|
267
|
-
if (hasKey(s, "phase")) {
|
|
268
|
-
if (typeof s.phase === "string")
|
|
269
|
-
step.phase = s.phase;
|
|
270
|
-
else
|
|
271
|
-
return { error: `config.steps[${i}].phase must be a string.` };
|
|
272
|
-
}
|
|
273
|
-
if (hasKey(s, "label")) {
|
|
274
|
-
if (typeof s.label === "string")
|
|
275
|
-
step.label = s.label;
|
|
276
|
-
else
|
|
277
|
-
return { error: `config.steps[${i}].label must be a string.` };
|
|
278
|
-
}
|
|
279
|
-
if (hasKey(s, "as")) {
|
|
280
|
-
if (typeof s.as === "string")
|
|
281
|
-
step.as = s.as;
|
|
282
|
-
else
|
|
283
|
-
return { error: `config.steps[${i}].as must be a string.` };
|
|
284
|
-
}
|
|
285
|
-
if (hasKey(s, "outputSchema")) {
|
|
286
|
-
if (typeof s.outputSchema === "string")
|
|
287
|
-
step.outputSchema = s.outputSchema;
|
|
288
|
-
else
|
|
289
|
-
return { error: `config.steps[${i}].outputSchema must be a schema file path string for saved chains.` };
|
|
290
|
-
}
|
|
291
|
-
if (hasKey(s, "output")) {
|
|
292
|
-
if (s.output === false)
|
|
293
|
-
step.output = false;
|
|
294
|
-
else if (typeof s.output === "string")
|
|
295
|
-
step.output = s.output;
|
|
296
|
-
else
|
|
297
|
-
return { error: `config.steps[${i}].output must be a string or false.` };
|
|
298
|
-
}
|
|
299
|
-
if (hasKey(s, "outputMode")) {
|
|
300
|
-
if (s.outputMode === "inline" || s.outputMode === "file-only")
|
|
301
|
-
step.outputMode = s.outputMode;
|
|
302
|
-
else
|
|
303
|
-
return { error: `config.steps[${i}].outputMode must be 'inline' or 'file-only'.` };
|
|
304
|
-
}
|
|
305
|
-
if (hasKey(s, "reads")) {
|
|
306
|
-
if (s.reads === false)
|
|
307
|
-
step.reads = false;
|
|
308
|
-
else if (Array.isArray(s.reads))
|
|
309
|
-
step.reads = s.reads.filter((v) => typeof v === "string").map((v) => v.trim()).filter(Boolean);
|
|
310
|
-
else
|
|
311
|
-
return { error: `config.steps[${i}].reads must be an array or false.` };
|
|
312
|
-
}
|
|
313
|
-
if (hasKey(s, "model")) {
|
|
314
|
-
if (typeof s.model === "string")
|
|
315
|
-
step.model = s.model;
|
|
316
|
-
else
|
|
317
|
-
return { error: `config.steps[${i}].model must be a string.` };
|
|
318
|
-
}
|
|
319
|
-
if (hasKey(s, "skills")) {
|
|
320
|
-
if (s.skills === false)
|
|
321
|
-
step.skills = false;
|
|
322
|
-
else if (Array.isArray(s.skills))
|
|
323
|
-
step.skills = s.skills.filter((v) => typeof v === "string").map((v) => v.trim()).filter(Boolean);
|
|
324
|
-
else
|
|
325
|
-
return { error: `config.steps[${i}].skills must be an array or false.` };
|
|
326
|
-
}
|
|
327
|
-
if (hasKey(s, "progress")) {
|
|
328
|
-
if (typeof s.progress === "boolean")
|
|
329
|
-
step.progress = s.progress;
|
|
330
|
-
else
|
|
331
|
-
return { error: `config.steps[${i}].progress must be a boolean.` };
|
|
332
|
-
}
|
|
333
|
-
if (hasKey(s, "toolBudget")) {
|
|
334
|
-
const validation = validateToolBudgetConfig(s.toolBudget, `config.steps[${i}].toolBudget`);
|
|
335
|
-
if (validation.error)
|
|
336
|
-
return { error: validation.error };
|
|
337
|
-
step.toolBudget = s.toolBudget;
|
|
338
|
-
}
|
|
339
|
-
steps.push(step);
|
|
340
|
-
}
|
|
341
|
-
return { steps };
|
|
342
|
-
}
|
|
343
339
|
function parseTools(raw) {
|
|
344
340
|
const tools = [];
|
|
345
341
|
const mcpDirectTools = [];
|
|
@@ -351,9 +347,30 @@ function parseTools(raw) {
|
|
|
351
347
|
} else
|
|
352
348
|
tools.push(item);
|
|
353
349
|
}
|
|
354
|
-
return {
|
|
350
|
+
return {
|
|
351
|
+
...tools.length ? { tools } : {},
|
|
352
|
+
...mcpDirectTools.length ? { mcpDirectTools } : {}
|
|
353
|
+
};
|
|
355
354
|
}
|
|
356
355
|
function applyAgentConfig(target, cfg) {
|
|
356
|
+
if (hasKey(cfg, "aliases")) {
|
|
357
|
+
if (cfg.aliases === false || cfg.aliases === "")
|
|
358
|
+
delete target.aliases;
|
|
359
|
+
else if (typeof cfg.aliases === "string") {
|
|
360
|
+
const aliases = parseCsv(cfg.aliases).filter((alias) => alias !== target.name);
|
|
361
|
+
if (aliases.length)
|
|
362
|
+
target.aliases = aliases;
|
|
363
|
+
else
|
|
364
|
+
delete target.aliases;
|
|
365
|
+
} else if (Array.isArray(cfg.aliases) && cfg.aliases.every((entry) => typeof entry === "string")) {
|
|
366
|
+
const aliases = [...new Set(cfg.aliases.map((entry) => entry.trim()).filter(Boolean).filter((alias) => alias !== target.name))];
|
|
367
|
+
if (aliases.length)
|
|
368
|
+
target.aliases = aliases;
|
|
369
|
+
else
|
|
370
|
+
delete target.aliases;
|
|
371
|
+
} else
|
|
372
|
+
return "config.aliases must be a comma-separated string, string array, or false when provided.";
|
|
373
|
+
}
|
|
357
374
|
if (hasKey(cfg, "systemPrompt")) {
|
|
358
375
|
if (cfg.systemPrompt === false || cfg.systemPrompt === "")
|
|
359
376
|
target.systemPrompt = "";
|
|
@@ -362,49 +379,103 @@ function applyAgentConfig(target, cfg) {
|
|
|
362
379
|
else
|
|
363
380
|
return "config.systemPrompt must be a string or false when provided.";
|
|
364
381
|
}
|
|
382
|
+
if (hasKey(cfg, "runner")) {
|
|
383
|
+
if (cfg.runner === false || cfg.runner === "")
|
|
384
|
+
delete target.runner;
|
|
385
|
+
else if (cfg.runner && typeof cfg.runner === "object" && !Array.isArray(cfg.runner)) {
|
|
386
|
+
const runner = cfg.runner;
|
|
387
|
+
if (runner.type === "dm" && Object.keys(runner).every((key) => key === "type"))
|
|
388
|
+
target.runner = { type: "dm" };
|
|
389
|
+
else if (runner.type === "external-cli" && typeof runner.command === "string" && runner.command.trim() && (runner.args === undefined || Array.isArray(runner.args) && runner.args.every((arg) => typeof arg === "string")) && (runner.adapter === undefined || isCodeOwnedExternalCliAdapterId(runner.adapter)) && (runner.adapter === undefined || runner.args === undefined || runner.args.length === 0) && (runner.promptDelivery === undefined || runner.promptDelivery === "stdin") && Object.keys(runner).every((key) => ["type", "adapter", "command", "args", "promptDelivery"].includes(key))) {
|
|
390
|
+
const runnerArgs = Array.isArray(runner.args) ? runner.args.filter((arg) => typeof arg === "string") : undefined;
|
|
391
|
+
target.runner = { type: "external-cli", ...isCodeOwnedExternalCliAdapterId(runner.adapter) ? { adapter: runner.adapter } : {}, command: runner.command.trim(), ...runnerArgs?.length ? { args: runnerArgs } : {}, ...runner.promptDelivery ? { promptDelivery: "stdin" } : {} };
|
|
392
|
+
} else if (runner.type === "external-job" && typeof runner.provider === "string" && runner.provider.trim() === runner.provider && runner.provider && (runner.options === undefined || runner.options && typeof runner.options === "object" && !Array.isArray(runner.options) && isJsonSerializable(runner.options)) && Object.keys(runner).every((key) => ["type", "provider", "options"].includes(key))) {
|
|
393
|
+
target.runner = { type: "external-job", provider: runner.provider, ...runner.options ? { options: runner.options } : {} };
|
|
394
|
+
} else
|
|
395
|
+
return `config.runner must be { type: 'dm' }, { type: 'external-cli', adapter?: ${CODE_OWNED_EXTERNAL_CLI_ADAPTER_LABEL}, command: string, args?: string[], promptDelivery?: 'stdin' }, or { type: 'external-job', provider: string, options?: object }.`;
|
|
396
|
+
} else
|
|
397
|
+
return "config.runner must be an object, false, or empty string when provided.";
|
|
398
|
+
}
|
|
365
399
|
if (hasKey(cfg, "model")) {
|
|
366
400
|
if (cfg.model === false || cfg.model === "")
|
|
367
|
-
target.model
|
|
368
|
-
else if (typeof cfg.model === "string")
|
|
369
|
-
|
|
370
|
-
|
|
401
|
+
delete target.model;
|
|
402
|
+
else if (typeof cfg.model === "string") {
|
|
403
|
+
const model = cfg.model.trim();
|
|
404
|
+
if (model)
|
|
405
|
+
target.model = model;
|
|
406
|
+
else
|
|
407
|
+
delete target.model;
|
|
408
|
+
} else
|
|
371
409
|
return "config.model must be a string or false when provided.";
|
|
372
410
|
}
|
|
373
411
|
if (hasKey(cfg, "fallbackModels")) {
|
|
374
412
|
if (cfg.fallbackModels === false || cfg.fallbackModels === "")
|
|
375
|
-
target.fallbackModels
|
|
413
|
+
delete target.fallbackModels;
|
|
376
414
|
else if (typeof cfg.fallbackModels === "string") {
|
|
377
415
|
const models = parseCsv(cfg.fallbackModels);
|
|
378
|
-
|
|
416
|
+
if (models.length)
|
|
417
|
+
target.fallbackModels = models;
|
|
418
|
+
else
|
|
419
|
+
delete target.fallbackModels;
|
|
379
420
|
} else if (Array.isArray(cfg.fallbackModels)) {
|
|
380
421
|
const models = cfg.fallbackModels.filter((value) => typeof value === "string").map((value) => value.trim()).filter(Boolean);
|
|
381
|
-
|
|
422
|
+
if (models.length)
|
|
423
|
+
target.fallbackModels = [...new Set(models)];
|
|
424
|
+
else
|
|
425
|
+
delete target.fallbackModels;
|
|
382
426
|
} else
|
|
383
427
|
return "config.fallbackModels must be a comma-separated string, string array, or false when provided.";
|
|
384
428
|
}
|
|
385
429
|
if (hasKey(cfg, "tools")) {
|
|
386
430
|
if (cfg.tools === false || cfg.tools === "") {
|
|
387
|
-
target.tools
|
|
388
|
-
target.mcpDirectTools
|
|
431
|
+
delete target.tools;
|
|
432
|
+
delete target.mcpDirectTools;
|
|
389
433
|
} else if (typeof cfg.tools === "string") {
|
|
390
434
|
const parsed = parseTools(cfg.tools);
|
|
391
|
-
|
|
392
|
-
|
|
435
|
+
if (parsed.tools)
|
|
436
|
+
target.tools = parsed.tools;
|
|
437
|
+
else
|
|
438
|
+
delete target.tools;
|
|
439
|
+
if (parsed.mcpDirectTools)
|
|
440
|
+
target.mcpDirectTools = parsed.mcpDirectTools;
|
|
441
|
+
else
|
|
442
|
+
delete target.mcpDirectTools;
|
|
393
443
|
} else
|
|
394
444
|
return "config.tools must be a comma-separated string or false when provided.";
|
|
395
445
|
}
|
|
396
446
|
if (hasKey(cfg, "skills")) {
|
|
397
447
|
if (cfg.skills === false || cfg.skills === "")
|
|
398
|
-
target.skills
|
|
448
|
+
delete target.skills;
|
|
399
449
|
else if (typeof cfg.skills === "string") {
|
|
400
450
|
const skills = parseCsv(cfg.skills);
|
|
401
|
-
|
|
451
|
+
if (skills.length)
|
|
452
|
+
target.skills = skills;
|
|
453
|
+
else
|
|
454
|
+
delete target.skills;
|
|
402
455
|
} else
|
|
403
456
|
return "config.skills must be a comma-separated string or false when provided.";
|
|
404
457
|
}
|
|
458
|
+
if (hasKey(cfg, "skillPath")) {
|
|
459
|
+
if (cfg.skillPath === false || cfg.skillPath === "")
|
|
460
|
+
delete target.skillPath;
|
|
461
|
+
else if (typeof cfg.skillPath === "string") {
|
|
462
|
+
const skillPath = parseCsv(cfg.skillPath);
|
|
463
|
+
if (skillPath.length)
|
|
464
|
+
target.skillPath = skillPath;
|
|
465
|
+
else
|
|
466
|
+
delete target.skillPath;
|
|
467
|
+
} else if (Array.isArray(cfg.skillPath) && cfg.skillPath.every((entry) => typeof entry === "string")) {
|
|
468
|
+
const skillPath = [...new Set(cfg.skillPath.map((entry) => entry.trim()).filter(Boolean))];
|
|
469
|
+
if (skillPath.length)
|
|
470
|
+
target.skillPath = skillPath;
|
|
471
|
+
else
|
|
472
|
+
delete target.skillPath;
|
|
473
|
+
} else
|
|
474
|
+
return "config.skillPath must be a comma-separated string, string array, or false when provided.";
|
|
475
|
+
}
|
|
405
476
|
if (hasKey(cfg, "extensions")) {
|
|
406
477
|
if (cfg.extensions === false)
|
|
407
|
-
target.extensions
|
|
478
|
+
delete target.extensions;
|
|
408
479
|
else if (cfg.extensions === "")
|
|
409
480
|
target.extensions = [];
|
|
410
481
|
else if (typeof cfg.extensions === "string")
|
|
@@ -414,7 +485,7 @@ function applyAgentConfig(target, cfg) {
|
|
|
414
485
|
}
|
|
415
486
|
if (hasKey(cfg, "subagentOnlyExtensions")) {
|
|
416
487
|
if (cfg.subagentOnlyExtensions === false)
|
|
417
|
-
target.subagentOnlyExtensions
|
|
488
|
+
delete target.subagentOnlyExtensions;
|
|
418
489
|
else if (cfg.subagentOnlyExtensions === "")
|
|
419
490
|
target.subagentOnlyExtensions = [];
|
|
420
491
|
else if (typeof cfg.subagentOnlyExtensions === "string")
|
|
@@ -422,12 +493,26 @@ function applyAgentConfig(target, cfg) {
|
|
|
422
493
|
else
|
|
423
494
|
return "config.subagentOnlyExtensions must be a comma-separated string, empty string, or false when provided.";
|
|
424
495
|
}
|
|
496
|
+
if (hasKey(cfg, "mutationTools")) {
|
|
497
|
+
if (cfg.mutationTools === false)
|
|
498
|
+
delete target.mutationTools;
|
|
499
|
+
else if (cfg.mutationTools === "")
|
|
500
|
+
target.mutationTools = [];
|
|
501
|
+
else if (typeof cfg.mutationTools === "string")
|
|
502
|
+
target.mutationTools = parseCsv(cfg.mutationTools);
|
|
503
|
+
else
|
|
504
|
+
return "config.mutationTools must be a comma-separated string, empty string, or false when provided.";
|
|
505
|
+
}
|
|
425
506
|
if (hasKey(cfg, "thinking")) {
|
|
426
507
|
if (cfg.thinking === false || cfg.thinking === "")
|
|
427
|
-
target.thinking
|
|
428
|
-
else if (typeof cfg.thinking === "string")
|
|
429
|
-
|
|
430
|
-
|
|
508
|
+
delete target.thinking;
|
|
509
|
+
else if (typeof cfg.thinking === "string") {
|
|
510
|
+
const thinking = cfg.thinking.trim();
|
|
511
|
+
if (thinking)
|
|
512
|
+
target.thinking = thinking;
|
|
513
|
+
else
|
|
514
|
+
delete target.thinking;
|
|
515
|
+
} else
|
|
431
516
|
return "config.thinking must be a string or false when provided.";
|
|
432
517
|
}
|
|
433
518
|
if (hasKey(cfg, "systemPromptMode")) {
|
|
@@ -441,6 +526,11 @@ function applyAgentConfig(target, cfg) {
|
|
|
441
526
|
return "config.inheritProjectContext must be a boolean when provided.";
|
|
442
527
|
target.inheritProjectContext = cfg.inheritProjectContext;
|
|
443
528
|
}
|
|
529
|
+
if (hasKey(cfg, "inheritGlobalContext")) {
|
|
530
|
+
if (typeof cfg.inheritGlobalContext !== "boolean")
|
|
531
|
+
return "config.inheritGlobalContext must be a boolean when provided.";
|
|
532
|
+
target.inheritGlobalContext = cfg.inheritGlobalContext;
|
|
533
|
+
}
|
|
444
534
|
if (hasKey(cfg, "inheritSkills")) {
|
|
445
535
|
if (typeof cfg.inheritSkills !== "boolean")
|
|
446
536
|
return "config.inheritSkills must be a boolean when provided.";
|
|
@@ -448,26 +538,69 @@ function applyAgentConfig(target, cfg) {
|
|
|
448
538
|
}
|
|
449
539
|
if (hasKey(cfg, "defaultContext")) {
|
|
450
540
|
if (cfg.defaultContext === false || cfg.defaultContext === "")
|
|
451
|
-
target.defaultContext
|
|
541
|
+
delete target.defaultContext;
|
|
452
542
|
else if (cfg.defaultContext === "fresh" || cfg.defaultContext === "fork")
|
|
453
543
|
target.defaultContext = cfg.defaultContext;
|
|
454
544
|
else
|
|
455
545
|
return "config.defaultContext must be 'fresh', 'fork', or false when provided.";
|
|
456
546
|
}
|
|
547
|
+
if (hasKey(cfg, "async")) {
|
|
548
|
+
if (cfg.async === "")
|
|
549
|
+
delete target.defaultAsync;
|
|
550
|
+
else if (typeof cfg.async === "boolean")
|
|
551
|
+
target.defaultAsync = cfg.async;
|
|
552
|
+
else
|
|
553
|
+
return "config.async must be a boolean or empty string when provided.";
|
|
554
|
+
}
|
|
555
|
+
if (hasKey(cfg, "timeoutMs")) {
|
|
556
|
+
if (cfg.timeoutMs === false || cfg.timeoutMs === "")
|
|
557
|
+
delete target.defaultTimeoutMs;
|
|
558
|
+
else if (typeof cfg.timeoutMs === "number" && Number.isInteger(cfg.timeoutMs) && cfg.timeoutMs > 0)
|
|
559
|
+
target.defaultTimeoutMs = cfg.timeoutMs;
|
|
560
|
+
else
|
|
561
|
+
return "config.timeoutMs must be a positive integer or false when provided.";
|
|
562
|
+
}
|
|
563
|
+
if (hasKey(cfg, "acceptance")) {
|
|
564
|
+
if (cfg.acceptance === "")
|
|
565
|
+
delete target.defaultAcceptance;
|
|
566
|
+
else {
|
|
567
|
+
const errors = validateAcceptanceInput(cfg.acceptance, "config.acceptance");
|
|
568
|
+
if (errors.length > 0)
|
|
569
|
+
return errors.join(" ");
|
|
570
|
+
target.defaultAcceptance = cfg.acceptance;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
if (hasKey(cfg, "acceptanceRole")) {
|
|
574
|
+
if (cfg.acceptanceRole === false || cfg.acceptanceRole === "")
|
|
575
|
+
delete target.acceptanceRole;
|
|
576
|
+
else if (cfg.acceptanceRole === "read-only" || cfg.acceptanceRole === "writer")
|
|
577
|
+
target.acceptanceRole = cfg.acceptanceRole;
|
|
578
|
+
else
|
|
579
|
+
return "config.acceptanceRole must be 'read-only', 'writer', or false when provided.";
|
|
580
|
+
}
|
|
457
581
|
if (hasKey(cfg, "output")) {
|
|
458
582
|
if (cfg.output === false || cfg.output === "")
|
|
459
|
-
target.output
|
|
583
|
+
delete target.output;
|
|
460
584
|
else if (typeof cfg.output === "string")
|
|
461
585
|
target.output = cfg.output;
|
|
462
586
|
else
|
|
463
587
|
return "config.output must be a string or false when provided.";
|
|
464
588
|
}
|
|
589
|
+
if (hasKey(cfg, "outputMode")) {
|
|
590
|
+
if (cfg.outputMode === "inline" || cfg.outputMode === "file-only")
|
|
591
|
+
target.outputMode = cfg.outputMode;
|
|
592
|
+
else
|
|
593
|
+
return "config.outputMode must be 'inline' or 'file-only' when provided.";
|
|
594
|
+
}
|
|
465
595
|
if (hasKey(cfg, "reads")) {
|
|
466
596
|
if (cfg.reads === false || cfg.reads === "")
|
|
467
|
-
target.defaultReads
|
|
597
|
+
delete target.defaultReads;
|
|
468
598
|
else if (typeof cfg.reads === "string") {
|
|
469
599
|
const reads = parseCsv(cfg.reads);
|
|
470
|
-
|
|
600
|
+
if (reads.length)
|
|
601
|
+
target.defaultReads = reads;
|
|
602
|
+
else
|
|
603
|
+
delete target.defaultReads;
|
|
471
604
|
} else
|
|
472
605
|
return "config.reads must be a comma-separated string or false when provided.";
|
|
473
606
|
}
|
|
@@ -478,7 +611,7 @@ function applyAgentConfig(target, cfg) {
|
|
|
478
611
|
}
|
|
479
612
|
if (hasKey(cfg, "maxSubagentDepth")) {
|
|
480
613
|
if (cfg.maxSubagentDepth === false || cfg.maxSubagentDepth === "")
|
|
481
|
-
target.maxSubagentDepth
|
|
614
|
+
delete target.maxSubagentDepth;
|
|
482
615
|
else if (typeof cfg.maxSubagentDepth === "number" && Number.isInteger(cfg.maxSubagentDepth) && cfg.maxSubagentDepth >= 0) {
|
|
483
616
|
target.maxSubagentDepth = cfg.maxSubagentDepth;
|
|
484
617
|
} else
|
|
@@ -491,7 +624,7 @@ function applyAgentConfig(target, cfg) {
|
|
|
491
624
|
}
|
|
492
625
|
if (hasKey(cfg, "toolBudget")) {
|
|
493
626
|
if (cfg.toolBudget === false || cfg.toolBudget === "")
|
|
494
|
-
target.toolBudget
|
|
627
|
+
delete target.toolBudget;
|
|
495
628
|
else {
|
|
496
629
|
const validation = validateToolBudgetConfig(cfg.toolBudget, "config.toolBudget");
|
|
497
630
|
if (validation.error)
|
|
@@ -499,51 +632,241 @@ function applyAgentConfig(target, cfg) {
|
|
|
499
632
|
target.toolBudget = cfg.toolBudget;
|
|
500
633
|
}
|
|
501
634
|
}
|
|
635
|
+
if (target.runner?.type === "external-cli" || target.runner?.type === "external-job") {
|
|
636
|
+
const unsupported = [
|
|
637
|
+
target.tools?.length || target.mcpDirectTools?.length ? "tools" : undefined,
|
|
638
|
+
target.model ? "model" : undefined,
|
|
639
|
+
target.fallbackModels?.length ? "fallbackModels" : undefined,
|
|
640
|
+
target.thinking ? "thinking" : undefined,
|
|
641
|
+
target.extensions?.length ? "extensions" : undefined,
|
|
642
|
+
target.subagentOnlyExtensions?.length ? "subagentOnlyExtensions" : undefined,
|
|
643
|
+
target.mutationTools?.length ? "mutationTools" : undefined,
|
|
644
|
+
target.skills?.length || target.skillPath?.length ? "skills" : undefined,
|
|
645
|
+
target.maxSubagentDepth !== undefined ? "maxSubagentDepth" : undefined,
|
|
646
|
+
target.completionGuard !== undefined ? "completionGuard" : undefined,
|
|
647
|
+
target.toolBudget ? "toolBudget" : undefined
|
|
648
|
+
].filter((field) => Boolean(field));
|
|
649
|
+
if (unsupported.length > 0)
|
|
650
|
+
return `config.runner type '${target.runner.type}' does not support DM-only fields: ${unsupported.join(", ")}.`;
|
|
651
|
+
}
|
|
502
652
|
return;
|
|
503
653
|
}
|
|
504
|
-
function resolveTarget(
|
|
505
|
-
const
|
|
654
|
+
function resolveTarget(name, matches, cwd, scopeHint) {
|
|
655
|
+
const distinctNames = [...new Set(matches.map((match) => match.name))];
|
|
656
|
+
if (distinctNames.length > 1)
|
|
657
|
+
return result(`Ambiguous agent alias or name '${name}': ${distinctNames.sort((a, b) => a.localeCompare(b)).join(", ")}`, true);
|
|
658
|
+
const mutable = matches.filter((match) => isMutableSource(match.source));
|
|
506
659
|
if (mutable.length === 0) {
|
|
507
|
-
if (matches.length > 0)
|
|
508
|
-
return result(
|
|
509
|
-
}
|
|
510
|
-
const available = availableNames(cwd, kind);
|
|
511
|
-
return result(`${kind === "agent" ? "Agent" : "Chain"} '${name}' not found. Available: ${available.join(", ") || "none"}.`, true);
|
|
660
|
+
if (matches.length > 0)
|
|
661
|
+
return result(`Agent '${name}' is read-only and cannot be modified. Create a same-named agent in user or project scope to override it.`, true);
|
|
662
|
+
return result(`Agent '${name}' not found. Available: ${availableAgentNames(cwd).join(", ") || "none"}.`, true);
|
|
512
663
|
}
|
|
513
664
|
if (mutable.length === 1)
|
|
514
665
|
return mutable[0];
|
|
515
666
|
const scope = asDisambiguationScope(scopeHint);
|
|
516
667
|
if (!scope) {
|
|
517
|
-
const paths = mutable.map((
|
|
668
|
+
const paths = mutable.map((match) => `${match.source}: ${match.filePath}`).join(`
|
|
518
669
|
`);
|
|
519
|
-
return result(
|
|
670
|
+
return result(`Agent '${name}' exists in both scopes. Specify agentScope: 'user' or 'project'.
|
|
520
671
|
${paths}`, true);
|
|
521
672
|
}
|
|
522
|
-
const scoped = mutable.filter((
|
|
673
|
+
const scoped = mutable.filter((match) => match.source === scope);
|
|
523
674
|
if (scoped.length === 0)
|
|
524
|
-
return result(
|
|
675
|
+
return result(`Agent '${name}' not found in scope '${scope}'.`, true);
|
|
525
676
|
if (scoped.length > 1)
|
|
526
|
-
return result(`Multiple
|
|
677
|
+
return result(`Multiple agents named '${name}' found in scope '${scope}': ${scoped.map((match) => match.filePath).join(", ")}`, true);
|
|
527
678
|
return scoped[0];
|
|
528
679
|
}
|
|
529
|
-
function renamePath(
|
|
680
|
+
function renamePath(currentPath, newName, scope, cwd) {
|
|
530
681
|
if (nameExistsInScope(cwd, scope, newName, currentPath))
|
|
531
682
|
return { error: `Name '${newName}' already exists in ${scope} scope.` };
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
return { error: `File already exists at ${filePath} but is not a valid ${kind} definition. Remove or rename it first.` };
|
|
536
|
-
}
|
|
683
|
+
const filePath = path.join(path.dirname(currentPath), `${newName}.md`);
|
|
684
|
+
if (fs.existsSync(filePath) && filePath !== currentPath)
|
|
685
|
+
return { error: `File already exists at ${filePath} but is not a valid agent definition. Remove or rename it first.` };
|
|
537
686
|
fs.renameSync(currentPath, filePath);
|
|
538
687
|
return { filePath };
|
|
539
688
|
}
|
|
689
|
+
function packageSourceLabel(agent) {
|
|
690
|
+
if (!agent.packageSourceName)
|
|
691
|
+
return agent.source;
|
|
692
|
+
return agent.packageSourceVersion ? `${agent.packageSourceName}@${agent.packageSourceVersion}` : agent.packageSourceName;
|
|
693
|
+
}
|
|
694
|
+
function errorMessage(error) {
|
|
695
|
+
return error instanceof Error ? error.message : String(error);
|
|
696
|
+
}
|
|
697
|
+
function registeredExternalJobProviderStatus() {
|
|
698
|
+
try {
|
|
699
|
+
return { ok: true, names: new Set(listExternalJobProviders().map((provider) => provider.name)) };
|
|
700
|
+
} catch (error) {
|
|
701
|
+
return { ok: false, error: errorMessage(error) };
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
function externalJobProviderSuffix(provider, names) {
|
|
705
|
+
if (!names)
|
|
706
|
+
return "?";
|
|
707
|
+
return names.has(provider) ? "✓" : "missing";
|
|
708
|
+
}
|
|
709
|
+
function runnerListBadge(agent, providerNames) {
|
|
710
|
+
if (agent.runner?.type === "external-job")
|
|
711
|
+
return `external-job:${agent.runner.provider} ${externalJobProviderSuffix(agent.runner.provider, providerNames)}`;
|
|
712
|
+
if (agent.runner?.type === "external-cli")
|
|
713
|
+
return "external-cli";
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
function agentListMetadata(agent, providerNames) {
|
|
717
|
+
const source = agent.source === "package" ? packageSourceLabel(agent) : agent.source;
|
|
718
|
+
return [
|
|
719
|
+
source,
|
|
720
|
+
runnerListBadge(agent, providerNames),
|
|
721
|
+
agent.defaultContext ? `context: ${agent.defaultContext}` : undefined,
|
|
722
|
+
agent.aliases?.length ? `aliases: ${agent.aliases.join(", ")}` : undefined
|
|
723
|
+
].filter((part) => Boolean(part)).join(", ");
|
|
724
|
+
}
|
|
725
|
+
function formatAgentListLine(agent, providerNames) {
|
|
726
|
+
return `- ${agent.name} (${agentListMetadata(agent, providerNames)}): ${agent.description}`;
|
|
727
|
+
}
|
|
728
|
+
function formatAgentCapabilitiesLine(agent, providerNames) {
|
|
729
|
+
const declaredTools = [
|
|
730
|
+
...agent.tools ?? [],
|
|
731
|
+
...(agent.mcpDirectTools ?? []).map((tool) => `mcp:${tool}`)
|
|
732
|
+
];
|
|
733
|
+
let tools = "none";
|
|
734
|
+
if (agent.tools === undefined && agent.mcpDirectTools === undefined) {
|
|
735
|
+
tools = "default/ambient";
|
|
736
|
+
} else if (declaredTools.length > 0) {
|
|
737
|
+
tools = declaredTools.join(", ");
|
|
738
|
+
}
|
|
739
|
+
let model = "inherits current session";
|
|
740
|
+
if (agent.model !== undefined) {
|
|
741
|
+
model = agent.model;
|
|
742
|
+
if (agent.modelProvider && !agent.model.includes("/"))
|
|
743
|
+
model = `${agent.modelProvider}/${agent.model}`;
|
|
744
|
+
}
|
|
745
|
+
const thinking = agent.thinking === false ? "off" : agent.thinking ?? "default";
|
|
746
|
+
return `- ${agent.name} (${agentListMetadata(agent, providerNames)}): Description: ${previewDisplayText(agent.description, 240)}; Tools: ${tools}; Model: ${model}; Thinking: ${thinking}`;
|
|
747
|
+
}
|
|
748
|
+
const EXTERNAL_JOB_CAPABILITIES = { stop: false, steer: false, resume: false, structuredOutput: false, toolEvents: false };
|
|
749
|
+
const PI_AGENT_RUNNER = { type: "dm" };
|
|
750
|
+
function listOrEmpty(values) {
|
|
751
|
+
return values ?? [];
|
|
752
|
+
}
|
|
753
|
+
function agentCapabilityRunner(agent, providerNames) {
|
|
754
|
+
const runner = agent.runner;
|
|
755
|
+
if (!runner || runner.type === "dm")
|
|
756
|
+
return PI_AGENT_RUNNER;
|
|
757
|
+
if (runner.type === "external-cli")
|
|
758
|
+
return { type: "external-cli", adapter: runner.adapter, capabilities: resolveExternalCliRunnerStatus(runner).capabilities };
|
|
759
|
+
return { type: "external-job", provider: runner.provider, available: providerNames?.has(runner.provider), capabilities: EXTERNAL_JOB_CAPABILITIES };
|
|
760
|
+
}
|
|
761
|
+
function agentCapabilityTools(agent) {
|
|
762
|
+
return {
|
|
763
|
+
ambient: agent.tools === undefined && agent.mcpDirectTools === undefined,
|
|
764
|
+
names: listOrEmpty(agent.tools),
|
|
765
|
+
mcpDirectTools: listOrEmpty(agent.mcpDirectTools),
|
|
766
|
+
mutationTools: agent.mutationTools
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
function agentCapabilityRow(agent, options) {
|
|
770
|
+
return {
|
|
771
|
+
name: agent.name,
|
|
772
|
+
description: previewDisplayText(agent.description, 1000),
|
|
773
|
+
source: agent.source,
|
|
774
|
+
executable: options.executable,
|
|
775
|
+
restrictionSources: options.executable ? undefined : options.restrictionSources ?? [],
|
|
776
|
+
aliases: agent.aliases ? [...agent.aliases] : undefined,
|
|
777
|
+
runner: agentCapabilityRunner(agent, options.providerNames),
|
|
778
|
+
tools: agentCapabilityTools(agent),
|
|
779
|
+
model: presentDetails({ value: agent.model, fallbackModels: agent.fallbackModels, thinking: agent.thinking }),
|
|
780
|
+
execution: presentDetails({ defaultAsync: agent.defaultAsync, timeoutMs: agent.defaultTimeoutMs }),
|
|
781
|
+
output: presentDetails({ path: agent.output, mode: agent.outputMode }),
|
|
782
|
+
extensions: presentDetails({ names: agent.extensions, subagentOnly: agent.subagentOnlyExtensions, skills: agent.skills })
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
function agentCapabilitiesSnapshot(input) {
|
|
786
|
+
return {
|
|
787
|
+
agents: [
|
|
788
|
+
...input.agents.map((agent) => agentCapabilityRow(agent, { executable: true, providerNames: input.providerNames })),
|
|
789
|
+
...input.restrictedAgents.map((agent) => agentCapabilityRow(agent, { executable: false, providerNames: input.providerNames, restrictionSources: input.restrictedSources }))
|
|
790
|
+
],
|
|
791
|
+
restrictedCount: input.restrictedAgents.length,
|
|
792
|
+
...input.restrictedSources?.length ? { capabilityCeilingSources: [...input.restrictedSources] } : {}
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
function providerNames(status) {
|
|
796
|
+
return status.ok ? status.names : undefined;
|
|
797
|
+
}
|
|
798
|
+
function appendRestrictedAgentLines(input) {
|
|
799
|
+
if (input.agents.length === 0)
|
|
800
|
+
return;
|
|
801
|
+
input.lines.push("", `Restricted agents (not executable in this session${input.sources?.length ? `; capability ceiling: ${input.sources.join(", ")}` : ""}):`, ...input.agents.map((agent) => input.formatLine(agent, input.providerNames)));
|
|
802
|
+
}
|
|
803
|
+
function appendExternalJobRegistryLine(lines, agents, status) {
|
|
804
|
+
if (status.ok || !agents.some((agent) => agent.runner?.type === "external-job"))
|
|
805
|
+
return;
|
|
806
|
+
lines.push("", `External-job provider registry unavailable: ${status.error}`);
|
|
807
|
+
}
|
|
808
|
+
function appendAgentDiagnosticLines(lines, diagnostics) {
|
|
809
|
+
if (!diagnostics?.length)
|
|
810
|
+
return;
|
|
811
|
+
lines.push("", "Invalid agent definitions:", ...diagnostics.map((diagnostic) => `- ${diagnostic.name ?? diagnostic.filePath} (${diagnostic.source}): ${diagnostic.error}`));
|
|
812
|
+
}
|
|
813
|
+
function agentCapabilityDetails(input) {
|
|
814
|
+
if (!input.capabilityMode)
|
|
815
|
+
return;
|
|
816
|
+
return {
|
|
817
|
+
agentCapabilities: jsonDetails(agentCapabilitiesSnapshot({
|
|
818
|
+
agents: input.agents,
|
|
819
|
+
restrictedAgents: input.restrictedAgents,
|
|
820
|
+
providerNames: input.providerNames,
|
|
821
|
+
restrictedSources: input.restrictedSources
|
|
822
|
+
}))
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
function formatAgentListSections(agents, providerNames, formatLine = formatAgentListLine) {
|
|
826
|
+
if (agents.length === 0)
|
|
827
|
+
return ["- (none)"];
|
|
828
|
+
const sections = [
|
|
829
|
+
["package", "Package agents"],
|
|
830
|
+
["user", "User agents"],
|
|
831
|
+
["project", "Project agents"],
|
|
832
|
+
["runtime", "Runtime agents"],
|
|
833
|
+
["builtin", "Builtin agents"]
|
|
834
|
+
];
|
|
835
|
+
const lines = [];
|
|
836
|
+
for (const [source, label] of sections) {
|
|
837
|
+
const matches = agents.filter((agent) => agent.source === source);
|
|
838
|
+
if (matches.length === 0)
|
|
839
|
+
continue;
|
|
840
|
+
if (lines.length > 0)
|
|
841
|
+
lines.push("");
|
|
842
|
+
lines.push(label, ...matches.map((agent) => formatLine(agent, providerNames)));
|
|
843
|
+
}
|
|
844
|
+
return lines;
|
|
845
|
+
}
|
|
846
|
+
function formatRunnerDetail(agent, providerNames) {
|
|
847
|
+
if (!agent.runner)
|
|
848
|
+
return;
|
|
849
|
+
if (agent.runner.type === "external-job")
|
|
850
|
+
return `Runner: external-job via ${agent.runner.provider} ${externalJobProviderSuffix(agent.runner.provider, providerNames)}`;
|
|
851
|
+
if (agent.runner.type === "external-cli")
|
|
852
|
+
return `Runner: external-cli ${agent.runner.command}`;
|
|
853
|
+
return `Runner: ${JSON.stringify(agent.runner)}`;
|
|
854
|
+
}
|
|
540
855
|
function formatAgentDetail(agent) {
|
|
541
856
|
const tools = [...agent.tools ?? [], ...(agent.mcpDirectTools ?? []).map((t) => `mcp:${t}`)];
|
|
857
|
+
const providerStatus = registeredExternalJobProviderStatus();
|
|
542
858
|
const lines = [`Agent: ${agent.name} (${agent.source})`, `Path: ${agent.filePath}`, `Description: ${agent.description}`];
|
|
859
|
+
if (agent.source === "package" && agent.packageSourceName) {
|
|
860
|
+
lines.push(`Source package: ${packageSourceLabel(agent)}`);
|
|
861
|
+
if (agent.packageSourceRoot)
|
|
862
|
+
lines.push(`Package root: ${agent.packageSourceRoot}`);
|
|
863
|
+
}
|
|
543
864
|
if (agent.packageName) {
|
|
544
865
|
lines.push(`Local name: ${frontmatterNameForConfig(agent)}`);
|
|
545
866
|
lines.push(`Package: ${agent.packageName}`);
|
|
546
867
|
}
|
|
868
|
+
if (agent.aliases?.length)
|
|
869
|
+
lines.push(`Aliases: ${agent.aliases.join(", ")}`);
|
|
547
870
|
if (agent.model)
|
|
548
871
|
lines.push(`Model: ${agent.model}`);
|
|
549
872
|
if (agent.fallbackModels?.length)
|
|
@@ -552,21 +875,44 @@ function formatAgentDetail(agent) {
|
|
|
552
875
|
lines.push(`Tools: ${tools.join(", ")}`);
|
|
553
876
|
if (agent.skills?.length)
|
|
554
877
|
lines.push(`Skills: ${agent.skills.join(", ")}`);
|
|
878
|
+
if (agent.skillPath?.length)
|
|
879
|
+
lines.push(`Skill paths: ${agent.skillPath.join(", ")}`);
|
|
555
880
|
lines.push(`System prompt mode: ${agent.systemPromptMode}`);
|
|
881
|
+
const runnerDetail = formatRunnerDetail(agent, providerStatus.ok ? providerStatus.names : undefined);
|
|
882
|
+
if (runnerDetail) {
|
|
883
|
+
lines.push(runnerDetail);
|
|
884
|
+
if (agent.runner?.type === "external-job" && !providerStatus.ok)
|
|
885
|
+
lines.push(`External-job provider registry unavailable: ${providerStatus.error}`);
|
|
886
|
+
if (agent.runner?.type === "external-job" && agent.runner.options)
|
|
887
|
+
lines.push(`Runner options: ${JSON.stringify(agent.runner.options)}`);
|
|
888
|
+
}
|
|
556
889
|
lines.push(`Inherit project context: ${agent.inheritProjectContext ? "true" : "false"}`);
|
|
890
|
+
lines.push(`Inherit global context: ${agent.inheritGlobalContext ? "true" : "false"}`);
|
|
557
891
|
lines.push(`Inherit skills: ${agent.inheritSkills ? "true" : "false"}`);
|
|
558
892
|
if (agent.defaultContext)
|
|
559
893
|
lines.push(`Default context: ${agent.defaultContext}`);
|
|
894
|
+
if (agent.defaultAsync !== undefined)
|
|
895
|
+
lines.push(`Async: ${agent.defaultAsync ? "true" : "false"}`);
|
|
896
|
+
if (agent.defaultTimeoutMs !== undefined)
|
|
897
|
+
lines.push(`Timeout: ${agent.defaultTimeoutMs}ms`);
|
|
898
|
+
if (agent.defaultAcceptance !== undefined)
|
|
899
|
+
lines.push(`Acceptance: ${typeof agent.defaultAcceptance === "object" ? JSON.stringify(agent.defaultAcceptance) : String(agent.defaultAcceptance)}`);
|
|
900
|
+
if (agent.acceptanceRole)
|
|
901
|
+
lines.push(`Acceptance role: ${agent.acceptanceRole}`);
|
|
560
902
|
if (agent.source === "builtin")
|
|
561
903
|
lines.push(`Disabled: ${agent.disabled ? "true" : "false"}`);
|
|
562
904
|
if (agent.extensions !== undefined)
|
|
563
905
|
lines.push(`Extensions: ${agent.extensions.length ? agent.extensions.join(", ") : "(none)"}`);
|
|
564
906
|
if (agent.subagentOnlyExtensions !== undefined)
|
|
565
907
|
lines.push(`Subagent-only extensions: ${agent.subagentOnlyExtensions.length ? agent.subagentOnlyExtensions.join(", ") : "(none)"}`);
|
|
908
|
+
if (agent.mutationTools !== undefined)
|
|
909
|
+
lines.push(`Mutation tools: ${agent.mutationTools.length ? agent.mutationTools.join(", ") : "(none)"}`);
|
|
566
910
|
if (agent.thinking)
|
|
567
911
|
lines.push(`Thinking: ${agent.thinking}`);
|
|
568
912
|
if (agent.output)
|
|
569
913
|
lines.push(`Output: ${agent.output}`);
|
|
914
|
+
if (agent.outputMode)
|
|
915
|
+
lines.push(`Output mode: ${agent.outputMode}`);
|
|
570
916
|
if (agent.defaultReads?.length)
|
|
571
917
|
lines.push(`Reads: ${agent.defaultReads.join(", ")}`);
|
|
572
918
|
if (agent.defaultProgress)
|
|
@@ -584,103 +930,51 @@ function formatAgentDetail(agent) {
|
|
|
584
930
|
return lines.join(`
|
|
585
931
|
`);
|
|
586
932
|
}
|
|
587
|
-
function formatChainStepDetail(step, index) {
|
|
588
|
-
const lines = [];
|
|
589
|
-
if (step.expand || step.collect) {
|
|
590
|
-
const parallel = step.parallel && !Array.isArray(step.parallel) && typeof step.parallel === "object" ? step.parallel : undefined;
|
|
591
|
-
const expand = step.expand && typeof step.expand === "object" ? step.expand : undefined;
|
|
592
|
-
const collect = step.collect && typeof step.collect === "object" ? step.collect : undefined;
|
|
593
|
-
lines.push(`${index + 1}. Dynamic fanout${typeof collect?.as === "string" ? ` -> ${collect.as}` : ""}`);
|
|
594
|
-
if (expand?.from)
|
|
595
|
-
lines.push(` Expand: ${String(expand.from.output ?? "?")}${String(expand.from.path ?? "")}`);
|
|
596
|
-
if (typeof expand?.item === "string")
|
|
597
|
-
lines.push(` Item variable: ${expand.item}`);
|
|
598
|
-
if (typeof expand?.key === "string")
|
|
599
|
-
lines.push(` Key: ${expand.key}`);
|
|
600
|
-
if (typeof expand?.maxItems === "number")
|
|
601
|
-
lines.push(` Max items: ${expand.maxItems}`);
|
|
602
|
-
if (typeof expand?.onEmpty === "string")
|
|
603
|
-
lines.push(` On empty: ${expand.onEmpty}`);
|
|
604
|
-
if (parallel?.agent)
|
|
605
|
-
lines.push(` Agent: ${String(parallel.agent)}`);
|
|
606
|
-
if (typeof parallel?.label === "string")
|
|
607
|
-
lines.push(` Label: ${parallel.label}`);
|
|
608
|
-
if (typeof parallel?.task === "string" && parallel.task.trim())
|
|
609
|
-
lines.push(` Task: ${parallel.task}`);
|
|
610
|
-
if (parallel?.outputSchema)
|
|
611
|
-
lines.push(" Structured output: true");
|
|
612
|
-
if (parallel && "toolBudget" in parallel)
|
|
613
|
-
lines.push(` Tool budget: ${JSON.stringify(parallel.toolBudget)}`);
|
|
614
|
-
if (collect?.outputSchema)
|
|
615
|
-
lines.push(" Collect schema: true");
|
|
616
|
-
if (step.concurrency !== undefined)
|
|
617
|
-
lines.push(` Concurrency: ${step.concurrency}`);
|
|
618
|
-
if (step.failFast !== undefined)
|
|
619
|
-
lines.push(` Fail fast: ${step.failFast ? "true" : "false"}`);
|
|
620
|
-
return lines;
|
|
621
|
-
}
|
|
622
|
-
lines.push(`${index + 1}. ${step.agent}`);
|
|
623
|
-
if (step.task?.trim())
|
|
624
|
-
lines.push(` Task: ${step.task}`);
|
|
625
|
-
if (step.output === false)
|
|
626
|
-
lines.push(" Output: false");
|
|
627
|
-
else if (step.output)
|
|
628
|
-
lines.push(` Output: ${step.output}`);
|
|
629
|
-
if (step.outputMode)
|
|
630
|
-
lines.push(` Output mode: ${step.outputMode}`);
|
|
631
|
-
if (step.toolBudget)
|
|
632
|
-
lines.push(` Tool budget: ${JSON.stringify(step.toolBudget)}`);
|
|
633
|
-
if (step.reads === false)
|
|
634
|
-
lines.push(" Reads: false");
|
|
635
|
-
else if (Array.isArray(step.reads) && step.reads.length > 0)
|
|
636
|
-
lines.push(` Reads: ${step.reads.join(", ")}`);
|
|
637
|
-
if (step.model)
|
|
638
|
-
lines.push(` Model: ${step.model}`);
|
|
639
|
-
if (step.skills === false)
|
|
640
|
-
lines.push(" Skills: false");
|
|
641
|
-
else if (Array.isArray(step.skills) && step.skills.length > 0)
|
|
642
|
-
lines.push(` Skills: ${step.skills.join(", ")}`);
|
|
643
|
-
if (step.progress !== undefined)
|
|
644
|
-
lines.push(` Progress: ${step.progress ? "true" : "false"}`);
|
|
645
|
-
return lines;
|
|
646
|
-
}
|
|
647
|
-
function formatChainDetail(chain) {
|
|
648
|
-
const lines = [`Chain: ${chain.name} (${chain.source})`, `Path: ${chain.filePath}`, `Description: ${chain.description}`];
|
|
649
|
-
if (chain.packageName) {
|
|
650
|
-
lines.push(`Local name: ${frontmatterNameForConfig(chain)}`);
|
|
651
|
-
lines.push(`Package: ${chain.packageName}`);
|
|
652
|
-
}
|
|
653
|
-
lines.push("", "Steps:");
|
|
654
|
-
for (let i = 0;i < chain.steps.length; i++) {
|
|
655
|
-
lines.push(...formatChainStepDetail(chain.steps[i], i));
|
|
656
|
-
}
|
|
657
|
-
return lines.join(`
|
|
658
|
-
`);
|
|
659
|
-
}
|
|
660
933
|
export function handleList(params, ctx) {
|
|
661
934
|
const scope = normalizeListScope(params.agentScope) ?? "both";
|
|
662
|
-
const d = discoverAgentsAll(ctx.cwd);
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
935
|
+
const d = discoverAgentsAll(ctx.cwd, ctx.model?.provider);
|
|
936
|
+
let scopedAgents = mergeAgentsForScope(scope, d.user, d.project, d.builtin, d.package);
|
|
937
|
+
if (ctx.runtimeAgentOwner && listRuntimeAgentConfigs(ctx.runtimeAgentOwner).length > 0) {
|
|
938
|
+
const configuredAgents = [
|
|
939
|
+
...d.builtin,
|
|
940
|
+
...d.package,
|
|
941
|
+
...d.user,
|
|
942
|
+
...d.project
|
|
943
|
+
];
|
|
944
|
+
scopedAgents = mergeRuntimeAgents(ctx.runtimeAgentOwner, { agents: scopedAgents }, configuredAgents).agents;
|
|
945
|
+
}
|
|
946
|
+
scopedAgents = scopedAgents.sort((a, b) => a.name.localeCompare(b.name));
|
|
947
|
+
const capabilityCeiling = resolveCurrentSubagentCapabilityCeiling(ctx.currentSessionId);
|
|
948
|
+
const visibleAgents = scopedAgents.filter((a) => !a.disabled);
|
|
949
|
+
const agents = visibleAgents.filter((a) => isAgentAllowedByCapabilityCeiling(a.name, capabilityCeiling));
|
|
950
|
+
const restrictedAgents = visibleAgents.filter((a) => !isAgentAllowedByCapabilityCeiling(a.name, capabilityCeiling));
|
|
951
|
+
const restrictedSources = capabilityCeilingAgentRestrictionSources(capabilityCeiling);
|
|
667
952
|
const proactiveSuggestions = buildProactiveSkillSubagentRecommendationLines({
|
|
668
953
|
agents,
|
|
669
|
-
|
|
670
|
-
config: ctx.config?.proactiveSkillSubagents,
|
|
954
|
+
...ctx.config?.proactiveSkillSubagents !== undefined ? { config: ctx.config.proactiveSkillSubagents } : {},
|
|
671
955
|
discoverAvailableSkills: () => discoverAvailableSkills(ctx.cwd)
|
|
672
956
|
});
|
|
957
|
+
const providerStatus = registeredExternalJobProviderStatus();
|
|
958
|
+
const providerNameSet = providerNames(providerStatus);
|
|
959
|
+
const capabilityMode = params.capabilities === true;
|
|
960
|
+
const formatLine = capabilityMode ? formatAgentCapabilitiesLine : formatAgentListLine;
|
|
673
961
|
const lines = [
|
|
674
|
-
"Executable agents:",
|
|
675
|
-
...agents
|
|
676
|
-
"",
|
|
677
|
-
"Chains:",
|
|
678
|
-
...chains.length ? chains.map((c) => `- ${c.name} (${c.source}): ${c.description}`) : ["- (none)"],
|
|
679
|
-
...proactiveSuggestions.length ? ["", ...proactiveSuggestions] : [],
|
|
680
|
-
...diagnostics.length ? ["", "Chain diagnostics:", ...diagnostics.map((entry) => `- ${entry.filePath}: ${entry.error}`)] : []
|
|
962
|
+
capabilityMode ? "Executable agents (capabilities):" : "Executable agents:",
|
|
963
|
+
...formatAgentListSections(agents, providerNameSet, formatLine)
|
|
681
964
|
];
|
|
965
|
+
appendRestrictedAgentLines({ lines, agents: restrictedAgents, sources: restrictedSources, providerNames: providerNameSet, formatLine });
|
|
966
|
+
appendExternalJobRegistryLine(lines, [...agents, ...restrictedAgents], providerStatus);
|
|
967
|
+
appendAgentDiagnosticLines(lines, d.agentDiagnostics);
|
|
968
|
+
if (proactiveSuggestions.length)
|
|
969
|
+
lines.push("", ...proactiveSuggestions);
|
|
682
970
|
return result(lines.join(`
|
|
683
|
-
`)
|
|
971
|
+
`), false, agentCapabilityDetails({
|
|
972
|
+
capabilityMode,
|
|
973
|
+
agents,
|
|
974
|
+
restrictedAgents,
|
|
975
|
+
providerNames: providerNameSet,
|
|
976
|
+
restrictedSources
|
|
977
|
+
}));
|
|
684
978
|
}
|
|
685
979
|
function formatModelSource(agent, currentModel) {
|
|
686
980
|
if (agent.override && agent.model !== agent.override.base.model) {
|
|
@@ -700,14 +994,15 @@ function handleModels(params, ctx) {
|
|
|
700
994
|
if (requestedAgent && !BUILTIN_AGENT_NAMES.includes(requestedAgent)) {
|
|
701
995
|
return result(`Builtin agent '${requestedAgent}' not found. Available: ${BUILTIN_AGENT_NAMES.join(", ")}.`, true);
|
|
702
996
|
}
|
|
703
|
-
const discovered = discoverAgentsAll(ctx.cwd);
|
|
997
|
+
const discovered = discoverAgentsAll(ctx.cwd, ctx.model?.provider);
|
|
704
998
|
const builtinByName = new Map(discovered.builtin.map((agent) => [agent.name, agent]));
|
|
999
|
+
const resolveBuiltinModelAgent = (name) => builtinByName.get(name) ?? resolveAgentName(name, discovered.builtin).agent;
|
|
705
1000
|
const availableModels = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
706
1001
|
const currentModel = ctx.model ? { provider: ctx.model.provider, id: ctx.model.id } : undefined;
|
|
707
1002
|
const preferredProvider = ctx.model?.provider;
|
|
708
1003
|
const names = requestedAgent ? [requestedAgent] : [...BUILTIN_AGENT_NAMES];
|
|
709
1004
|
if (requestedAgent) {
|
|
710
|
-
const agent =
|
|
1005
|
+
const agent = resolveBuiltinModelAgent(requestedAgent);
|
|
711
1006
|
if (!agent)
|
|
712
1007
|
return result(`Builtin agent '${requestedAgent}' not found.`, true);
|
|
713
1008
|
const resolvedModel = resolveSubagentModelOverride(agent.model, currentModel, availableModels, preferredProvider);
|
|
@@ -742,7 +1037,7 @@ function handleModels(params, ctx) {
|
|
|
742
1037
|
""
|
|
743
1038
|
];
|
|
744
1039
|
for (const name of names) {
|
|
745
|
-
const agent =
|
|
1040
|
+
const agent = resolveBuiltinModelAgent(name);
|
|
746
1041
|
if (!agent) {
|
|
747
1042
|
lines.push(name);
|
|
748
1043
|
lines.push(" model:");
|
|
@@ -759,50 +1054,52 @@ function handleModels(params, ctx) {
|
|
|
759
1054
|
lines.push(` source: ${source}`);
|
|
760
1055
|
lines.push("");
|
|
761
1056
|
}
|
|
1057
|
+
const availableFullIds = availableModels.map((m) => m.fullId).sort();
|
|
1058
|
+
if (availableFullIds.length > 0) {
|
|
1059
|
+
lines.push("Available models in this session's registry (copy an exact provider/id when passing model):");
|
|
1060
|
+
lines.push("");
|
|
1061
|
+
const shown = availableFullIds.slice(0, 80);
|
|
1062
|
+
for (const fullId of shown)
|
|
1063
|
+
lines.push(` ${fullId}`);
|
|
1064
|
+
if (availableFullIds.length > shown.length)
|
|
1065
|
+
lines.push(` ... and ${availableFullIds.length - shown.length} more`);
|
|
1066
|
+
lines.push("");
|
|
1067
|
+
lines.push("Use an exact provider/id from this list when you pass model; bare ids resolve only when unique in the registry.");
|
|
1068
|
+
}
|
|
762
1069
|
return result(lines.join(`
|
|
763
1070
|
`));
|
|
764
1071
|
}
|
|
765
1072
|
function handleGet(params, ctx) {
|
|
766
|
-
if (!params.agent
|
|
767
|
-
return result("Specify 'agent'
|
|
768
|
-
const
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
const msg = `Chain '${params.chainName}' not found. Available: ${availableNames(ctx.cwd, "chain").join(", ") || "none"}.`;
|
|
787
|
-
if (!hasBoth)
|
|
788
|
-
return result(msg, true);
|
|
789
|
-
blocks.push(msg);
|
|
790
|
-
} else {
|
|
791
|
-
anyFound = true;
|
|
792
|
-
blocks.push(...matches.map(formatChainDetail));
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
return result(blocks.join(`
|
|
1073
|
+
if (!params.agent)
|
|
1074
|
+
return result("Specify 'agent' for get.", true);
|
|
1075
|
+
const scope = normalizeListScope(params.agentScope);
|
|
1076
|
+
if (!scope)
|
|
1077
|
+
return result("agentScope must be 'user', 'project', or 'both' for get.", true);
|
|
1078
|
+
const discovered = discoverAgentsAll(ctx.cwd, ctx.model?.provider);
|
|
1079
|
+
const matches = findAgentsInDiscovery(params.agent, discovered, scope);
|
|
1080
|
+
const diagnostics = diagnosticsForScope(discovered.agentDiagnostics, scope);
|
|
1081
|
+
const rawName = params.agent.trim();
|
|
1082
|
+
const normalizedName = sanitizeName(rawName);
|
|
1083
|
+
const diagnostic = findBlockingAgentDiagnostic(rawName, matches, diagnostics) ?? (normalizedName !== rawName ? findBlockingAgentDiagnostic(normalizedName, matches, diagnostics) : undefined);
|
|
1084
|
+
if (diagnostic)
|
|
1085
|
+
return result(`Agent '${params.agent}' has invalid configuration: ${diagnostic.error}`, true);
|
|
1086
|
+
const distinctNames = [...new Set(matches.map((agent) => agent.name))];
|
|
1087
|
+
if (distinctNames.length > 1)
|
|
1088
|
+
return result(`Ambiguous agent alias or name '${params.agent}': ${distinctNames.sort((a, b) => a.localeCompare(b)).join(", ")}`, true);
|
|
1089
|
+
if (!matches.length) {
|
|
1090
|
+
return result(`Agent '${params.agent}' not found. Available: ${availableAgentNamesFromDiscovery(discovered).join(", ") || "none"}.`, true);
|
|
1091
|
+
}
|
|
1092
|
+
return result(matches.map(formatAgentDetail).join(`
|
|
796
1093
|
|
|
797
|
-
`)
|
|
1094
|
+
`));
|
|
798
1095
|
}
|
|
799
1096
|
export function handleCreate(params, ctx) {
|
|
800
1097
|
const parsedConfig = configObject(params.config);
|
|
801
|
-
if (parsedConfig.error)
|
|
802
|
-
return result(parsedConfig.
|
|
803
|
-
|
|
804
|
-
if (!cfg)
|
|
1098
|
+
if (parsedConfig.status === "error")
|
|
1099
|
+
return result(parsedConfig.message, true);
|
|
1100
|
+
if (parsedConfig.status === "missing")
|
|
805
1101
|
return result("config required for create.", true);
|
|
1102
|
+
const cfg = parsedConfig.value;
|
|
806
1103
|
if (typeof cfg.name !== "string" || !cfg.name.trim())
|
|
807
1104
|
return result("config.name is required and must be a non-empty string.", true);
|
|
808
1105
|
if (typeof cfg.description !== "string" || !cfg.description.trim())
|
|
@@ -818,54 +1115,46 @@ export function handleCreate(params, ctx) {
|
|
|
818
1115
|
if (scopeRaw !== "user" && scopeRaw !== "project")
|
|
819
1116
|
return result("config.scope must be 'user' or 'project'.", true);
|
|
820
1117
|
const scope = scopeRaw;
|
|
821
|
-
|
|
1118
|
+
if (hasKey(cfg, "steps"))
|
|
1119
|
+
return result("Durable chain definitions were removed; use workflowScript or /prompt-workflow for repeatable workflows.", true);
|
|
822
1120
|
const d = discoverAgentsAll(ctx.cwd);
|
|
823
1121
|
const projectConfigDir = getProjectConfigDir(ctx.cwd);
|
|
824
|
-
const targetDir =
|
|
1122
|
+
const targetDir = scope === "user" ? d.userDir : d.projectDir ?? path.join(projectConfigDir, "agents");
|
|
825
1123
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
826
1124
|
if (nameExistsInScope(ctx.cwd, scope, runtimeName))
|
|
827
1125
|
return result(`Name '${runtimeName}' already exists in ${scope} scope. Use update instead.`, true);
|
|
828
|
-
const targetPath = path.join(targetDir,
|
|
1126
|
+
const targetPath = path.join(targetDir, `${runtimeName}.md`);
|
|
829
1127
|
if (fs.existsSync(targetPath))
|
|
830
|
-
return result(`File already exists at ${targetPath} but is not a valid
|
|
1128
|
+
return result(`File already exists at ${targetPath} but is not a valid agent definition. Remove or rename it first.`, true);
|
|
831
1129
|
const warnings = [];
|
|
832
|
-
if (
|
|
1130
|
+
if (d.builtin.some((a) => a.name === runtimeName))
|
|
833
1131
|
warnings.push(`Note: this shadows the builtin agent '${runtimeName}'.`);
|
|
834
|
-
if (isChain) {
|
|
835
|
-
const parsed = parseStepList(cfg.steps);
|
|
836
|
-
if (parsed.error)
|
|
837
|
-
return result(parsed.error, true);
|
|
838
|
-
const chain = { name: runtimeName, localName: name, packageName: parsedPackage.packageName, description: cfg.description.trim(), source: scope, filePath: targetPath, steps: parsed.steps };
|
|
839
|
-
fs.writeFileSync(targetPath, serializeChain(chain), "utf-8");
|
|
840
|
-
const missing = unknownChainAgents(ctx.cwd, chain.steps);
|
|
841
|
-
if (missing.length)
|
|
842
|
-
warnings.push(`Warning: chain steps reference unknown agents: ${missing.join(", ")}.`);
|
|
843
|
-
warnings.push(...chainStepWarnings(ctx, chain.steps));
|
|
844
|
-
return result([`Created chain '${runtimeName}' at ${targetPath}.`, ...warnings].join(`
|
|
845
|
-
`));
|
|
846
|
-
}
|
|
847
1132
|
const agent = {
|
|
848
1133
|
name: runtimeName,
|
|
849
1134
|
localName: name,
|
|
850
|
-
packageName: parsedPackage.packageName,
|
|
1135
|
+
...parsedPackage.packageName !== undefined ? { packageName: parsedPackage.packageName } : {},
|
|
851
1136
|
description: cfg.description.trim(),
|
|
852
1137
|
source: scope,
|
|
853
1138
|
filePath: targetPath,
|
|
854
1139
|
systemPrompt: "",
|
|
855
1140
|
systemPromptMode: defaultSystemPromptMode(name),
|
|
856
1141
|
inheritProjectContext: defaultInheritProjectContext(name),
|
|
1142
|
+
inheritGlobalContext: false,
|
|
857
1143
|
inheritSkills: defaultInheritSkills()
|
|
858
1144
|
};
|
|
859
1145
|
const applyError = applyAgentConfig(agent, cfg);
|
|
860
1146
|
if (applyError)
|
|
861
1147
|
return result(applyError, true);
|
|
1148
|
+
const profileError = validateCodeOwnedProfileRunner(agent);
|
|
1149
|
+
if (profileError)
|
|
1150
|
+
return result(profileError, true);
|
|
862
1151
|
const mw = modelWarning(ctx, agent.model);
|
|
863
1152
|
if (mw)
|
|
864
1153
|
warnings.push(mw);
|
|
865
1154
|
const fmw = fallbackModelsWarning(ctx, agent.fallbackModels);
|
|
866
1155
|
if (fmw)
|
|
867
1156
|
warnings.push(fmw);
|
|
868
|
-
const sw = skillsWarning(ctx.cwd, agent
|
|
1157
|
+
const sw = skillsWarning(ctx.cwd, agent);
|
|
869
1158
|
if (sw)
|
|
870
1159
|
warnings.push(sw);
|
|
871
1160
|
fs.writeFileSync(targetPath, serializeAgent(agent), "utf-8");
|
|
@@ -873,88 +1162,31 @@ export function handleCreate(params, ctx) {
|
|
|
873
1162
|
`));
|
|
874
1163
|
}
|
|
875
1164
|
export function handleUpdate(params, ctx) {
|
|
876
|
-
if (!params.agent
|
|
877
|
-
return result("Specify 'agent'
|
|
878
|
-
if (params.agent && params.chainName)
|
|
879
|
-
return result("Specify either 'agent' or 'chainName', not both.", true);
|
|
1165
|
+
if (!params.agent)
|
|
1166
|
+
return result("Specify 'agent' for update.", true);
|
|
880
1167
|
const parsedConfig = configObject(params.config);
|
|
881
|
-
if (parsedConfig.error)
|
|
882
|
-
return result(parsedConfig.
|
|
883
|
-
|
|
884
|
-
if (!cfg)
|
|
1168
|
+
if (parsedConfig.status === "error")
|
|
1169
|
+
return result(parsedConfig.message, true);
|
|
1170
|
+
if (parsedConfig.status === "missing")
|
|
885
1171
|
return result("config required for update.", true);
|
|
1172
|
+
const cfg = parsedConfig.value;
|
|
1173
|
+
if (hasKey(cfg, "steps"))
|
|
1174
|
+
return result("Durable chain definitions were removed; use workflowScript or /prompt-workflow for repeatable workflows.", true);
|
|
886
1175
|
const warnings = [];
|
|
887
|
-
if (params.agent) {
|
|
888
|
-
const scopeHint = asDisambiguationScope(params.agentScope);
|
|
889
|
-
const targetOrError = resolveTarget("agent", params.agent, findAgents(params.agent, ctx.cwd, scopeHint ?? "both"), ctx.cwd, params.agentScope);
|
|
890
|
-
if ("content" in targetOrError)
|
|
891
|
-
return targetOrError;
|
|
892
|
-
const target = targetOrError;
|
|
893
|
-
const updated = editableAgentConfig(target);
|
|
894
|
-
const oldName = target.name;
|
|
895
|
-
if (hasKey(cfg, "name") && (typeof cfg.name !== "string" || !cfg.name.trim()))
|
|
896
|
-
return result("config.name must be a non-empty string when provided.", true);
|
|
897
|
-
if (hasKey(cfg, "description") && (typeof cfg.description !== "string" || !cfg.description.trim()))
|
|
898
|
-
return result("config.description must be a non-empty string when provided.", true);
|
|
899
|
-
let newLocalName = target.localName ?? frontmatterNameForConfig(target);
|
|
900
|
-
if (hasKey(cfg, "name")) {
|
|
901
|
-
newLocalName = sanitizeName(cfg.name);
|
|
902
|
-
if (!newLocalName)
|
|
903
|
-
return result("config.name is invalid after sanitization.", true);
|
|
904
|
-
}
|
|
905
|
-
let newPackageName = target.packageName;
|
|
906
|
-
if (hasKey(cfg, "package")) {
|
|
907
|
-
const parsedPackage = parsePackageConfig(cfg.package);
|
|
908
|
-
if (parsedPackage.error)
|
|
909
|
-
return result(parsedPackage.error, true);
|
|
910
|
-
newPackageName = parsedPackage.packageName;
|
|
911
|
-
}
|
|
912
|
-
const applyError = applyAgentConfig(updated, cfg);
|
|
913
|
-
if (applyError)
|
|
914
|
-
return result(applyError, true);
|
|
915
|
-
const preserveFrontmatterFields = preservedAgentFrontmatterFields(target, cfg);
|
|
916
|
-
updated.localName = newLocalName;
|
|
917
|
-
updated.packageName = newPackageName;
|
|
918
|
-
updated.name = buildRuntimeName(newLocalName, newPackageName);
|
|
919
|
-
if (hasKey(cfg, "description"))
|
|
920
|
-
updated.description = cfg.description.trim();
|
|
921
|
-
if (hasKey(cfg, "model")) {
|
|
922
|
-
const mw = modelWarning(ctx, updated.model);
|
|
923
|
-
if (mw)
|
|
924
|
-
warnings.push(mw);
|
|
925
|
-
}
|
|
926
|
-
if (hasKey(cfg, "fallbackModels")) {
|
|
927
|
-
const fmw = fallbackModelsWarning(ctx, updated.fallbackModels);
|
|
928
|
-
if (fmw)
|
|
929
|
-
warnings.push(fmw);
|
|
930
|
-
}
|
|
931
|
-
if (hasKey(cfg, "skills")) {
|
|
932
|
-
const sw = skillsWarning(ctx.cwd, updated.skills);
|
|
933
|
-
if (sw)
|
|
934
|
-
warnings.push(sw);
|
|
935
|
-
}
|
|
936
|
-
if (updated.name !== oldName) {
|
|
937
|
-
const renamed = renamePath("agent", target.filePath, updated.name, target.source, ctx.cwd);
|
|
938
|
-
if (renamed.error)
|
|
939
|
-
return result(renamed.error, true);
|
|
940
|
-
updated.filePath = renamed.filePath;
|
|
941
|
-
}
|
|
942
|
-
fs.writeFileSync(updated.filePath, serializeAgent(updated, { preserveFrontmatterFields }), "utf-8");
|
|
943
|
-
if (updated.name !== oldName) {
|
|
944
|
-
const refs = discoverAgentsAll(ctx.cwd).chains.filter((c) => c.steps.some((s) => s.agent === oldName)).map((c) => `${c.name} (${c.source})`);
|
|
945
|
-
if (refs.length)
|
|
946
|
-
warnings.push(`Warning: chains still reference '${oldName}': ${refs.join(", ")}.`);
|
|
947
|
-
}
|
|
948
|
-
const headline = updated.name === oldName ? `Updated agent '${updated.name}' at ${updated.filePath}.` : `Updated agent '${oldName}' to '${updated.name}' at ${updated.filePath}.`;
|
|
949
|
-
return result([headline, ...warnings].join(`
|
|
950
|
-
`));
|
|
951
|
-
}
|
|
952
1176
|
const scopeHint = asDisambiguationScope(params.agentScope);
|
|
953
|
-
const targetOrError = resolveTarget(
|
|
1177
|
+
const targetOrError = resolveTarget(params.agent, findAgents(params.agent, ctx.cwd, scopeHint ?? "both"), ctx.cwd, scopeHint);
|
|
954
1178
|
if ("content" in targetOrError)
|
|
955
1179
|
return targetOrError;
|
|
956
1180
|
const target = targetOrError;
|
|
957
|
-
|
|
1181
|
+
if (target.source !== "user" && target.source !== "project")
|
|
1182
|
+
return result(`Cannot update ${target.source} agent '${target.name}'. Eject it to user or project scope first.`, true);
|
|
1183
|
+
let updated;
|
|
1184
|
+
try {
|
|
1185
|
+
updated = editableAgentConfig(target);
|
|
1186
|
+
} catch (error) {
|
|
1187
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1188
|
+
return result(`Could not reread agent definition ${target.filePath} before updating '${target.name}': ${message}`, true);
|
|
1189
|
+
}
|
|
958
1190
|
const oldName = target.name;
|
|
959
1191
|
if (hasKey(cfg, "name") && (typeof cfg.name !== "string" || !cfg.name.trim()))
|
|
960
1192
|
return result("config.name must be a non-empty string when provided.", true);
|
|
@@ -973,61 +1205,57 @@ export function handleUpdate(params, ctx) {
|
|
|
973
1205
|
return result(parsedPackage.error, true);
|
|
974
1206
|
newPackageName = parsedPackage.packageName;
|
|
975
1207
|
}
|
|
976
|
-
|
|
977
|
-
if (
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
return result(parsed.error, true);
|
|
981
|
-
parsedSteps = parsed.steps;
|
|
982
|
-
}
|
|
1208
|
+
const applyError = applyAgentConfig(updated, cfg);
|
|
1209
|
+
if (applyError)
|
|
1210
|
+
return result(applyError, true);
|
|
1211
|
+
const preserveFrontmatterFields = preservedAgentFrontmatterFields(target, cfg);
|
|
983
1212
|
updated.localName = newLocalName;
|
|
984
|
-
|
|
1213
|
+
if (newPackageName !== undefined)
|
|
1214
|
+
updated.packageName = newPackageName;
|
|
1215
|
+
else
|
|
1216
|
+
delete updated.packageName;
|
|
985
1217
|
updated.name = buildRuntimeName(newLocalName, newPackageName);
|
|
1218
|
+
const profileError = validateCodeOwnedProfileRunner(updated);
|
|
1219
|
+
if (profileError)
|
|
1220
|
+
return result(profileError, true);
|
|
986
1221
|
if (hasKey(cfg, "description"))
|
|
987
1222
|
updated.description = cfg.description.trim();
|
|
988
|
-
if (
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1223
|
+
if (hasKey(cfg, "model")) {
|
|
1224
|
+
const mw = modelWarning(ctx, updated.model);
|
|
1225
|
+
if (mw)
|
|
1226
|
+
warnings.push(mw);
|
|
1227
|
+
}
|
|
1228
|
+
if (hasKey(cfg, "fallbackModels")) {
|
|
1229
|
+
const fmw = fallbackModelsWarning(ctx, updated.fallbackModels);
|
|
1230
|
+
if (fmw)
|
|
1231
|
+
warnings.push(fmw);
|
|
1232
|
+
}
|
|
1233
|
+
if (hasKey(cfg, "skills") || hasKey(cfg, "skillPath")) {
|
|
1234
|
+
const sw = skillsWarning(ctx.cwd, updated);
|
|
1235
|
+
if (sw)
|
|
1236
|
+
warnings.push(sw);
|
|
994
1237
|
}
|
|
995
1238
|
if (updated.name !== oldName) {
|
|
996
|
-
const renamed = renamePath(
|
|
1239
|
+
const renamed = renamePath(target.filePath, updated.name, target.source, ctx.cwd);
|
|
997
1240
|
if (renamed.error)
|
|
998
1241
|
return result(renamed.error, true);
|
|
999
1242
|
updated.filePath = renamed.filePath;
|
|
1000
1243
|
}
|
|
1001
|
-
fs.writeFileSync(updated.filePath, updated
|
|
1002
|
-
const headline = updated.name === oldName ? `Updated
|
|
1244
|
+
fs.writeFileSync(updated.filePath, serializeAgent(updated, { preserveFrontmatterFields }), "utf-8");
|
|
1245
|
+
const headline = updated.name === oldName ? `Updated agent '${updated.name}' at ${updated.filePath}.` : `Updated agent '${oldName}' to '${updated.name}' at ${updated.filePath}.`;
|
|
1003
1246
|
return result([headline, ...warnings].join(`
|
|
1004
1247
|
`));
|
|
1005
1248
|
}
|
|
1006
1249
|
function handleDelete(params, ctx) {
|
|
1007
|
-
if (!params.agent
|
|
1008
|
-
return result("Specify 'agent'
|
|
1009
|
-
if (params.agent && params.chainName)
|
|
1010
|
-
return result("Specify either 'agent' or 'chainName', not both.", true);
|
|
1250
|
+
if (!params.agent)
|
|
1251
|
+
return result("Specify 'agent' for delete.", true);
|
|
1011
1252
|
const scopeHint = asDisambiguationScope(params.agentScope);
|
|
1012
|
-
|
|
1013
|
-
const targetOrError = resolveTarget("agent", params.agent, findAgents(params.agent, ctx.cwd, scopeHint ?? "both"), ctx.cwd, params.agentScope);
|
|
1014
|
-
if ("content" in targetOrError)
|
|
1015
|
-
return targetOrError;
|
|
1016
|
-
const target = targetOrError;
|
|
1017
|
-
fs.unlinkSync(target.filePath);
|
|
1018
|
-
const refs = discoverAgentsAll(ctx.cwd).chains.filter((c) => c.steps.some((s) => s.agent === target.name)).map((c) => `${c.name} (${c.source})`);
|
|
1019
|
-
const lines = [`Deleted agent '${target.name}' at ${target.filePath}.`];
|
|
1020
|
-
if (refs.length)
|
|
1021
|
-
lines.push(`Warning: chains reference deleted agent '${target.name}': ${refs.join(", ")}.`);
|
|
1022
|
-
return result(lines.join(`
|
|
1023
|
-
`));
|
|
1024
|
-
}
|
|
1025
|
-
const targetOrError = resolveTarget("chain", params.chainName, findChains(params.chainName, ctx.cwd, scopeHint ?? "both"), ctx.cwd, params.agentScope);
|
|
1253
|
+
const targetOrError = resolveTarget(params.agent, findAgents(params.agent, ctx.cwd, scopeHint ?? "both"), ctx.cwd, scopeHint);
|
|
1026
1254
|
if ("content" in targetOrError)
|
|
1027
1255
|
return targetOrError;
|
|
1028
1256
|
const target = targetOrError;
|
|
1029
1257
|
fs.unlinkSync(target.filePath);
|
|
1030
|
-
return result(`Deleted
|
|
1258
|
+
return result(`Deleted agent '${target.name}' at ${target.filePath}.`);
|
|
1031
1259
|
}
|
|
1032
1260
|
function handleEject(params, ctx) {
|
|
1033
1261
|
if (!params.agent)
|
|
@@ -1041,7 +1269,7 @@ function handleEject(params, ctx) {
|
|
|
1041
1269
|
const d = discoverAgentsAll(ctx.cwd);
|
|
1042
1270
|
const source = [...d.package, ...d.builtin].find((a) => a.name === raw || a.name === sanitized);
|
|
1043
1271
|
if (!source) {
|
|
1044
|
-
return result(`Agent '${raw}' not found or is not a bundled/package agent. eject copies a builtin or package agent to ${scope} scope so it can be customized. Available: ${
|
|
1272
|
+
return result(`Agent '${raw}' not found or is not a bundled/package agent. eject copies a builtin or package agent to ${scope} scope so it can be customized. Available: ${availableAgentNames(ctx.cwd).join(", ") || "none"}.`, true);
|
|
1045
1273
|
}
|
|
1046
1274
|
const runtimeName = source.name;
|
|
1047
1275
|
const existingCustom = (scope === "user" ? d.user : d.project).find((a) => a.name === runtimeName);
|
|
@@ -1049,7 +1277,7 @@ function handleEject(params, ctx) {
|
|
|
1049
1277
|
return result(`Agent '${runtimeName}' is already a custom ${scope} agent at ${existingCustom.filePath}. Edit it with { action: "update", agent: "${runtimeName}" } or delete it first.`, true);
|
|
1050
1278
|
}
|
|
1051
1279
|
if (nameExistsInScope(ctx.cwd, scope, runtimeName)) {
|
|
1052
|
-
return result(`An agent
|
|
1280
|
+
return result(`An agent named '${runtimeName}' already exists in ${scope} scope. Remove or rename it first.`, true);
|
|
1053
1281
|
}
|
|
1054
1282
|
const projectConfigDir = getProjectConfigDir(ctx.cwd);
|
|
1055
1283
|
const targetDir = scope === "user" ? d.userDir : d.projectDir ?? path.join(projectConfigDir, "agents");
|
|
@@ -1078,15 +1306,17 @@ function handleDisable(params, ctx) {
|
|
|
1078
1306
|
const scope = parsedScope.scope;
|
|
1079
1307
|
const d = discoverAgentsAll(ctx.cwd);
|
|
1080
1308
|
if (scope === "project" && d.projectSettingsPath === null) {
|
|
1081
|
-
return result("Project override is not available here: no
|
|
1309
|
+
return result("Project override is not available here: no project config root (.dm or .agents) was found above the cwd. Use agentScope: 'user' or run from inside a project.", true);
|
|
1082
1310
|
}
|
|
1083
|
-
const effective =
|
|
1084
|
-
if (
|
|
1085
|
-
return result(
|
|
1311
|
+
const effective = resolveEffectiveAgent(d, raw);
|
|
1312
|
+
if (effective.error)
|
|
1313
|
+
return result(effective.error, true);
|
|
1314
|
+
if (!effective.agent) {
|
|
1315
|
+
return result(`Agent '${raw}' not found. Available: ${availableAgentNames(ctx.cwd).join(", ") || "none"}.`, true);
|
|
1086
1316
|
}
|
|
1087
|
-
const runtimeName = effective.name;
|
|
1317
|
+
const runtimeName = effective.agent.name;
|
|
1088
1318
|
const settingsPath = mergeBuiltinAgentOverride(ctx.cwd, runtimeName, scope, { disabled: true });
|
|
1089
|
-
const after =
|
|
1319
|
+
const after = resolveEffectiveAgent(discoverAgentsAll(ctx.cwd), raw).agent;
|
|
1090
1320
|
if (after?.disabled === true) {
|
|
1091
1321
|
return result(`Disabled agent '${runtimeName}' via ${scope} settings override at ${settingsPath}. It is now hidden from runtime discovery and { action: "list" }.`);
|
|
1092
1322
|
}
|
|
@@ -1102,15 +1332,17 @@ function handleEnable(params, ctx) {
|
|
|
1102
1332
|
const scope = parsedScope.scope;
|
|
1103
1333
|
const d = discoverAgentsAll(ctx.cwd);
|
|
1104
1334
|
if (scope === "project" && d.projectSettingsPath === null) {
|
|
1105
|
-
return result("Project override is not available here: no
|
|
1335
|
+
return result("Project override is not available here: no project config root (.dm or .agents) was found above the cwd. Use agentScope: 'user' or run from inside a project.", true);
|
|
1106
1336
|
}
|
|
1107
|
-
const effective =
|
|
1108
|
-
if (
|
|
1109
|
-
return result(
|
|
1337
|
+
const effective = resolveEffectiveAgent(d, raw);
|
|
1338
|
+
if (effective.error)
|
|
1339
|
+
return result(effective.error, true);
|
|
1340
|
+
if (!effective.agent) {
|
|
1341
|
+
return result(`Agent '${raw}' not found. Available: ${availableAgentNames(ctx.cwd).join(", ") || "none"}.`, true);
|
|
1110
1342
|
}
|
|
1111
|
-
const runtimeName = effective.name;
|
|
1343
|
+
const runtimeName = effective.agent.name;
|
|
1112
1344
|
const { path: settingsPath, removed } = removeBuiltinAgentOverrideFields(ctx.cwd, runtimeName, scope, ["disabled"]);
|
|
1113
|
-
const after =
|
|
1345
|
+
const after = resolveEffectiveAgent(discoverAgentsAll(ctx.cwd), raw).agent;
|
|
1114
1346
|
if (after && after.disabled !== true) {
|
|
1115
1347
|
if (removed)
|
|
1116
1348
|
return result(`Enabled agent '${runtimeName}' (removed disabled override at ${settingsPath}).`);
|
|
@@ -1132,7 +1364,7 @@ function handleReset(params, ctx) {
|
|
|
1132
1364
|
const scope = parsedScope.scope;
|
|
1133
1365
|
const d = discoverAgentsAll(ctx.cwd);
|
|
1134
1366
|
if (scope === "project" && d.projectSettingsPath === null) {
|
|
1135
|
-
return result("Project override is not available here: no
|
|
1367
|
+
return result("Project override is not available here: no project config root (.dm or .agents) was found above the cwd. Use agentScope: 'user' or run from inside a project.", true);
|
|
1136
1368
|
}
|
|
1137
1369
|
const bundled = [...d.package, ...d.builtin].find((a) => a.name === raw || a.name === sanitized);
|
|
1138
1370
|
if (!bundled) {
|
|
@@ -1140,7 +1372,7 @@ function handleReset(params, ctx) {
|
|
|
1140
1372
|
if (custom) {
|
|
1141
1373
|
return result(`Agent '${raw}' has no bundled default to reset to. Use { action: "delete", agent: "${custom.name}" } to remove the custom ${custom.source} agent.`, true);
|
|
1142
1374
|
}
|
|
1143
|
-
return result(`Agent '${raw}' not found. Available: ${
|
|
1375
|
+
return result(`Agent '${raw}' not found. Available: ${availableAgentNames(ctx.cwd).join(", ") || "none"}.`, true);
|
|
1144
1376
|
}
|
|
1145
1377
|
const runtimeName = bundled.name;
|
|
1146
1378
|
const custom = (scope === "user" ? d.user : d.project).find((a) => a.name === raw || a.name === sanitized);
|