peaks-loop 4.1.2 → 4.1.3
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/.claude-plugin/marketplace.json +136 -47
- package/CHANGELOG.md +56 -0
- package/README-en.md +1 -1
- package/README.md +1 -1
- package/contracts/readonly-argv-whitelist.json +211 -0
- package/dist/cli/commands/audit-artifact-runners.d.ts +16 -0
- package/dist/cli/commands/audit-artifact-runners.js +170 -0
- package/dist/cli/commands/audit-command-shared.d.ts +97 -0
- package/dist/cli/commands/audit-command-shared.js +60 -0
- package/dist/cli/commands/audit-commands.d.ts +7 -31
- package/dist/cli/commands/audit-commands.js +64 -473
- package/dist/cli/commands/audit-goal-runners.d.ts +17 -0
- package/dist/cli/commands/audit-goal-runners.js +114 -0
- package/dist/cli/commands/audit-red-lines-runners.d.ts +11 -0
- package/dist/cli/commands/audit-red-lines-runners.js +43 -0
- package/dist/cli/commands/audit-refusal-data.d.ts +23 -0
- package/dist/cli/commands/audit-refusal-data.js +69 -0
- package/dist/cli/commands/audit-static-runners.d.ts +13 -0
- package/dist/cli/commands/audit-static-runners.js +139 -0
- package/dist/cli/commands/await-runners.d.ts +11 -0
- package/dist/cli/commands/await-runners.js +148 -0
- package/dist/cli/commands/code-auto-compact-command.d.ts +3 -0
- package/dist/cli/commands/code-auto-compact-command.js +124 -0
- package/dist/cli/commands/code-auto-compact-envelope.d.ts +22 -0
- package/dist/cli/commands/code-auto-compact-envelope.js +39 -0
- package/dist/cli/commands/code-context-audit-command.d.ts +3 -0
- package/dist/cli/commands/code-context-audit-command.js +68 -0
- package/dist/cli/commands/code-context-now-command.d.ts +3 -0
- package/dist/cli/commands/code-context-now-command.js +124 -0
- package/dist/cli/commands/code-context-now-envelope.d.ts +66 -0
- package/dist/cli/commands/code-context-now-envelope.js +136 -0
- package/dist/cli/commands/code-context-now-mapping.d.ts +27 -0
- package/dist/cli/commands/code-context-now-mapping.js +43 -0
- package/dist/cli/commands/code-emit-handoff-command.d.ts +3 -0
- package/dist/cli/commands/code-emit-handoff-command.js +99 -0
- package/dist/cli/commands/code-gate-step-08-command.d.ts +3 -0
- package/dist/cli/commands/code-gate-step-08-command.js +139 -0
- package/dist/cli/commands/code-post-compact-detect-command.d.ts +3 -0
- package/dist/cli/commands/code-post-compact-detect-command.js +50 -0
- package/dist/cli/commands/code-runtime-commands.d.ts +9 -43
- package/dist/cli/commands/code-runtime-commands.js +20 -672
- package/dist/cli/commands/code-runtime-session.d.ts +1 -0
- package/dist/cli/commands/code-runtime-session.js +15 -0
- package/dist/cli/commands/compact-command.d.ts +6 -2
- package/dist/cli/commands/compact-command.js +12 -559
- package/dist/cli/commands/compact-dry-run-command.d.ts +3 -0
- package/dist/cli/commands/compact-dry-run-command.js +87 -0
- package/dist/cli/commands/compact-force-command.d.ts +3 -0
- package/dist/cli/commands/compact-force-command.js +98 -0
- package/dist/cli/commands/compact-harness-window-command.d.ts +3 -0
- package/dist/cli/commands/compact-harness-window-command.js +174 -0
- package/dist/cli/commands/compact-history-command.d.ts +3 -0
- package/dist/cli/commands/compact-history-command.js +89 -0
- package/dist/cli/commands/compact-read-commands.d.ts +3 -0
- package/dist/cli/commands/compact-read-commands.js +123 -0
- package/dist/cli/commands/compact-settle-command.d.ts +3 -0
- package/dist/cli/commands/compact-settle-command.js +130 -0
- package/dist/cli/commands/compact-shared.d.ts +9 -0
- package/dist/cli/commands/compact-shared.js +26 -0
- package/dist/cli/commands/core/skill-command.d.ts +1 -44
- package/dist/cli/commands/core/skill-command.js +13 -541
- package/dist/cli/commands/core/skill-context-verdict.d.ts +38 -0
- package/dist/cli/commands/core/skill-context-verdict.js +63 -0
- package/dist/cli/commands/core/skill-generated-config-notice.d.ts +41 -0
- package/dist/cli/commands/core/skill-generated-config-notice.js +75 -0
- package/dist/cli/commands/core/skill-heartbeat-commands.d.ts +3 -0
- package/dist/cli/commands/core/skill-heartbeat-commands.js +50 -0
- package/dist/cli/commands/core/skill-presence-commands.d.ts +3 -0
- package/dist/cli/commands/core/skill-presence-commands.js +123 -0
- package/dist/cli/commands/core/skill-presence-housekeeping-commands.d.ts +3 -0
- package/dist/cli/commands/core/skill-presence-housekeeping-commands.js +165 -0
- package/dist/cli/commands/core/skill-registry-commands.d.ts +3 -0
- package/dist/cli/commands/core/skill-registry-commands.js +117 -0
- package/dist/cli/commands/core/skill-runbook-command.d.ts +3 -0
- package/dist/cli/commands/core/skill-runbook-command.js +29 -0
- package/dist/cli/commands/dispatch-command-spec.d.ts +2 -0
- package/dist/cli/commands/dispatch-command-spec.js +62 -0
- package/dist/cli/commands/dispatch-commands.js +159 -775
- package/dist/cli/commands/dispatch-detached-branch.d.ts +3 -0
- package/dist/cli/commands/dispatch-detached-branch.js +58 -0
- package/dist/cli/commands/dispatch-envelope.d.ts +36 -0
- package/dist/cli/commands/dispatch-envelope.js +104 -0
- package/dist/cli/commands/dispatch-isolation-lease.d.ts +17 -0
- package/dist/cli/commands/dispatch-isolation-lease.js +149 -0
- package/dist/cli/commands/dispatch-preflight.d.ts +7 -0
- package/dist/cli/commands/dispatch-preflight.js +105 -0
- package/dist/cli/commands/dispatch-prompt-blocks.d.ts +10 -0
- package/dist/cli/commands/dispatch-prompt-blocks.js +56 -0
- package/dist/cli/commands/dispatch-prompt-composition.d.ts +30 -0
- package/dist/cli/commands/dispatch-prompt-composition.js +171 -0
- package/dist/cli/commands/dispatch-record-write.d.ts +24 -0
- package/dist/cli/commands/dispatch-record-write.js +96 -0
- package/dist/cli/commands/dispatch-tool-call.d.ts +15 -0
- package/dist/cli/commands/dispatch-tool-call.js +128 -0
- package/dist/cli/commands/evolution-command-shared.d.ts +78 -0
- package/dist/cli/commands/evolution-command-shared.js +107 -0
- package/dist/cli/commands/evolution-commands.d.ts +11 -1
- package/dist/cli/commands/evolution-commands.js +19 -350
- package/dist/cli/commands/evolution-evaluate-command.d.ts +24 -0
- package/dist/cli/commands/evolution-evaluate-command.js +138 -0
- package/dist/cli/commands/evolution-propose-command.d.ts +23 -0
- package/dist/cli/commands/evolution-propose-command.js +145 -0
- package/dist/cli/commands/evolution-status-command.d.ts +17 -0
- package/dist/cli/commands/evolution-status-command.js +41 -0
- package/dist/cli/commands/evolution-verdict-commands.d.ts +30 -0
- package/dist/cli/commands/evolution-verdict-commands.js +100 -0
- package/dist/cli/commands/finalize-accumulator.d.ts +44 -0
- package/dist/cli/commands/finalize-accumulator.js +55 -0
- package/dist/cli/commands/finalize-branches.d.ts +34 -0
- package/dist/cli/commands/finalize-branches.js +119 -0
- package/dist/cli/commands/finalize-runners.d.ts +3 -0
- package/dist/cli/commands/finalize-runners.js +92 -0
- package/dist/cli/commands/finalize-selection.d.ts +65 -0
- package/dist/cli/commands/finalize-selection.js +35 -0
- package/dist/cli/commands/gate-commands.js +26 -8
- package/dist/cli/commands/job-checkpoint-commands.d.ts +3 -0
- package/dist/cli/commands/job-checkpoint-commands.js +157 -0
- package/dist/cli/commands/job-command-shared.d.ts +109 -0
- package/dist/cli/commands/job-command-shared.js +72 -0
- package/dist/cli/commands/job-commands.d.ts +4 -64
- package/dist/cli/commands/job-commands.js +42 -552
- package/dist/cli/commands/job-cost-check-command.d.ts +3 -0
- package/dist/cli/commands/job-cost-check-command.js +41 -0
- package/dist/cli/commands/job-init-status-commands.d.ts +3 -0
- package/dist/cli/commands/job-init-status-commands.js +149 -0
- package/dist/cli/commands/job-run-commands.d.ts +3 -0
- package/dist/cli/commands/job-run-commands.js +97 -0
- package/dist/cli/commands/job-state-root.d.ts +35 -0
- package/dist/cli/commands/job-state-root.js +76 -0
- package/dist/cli/commands/loop-eval-capture-index.d.ts +4 -0
- package/dist/cli/commands/loop-eval-capture-index.js +44 -0
- package/dist/cli/commands/loop-eval-commands.d.ts +8 -5
- package/dist/cli/commands/loop-eval-commands.js +12 -626
- package/dist/cli/commands/loop-eval-eval-command.d.ts +3 -0
- package/dist/cli/commands/loop-eval-eval-command.js +168 -0
- package/dist/cli/commands/loop-eval-monotonic-command.d.ts +3 -0
- package/dist/cli/commands/loop-eval-monotonic-command.js +90 -0
- package/dist/cli/commands/loop-eval-parents.d.ts +7 -0
- package/dist/cli/commands/loop-eval-parents.js +20 -0
- package/dist/cli/commands/loop-eval-run-code.d.ts +7 -0
- package/dist/cli/commands/loop-eval-run-code.js +40 -0
- package/dist/cli/commands/loop-eval-run-command.d.ts +3 -0
- package/dist/cli/commands/loop-eval-run-command.js +113 -0
- package/dist/cli/commands/loop-eval-spec-commands.d.ts +3 -0
- package/dist/cli/commands/loop-eval-spec-commands.js +165 -0
- package/dist/cli/commands/loop-eval-spec-lint-command.d.ts +3 -0
- package/dist/cli/commands/loop-eval-spec-lint-command.js +42 -0
- package/dist/cli/commands/loop-eval-workflow-commands.d.ts +3 -0
- package/dist/cli/commands/loop-eval-workflow-commands.js +141 -0
- package/dist/cli/commands/mcp-commands.d.ts +10 -0
- package/dist/cli/commands/mcp-commands.js +157 -0
- package/dist/cli/commands/request-command-options.d.ts +49 -0
- package/dist/cli/commands/request-command-options.js +1 -0
- package/dist/cli/commands/request-commands.d.ts +3 -9
- package/dist/cli/commands/request-commands.js +17 -522
- package/dist/cli/commands/request-init-command.d.ts +3 -0
- package/dist/cli/commands/request-init-command.js +100 -0
- package/dist/cli/commands/request-lint-command.d.ts +3 -0
- package/dist/cli/commands/request-lint-command.js +50 -0
- package/dist/cli/commands/request-list-command.d.ts +10 -0
- package/dist/cli/commands/request-list-command.js +53 -0
- package/dist/cli/commands/request-repair-status-command.d.ts +3 -0
- package/dist/cli/commands/request-repair-status-command.js +61 -0
- package/dist/cli/commands/request-show-command.d.ts +3 -0
- package/dist/cli/commands/request-show-command.js +56 -0
- package/dist/cli/commands/request-transition-command.d.ts +3 -0
- package/dist/cli/commands/request-transition-command.js +122 -0
- package/dist/cli/commands/request-transition-failures.d.ts +8 -0
- package/dist/cli/commands/request-transition-failures.js +90 -0
- package/dist/cli/commands/request-transition-hooks.d.ts +50 -0
- package/dist/cli/commands/request-transition-hooks.js +115 -0
- package/dist/cli/commands/request-transition-preflight.d.ts +10 -0
- package/dist/cli/commands/request-transition-preflight.js +107 -0
- package/dist/cli/commands/scan-command-shared.d.ts +96 -0
- package/dist/cli/commands/scan-command-shared.js +83 -0
- package/dist/cli/commands/scan-commands.d.ts +3 -2
- package/dist/cli/commands/scan-commands.js +23 -463
- package/dist/cli/commands/scan-inventory-commands.d.ts +3 -0
- package/dist/cli/commands/scan-inventory-commands.js +96 -0
- package/dist/cli/commands/scan-project-commands.d.ts +3 -0
- package/dist/cli/commands/scan-project-commands.js +65 -0
- package/dist/cli/commands/scan-scope-commands.d.ts +3 -0
- package/dist/cli/commands/scan-scope-commands.js +149 -0
- package/dist/cli/commands/scan-scope-helpers.d.ts +8 -0
- package/dist/cli/commands/scan-scope-helpers.js +54 -0
- package/dist/cli/commands/scan-structural-commands.d.ts +3 -0
- package/dist/cli/commands/scan-structural-commands.js +113 -0
- package/dist/cli/commands/share-commands.d.ts +12 -68
- package/dist/cli/commands/share-commands.js +47 -556
- package/dist/cli/commands/share-error-hints.d.ts +14 -0
- package/dist/cli/commands/share-error-hints.js +38 -0
- package/dist/cli/commands/share-identity.d.ts +13 -0
- package/dist/cli/commands/share-identity.js +22 -0
- package/dist/cli/commands/share-record-paths.d.ts +37 -0
- package/dist/cli/commands/share-record-paths.js +68 -0
- package/dist/cli/commands/share-runners.d.ts +3 -0
- package/dist/cli/commands/share-runners.js +158 -0
- package/dist/cli/commands/shared-read-runners.d.ts +3 -0
- package/dist/cli/commands/shared-read-runners.js +51 -0
- package/dist/cli/commands/slice-check-command.d.ts +3 -0
- package/dist/cli/commands/slice-check-command.js +54 -0
- package/dist/cli/commands/slice-commands.d.ts +2 -22
- package/dist/cli/commands/slice-commands.js +18 -517
- package/dist/cli/commands/slice-decompose-artifacts.d.ts +18 -0
- package/dist/cli/commands/slice-decompose-artifacts.js +79 -0
- package/dist/cli/commands/slice-decompose-command.d.ts +3 -0
- package/dist/cli/commands/slice-decompose-command.js +123 -0
- package/dist/cli/commands/slice-list-commands.d.ts +3 -0
- package/dist/cli/commands/slice-list-commands.js +182 -0
- package/dist/cli/commands/slice-pick-command.d.ts +3 -0
- package/dist/cli/commands/slice-pick-command.js +60 -0
- package/dist/cli/commands/slice-plan-command.d.ts +24 -0
- package/dist/cli/commands/slice-plan-command.js +111 -0
- package/dist/cli/commands/workflow-commands.d.ts +10 -1
- package/dist/cli/commands/workflow-commands.js +6 -594
- package/dist/cli/commands/workflow-gate-commands.d.ts +3 -0
- package/dist/cli/commands/workflow-gate-commands.js +116 -0
- package/dist/cli/commands/workflow-plan-helpers.d.ts +48 -0
- package/dist/cli/commands/workflow-plan-helpers.js +103 -0
- package/dist/cli/commands/workflow-planning-commands.d.ts +3 -0
- package/dist/cli/commands/workflow-planning-commands.js +56 -0
- package/dist/cli/commands/workflow-swarm-actions.d.ts +7 -0
- package/dist/cli/commands/workflow-swarm-actions.js +109 -0
- package/dist/cli/commands/workflow-swarm-commands.d.ts +3 -0
- package/dist/cli/commands/workflow-swarm-commands.js +138 -0
- package/dist/cli/commands/workflow-tech-actions.d.ts +10 -0
- package/dist/cli/commands/workflow-tech-actions.js +150 -0
- package/dist/cli/commands/workspace/init-actions.d.ts +10 -0
- package/dist/cli/commands/workspace/init-actions.js +199 -0
- package/dist/cli/commands/workspace/init-codegraph-stake.d.ts +10 -0
- package/dist/cli/commands/workspace/init-codegraph-stake.js +54 -0
- package/dist/cli/commands/workspace/init-command.d.ts +8 -124
- package/dist/cli/commands/workspace/init-command.js +59 -623
- package/dist/cli/commands/workspace/init-context.d.ts +58 -0
- package/dist/cli/commands/workspace/init-context.js +121 -0
- package/dist/cli/commands/workspace/init-envelope.d.ts +3 -0
- package/dist/cli/commands/workspace/init-envelope.js +34 -0
- package/dist/cli/commands/workspace/init-failures.d.ts +3 -0
- package/dist/cli/commands/workspace/init-failures.js +84 -0
- package/dist/cli/commands/workspace/init-hooks-decision.d.ts +24 -0
- package/dist/cli/commands/workspace/init-hooks-decision.js +189 -0
- package/dist/cli/commands/workspace/init-options.d.ts +102 -0
- package/dist/cli/commands/workspace/init-options.js +1 -0
- package/dist/cli/commands/worktree-lease-commands.d.ts +10 -6
- package/dist/cli/commands/worktree-lease-commands.js +42 -512
- package/dist/cli/commands/worktree-lease-gc-command.d.ts +12 -0
- package/dist/cli/commands/worktree-lease-gc-command.js +117 -0
- package/dist/cli/commands/worktree-lease-git.d.ts +22 -0
- package/dist/cli/commands/worktree-lease-git.js +48 -0
- package/dist/cli/commands/worktree-lease-list-command.d.ts +12 -0
- package/dist/cli/commands/worktree-lease-list-command.js +100 -0
- package/dist/cli/commands/worktree-lease-load.d.ts +37 -0
- package/dist/cli/commands/worktree-lease-load.js +28 -0
- package/dist/cli/commands/worktree-lease-release-command.d.ts +13 -0
- package/dist/cli/commands/worktree-lease-release-command.js +105 -0
- package/dist/cli/commands/worktree-lease-renew-command.d.ts +11 -0
- package/dist/cli/commands/worktree-lease-renew-command.js +99 -0
- package/dist/cli/commands/worktree-lease-session.d.ts +22 -0
- package/dist/cli/commands/worktree-lease-session.js +29 -0
- package/dist/cli/commands/worktree-lease-spawn-command.d.ts +11 -0
- package/dist/cli/commands/worktree-lease-spawn-command.js +119 -0
- package/dist/cli/commands/worktree-lease-status-command.d.ts +11 -0
- package/dist/cli/commands/worktree-lease-status-command.js +86 -0
- package/dist/cli/commands/worktree-lease-store.d.ts +19 -0
- package/dist/cli/commands/worktree-lease-store.js +24 -0
- package/dist/cli/program.js +5 -0
- package/dist/services/distribution/mcp-install-runner.d.ts +21 -0
- package/dist/services/distribution/mcp-install-runner.js +59 -0
- package/dist/services/distribution/mcp-install.d.ts +95 -0
- package/dist/services/distribution/mcp-install.js +179 -0
- package/dist/services/distribution/plugin-manifest.d.ts +97 -0
- package/dist/services/distribution/plugin-manifest.js +126 -0
- package/dist/services/hooks/mcp-surface-gate.d.ts +19 -0
- package/dist/services/hooks/mcp-surface-gate.js +87 -0
- package/dist/services/ide/adapters/claude-code-adapter.d.ts +4 -35
- package/dist/services/ide/adapters/claude-code-adapter.js +48 -171
- package/dist/services/ide/adapters/claude-code-local-state.d.ts +28 -0
- package/dist/services/ide/adapters/claude-code-local-state.js +112 -0
- package/dist/services/ide/adapters/claude-code-model-window.d.ts +37 -0
- package/dist/services/ide/adapters/claude-code-model-window.js +113 -0
- package/dist/services/ide/ide-mcp-install-types.d.ts +78 -0
- package/dist/services/ide/ide-mcp-install-types.js +104 -0
- package/dist/services/ide/ide-types.d.ts +45 -1
- package/dist/services/ide/mcp-tool-matcher.d.ts +34 -0
- package/dist/services/ide/mcp-tool-matcher.js +84 -0
- package/dist/services/lint/npx-resolver.js +7 -0
- package/dist/services/mcp/cli-executor.d.ts +36 -0
- package/dist/services/mcp/cli-executor.js +97 -0
- package/dist/services/mcp/json-rpc.d.ts +81 -0
- package/dist/services/mcp/json-rpc.js +116 -0
- package/dist/services/mcp/memory-tool.d.ts +3 -0
- package/dist/services/mcp/memory-tool.js +62 -0
- package/dist/services/mcp/server-main.d.ts +1 -0
- package/dist/services/mcp/server-main.js +66 -0
- package/dist/services/mcp/server.d.ts +22 -0
- package/dist/services/mcp/server.js +152 -0
- package/dist/services/mcp/surface.d.ts +62 -0
- package/dist/services/mcp/surface.js +198 -0
- package/dist/services/mcp/tool-core.d.ts +42 -0
- package/dist/services/mcp/tool-core.js +137 -0
- package/dist/services/mcp/tools.d.ts +13 -0
- package/dist/services/mcp/tools.js +58 -0
- package/dist/services/readonly-surface/argv-guard.d.ts +32 -0
- package/dist/services/readonly-surface/argv-guard.js +164 -0
- package/dist/services/readonly-surface/readonly-whitelist.d.ts +147 -0
- package/dist/services/readonly-surface/readonly-whitelist.js +107 -0
- package/dist/services/readonly-surface/whitelist-generator.d.ts +64 -0
- package/dist/services/readonly-surface/whitelist-generator.js +212 -0
- package/dist/services/skills/hooks-codegate-superpowers.d.ts +1 -0
- package/dist/services/skills/hooks-codegate-superpowers.js +26 -0
- package/dist/services/skills/hooks-settings-service.js +10 -2
- package/package.json +17 -6
- package/scripts/install-skills-bundles.mjs +233 -0
- package/scripts/install-skills-fs.mjs +148 -0
- package/scripts/install-skills-ide.mjs +279 -0
- package/scripts/install-skills-output-style-default.mjs +196 -0
- package/scripts/install-skills-output-styles.mjs +121 -0
- package/scripts/install-skills-report.mjs +42 -0
- package/scripts/install-skills-user-config.mjs +198 -0
- package/scripts/install-skills.mjs +36 -1066
- package/scripts/watch-tree.mjs +140 -0
- package/scripts/watch.mjs +4 -126
- package/skills/peaks-status/SKILL.md +31 -13
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// The prompt `peaks sub-agent dispatch` hands a sub-agent: the adapter check, the
|
|
2
|
+
// optional preflight blocks (memory / codegraph / UI library / fresh context /
|
|
3
|
+
// context probe / session capsule), the isolation and must-ls-files blocks, and the
|
|
4
|
+
// warning list the envelope carries.
|
|
5
|
+
import { fail, getErrorMessage } from 'peaks-loop-shared/result';
|
|
6
|
+
import { printResult } from '../cli-helpers.js';
|
|
7
|
+
import { detectInstalledIde } from '../../services/ide/ide-detector.js';
|
|
8
|
+
import { getAdapter } from '../../services/ide/ide-registry.js';
|
|
9
|
+
import { resolveOuterSessionId } from '../../services/session/binding-status-service.js';
|
|
10
|
+
import { loadPreferences } from '../../services/preferences/preferences-service.js';
|
|
11
|
+
import { DEFAULT_PREFERENCES } from '../../services/preferences/preferences-types.js';
|
|
12
|
+
import { MemoryPreflightService, deriveMemoryQuery } from '../../services/context/memory-preflight-service.js';
|
|
13
|
+
import { buildDispatchSystemPrompt } from '../../services/context/build-dispatch-system-prompt.js';
|
|
14
|
+
import { readSessionCapsule } from '../../services/dispatch/session-capsule.js';
|
|
15
|
+
import { computeUiLibraryDispatchBlock } from '../../services/standards/ui-library-dispatch-block.js';
|
|
16
|
+
import { readFreshContextBlock } from '../../services/fresh-context/fresh-context-block.js';
|
|
17
|
+
import { deprecatedReviewerWarnings } from './sub-agent-shared.js';
|
|
18
|
+
import { buildIsolationBlock, buildMustLsFilesBlock } from './dispatch-prompt-blocks.js';
|
|
19
|
+
// loadPreferences can throw on schema mismatch; we fall back to defaults
|
|
20
|
+
// to avoid breaking the dispatch on a stale preferences.json file.
|
|
21
|
+
function loadProjectPreferences(projectRoot) {
|
|
22
|
+
try {
|
|
23
|
+
return loadPreferences(projectRoot);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// TODO(g2): legacy silent catch — grace: 1 minor release (v2.14.0)
|
|
27
|
+
// Keep default preferences.
|
|
28
|
+
return DEFAULT_PREFERENCES;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function rejectUnsupportedIde(io, ide, role, asJson) {
|
|
32
|
+
printResult(io, fail('sub-agent.dispatch', 'IDE_NOT_SUPPORTED', `IDE ${ide} does not support role "${role}"`, { role, toolCall: null, dispatchRecordPath: null }, ['Switch to a registered IDE (e.g. claude-code) or pick a role the current IDE supports.']), asJson);
|
|
33
|
+
process.exitCode = 1;
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
// memory preflight block (or silently skip when unavailable) via the
|
|
37
|
+
// pure-function builder.
|
|
38
|
+
function loadMemoryBlock(projectRoot, projectPrefs, role, prompt) {
|
|
39
|
+
const preflightService = new MemoryPreflightService(projectRoot, projectPrefs);
|
|
40
|
+
// task at hand (role + first line of the brief), not the bare role.
|
|
41
|
+
return preflightService.fetchBlock(deriveMemoryQuery(role, prompt));
|
|
42
|
+
}
|
|
43
|
+
// codegraph preflight for RD planning. BEFORE the RD sub-agent's
|
|
44
|
+
// prompt is composed, ensure the index exists (init + index best-effort
|
|
45
|
+
// when `.codegraph/` is absent) and read a BOUNDED structure summary.
|
|
46
|
+
// `rd` only — other roles keep the legacy prompt byte-identical.
|
|
47
|
+
// Fail-soft: any failure degrades and dispatch proceeds. On failure the
|
|
48
|
+
// preflight's NOTE — the upstream cause — travels as the same value as
|
|
49
|
+
// the block, so the reason cannot be dropped while the block survives.
|
|
50
|
+
// The old `block : null` dropped it, so every degraded dispatch read as success.
|
|
51
|
+
async function loadCodegraphBlock(projectRoot, role) {
|
|
52
|
+
let codegraphBlock;
|
|
53
|
+
if (role === 'rd') {
|
|
54
|
+
try {
|
|
55
|
+
const { buildCodegraphPreflightBlock } = await import('../../services/codegraph/codegraph-preflight-service.js');
|
|
56
|
+
const preflight = await buildCodegraphPreflightBlock(projectRoot);
|
|
57
|
+
codegraphBlock = preflight.available ? preflight.block : preflight.note;
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
codegraphBlock = `codegraph preflight threw: ${getErrorMessage(error)}`;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return codegraphBlock;
|
|
64
|
+
}
|
|
65
|
+
// component library (+ CSS framework + build tool) in the RD/UI
|
|
66
|
+
// dispatch system prompt so the sub-agent prefers the library over
|
|
67
|
+
// hand-rolled native DOM. Only injected for frontend-generating roles
|
|
68
|
+
// (rd + ui) — qa/sc/txt/prd keep the legacy prompt byte-identical.
|
|
69
|
+
// Fail-soft inside the wrapper: a detection error degrades to null.
|
|
70
|
+
function loadProjectStackBlock(projectRoot, role) {
|
|
71
|
+
let projectStackBlock;
|
|
72
|
+
if (role === 'rd' || role === 'ui') {
|
|
73
|
+
projectStackBlock = computeUiLibraryDispatchBlock(projectRoot);
|
|
74
|
+
}
|
|
75
|
+
return projectStackBlock;
|
|
76
|
+
}
|
|
77
|
+
// Slice 2026-09-07-search-first-preflight: read the orchestrator-
|
|
78
|
+
// synthesized fresh-context block for rd + prd dispatches. The block
|
|
79
|
+
// was written to .peaks/_runtime/<sid>/fresh-context.md when the
|
|
80
|
+
// preflight triggered; it carries ≤5 binding directives that hedge
|
|
81
|
+
// model training-data lag. Fail-soft: a missing / unreadable file, or
|
|
82
|
+
// a file without the `## Fresh context` heading, degrades to null so
|
|
83
|
+
// the prompt stays byte-identical to the legacy shape. Other roles
|
|
84
|
+
// (qa/sc/txt/ui) keep the legacy prompt unchanged.
|
|
85
|
+
function loadFreshContextBlock(projectRoot, sid, role) {
|
|
86
|
+
let freshContextBlock;
|
|
87
|
+
if (role === 'rd' || role === 'prd') {
|
|
88
|
+
freshContextBlock = readFreshContextBlock(projectRoot, sid);
|
|
89
|
+
}
|
|
90
|
+
return freshContextBlock;
|
|
91
|
+
}
|
|
92
|
+
// authoritative context-fill probe before composing the
|
|
93
|
+
// dispatch prompt. The probe is token-counted (IDE adapter's
|
|
94
|
+
// `compact` env-var), not a byte estimate. The composer
|
|
95
|
+
// prepends a `## Context window` block so the dispatched
|
|
96
|
+
// sub-agent reads the actual ratio instead of guessing
|
|
97
|
+
// from message length (char/4 estimates diverge by 2-4x
|
|
98
|
+
// and have caused false "context too low" reports at 60%+
|
|
99
|
+
// free).
|
|
100
|
+
async function loadContextProbe(projectRoot, sid) {
|
|
101
|
+
let contextProbe = null;
|
|
102
|
+
try {
|
|
103
|
+
const { readContextPercent } = await import('../../services/context/auto-compact-reader.js');
|
|
104
|
+
const outerSessionId = resolveOuterSessionId(projectRoot, sid);
|
|
105
|
+
contextProbe = readContextPercent({
|
|
106
|
+
projectRoot,
|
|
107
|
+
sessionId: sid,
|
|
108
|
+
outerSessionId,
|
|
109
|
+
env: process.env
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// Probe is best-effort; the composer renders a
|
|
114
|
+
// "no probe available" hint instead of failing the
|
|
115
|
+
// dispatch.
|
|
116
|
+
}
|
|
117
|
+
return contextProbe;
|
|
118
|
+
}
|
|
119
|
+
async function composeMemoryAugmentedBody(input, projectPrefs) {
|
|
120
|
+
const { projectRoot, sid, rid, role, prompt } = input;
|
|
121
|
+
const memoryBlock = await loadMemoryBlock(projectRoot, projectPrefs, role, prompt);
|
|
122
|
+
const codegraphBlock = await loadCodegraphBlock(projectRoot, role);
|
|
123
|
+
const projectStackBlock = loadProjectStackBlock(projectRoot, role);
|
|
124
|
+
const freshContextBlock = loadFreshContextBlock(projectRoot, sid, role);
|
|
125
|
+
const contextProbe = await loadContextProbe(projectRoot, sid);
|
|
126
|
+
// capsule published by the orchestrator via `peaks sub-agent share`.
|
|
127
|
+
// Absent capsule → no pointer and no precedence line (byte-identical
|
|
128
|
+
// legacy prompt).
|
|
129
|
+
const capsuleRef = readSessionCapsule({ projectRoot, sid, rid });
|
|
130
|
+
return buildDispatchSystemPrompt({
|
|
131
|
+
taskTitle: role,
|
|
132
|
+
taskBody: prompt,
|
|
133
|
+
memoryBlock,
|
|
134
|
+
// unified Test Tool Detection injection for every role.
|
|
135
|
+
contextProbe,
|
|
136
|
+
// exactOptionalPropertyTypes: only set codegraphBlock when the rd
|
|
137
|
+
// preflight actually produced a value (null = attempted-unavailable,
|
|
138
|
+
// undefined = not requested → legacy prompt unchanged).
|
|
139
|
+
...(codegraphBlock !== undefined ? { codegraphBlock } : {}),
|
|
140
|
+
// Same optionality contract for the project-stack block: set only
|
|
141
|
+
// when the rd/ui detection ran (null = no library → no block,
|
|
142
|
+
// undefined = non-frontend role → legacy prompt unchanged).
|
|
143
|
+
...(projectStackBlock !== undefined ? { projectStackBlock } : {}),
|
|
144
|
+
// Same optionality contract for the fresh-context block: set only
|
|
145
|
+
// when the rd/prd read ran (null = no block on disk → no block,
|
|
146
|
+
// undefined = non-rd/prd role → legacy prompt unchanged).
|
|
147
|
+
...(freshContextBlock !== undefined ? { freshContextBlock } : {}),
|
|
148
|
+
// §4: advisory session capsule pointer + precedence line.
|
|
149
|
+
...(capsuleRef !== null
|
|
150
|
+
? {
|
|
151
|
+
capsule: { batchId: capsuleRef.batchId, key: capsuleRef.key, bytes: capsuleRef.bytes }
|
|
152
|
+
}
|
|
153
|
+
: {})
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
export async function composeDispatchPrompt(io, input) {
|
|
157
|
+
const { projectRoot, role, options, isolationMode, leaseId, worktreePath, worktreeBranch, decision, asJson } = input;
|
|
158
|
+
const projectPrefs = loadProjectPreferences(projectRoot);
|
|
159
|
+
const ide = detectInstalledIde(projectRoot) ?? 'claude-code';
|
|
160
|
+
const adapter = getAdapter(ide);
|
|
161
|
+
if (!adapter.subAgentDispatcher.supportsRole(role)) {
|
|
162
|
+
return rejectUnsupportedIde(io, ide, role, asJson);
|
|
163
|
+
}
|
|
164
|
+
const memoryAugmentedBody = await composeMemoryAugmentedBody(input, projectPrefs);
|
|
165
|
+
const isolationBlock = buildIsolationBlock(isolationMode, leaseId, worktreePath, worktreeBranch);
|
|
166
|
+
const { mustLsFilesVerification, mustLsFilesBlock } = buildMustLsFilesBlock(options, projectRoot);
|
|
167
|
+
const effectivePrompt = `${memoryAugmentedBody}${isolationBlock}${mustLsFilesBlock}`;
|
|
168
|
+
// + rerouted here, never refused — rationale on the helper itself.
|
|
169
|
+
const warnings = [...decision.warnings, ...deprecatedReviewerWarnings(role)];
|
|
170
|
+
return { adapter, effectivePrompt, warnings, mustLsFilesVerification };
|
|
171
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { noteDispatched } from '../../services/dispatch/batch-counter.js';
|
|
2
|
+
import { type ArtifactMeta } from '../../services/context/artifact-meta.js';
|
|
3
|
+
import { type SubAgentToolCall } from '../../services/dispatch/sub-agent-dispatcher.js';
|
|
4
|
+
import { type DispatchOptions } from './sub-agent-shared.js';
|
|
5
|
+
export interface WriteDispatchRecordInput {
|
|
6
|
+
options: DispatchOptions;
|
|
7
|
+
projectRoot: string;
|
|
8
|
+
sid: string;
|
|
9
|
+
rid: string;
|
|
10
|
+
role: string;
|
|
11
|
+
effectivePrompt: string;
|
|
12
|
+
toolCall: SubAgentToolCall;
|
|
13
|
+
batchId: string;
|
|
14
|
+
isolationMode: 'worktree' | 'container' | 'vm' | null;
|
|
15
|
+
leaseId: string | null;
|
|
16
|
+
/** The dispatch's warning list — this function appends to it, as the inline block did. */
|
|
17
|
+
warnings: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface DispatchRecordWrite {
|
|
20
|
+
artifactMeta: ArtifactMeta | null;
|
|
21
|
+
dispatchRecordPath: string;
|
|
22
|
+
counter: ReturnType<typeof noteDispatched>;
|
|
23
|
+
}
|
|
24
|
+
export declare function writeDispatchRecord(input: WriteDispatchRecordInput): DispatchRecordWrite;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// The `peaks sub-agent dispatch` record write: the optional G7 artifact meta, the graph
|
|
2
|
+
// node binding, the dispatch record itself, and the batch counter.
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { getErrorMessage } from 'peaks-loop-shared/result';
|
|
5
|
+
import { noteDispatched } from '../../services/dispatch/batch-counter.js';
|
|
6
|
+
import { writeInitialDispatchRecord } from '../../services/dispatch/dispatch-record-writer.js';
|
|
7
|
+
import { provisionDispatchNode } from '../../services/workflow/provision-dispatch-node.js';
|
|
8
|
+
import { buildArtifactMeta } from '../../services/context/artifact-meta.js';
|
|
9
|
+
import { assertSafeArtifactPath } from 'peaks-loop-shared-channel';
|
|
10
|
+
// G7 — optional --write-artifact: build ArtifactMeta, attach to record.
|
|
11
|
+
function resolveArtifactMeta(input) {
|
|
12
|
+
const { options, projectRoot, rid, role, warnings } = input;
|
|
13
|
+
let artifactMeta = null;
|
|
14
|
+
if (typeof options.writeArtifact === 'string' && options.writeArtifact.length > 0) {
|
|
15
|
+
try {
|
|
16
|
+
assertSafeArtifactPath(options.writeArtifact, projectRoot);
|
|
17
|
+
if (!existsSync(options.writeArtifact)) {
|
|
18
|
+
warnings.push('ARTIFACT_NOT_FOUND');
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
artifactMeta = buildArtifactMeta({
|
|
22
|
+
path: options.writeArtifact,
|
|
23
|
+
rid,
|
|
24
|
+
role,
|
|
25
|
+
idx: 1, // single dispatch, idx=1
|
|
26
|
+
summary: null
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
warnings.push(`ARTIFACT_PATH_INVALID: ${getErrorMessage(err)}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return artifactMeta;
|
|
35
|
+
}
|
|
36
|
+
// Slice 4.0.8 RD §4 D4c: bind this dispatch to a graph node. When the
|
|
37
|
+
// caller names none, provision one — that is what collapses the
|
|
38
|
+
// documented three-step ritual (create graph -> `peaks workflow node
|
|
39
|
+
// prepare` -> dispatch) into a single call. Those three fields were
|
|
40
|
+
// also never passed to the writer, so the record's graph binding was
|
|
41
|
+
// always null and the writer's transition never fired: the feature was
|
|
42
|
+
// inert, and only its precondition (the required flag) was real.
|
|
43
|
+
function resolveGraphBinding(options, projectRoot, sid, role) {
|
|
44
|
+
if (typeof options.graphNode === 'string' && options.graphNode.length > 0) {
|
|
45
|
+
return {
|
|
46
|
+
nodeId: options.graphNode,
|
|
47
|
+
workflowId: options.workflowId ?? null,
|
|
48
|
+
graphRef: options.graphRef ?? null
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const provisioned = provisionDispatchNode({
|
|
52
|
+
projectRoot,
|
|
53
|
+
sessionId: sid,
|
|
54
|
+
role,
|
|
55
|
+
workflowId: options.workflowId,
|
|
56
|
+
graphRef: options.graphRef
|
|
57
|
+
});
|
|
58
|
+
return {
|
|
59
|
+
nodeId: provisioned.nodeId,
|
|
60
|
+
workflowId: provisioned.workflowId,
|
|
61
|
+
graphRef: provisioned.graphRef
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export function writeDispatchRecord(input) {
|
|
65
|
+
const { options, projectRoot, sid, rid, role, effectivePrompt, toolCall, batchId, isolationMode, leaseId, warnings } = input;
|
|
66
|
+
const artifactMeta = resolveArtifactMeta(input);
|
|
67
|
+
const graphBinding = resolveGraphBinding(options, projectRoot, sid, role);
|
|
68
|
+
const { path: dispatchRecordPath } = writeInitialDispatchRecord({
|
|
69
|
+
projectRoot,
|
|
70
|
+
sessionId: sid,
|
|
71
|
+
requestId: rid,
|
|
72
|
+
role,
|
|
73
|
+
prompt: effectivePrompt,
|
|
74
|
+
workflowId: graphBinding.workflowId,
|
|
75
|
+
graphNodeId: graphBinding.nodeId,
|
|
76
|
+
graphRef: graphBinding.graphRef,
|
|
77
|
+
toolCall,
|
|
78
|
+
batchId,
|
|
79
|
+
// lease id on the dispatch record so the finalize-time
|
|
80
|
+
// release hook (markCompleted / heartbeat --status done) can
|
|
81
|
+
// auto-fire `peaks worktree release` when the sub-agent
|
|
82
|
+
// completes. Null when --isolation was not requested.
|
|
83
|
+
leaseId,
|
|
84
|
+
// ISO timestamp when the isolation mode was set up. Null
|
|
85
|
+
// when --isolation was not requested. The dashboard reads
|
|
86
|
+
// this directly off the dispatch record to compute
|
|
87
|
+
// isolation duration without cross-referencing the
|
|
88
|
+
// metrics stream.
|
|
89
|
+
isolationStartedAt: isolationMode !== null ? new Date().toISOString() : null
|
|
90
|
+
});
|
|
91
|
+
const counter = noteDispatched(projectRoot, sid, batchId);
|
|
92
|
+
if (counter.warning) {
|
|
93
|
+
warnings.push(counter.warning.message);
|
|
94
|
+
}
|
|
95
|
+
return { artifactMeta, dispatchRecordPath, counter };
|
|
96
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ProgramIO } from '../cli-helpers.js';
|
|
2
|
+
import { getAdapter } from '../../services/ide/ide-registry.js';
|
|
3
|
+
import { type SubAgentToolCall } from '../../services/dispatch/sub-agent-dispatcher.js';
|
|
4
|
+
export interface BuildDispatchToolCallInput {
|
|
5
|
+
adapter: ReturnType<typeof getAdapter>;
|
|
6
|
+
role: string;
|
|
7
|
+
effectivePrompt: string;
|
|
8
|
+
rid: string;
|
|
9
|
+
sid: string;
|
|
10
|
+
projectRoot: string;
|
|
11
|
+
isolationMode: 'worktree' | 'container' | 'vm' | null;
|
|
12
|
+
leaseId: string | null;
|
|
13
|
+
asJson: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function buildDispatchToolCall(io: ProgramIO, input: BuildDispatchToolCallInput): SubAgentToolCall | null;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// The tool call `peaks sub-agent dispatch` returns: built by the active adapter, then
|
|
2
|
+
// stamped with the isolation lease, the provenance token, the Playwright profile env
|
|
3
|
+
// and the observability event.
|
|
4
|
+
import { fail } from 'peaks-loop-shared/result';
|
|
5
|
+
import { printResult } from '../cli-helpers.js';
|
|
6
|
+
import { SubAgentNotSupportedError } from '../../services/dispatch/sub-agent-dispatcher.js';
|
|
7
|
+
import { emitObservabilityEvent, OBSERVABILITY_SUBAGENT_ROLES } from '../../services/observability/observability-service.js';
|
|
8
|
+
import { createDispatchProvenanceToken, DISPATCH_PROVENANCE_ENV, writeDispatchProvenance } from '../../services/worktree/dispatch-provenance.js';
|
|
9
|
+
import { playwrightProfilePaths } from '../../services/worktree/playwright-profile.js';
|
|
10
|
+
function writeWorktreeProvenance(input) {
|
|
11
|
+
const { projectRoot, sid, rid, leaseId, provenanceToken } = input;
|
|
12
|
+
writeDispatchProvenance({
|
|
13
|
+
projectRoot,
|
|
14
|
+
record: {
|
|
15
|
+
schemaVersion: 1,
|
|
16
|
+
token: provenanceToken,
|
|
17
|
+
sessionId: sid,
|
|
18
|
+
requestId: rid,
|
|
19
|
+
leaseId,
|
|
20
|
+
isolation: 'worktree',
|
|
21
|
+
issuedAt: new Date().toISOString()
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
// Part 2.C: stamp the toolCall with `isolation` + a sub-agent
|
|
26
|
+
// env block so adapters that surface it (Claude Code's Task
|
|
27
|
+
// tool) propagate the lease id to the spawned process. The
|
|
28
|
+
// env block is the canonical hook the PreToolUse gate reads
|
|
29
|
+
// (gate-commands.ts: process.env.PEAKS_WORKTREE_LEASE_ID).
|
|
30
|
+
function applyIsolationStamp(toolCall, input) {
|
|
31
|
+
const { projectRoot, sid, rid, isolationMode, leaseId } = input;
|
|
32
|
+
if (isolationMode !== null && leaseId !== null) {
|
|
33
|
+
const existingEnv = toolCall.args['env'] ?? {};
|
|
34
|
+
const provenanceToken = createDispatchProvenanceToken({
|
|
35
|
+
sessionId: sid,
|
|
36
|
+
requestId: rid,
|
|
37
|
+
leaseId
|
|
38
|
+
});
|
|
39
|
+
if (isolationMode === 'worktree') {
|
|
40
|
+
writeWorktreeProvenance({ projectRoot, sid, rid, leaseId, provenanceToken });
|
|
41
|
+
}
|
|
42
|
+
// two Playwright profile-isolation env vars so the sub-agent's
|
|
43
|
+
// browser MCP session lands in a deterministic
|
|
44
|
+
// `.peaks/_runtime/<sid>/pw-profiles/<dispatchId>/` directory
|
|
45
|
+
// (see src/services/worktree/playwright-profile.ts). Without
|
|
46
|
+
// these, concurrent dispatches share the user's default
|
|
47
|
+
// Chromium profile and corrupt cookies / localStorage.
|
|
48
|
+
const profile = playwrightProfilePaths({
|
|
49
|
+
projectRoot,
|
|
50
|
+
sessionId: sid,
|
|
51
|
+
dispatchId: rid
|
|
52
|
+
});
|
|
53
|
+
toolCall = {
|
|
54
|
+
...toolCall,
|
|
55
|
+
args: {
|
|
56
|
+
...toolCall.args,
|
|
57
|
+
isolation: isolationMode,
|
|
58
|
+
env: {
|
|
59
|
+
...existingEnv,
|
|
60
|
+
PEAKS_WORKTREE_LEASE_ID: leaseId,
|
|
61
|
+
PEAKS_PLAYWRIGHT_USER_DATA_DIR: profile.userDataDir,
|
|
62
|
+
PEAKS_PLAYWRIGHT_PROFILE_NAME: profile.profileName,
|
|
63
|
+
...(isolationMode === 'worktree' ? { [DISPATCH_PROVENANCE_ENV]: provenanceToken } : {})
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return toolCall;
|
|
69
|
+
}
|
|
70
|
+
// Slice C of v2.11.1 — observability hook #2/7. Fire-and-forget
|
|
71
|
+
// per PRD Q4 (full-auto must never fail-loud). The
|
|
72
|
+
// synchronous emit returns {written:false} on disk-full; we
|
|
73
|
+
// deliberately swallow the result so dispatch contract is
|
|
74
|
+
// unchanged. role is only included when it matches the schema's
|
|
75
|
+
// known sub-agent role set; otherwise it's omitted (non-standard
|
|
76
|
+
// roles like 'qa-business' would otherwise drop the event
|
|
77
|
+
// through schema rejection).
|
|
78
|
+
function emitDispatchObservability(input) {
|
|
79
|
+
const { adapter, role, effectivePrompt, sid, rid, projectRoot } = input;
|
|
80
|
+
const KNOWN_ROLES = new Set(OBSERVABILITY_SUBAGENT_ROLES);
|
|
81
|
+
const knownRole = KNOWN_ROLES.has(role)
|
|
82
|
+
? role
|
|
83
|
+
: null;
|
|
84
|
+
emitObservabilityEvent({
|
|
85
|
+
schemaVersion: 1,
|
|
86
|
+
ts: new Date().toISOString(),
|
|
87
|
+
sessionId: sid,
|
|
88
|
+
category: 'dispatch',
|
|
89
|
+
...(knownRole !== null ? { role: knownRole } : {}),
|
|
90
|
+
detail: {
|
|
91
|
+
requestId: rid,
|
|
92
|
+
ide: adapter.subAgentDispatcher.label,
|
|
93
|
+
promptBytes: effectivePrompt.length
|
|
94
|
+
}
|
|
95
|
+
}, { projectRoot });
|
|
96
|
+
}
|
|
97
|
+
function rejectUnsupportedAdapter(io, role, error, asJson) {
|
|
98
|
+
printResult(io, fail('sub-agent.dispatch', 'IDE_NOT_SUPPORTED', error.message, { role, toolCall: null, dispatchRecordPath: null }, ['Switch IDE or pick a role the current IDE supports.']), asJson);
|
|
99
|
+
process.exitCode = 1;
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
export function buildDispatchToolCall(io, input) {
|
|
103
|
+
const { adapter, role, effectivePrompt, rid, sid, projectRoot, isolationMode, leaseId, asJson } = input;
|
|
104
|
+
let toolCall;
|
|
105
|
+
try {
|
|
106
|
+
toolCall = adapter.subAgentDispatcher.buildToolCall({
|
|
107
|
+
role,
|
|
108
|
+
prompt: effectivePrompt,
|
|
109
|
+
requestId: rid,
|
|
110
|
+
sessionId: sid
|
|
111
|
+
});
|
|
112
|
+
toolCall = applyIsolationStamp(toolCall, {
|
|
113
|
+
projectRoot,
|
|
114
|
+
sid,
|
|
115
|
+
rid,
|
|
116
|
+
isolationMode,
|
|
117
|
+
leaseId
|
|
118
|
+
});
|
|
119
|
+
emitDispatchObservability({ adapter, role, effectivePrompt, sid, rid, projectRoot });
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
if (error instanceof SubAgentNotSupportedError) {
|
|
123
|
+
return rejectUnsupportedAdapter(io, role, error, asJson);
|
|
124
|
+
}
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
return toolCall;
|
|
128
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { EvolutionService, type EvolutionIntegrityError } from '../../services/evolution/evolution-service.js';
|
|
2
|
+
import { type EvolutionTargetKind } from '../../services/evolution/evolution-types.js';
|
|
3
|
+
import { type ProgramIO } from '../cli-helpers.js';
|
|
4
|
+
import { type ResultEnvelope } from 'peaks-loop-shared/result';
|
|
5
|
+
/** A parsed `--target <kind:id>` flag. */
|
|
6
|
+
export interface EvolutionTarget {
|
|
7
|
+
kind: EvolutionTargetKind;
|
|
8
|
+
id: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Parse `--target <kind:id>`. Returns the kind + id, or `null` on
|
|
12
|
+
* failure. Validates `kind` against the EVOLUTION_TARGET_KINDS
|
|
13
|
+
* union.
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseTargetFlag(raw: string): EvolutionTarget | null;
|
|
16
|
+
/** The shared `--target` parse failure envelope (`propose` + `status`). */
|
|
17
|
+
export declare function invalidTargetFailure(command: string, target: string): ResultEnvelope<{
|
|
18
|
+
target: string;
|
|
19
|
+
}>;
|
|
20
|
+
/** The shared "no such proposal" failure envelope. */
|
|
21
|
+
export declare function proposalNotFoundFailure(command: string, proposalId: string, nextActions: string[]): ResultEnvelope<{
|
|
22
|
+
proposalId: string;
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
* Helper: collect repeatable `--risk-tag` values into an array.
|
|
26
|
+
* Commander's `collect` is not always available; we read
|
|
27
|
+
* `previous` from the default value.
|
|
28
|
+
*/
|
|
29
|
+
export declare function collectRepeatable(value: string, previous: string[]): string[];
|
|
30
|
+
/** Upper bound of the 0..10 score scale used by proposal + evaluator scores. */
|
|
31
|
+
export declare const SCORE_SCALE_MAX = 10;
|
|
32
|
+
/** True when `value` is a finite number on the 0..10 score scale. */
|
|
33
|
+
export declare function isScoreInRange(value: number): boolean;
|
|
34
|
+
/** Inputs for {@link scoreRangeFailure}. */
|
|
35
|
+
export interface ScoreRangeFailureArgs {
|
|
36
|
+
command: string;
|
|
37
|
+
code: string;
|
|
38
|
+
/** Message label, e.g. `before_score`. */
|
|
39
|
+
label: string;
|
|
40
|
+
/** CLI flag named in the hint, e.g. `--before-score`. */
|
|
41
|
+
flag: string;
|
|
42
|
+
/** `data` key carrying the raw value, e.g. `beforeScore`. */
|
|
43
|
+
key: string;
|
|
44
|
+
/** The raw, unparsed flag value. */
|
|
45
|
+
raw: string;
|
|
46
|
+
}
|
|
47
|
+
/** The shared "[0, 10] finite number" validation failure envelope. */
|
|
48
|
+
export declare function scoreRangeFailure(args: ScoreRangeFailureArgs): ResultEnvelope<Record<string, string>>;
|
|
49
|
+
/** The `--delta-min` validation failure envelope. */
|
|
50
|
+
export declare function deltaMinFailure(command: string, raw: string): ResultEnvelope<Record<string, string>>;
|
|
51
|
+
/** Run `body` against a fresh EvolutionService, closing the DB after. */
|
|
52
|
+
export declare function withEvolutionDb<T>(project: string | undefined, body: (svc: EvolutionService) => T): T;
|
|
53
|
+
/** `await`-friendly sibling of {@link withEvolutionDb}. */
|
|
54
|
+
export declare function withEvolutionDbAsync<T>(project: string | undefined, body: (svc: EvolutionService) => Promise<T>): Promise<T>;
|
|
55
|
+
/** Params for {@link reportIntegrityFailure}. */
|
|
56
|
+
export interface IntegrityFailureReport {
|
|
57
|
+
io: ProgramIO;
|
|
58
|
+
command: string;
|
|
59
|
+
error: EvolutionIntegrityError;
|
|
60
|
+
nextActions: string[];
|
|
61
|
+
/** `options.json` — the caller's `--json` flag, possibly absent. */
|
|
62
|
+
asJson?: boolean | undefined;
|
|
63
|
+
}
|
|
64
|
+
/** Print an `EvolutionIntegrityError` envelope and set exit code 1. */
|
|
65
|
+
export declare function reportIntegrityFailure(report: IntegrityFailureReport): void;
|
|
66
|
+
/** Params for {@link reportFailure}. */
|
|
67
|
+
export interface CommandFailureReport {
|
|
68
|
+
io: ProgramIO;
|
|
69
|
+
command: string;
|
|
70
|
+
code: string;
|
|
71
|
+
error: unknown;
|
|
72
|
+
data: Record<string, unknown>;
|
|
73
|
+
nextActions: string[];
|
|
74
|
+
/** `options.json` — the caller's `--json` flag, possibly absent. */
|
|
75
|
+
asJson?: boolean | undefined;
|
|
76
|
+
}
|
|
77
|
+
/** Print a generic `<command>_FAILED` envelope and set exit code 1. */
|
|
78
|
+
export declare function reportFailure(report: CommandFailureReport): void;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helpers for the `peaks evolution *` subcommand modules
|
|
3
|
+
* (propose / evaluate / mark-keep / revert / status). Split out of
|
|
4
|
+
* `evolution-commands.ts` in the size-debt batch: every command name,
|
|
5
|
+
* option, envelope key, error code and exit-code site is unchanged.
|
|
6
|
+
*
|
|
7
|
+
* Nothing here holds module-level mutable state: each helper takes
|
|
8
|
+
* parameters and returns a value, and the DB helpers own the
|
|
9
|
+
* open/close pair so callers never see a half-closed handle.
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, mkdirSync } from 'node:fs';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
import { findProjectRoot } from '../../services/config/config-safety.js';
|
|
14
|
+
import { EvolutionService } from '../../services/evolution/evolution-service.js';
|
|
15
|
+
import { EVOLUTION_TARGET_KINDS } from '../../services/evolution/evolution-types.js';
|
|
16
|
+
import { openStateDb } from '../../services/skillhub/sqlite-store.js';
|
|
17
|
+
import { getErrorMessage, printResult } from '../cli-helpers.js';
|
|
18
|
+
import { fail } from 'peaks-loop-shared/result';
|
|
19
|
+
/**
|
|
20
|
+
* Parse `--target <kind:id>`. Returns the kind + id, or `null` on
|
|
21
|
+
* failure. Validates `kind` against the EVOLUTION_TARGET_KINDS
|
|
22
|
+
* union.
|
|
23
|
+
*/
|
|
24
|
+
export function parseTargetFlag(raw) {
|
|
25
|
+
const idx = raw.indexOf(':');
|
|
26
|
+
if (idx <= 0 || idx === raw.length - 1)
|
|
27
|
+
return null;
|
|
28
|
+
const kind = raw.slice(0, idx);
|
|
29
|
+
const id = raw.slice(idx + 1);
|
|
30
|
+
if (!EVOLUTION_TARGET_KINDS.includes(kind))
|
|
31
|
+
return null;
|
|
32
|
+
return { kind: kind, id };
|
|
33
|
+
}
|
|
34
|
+
/** The shared `--target` parse failure envelope (`propose` + `status`). */
|
|
35
|
+
export function invalidTargetFailure(command, target) {
|
|
36
|
+
return fail(command, 'EVOLUTION_INVALID_TARGET', `--target must be '<kind>:<id>' where kind ∈ {${EVOLUTION_TARGET_KINDS.join(',')}}`, { target }, ['Pass --target loop:<loop-id> or --target bee:<bee-id>.']);
|
|
37
|
+
}
|
|
38
|
+
/** The shared "no such proposal" failure envelope. */
|
|
39
|
+
export function proposalNotFoundFailure(command, proposalId, nextActions) {
|
|
40
|
+
return fail(command, 'EVOLUTION_PROPOSAL_NOT_FOUND', `proposal '${proposalId}' not found`, { proposalId }, nextActions);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Helper: collect repeatable `--risk-tag` values into an array.
|
|
44
|
+
* Commander's `collect` is not always available; we read
|
|
45
|
+
* `previous` from the default value.
|
|
46
|
+
*/
|
|
47
|
+
export function collectRepeatable(value, previous) {
|
|
48
|
+
if (Array.isArray(previous))
|
|
49
|
+
return [...previous, value];
|
|
50
|
+
return [value];
|
|
51
|
+
}
|
|
52
|
+
/** Upper bound of the 0..10 score scale used by proposal + evaluator scores. */
|
|
53
|
+
export const SCORE_SCALE_MAX = 10;
|
|
54
|
+
/** True when `value` is a finite number on the 0..10 score scale. */
|
|
55
|
+
export function isScoreInRange(value) {
|
|
56
|
+
return Number.isFinite(value) && value >= 0 && value <= SCORE_SCALE_MAX;
|
|
57
|
+
}
|
|
58
|
+
/** The shared "[0, 10] finite number" validation failure envelope. */
|
|
59
|
+
export function scoreRangeFailure(args) {
|
|
60
|
+
return fail(args.command, args.code, `${args.label} must be a finite number in [0, 10] (got "${args.raw}")`, { [args.key]: args.raw }, [`Pass a numeric ${args.flag} in [0, 10].`]);
|
|
61
|
+
}
|
|
62
|
+
/** The `--delta-min` validation failure envelope. */
|
|
63
|
+
export function deltaMinFailure(command, raw) {
|
|
64
|
+
return fail(command, 'EVOLUTION_INVALID_DELTA_MIN', `delta_min must be a finite number >= 0 (got "${raw}")`, { deltaMin: raw }, ['Pass a numeric --delta-min >= 0 (default 1.0).']);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Resolve the project root, bootstrap an empty `.peaks/` dir when it
|
|
68
|
+
* is missing (so tests do not need a full peaks project) and open the
|
|
69
|
+
* state DB.
|
|
70
|
+
*/
|
|
71
|
+
function openEvolutionDb(project) {
|
|
72
|
+
const projectRoot = project ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
73
|
+
if (!existsSync(join(projectRoot, '.peaks'))) {
|
|
74
|
+
mkdirSync(join(projectRoot, '.peaks'), { recursive: true });
|
|
75
|
+
}
|
|
76
|
+
return openStateDb(join(projectRoot, '.peaks', 'state.db'));
|
|
77
|
+
}
|
|
78
|
+
/** Run `body` against a fresh EvolutionService, closing the DB after. */
|
|
79
|
+
export function withEvolutionDb(project, body) {
|
|
80
|
+
const db = openEvolutionDb(project);
|
|
81
|
+
try {
|
|
82
|
+
return body(new EvolutionService(db));
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
db.close();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** `await`-friendly sibling of {@link withEvolutionDb}. */
|
|
89
|
+
export async function withEvolutionDbAsync(project, body) {
|
|
90
|
+
const db = openEvolutionDb(project);
|
|
91
|
+
try {
|
|
92
|
+
return await body(new EvolutionService(db));
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
db.close();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/** Print an `EvolutionIntegrityError` envelope and set exit code 1. */
|
|
99
|
+
export function reportIntegrityFailure(report) {
|
|
100
|
+
printResult(report.io, fail(report.command, report.error.code, report.error.message, { findings: report.error.findings }, report.nextActions), report.asJson);
|
|
101
|
+
process.exitCode = 1;
|
|
102
|
+
}
|
|
103
|
+
/** Print a generic `<command>_FAILED` envelope and set exit code 1. */
|
|
104
|
+
export function reportFailure(report) {
|
|
105
|
+
printResult(report.io, fail(report.command, report.code, getErrorMessage(report.error), report.data, report.nextActions), report.asJson);
|
|
106
|
+
process.exitCode = 1;
|
|
107
|
+
}
|
|
@@ -20,7 +20,17 @@
|
|
|
20
20
|
*
|
|
21
21
|
* Defense in depth: the EvolutionService enforces the ratchet
|
|
22
22
|
* into the service payload.
|
|
23
|
+
*
|
|
24
|
+
* Size-debt split: each verb's registration and action body now lives
|
|
25
|
+
* in its own sibling module — `evolution-propose-command.ts`,
|
|
26
|
+
* `evolution-evaluate-command.ts`, `evolution-verdict-commands.ts`
|
|
27
|
+
* (mark-keep + revert) and `evolution-status-command.ts` — over the
|
|
28
|
+
* shared parse / validate / DB / failure helpers in
|
|
29
|
+
* `evolution-command-shared.ts`. This file keeps the parent and the
|
|
30
|
+
* delegation only; every command name, option, envelope key, error
|
|
31
|
+
* code and exit-code site is unchanged.
|
|
23
32
|
*/
|
|
24
33
|
import type { Command } from 'commander';
|
|
25
|
-
import {
|
|
34
|
+
import type { ProgramIO } from '../cli-helpers.js';
|
|
35
|
+
export type { EvolutionTarget } from './evolution-command-shared.js';
|
|
26
36
|
export declare function registerEvolutionCommands(program: Command, io: ProgramIO): void;
|