@prestyj/cli 5.11.0 → 5.13.0
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/README.md +46 -36
- package/assets/skills/bulletproof/SKILL.md +158 -0
- package/assets/skills/bulletproof/references/agent-surface.md +82 -0
- package/assets/skills/bulletproof/references/audit-protocol.md +147 -0
- package/assets/skills/bulletproof/references/platform-playbooks.md +176 -0
- package/assets/skills/bulletproof/references/provenance.md +45 -0
- package/assets/skills/bulletproof/references/secure-defaults.md +108 -0
- package/assets/skills/bulletproof/references/supply-chain.md +76 -0
- package/assets/skills/bulletproof/references/threat-landscape.md +74 -0
- package/assets/skills/bulletproof/references/verification.md +65 -0
- package/assets/skills/compliance-guard/SKILL.md +251 -0
- package/assets/skills/compliance-guard/references/artifacts.md +186 -0
- package/assets/skills/compliance-guard/references/eu-uk.md +151 -0
- package/assets/skills/compliance-guard/references/exposure-triage.md +161 -0
- package/assets/skills/compliance-guard/references/lawsuit-vectors.md +141 -0
- package/assets/skills/compliance-guard/references/provenance.md +42 -0
- package/assets/skills/compliance-guard/references/sector-gates.md +173 -0
- package/assets/skills/compliance-guard/references/security-baseline.md +130 -0
- package/assets/skills/compliance-guard/references/trigger-map.md +163 -0
- package/assets/skills/compliance-guard/references/us.md +164 -0
- package/assets/skills/durable/SKILL.md +111 -0
- package/assets/skills/durable/references/backups-and-runtime.md +86 -0
- package/assets/skills/durable/references/migrations-and-schema.md +79 -0
- package/assets/skills/lean/SKILL.md +110 -0
- package/assets/skills/lean/references/memory-and-processes.md +98 -0
- package/assets/skills/lean/references/playbooks.md +107 -0
- package/dist/app-sidecar-auth-broadcast.test.js +111 -10
- package/dist/app-sidecar-auth-broadcast.test.js.map +1 -1
- package/dist/app-sidecar-sessions.test.js +1 -1
- package/dist/app-sidecar.js +210 -72
- package/dist/app-sidecar.js.map +1 -1
- package/dist/chat-agents/jiwa.test.js +1 -1
- package/dist/cli/auth.d.ts.map +1 -1
- package/dist/cli/auth.js +33 -36
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/mcp.js +30 -10
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +18 -5
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +28 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +50 -76
- package/dist/config.js.map +1 -1
- package/dist/config.test.js +56 -13
- package/dist/config.test.js.map +1 -1
- package/dist/core/agent-session-checkpoint-flush.test.js +2 -2
- package/dist/core/agent-session-compaction.test.js +60 -0
- package/dist/core/agent-session-compaction.test.js.map +1 -1
- package/dist/core/agent-session-crash-durability.test.js +3 -3
- package/dist/core/agent-session-model-switch.test.js +1 -1
- package/dist/core/agent-session-process-gate.test.js +7 -1
- package/dist/core/agent-session-process-gate.test.js.map +1 -1
- package/dist/core/agent-session-review-coverage.test.js +52 -1
- package/dist/core/agent-session-review-coverage.test.js.map +1 -1
- package/dist/core/agent-session-tool-tiers.test.d.ts +2 -0
- package/dist/core/agent-session-tool-tiers.test.d.ts.map +1 -0
- package/dist/core/agent-session-tool-tiers.test.js +138 -0
- package/dist/core/agent-session-tool-tiers.test.js.map +1 -0
- package/dist/core/agent-session-verification-gate.test.d.ts +2 -0
- package/dist/core/agent-session-verification-gate.test.d.ts.map +1 -0
- package/dist/core/agent-session-verification-gate.test.js +135 -0
- package/dist/core/agent-session-verification-gate.test.js.map +1 -0
- package/dist/core/agent-session.d.ts +77 -3
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +268 -33
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/agents.d.ts +29 -1
- package/dist/core/agents.d.ts.map +1 -1
- package/dist/core/agents.js +47 -97
- package/dist/core/agents.js.map +1 -1
- package/dist/core/agents.test.js +87 -7
- package/dist/core/agents.test.js.map +1 -1
- package/dist/core/api-benchmark.d.ts +3 -3
- package/dist/core/api-benchmark.js +7 -7
- package/dist/core/auth-providers.d.ts +37 -1
- package/dist/core/auth-providers.d.ts.map +1 -1
- package/dist/core/auth-providers.js +84 -4
- package/dist/core/auth-providers.js.map +1 -1
- package/dist/core/auto-update.test.js +1 -1
- package/dist/core/autopilot-gate.d.ts +2 -2
- package/dist/core/autopilot-gate.js +1 -1
- package/dist/core/autopilot-gate.test.js +7 -4
- package/dist/core/autopilot-gate.test.js.map +1 -1
- package/dist/core/bash-spawn-benchmark.js +6 -6
- package/dist/core/bundled-agents.d.ts +3 -0
- package/dist/core/bundled-agents.d.ts.map +1 -0
- package/dist/core/bundled-agents.js +255 -0
- package/dist/core/bundled-agents.js.map +1 -0
- package/dist/core/cache-warm-benchmark.d.ts +2 -2
- package/dist/core/cache-warm-benchmark.js +5 -5
- package/dist/core/code-retrieval-chunkers.d.ts +27 -0
- package/dist/core/code-retrieval-chunkers.d.ts.map +1 -0
- package/dist/core/code-retrieval-chunkers.js +264 -0
- package/dist/core/code-retrieval-chunkers.js.map +1 -0
- package/dist/core/code-retrieval-chunkers.test.d.ts +2 -0
- package/dist/core/code-retrieval-chunkers.test.d.ts.map +1 -0
- package/dist/core/code-retrieval-chunkers.test.js +203 -0
- package/dist/core/code-retrieval-chunkers.test.js.map +1 -0
- package/dist/core/code-retrieval.d.ts +6 -0
- package/dist/core/code-retrieval.d.ts.map +1 -1
- package/dist/core/code-retrieval.js +38 -1
- package/dist/core/code-retrieval.js.map +1 -1
- package/dist/core/compaction/token-estimator.test.js +1 -1
- package/dist/core/encode-cwd.test.js +1 -1
- package/dist/core/event-bus.d.ts +11 -1
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/event-bus.js +1 -0
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/event-bus.test.d.ts +2 -0
- package/dist/core/event-bus.test.d.ts.map +1 -0
- package/dist/core/event-bus.test.js +33 -0
- package/dist/core/event-bus.test.js.map +1 -0
- package/dist/core/extensions/plugin-bundles.js +2 -2
- package/dist/core/extensions/plugin-bundles.js.map +1 -1
- package/dist/core/extensions/plugin-bundles.test.js +2 -2
- package/dist/core/extensions/plugin-bundles.test.js.map +1 -1
- package/dist/core/fast-apply-benchmark.d.ts +2 -2
- package/dist/core/fast-apply-benchmark.js +6 -6
- package/dist/core/foreign-session-import.test.js +1 -1
- package/dist/core/goal-lifecycle-smoke.test.js +2 -2
- package/dist/core/goal-store.js +1 -1
- package/dist/core/goal-store.test.js +2 -2
- package/dist/core/goal-verifier.test.js +2 -2
- package/dist/core/goal-worker-dev-server-lifecycle.test.js +1 -1
- package/dist/core/goal-worker.test.js +2 -2
- package/dist/core/hashline-edit-benchmark.d.ts +2 -2
- package/dist/core/hashline-edit-benchmark.js +7 -7
- package/dist/core/local-endpoint-store.test.js +1 -1
- package/dist/core/logger.d.ts +1 -1
- package/dist/core/logger.js +2 -2
- package/dist/core/logger.js.map +1 -1
- package/dist/core/lsp/client-navigation.test.d.ts +2 -0
- package/dist/core/lsp/client-navigation.test.d.ts.map +1 -0
- package/dist/core/lsp/client-navigation.test.js +135 -0
- package/dist/core/lsp/client-navigation.test.js.map +1 -0
- package/dist/core/lsp/client.d.ts +69 -0
- package/dist/core/lsp/client.d.ts.map +1 -1
- package/dist/core/lsp/client.js +151 -2
- package/dist/core/lsp/client.js.map +1 -1
- package/dist/core/lsp/integration.test.js +2 -2
- package/dist/core/lsp/manager-navigation.test.d.ts +2 -0
- package/dist/core/lsp/manager-navigation.test.d.ts.map +1 -0
- package/dist/core/lsp/manager-navigation.test.js +121 -0
- package/dist/core/lsp/manager-navigation.test.js.map +1 -0
- package/dist/core/lsp/manager.d.ts +35 -1
- package/dist/core/lsp/manager.d.ts.map +1 -1
- package/dist/core/lsp/manager.js +92 -0
- package/dist/core/lsp/manager.js.map +1 -1
- package/dist/core/lsp/servers.test.js +1 -1
- package/dist/core/lsp/windows.test.js +4 -4
- package/dist/core/mcp/catalog-cache.test.js +1 -1
- package/dist/core/mcp/client-session-recovery.test.js +1 -1
- package/dist/core/mcp/client.d.ts.map +1 -1
- package/dist/core/mcp/client.js +2 -10
- package/dist/core/mcp/client.js.map +1 -1
- package/dist/core/mcp/content.d.ts +19 -0
- package/dist/core/mcp/content.d.ts.map +1 -0
- package/dist/core/mcp/content.js +172 -0
- package/dist/core/mcp/content.js.map +1 -0
- package/dist/core/mcp/content.test.d.ts +2 -0
- package/dist/core/mcp/content.test.d.ts.map +1 -0
- package/dist/core/mcp/content.test.js +135 -0
- package/dist/core/mcp/content.test.js.map +1 -0
- package/dist/core/mcp/defaults.d.ts +3 -1
- package/dist/core/mcp/defaults.d.ts.map +1 -1
- package/dist/core/mcp/defaults.js +9 -2
- package/dist/core/mcp/defaults.js.map +1 -1
- package/dist/core/mcp/defaults.test.d.ts +2 -0
- package/dist/core/mcp/defaults.test.d.ts.map +1 -0
- package/dist/core/mcp/defaults.test.js +60 -0
- package/dist/core/mcp/defaults.test.js.map +1 -0
- package/dist/core/mcp/deferred-catalog.d.ts +1 -1
- package/dist/core/mcp/deferred-catalog.js +1 -1
- package/dist/core/mcp/elicitation.test.js +1 -1
- package/dist/core/mcp/legacy-negotiation.test.js +2 -2
- package/dist/core/mcp/oauth-store.test.js +2 -2
- package/dist/core/mcp/resolve-stdio.test.js +5 -5
- package/dist/core/mcp/shared-pool.test.js +5 -5
- package/dist/core/mcp/store.test.js +5 -5
- package/dist/core/mcp/when-connected.test.js +2 -2
- package/dist/core/nolan-model.test.js +1 -1
- package/dist/core/nolan-prompt.js +5 -5
- package/dist/core/oauth/xai.d.ts +2 -0
- package/dist/core/oauth/xai.d.ts.map +1 -0
- package/dist/core/oauth/xai.js +4 -0
- package/dist/core/oauth/xai.js.map +1 -0
- package/dist/core/persistent-shell.js +1 -1
- package/dist/core/persistent-shell.test.js +6 -6
- package/dist/core/process-manager-dev-server-repro.test.js +51 -12
- package/dist/core/process-manager-dev-server-repro.test.js.map +1 -1
- package/dist/core/process-manager-notifications.test.js +24 -14
- package/dist/core/process-manager-notifications.test.js.map +1 -1
- package/dist/core/process-manager-wake.test.d.ts +2 -0
- package/dist/core/process-manager-wake.test.d.ts.map +1 -0
- package/dist/core/process-manager-wake.test.js +96 -0
- package/dist/core/process-manager-wake.test.js.map +1 -0
- package/dist/core/process-manager.d.ts +61 -1
- package/dist/core/process-manager.d.ts.map +1 -1
- package/dist/core/process-manager.js +204 -4
- package/dist/core/process-manager.js.map +1 -1
- package/dist/core/progress/git-xp.test.js +2 -2
- package/dist/core/progress/ranks.d.ts +14 -3
- package/dist/core/progress/ranks.d.ts.map +1 -1
- package/dist/core/progress/ranks.js +181 -12
- package/dist/core/progress/ranks.js.map +1 -1
- package/dist/core/progress/ranks.test.js +48 -7
- package/dist/core/progress/ranks.test.js.map +1 -1
- package/dist/core/progress/rebuild.test.js +1 -1
- package/dist/core/progress/store.test.js +1 -1
- package/dist/core/progress/types.d.ts +2 -1
- package/dist/core/progress/types.d.ts.map +1 -1
- package/dist/core/project-discovery.d.ts.map +1 -1
- package/dist/core/project-discovery.js +62 -48
- package/dist/core/project-discovery.js.map +1 -1
- package/dist/core/project-discovery.test.js +10 -10
- package/dist/core/prompt-commands.d.ts.map +1 -1
- package/dist/core/prompt-commands.js +3 -3
- package/dist/core/prompt-commands.js.map +1 -1
- package/dist/core/provider-cache.e2e.test.d.ts +2 -0
- package/dist/core/provider-cache.e2e.test.d.ts.map +1 -0
- package/dist/core/provider-cache.e2e.test.js +125 -0
- package/dist/core/provider-cache.e2e.test.js.map +1 -0
- package/dist/core/radio.d.ts +1 -1
- package/dist/core/radio.d.ts.map +1 -1
- package/dist/core/radio.js +90 -6
- package/dist/core/radio.js.map +1 -1
- package/dist/core/radio.test.js +15 -2
- package/dist/core/radio.test.js.map +1 -1
- package/dist/core/run-journal.test.js +2 -2
- package/dist/core/sandbox.test.js +6 -6
- package/dist/core/semantic-search-benchmark.d.ts +2 -2
- package/dist/core/semantic-search-benchmark.js +5 -5
- package/dist/core/session-compaction.test.js +1 -1
- package/dist/core/session-injections.test.d.ts +2 -0
- package/dist/core/session-injections.test.d.ts.map +1 -0
- package/dist/core/session-injections.test.js +117 -0
- package/dist/core/session-injections.test.js.map +1 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +83 -67
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-manager.test.js +7 -7
- package/dist/core/session-reconstructability.test.d.ts +2 -0
- package/dist/core/session-reconstructability.test.d.ts.map +1 -0
- package/dist/core/session-reconstructability.test.js +105 -0
- package/dist/core/session-reconstructability.test.js.map +1 -0
- package/dist/core/session-storage-fd-leak.test.d.ts +2 -0
- package/dist/core/session-storage-fd-leak.test.d.ts.map +1 -0
- package/dist/core/session-storage-fd-leak.test.js +116 -0
- package/dist/core/session-storage-fd-leak.test.js.map +1 -0
- package/dist/core/session-storage.d.ts +22 -2
- package/dist/core/session-storage.d.ts.map +1 -1
- package/dist/core/session-storage.js +33 -6
- package/dist/core/session-storage.js.map +1 -1
- package/dist/core/session-storage.test.js +2 -2
- package/dist/core/settings-manager.d.ts +12 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +46 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/shell-path.js +1 -1
- package/dist/core/shell.d.ts +1 -1
- package/dist/core/shell.js +2 -2
- package/dist/core/shell.test.js +2 -2
- package/dist/core/shutdown.d.ts +71 -0
- package/dist/core/shutdown.d.ts.map +1 -0
- package/dist/core/shutdown.js +144 -0
- package/dist/core/shutdown.js.map +1 -0
- package/dist/core/shutdown.test.d.ts +2 -0
- package/dist/core/shutdown.test.d.ts.map +1 -0
- package/dist/core/shutdown.test.js +160 -0
- package/dist/core/shutdown.test.js.map +1 -0
- package/dist/core/sidecar-error-reporter.js +1 -1
- package/dist/core/sidecar-error-reporter.test.js +2 -2
- package/dist/core/skills-routing.test.js +142 -0
- package/dist/core/skills-routing.test.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +4 -1
- package/dist/core/skills.js.map +1 -1
- package/dist/core/subagent-manager.d.ts +9 -0
- package/dist/core/subagent-manager.d.ts.map +1 -1
- package/dist/core/subagent-manager.js +45 -12
- package/dist/core/subagent-manager.js.map +1 -1
- package/dist/core/subagent-manager.test.js +14 -8
- package/dist/core/subagent-manager.test.js.map +1 -1
- package/dist/core/subagent-store.test.js +3 -3
- package/dist/core/task-store.js +1 -1
- package/dist/core/verification-gate.d.ts +55 -0
- package/dist/core/verification-gate.d.ts.map +1 -0
- package/dist/core/verification-gate.js +188 -0
- package/dist/core/verification-gate.js.map +1 -0
- package/dist/core/verification-gate.test.d.ts +2 -0
- package/dist/core/verification-gate.test.d.ts.map +1 -0
- package/dist/core/verification-gate.test.js +102 -0
- package/dist/core/verification-gate.test.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/acp-mode.js +2 -2
- package/dist/modes/acp-mode.test.js +10 -8
- package/dist/modes/acp-mode.test.js.map +1 -1
- package/dist/modes/agent-home-mode.d.ts.map +1 -1
- package/dist/modes/agent-home-mode.js +15 -11
- package/dist/modes/agent-home-mode.js.map +1 -1
- package/dist/modes/json-mode.d.ts +9 -1
- package/dist/modes/json-mode.d.ts.map +1 -1
- package/dist/modes/json-mode.js +3 -1
- package/dist/modes/json-mode.js.map +1 -1
- package/dist/modes/serve-mode.d.ts +1 -1
- package/dist/modes/serve-mode.d.ts.map +1 -1
- package/dist/modes/serve-mode.js +14 -9
- package/dist/modes/serve-mode.js.map +1 -1
- package/dist/modes/subagent-worker-mode.d.ts +5 -0
- package/dist/modes/subagent-worker-mode.d.ts.map +1 -1
- package/dist/modes/subagent-worker-mode.js.map +1 -1
- package/dist/session.test.js +1 -1
- package/dist/system-prompt.d.ts +37 -1
- package/dist/system-prompt.d.ts.map +1 -1
- package/dist/system-prompt.js +170 -12
- package/dist/system-prompt.js.map +1 -1
- package/dist/system-prompt.test.js +170 -11
- package/dist/system-prompt.test.js.map +1 -1
- package/dist/system-prompt.tiering.test.d.ts +2 -0
- package/dist/system-prompt.tiering.test.d.ts.map +1 -0
- package/dist/system-prompt.tiering.test.js +108 -0
- package/dist/system-prompt.tiering.test.js.map +1 -0
- package/dist/tools/bash.d.ts +4 -0
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +57 -3
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/bash.test.js +37 -0
- package/dist/tools/bash.test.js.map +1 -1
- package/dist/tools/code-nav.d.ts +30 -0
- package/dist/tools/code-nav.d.ts.map +1 -0
- package/dist/tools/code-nav.js +320 -0
- package/dist/tools/code-nav.js.map +1 -0
- package/dist/tools/code-nav.test.d.ts +2 -0
- package/dist/tools/code-nav.test.d.ts.map +1 -0
- package/dist/tools/code-nav.test.js +136 -0
- package/dist/tools/code-nav.test.js.map +1 -0
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +37 -4
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/edit.test.js +45 -1
- package/dist/tools/edit.test.js.map +1 -1
- package/dist/tools/generate-image.d.ts +1 -1
- package/dist/tools/goals.d.ts +2 -2
- package/dist/tools/goals.test.js +2 -2
- package/dist/tools/grep-parity.test.d.ts +2 -0
- package/dist/tools/grep-parity.test.d.ts.map +1 -0
- package/dist/tools/grep-parity.test.js +92 -0
- package/dist/tools/grep-parity.test.js.map +1 -0
- package/dist/tools/grep-recall.test.d.ts +2 -0
- package/dist/tools/grep-recall.test.d.ts.map +1 -0
- package/dist/tools/grep-recall.test.js +114 -0
- package/dist/tools/grep-recall.test.js.map +1 -0
- package/dist/tools/grep-spawn.test.d.ts +2 -0
- package/dist/tools/grep-spawn.test.d.ts.map +1 -0
- package/dist/tools/grep-spawn.test.js +66 -0
- package/dist/tools/grep-spawn.test.js.map +1 -0
- package/dist/tools/grep.d.ts +13 -3
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +340 -40
- package/dist/tools/grep.js.map +1 -1
- package/dist/tools/grep.test.js +17 -14
- package/dist/tools/grep.test.js.map +1 -1
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +8 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/plan-mode.test.js +1 -1
- package/dist/tools/prompt-hints.d.ts +9 -0
- package/dist/tools/prompt-hints.d.ts.map +1 -1
- package/dist/tools/prompt-hints.js +62 -8
- package/dist/tools/prompt-hints.js.map +1 -1
- package/dist/tools/read-only-bash.d.ts +6 -0
- package/dist/tools/read-only-bash.d.ts.map +1 -1
- package/dist/tools/read-only-bash.js +168 -9
- package/dist/tools/read-only-bash.js.map +1 -1
- package/dist/tools/read-only-bash.test.js +49 -0
- package/dist/tools/read-only-bash.test.js.map +1 -1
- package/dist/tools/safe-env.js +1 -1
- package/dist/tools/search-code.d.ts.map +1 -1
- package/dist/tools/search-code.js +7 -6
- package/dist/tools/search-code.js.map +1 -1
- package/dist/tools/search-code.test.js +8 -2
- package/dist/tools/search-code.test.js.map +1 -1
- package/dist/tools/skill.js +3 -1
- package/dist/tools/skill.js.map +1 -1
- package/dist/tools/subagent-control.d.ts.map +1 -1
- package/dist/tools/subagent-control.js +20 -5
- package/dist/tools/subagent-control.js.map +1 -1
- package/dist/tools/subagent-control.test.js +34 -1
- package/dist/tools/subagent-control.test.js.map +1 -1
- package/dist/tools/subagent-shared.d.ts +20 -1
- package/dist/tools/subagent-shared.d.ts.map +1 -1
- package/dist/tools/subagent-shared.js +34 -7
- package/dist/tools/subagent-shared.js.map +1 -1
- package/dist/tools/subagent-shared.test.js +43 -9
- package/dist/tools/subagent-shared.test.js.map +1 -1
- package/dist/tools/subagent.d.ts.map +1 -1
- package/dist/tools/subagent.js +11 -8
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/subagent.test.js +3 -0
- package/dist/tools/subagent.test.js.map +1 -1
- package/dist/tools/task-send.test.js +19 -10
- package/dist/tools/task-send.test.js.map +1 -1
- package/dist/tools/tool-catalog.test.d.ts +2 -0
- package/dist/tools/tool-catalog.test.d.ts.map +1 -0
- package/dist/tools/tool-catalog.test.js +124 -0
- package/dist/tools/tool-catalog.test.js.map +1 -0
- package/dist/tools/tool-search.d.ts.map +1 -1
- package/dist/tools/tool-search.js +2 -1
- package/dist/tools/tool-search.js.map +1 -1
- package/dist/tools/tool-tiers.d.ts +42 -0
- package/dist/tools/tool-tiers.d.ts.map +1 -0
- package/dist/tools/tool-tiers.js +78 -0
- package/dist/tools/tool-tiers.js.map +1 -0
- package/dist/tools/tool-tiers.test.d.ts +2 -0
- package/dist/tools/tool-tiers.test.d.ts.map +1 -0
- package/dist/tools/tool-tiers.test.js +48 -0
- package/dist/tools/tool-tiers.test.js.map +1 -0
- package/dist/tools/write.test.js +1 -1
- package/dist/ui/App.d.ts +3 -0
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +39 -3
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/app-items.d.ts +2 -0
- package/dist/ui/app-items.d.ts.map +1 -1
- package/dist/ui/app-items.js +2 -0
- package/dist/ui/app-items.js.map +1 -1
- package/dist/ui/components/Banner.d.ts.map +1 -1
- package/dist/ui/components/Banner.js +24 -16
- package/dist/ui/components/Banner.js.map +1 -1
- package/dist/ui/components/ToolExecution.js +42 -34
- package/dist/ui/components/ToolExecution.js.map +1 -1
- package/dist/ui/components/force-color.d.ts +2 -0
- package/dist/ui/components/force-color.d.ts.map +1 -0
- package/dist/ui/components/force-color.js +11 -0
- package/dist/ui/components/force-color.js.map +1 -0
- package/dist/ui/components/themed-output.test.d.ts +2 -0
- package/dist/ui/components/themed-output.test.d.ts.map +1 -0
- package/dist/ui/components/themed-output.test.js +111 -0
- package/dist/ui/components/themed-output.test.js.map +1 -0
- package/dist/ui/error-item.d.ts +1 -1
- package/dist/ui/error-item.js +3 -3
- package/dist/ui/error-item.js.map +1 -1
- package/dist/ui/hooks/useAgentLoop.d.ts +4 -1
- package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
- package/dist/ui/hooks/useAgentLoop.js +27 -2
- package/dist/ui/hooks/useAgentLoop.js.map +1 -1
- package/dist/ui/login.js +2 -2
- package/dist/ui/login.js.map +1 -1
- package/dist/ui/render.d.ts +1 -1
- package/dist/ui/render.js +6 -6
- package/dist/ui/theme/dark-ansi.json +6 -0
- package/dist/ui/theme/dark-daltonized.json +6 -0
- package/dist/ui/theme/dark.json +6 -0
- package/dist/ui/theme/light-ansi.json +6 -0
- package/dist/ui/theme/light-daltonized.json +6 -0
- package/dist/ui/theme/light.json +6 -0
- package/dist/ui/theme/theme.d.ts +6 -0
- package/dist/ui/theme/theme.d.ts.map +1 -1
- package/dist/ui/tui-terminal-recorder.test.js +1 -1
- package/dist/utils/git.test.js +3 -3
- package/dist/utils/image.d.ts.map +1 -1
- package/dist/utils/image.js.map +1 -1
- package/package.json +7 -7
|
@@ -6,9 +6,10 @@ import { PROMPT_COMMANDS, getPromptCommand } from "./prompt-commands.js";
|
|
|
6
6
|
import { loadCustomCommands } from "./custom-commands.js";
|
|
7
7
|
import { SettingsManager } from "./settings-manager.js";
|
|
8
8
|
import { AuthStorage } from "./auth-storage.js";
|
|
9
|
-
import {
|
|
9
|
+
import { dualAuthProvider } from "@prestyj/core";
|
|
10
10
|
import { getClaudeCliUserAgent } from "./claude-code-version.js";
|
|
11
11
|
import { kimiCodingHeaders, isKimiCodingEndpoint } from "./oauth/kimi.js";
|
|
12
|
+
import { isGrokCliEndpoint } from "./oauth/xai.js";
|
|
12
13
|
import { SessionManager, NOLAN_TURN_CUSTOM_KIND, AUTOPILOT_MARKER_CUSTOM_KIND, APP_MARKER_CUSTOM_KIND, } from "./session-manager.js";
|
|
13
14
|
import { ExtensionLoader } from "./extensions/loader.js";
|
|
14
15
|
import { shouldCompact, compact, } from "./compaction/compactor.js";
|
|
@@ -17,8 +18,9 @@ import { sourceFingerprint as computeSourceFingerprint } from "./session-compact
|
|
|
17
18
|
import { getAuthStorageKeys, getContextWindow, getModel, getToolResultCharLimit, MODELS, } from "./model-registry.js";
|
|
18
19
|
import { discoverSkills } from "./skills.js";
|
|
19
20
|
import { ensureAppDirs } from "../config.js";
|
|
20
|
-
import { buildSystemPrompt } from "../system-prompt.js";
|
|
21
|
+
import { buildSubAgentSystemPrompt, buildSystemPrompt, } from "../system-prompt.js";
|
|
21
22
|
import { createTools, createWebSearchTool, } from "../tools/index.js";
|
|
23
|
+
import { partitionToolsByTier } from "../tools/tool-tiers.js";
|
|
22
24
|
import { buildProcessCompletionFollowUp } from "./process-gate.js";
|
|
23
25
|
import { buildSubAgentCompletionFollowUp } from "./subagent-manager.js";
|
|
24
26
|
import { applyAsyncSubagentPolicy } from "./subagent-policy.js";
|
|
@@ -41,6 +43,7 @@ import { evaluateLoopBreak, buildLoopBreakMessage, CycleDetector, ToolCallProgre
|
|
|
41
43
|
import { buildRegroundingMessage } from "./regrounding.js";
|
|
42
44
|
import { wrapSteeringText, buildNotificationSteeringText, STEERING_PREFIX } from "./steering.js";
|
|
43
45
|
import { AgentNotificationQueue } from "./agent-notifications.js";
|
|
46
|
+
import { VerificationGate, isCodeFilePath, isVerificationCommand } from "./verification-gate.js";
|
|
44
47
|
import { findUserSessionPrompt, getUserSessionPrompt } from "./session-preview.js";
|
|
45
48
|
import { normalizeMessageImages } from "./message-images.js";
|
|
46
49
|
import crypto from "node:crypto";
|
|
@@ -138,6 +141,14 @@ export class AgentSession {
|
|
|
138
141
|
idealReviewPhase = "idle";
|
|
139
142
|
/** Runtime-only suppression while Nolan owns verification in autopilot mode. */
|
|
140
143
|
idealReviewSuppressed = false;
|
|
144
|
+
/** Mirror of the last `hook_armed` value broadcast this run, so the event
|
|
145
|
+
* fires only on a real edge. */
|
|
146
|
+
idealReviewArmed = false;
|
|
147
|
+
/** Cached test-drift probe, keyed by the size of the edited-file set. Drift
|
|
148
|
+
* depends only on WHICH files were edited and that set only grows, so this
|
|
149
|
+
* keeps the arming check off the filesystem on most tool results — the probe
|
|
150
|
+
* is several sync existsSync calls per edited file. */
|
|
151
|
+
idealDriftProbe = null;
|
|
141
152
|
reviewCoverage;
|
|
142
153
|
/** Coverage follow-ups spent this run, capped by MAX_REVIEW_COVERAGE_INJECTIONS. */
|
|
143
154
|
reviewCoverageInjected = 0;
|
|
@@ -148,6 +159,8 @@ export class AgentSession {
|
|
|
148
159
|
runStartedAt = 0;
|
|
149
160
|
/** Gate injections spent this run, capped by MAX_PROCESS_GATE_INJECTIONS. */
|
|
150
161
|
processGateInjected = 0;
|
|
162
|
+
/** Verification gate: code edited this run, nothing proved it since. */
|
|
163
|
+
verificationGate = new VerificationGate();
|
|
151
164
|
compactionOccurred = false;
|
|
152
165
|
lastCompactionCompacted = false;
|
|
153
166
|
compactionRetryAfter = 0;
|
|
@@ -180,8 +193,14 @@ export class AgentSession {
|
|
|
180
193
|
void this.subAgentManager?.interruptAll();
|
|
181
194
|
};
|
|
182
195
|
mcpManager;
|
|
183
|
-
/** Deferred MCP tools awaiting discovery via tool_search
|
|
196
|
+
/** Deferred MCP tools awaiting discovery via tool_search. */
|
|
184
197
|
mcpCatalog;
|
|
198
|
+
/**
|
|
199
|
+
* Built-in tools held in the catalog instead of the live toolset. Their names
|
|
200
|
+
* still render as one-line hints in the prompt's Tools section, so the model
|
|
201
|
+
* can discover and promote them; a promoted name drops out of this list.
|
|
202
|
+
*/
|
|
203
|
+
deferredBuiltinToolNames = [];
|
|
185
204
|
/** Live (connected) MCP tools by name — the reconcile target for cached stubs. */
|
|
186
205
|
liveMcpTools = new Map();
|
|
187
206
|
/** Server name for each cached-only tool, so a stub knows what to wait on. */
|
|
@@ -199,6 +218,8 @@ export class AgentSession {
|
|
|
199
218
|
maxTokens;
|
|
200
219
|
thinkingLevel;
|
|
201
220
|
customSystemPrompt;
|
|
221
|
+
/** Sub-agent definition body composed into the standard prompt scaffolding. */
|
|
222
|
+
agentPrompt;
|
|
202
223
|
/** Stable prompt prefix retained separately from the volatile uncached tail. */
|
|
203
224
|
baseSystemPrompt = "";
|
|
204
225
|
/** Shared with the tool layer so plan-mode restrictions read live state. */
|
|
@@ -258,6 +279,7 @@ export class AgentSession {
|
|
|
258
279
|
this.maxTokens = this.resolveMaxTokens(options.model);
|
|
259
280
|
this.thinkingLevel = options.thinkingLevel;
|
|
260
281
|
this.customSystemPrompt = options.systemPrompt;
|
|
282
|
+
this.agentPrompt = options.agentPrompt;
|
|
261
283
|
}
|
|
262
284
|
/**
|
|
263
285
|
* Derive the output-token cap for a model. Follows the active model's
|
|
@@ -338,6 +360,7 @@ export class AgentSession {
|
|
|
338
360
|
additionalRoots: this.additionalRoots,
|
|
339
361
|
allowOutsideWorkspaceWrites: this.settingsManager.get("allowOutsideWorkspaceWrites"),
|
|
340
362
|
}),
|
|
363
|
+
getUseExternalGrep: () => this.settingsManager.get("grepUseRipgrep"),
|
|
341
364
|
authStorage: this.authStorage,
|
|
342
365
|
onFileRead: (filePath) => this.reviewCoverage.recordRead(filePath),
|
|
343
366
|
onFileMutated: (filePath) => {
|
|
@@ -375,6 +398,23 @@ export class AgentSession {
|
|
|
375
398
|
// a hallucinated call can't mutate the repo — and buildSystemPrompt below is
|
|
376
399
|
// fed the same filtered names so the Tools section matches exactly.
|
|
377
400
|
this.tools = this.opts.allowedTools ? tools.filter((t) => this.isToolAllowed(t.name)) : tools;
|
|
401
|
+
// Tier the built-ins: rarely reached schemas move into the tool_search
|
|
402
|
+
// catalog and cost one hint line each instead of a full parameter schema on
|
|
403
|
+
// every request. Allow-listed sessions keep the eager path — their fixed
|
|
404
|
+
// tool expectations predate the catalog, and tool_search isn't allow-listed.
|
|
405
|
+
if (!this.opts.allowedTools && this.settingsManager.get("deferredBuiltinTools")) {
|
|
406
|
+
const { core, deferred } = partitionToolsByTier(this.tools);
|
|
407
|
+
if (deferred.length > 0) {
|
|
408
|
+
// Append-only: `core` preserves the original relative order and
|
|
409
|
+
// tool_search is pushed after it, so the serialized tool block that
|
|
410
|
+
// sits inside the cached prefix stays byte-stable across turns.
|
|
411
|
+
this.tools = core;
|
|
412
|
+
this.deferredBuiltinToolNames = deferred.map((t) => t.name);
|
|
413
|
+
this.mcpCatalog ??= new DeferredToolCatalog();
|
|
414
|
+
this.mcpCatalog.add(deferred);
|
|
415
|
+
this.ensureToolSearchTool();
|
|
416
|
+
}
|
|
417
|
+
}
|
|
378
418
|
this.rebuildReadTool = rebuildReadTool;
|
|
379
419
|
this.processManager = processManager;
|
|
380
420
|
this.lspManager = lspManager;
|
|
@@ -394,8 +434,7 @@ export class AgentSession {
|
|
|
394
434
|
else {
|
|
395
435
|
await this.connectMcpServers();
|
|
396
436
|
}
|
|
397
|
-
const basePrompt = this.
|
|
398
|
-
(await buildSystemPrompt(this.cwd, this.skills, false, undefined, this.tools.map((tool) => tool.name), undefined, this.provider, this.promptEnvironment()));
|
|
437
|
+
const basePrompt = await this.buildBasePrompt(false, undefined);
|
|
399
438
|
this.baseSystemPrompt = basePrompt;
|
|
400
439
|
this.messages = [{ role: "system", content: this.withSystemPromptTail(basePrompt) }];
|
|
401
440
|
// Load or create session. Transient sessions (subagent spawns) never
|
|
@@ -542,7 +581,9 @@ export class AgentSession {
|
|
|
542
581
|
// GLM not configured — skip Z.AI MCP servers
|
|
543
582
|
}
|
|
544
583
|
}
|
|
545
|
-
let servers = await getAllMcpServers(this.provider, apiKey, this.cwd
|
|
584
|
+
let servers = await getAllMcpServers(this.provider, apiKey, this.cwd, {
|
|
585
|
+
allowProjectScope: this.settingsManager.isProjectTrusted(this.cwd),
|
|
586
|
+
});
|
|
546
587
|
// Whitelisted allow-listed session: connect ONLY the named servers, never
|
|
547
588
|
// the user's full configured set (which could include mutating tools). The
|
|
548
589
|
// whitelist only restricts in allow-list mode (the documented contract) so
|
|
@@ -573,15 +614,25 @@ export class AgentSession {
|
|
|
573
614
|
if (this.opts.backgroundMcpConnect && mcpTools.length > 0) {
|
|
574
615
|
await this.rebuildSystemPromptInPlace();
|
|
575
616
|
}
|
|
617
|
+
// Detect project-scope servers excluded because the repo isn't trusted,
|
|
618
|
+
// so the host can offer a per-repo "Trust" button. Computed after the
|
|
619
|
+
// connect so the blocked list reflects the same connect attempt.
|
|
576
620
|
}
|
|
577
621
|
catch (err) {
|
|
578
622
|
log("WARN", "mcp", `MCP initialization failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
579
623
|
}
|
|
580
624
|
}
|
|
625
|
+
/** Persist `cwd` as a trusted project for project-scope MCP. Called by the
|
|
626
|
+
* sidecar's `/mcp/add` handler when a user adds a project-scope server via
|
|
627
|
+
* the MCP modal — the explicit add is itself the trust signal. The next
|
|
628
|
+
* session load connects its `.ezcoder/mcp.json` servers. */
|
|
629
|
+
async trustProject(cwd) {
|
|
630
|
+
await this.settingsManager.trustProject(cwd);
|
|
631
|
+
}
|
|
581
632
|
/**
|
|
582
633
|
* Route freshly connected MCP tools: deferred into the tool_search catalog
|
|
583
|
-
* (default — keeps ~8k tokens of schema out of every cache-miss turn
|
|
584
|
-
*
|
|
634
|
+
* (default — keeps ~8k tokens of schema out of every cache-miss turn) or
|
|
635
|
+
* pushed eagerly when the user opted out.
|
|
585
636
|
* Allow-listed sessions (Nolan) always get the eager path — their fixed tool
|
|
586
637
|
* expectations predate the catalog, and tool_search isn't allow-listed.
|
|
587
638
|
* Promotion pushes onto the live `this.tools` array the running agent loop
|
|
@@ -611,10 +662,13 @@ export class AgentSession {
|
|
|
611
662
|
* Register `tool_search` once. Promotion of a cached-only entry waits for its
|
|
612
663
|
* server so the model is told immediately when that capability turns out to
|
|
613
664
|
* be unreachable, instead of promoting a tool that fails on first call.
|
|
665
|
+
*
|
|
666
|
+
* The catalog is created on demand rather than required up front: deferred
|
|
667
|
+
* built-in tools populate it with zero MCP servers connected, so gating
|
|
668
|
+
* registration on an existing catalog would leave those tools unreachable.
|
|
614
669
|
*/
|
|
615
670
|
ensureToolSearchTool() {
|
|
616
|
-
|
|
617
|
-
return;
|
|
671
|
+
this.mcpCatalog ??= new DeferredToolCatalog();
|
|
618
672
|
if (this.tools.some((t) => t.name === "tool_search"))
|
|
619
673
|
return;
|
|
620
674
|
this.tools.push(createToolSearchTool(this.mcpCatalog, (promoted) => {
|
|
@@ -905,10 +959,14 @@ export class AgentSession {
|
|
|
905
959
|
this.reviewCoverage.reset();
|
|
906
960
|
this.reviewCoverageInjected = 0;
|
|
907
961
|
this.idealReviewPhase = "idle";
|
|
962
|
+
// No event here: clients reset their own hold on run_start.
|
|
963
|
+
this.idealReviewArmed = false;
|
|
964
|
+
this.idealDriftProbe = null;
|
|
908
965
|
this.loopBreakInjected = 0;
|
|
909
966
|
this.regroundingInjected = false;
|
|
910
967
|
this.runStartedAt = Date.now();
|
|
911
968
|
this.processGateInjected = 0;
|
|
969
|
+
this.verificationGate.reset();
|
|
912
970
|
this.compactionOccurred = false;
|
|
913
971
|
this.originalRequest = originalRequest;
|
|
914
972
|
}
|
|
@@ -947,10 +1005,40 @@ export class AgentSession {
|
|
|
947
1005
|
const removed = (diff.match(/^-[^-]/gm) ?? []).length;
|
|
948
1006
|
this.hookStats.changedLines += added + removed;
|
|
949
1007
|
}
|
|
1008
|
+
// Verification-gate bookkeeping: successful code mutations and completed
|
|
1009
|
+
// foreground verification commands, in occurrence order.
|
|
1010
|
+
if (!event.isError && args) {
|
|
1011
|
+
if ((name === "edit" || name === "write") &&
|
|
1012
|
+
isCodeFilePath(String(args.file_path ?? ""))) {
|
|
1013
|
+
this.verificationGate.recordMutation(String(args.file_path));
|
|
1014
|
+
}
|
|
1015
|
+
if (name === "bash" &&
|
|
1016
|
+
!args.run_in_background &&
|
|
1017
|
+
isVerificationCommand(String(args.command ?? ""))) {
|
|
1018
|
+
this.verificationGate.recordVerification();
|
|
1019
|
+
}
|
|
1020
|
+
// Reading the final output of an EXITED background verification run
|
|
1021
|
+
// counts: the process gate forces this read anyway, so without it the
|
|
1022
|
+
// gate would demand a redundant foreground re-run of tests the agent
|
|
1023
|
+
// already watched finish.
|
|
1024
|
+
if (name === "task_output") {
|
|
1025
|
+
const proc = this.processManager
|
|
1026
|
+
?.list()
|
|
1027
|
+
.find((p) => p.id === args.id);
|
|
1028
|
+
if (proc && proc.exitCode !== null && isVerificationCommand(proc.command)) {
|
|
1029
|
+
this.verificationGate.recordVerification();
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
// Tool results are what push the run over the review gate, and they all
|
|
1034
|
+
// land before the model writes its candidate final answer — so this is
|
|
1035
|
+
// the point where arming still beats the draft's first token.
|
|
1036
|
+
this.refreshIdealReviewArmed();
|
|
950
1037
|
break;
|
|
951
1038
|
}
|
|
952
1039
|
case "turn_end":
|
|
953
1040
|
this.hookStats.turns = event.turn;
|
|
1041
|
+
this.refreshIdealReviewArmed();
|
|
954
1042
|
for (let index = this.messages.length - 1; index >= 0; index--) {
|
|
955
1043
|
const anchor = this.messages[index];
|
|
956
1044
|
if (anchor?.role === "assistant") {
|
|
@@ -1134,6 +1222,51 @@ export class AgentSession {
|
|
|
1134
1222
|
});
|
|
1135
1223
|
return granted;
|
|
1136
1224
|
}
|
|
1225
|
+
/**
|
|
1226
|
+
* Would the stop AFTER the current turn inject the Ideal review? Same inputs
|
|
1227
|
+
* as the pre-stop gate below, evaluated early so clients know a candidate
|
|
1228
|
+
* final answer is a review draft BEFORE it streams.
|
|
1229
|
+
*
|
|
1230
|
+
* The turn count is looked ahead by one on purpose. `hookStats.turns` only
|
|
1231
|
+
* advances at `turn_end`, so while the model is writing the draft the counter
|
|
1232
|
+
* still reads the PREVIOUS turn; the real gate sees one more. Without the
|
|
1233
|
+
* lookahead a run sitting on score 3 crosses to 4 on the draft's own
|
|
1234
|
+
* `turn_end` — after the text already streamed — which is precisely the
|
|
1235
|
+
* appear-then-vanish flash. Over-arming by one turn point costs only live
|
|
1236
|
+
* token streaming on a final answer that then shows whole; under-arming costs
|
|
1237
|
+
* the flash, so this errs toward arming.
|
|
1238
|
+
*/
|
|
1239
|
+
wouldInjectIdealReview() {
|
|
1240
|
+
if (this.opts.selfCorrectionHooks === false || this.idealReviewSuppressed)
|
|
1241
|
+
return false;
|
|
1242
|
+
if (this.idealReviewPhase !== "idle")
|
|
1243
|
+
return false;
|
|
1244
|
+
if (!this.settingsManager.get("idealReviewEnabled"))
|
|
1245
|
+
return false;
|
|
1246
|
+
if (evaluateIdealReview({ ...this.hookStats, turns: this.hookStats.turns + 1 }).shouldReview) {
|
|
1247
|
+
return true;
|
|
1248
|
+
}
|
|
1249
|
+
const files = this.hookFileEditCounts.size;
|
|
1250
|
+
if (files === 0)
|
|
1251
|
+
return false;
|
|
1252
|
+
if (this.idealDriftProbe?.files !== files) {
|
|
1253
|
+
this.idealDriftProbe = {
|
|
1254
|
+
files,
|
|
1255
|
+
drifted: detectTestDrift(this.hookFileEditCounts.keys(), this.cwd).length > 0,
|
|
1256
|
+
};
|
|
1257
|
+
}
|
|
1258
|
+
return this.idealDriftProbe.drifted;
|
|
1259
|
+
}
|
|
1260
|
+
/** Broadcast Ideal-review arming on change. Both edges matter: armed=false
|
|
1261
|
+
* after the review fires is what lets a client stream the REVIEWED final
|
|
1262
|
+
* answer live again. */
|
|
1263
|
+
refreshIdealReviewArmed() {
|
|
1264
|
+
const armed = this.wouldInjectIdealReview();
|
|
1265
|
+
if (armed === this.idealReviewArmed)
|
|
1266
|
+
return;
|
|
1267
|
+
this.idealReviewArmed = armed;
|
|
1268
|
+
this.eventBus.emit("hook_armed", { kind: "ideal", armed });
|
|
1269
|
+
}
|
|
1137
1270
|
/**
|
|
1138
1271
|
* Pre-stop Ideal review phase machine. Once review starts, completion is
|
|
1139
1272
|
* blocked until harness-owned post-injection reads cover every changed file.
|
|
@@ -1153,6 +1286,18 @@ export class AgentSession {
|
|
|
1153
1286
|
});
|
|
1154
1287
|
return processFollowUp;
|
|
1155
1288
|
}
|
|
1289
|
+
// Verification gate: code was edited but nothing verified since the last
|
|
1290
|
+
// edit. Above the Ideal review so checks RUN before the read-based review
|
|
1291
|
+
// starts; off for allow-listed sessions that cannot run commands at all.
|
|
1292
|
+
if (this.opts.selfCorrectionHooks !== false &&
|
|
1293
|
+
this.settingsManager.get("verificationGateEnabled") &&
|
|
1294
|
+
(!this.opts.allowedTools || this.opts.allowedTools.includes("bash"))) {
|
|
1295
|
+
const verificationFollowUp = this.verificationGate.followUp();
|
|
1296
|
+
if (verificationFollowUp) {
|
|
1297
|
+
log("INFO", "verification-gate", "Injecting verification follow-up", {});
|
|
1298
|
+
return verificationFollowUp;
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1156
1301
|
if (this.opts.selfCorrectionHooks === false || this.idealReviewSuppressed)
|
|
1157
1302
|
return null;
|
|
1158
1303
|
if (this.idealReviewPhase === "reviewing") {
|
|
@@ -1202,6 +1347,11 @@ export class AgentSession {
|
|
|
1202
1347
|
coverageExpected: coverage.expected,
|
|
1203
1348
|
coverageMissing: coverage.missing,
|
|
1204
1349
|
});
|
|
1350
|
+
// Disarm strictly AFTER the hook event. Clients release held text on
|
|
1351
|
+
// disarm, so the reverse order would paint the draft and then delete it —
|
|
1352
|
+
// the exact flash arming exists to prevent. Leaving `idle` is what lets the
|
|
1353
|
+
// reviewed final answer stream live instead of being held.
|
|
1354
|
+
this.refreshIdealReviewArmed();
|
|
1205
1355
|
log("INFO", "ideal", "Injecting ideal review before final response", {
|
|
1206
1356
|
coverageExpected: coverage.expected,
|
|
1207
1357
|
coverageMissing: coverage.missing,
|
|
@@ -1271,6 +1421,10 @@ export class AgentSession {
|
|
|
1271
1421
|
// Cache for sync callers (see field doc) — kept in step with `creds`
|
|
1272
1422
|
// through the 401 force-refresh retry below.
|
|
1273
1423
|
this.lastAccountId = creds.accountId;
|
|
1424
|
+
// The access token most recently handed to the provider. Tracked separately
|
|
1425
|
+
// from `creds` because the per-turn resolver can rotate it mid-run, and the
|
|
1426
|
+
// 401 handler must name the token that was actually rejected.
|
|
1427
|
+
let lastResolvedAccessToken = creds.accessToken;
|
|
1274
1428
|
// Auto-compact if needed. This must happen after credential resolution so
|
|
1275
1429
|
// OpenAI OAuth/Codex sessions use the Codex product context window instead
|
|
1276
1430
|
// of the public API model window. Failed/no-op attempts cool down across
|
|
@@ -1332,6 +1486,7 @@ export class AgentSession {
|
|
|
1332
1486
|
const userAgent = this.provider === "anthropic" ? await getClaudeCliUserAgent() : undefined;
|
|
1333
1487
|
const loopMessages = await this.prepareDynamicContext();
|
|
1334
1488
|
const runAgentLoop = async (apiKey, accountId, projectId) => {
|
|
1489
|
+
lastResolvedAccessToken = apiKey;
|
|
1335
1490
|
const modelInfo = getModel(this.model);
|
|
1336
1491
|
const effectiveBaseUrl = this.baseUrl ?? creds.baseUrl;
|
|
1337
1492
|
const generator = agentLoop(loopMessages, {
|
|
@@ -1344,6 +1499,23 @@ export class AgentSession {
|
|
|
1344
1499
|
maxTurnExtensions: this.opts.maxTurnExtensions,
|
|
1345
1500
|
thinking: this.thinkingLevel,
|
|
1346
1501
|
apiKey,
|
|
1502
|
+
// Per-turn credential resolution. A run can span many minutes; if any
|
|
1503
|
+
// process sharing auth.json refreshes this grant meanwhile, the token
|
|
1504
|
+
// captured above is invalidated server-side and every remaining turn
|
|
1505
|
+
// would fail with an authentication error until the user restarted.
|
|
1506
|
+
// Static API keys resolve to the same value, so this is a no-op for them.
|
|
1507
|
+
resolveCredentials: async () => {
|
|
1508
|
+
const live = await this.authStorage.resolveCredentials(this.provider, {
|
|
1509
|
+
storageKeys: this.currentAuthStorageKeys(),
|
|
1510
|
+
});
|
|
1511
|
+
this.lastAccountId = live.accountId;
|
|
1512
|
+
lastResolvedAccessToken = live.accessToken;
|
|
1513
|
+
return {
|
|
1514
|
+
apiKey: live.accessToken,
|
|
1515
|
+
...(live.accountId !== undefined ? { accountId: live.accountId } : {}),
|
|
1516
|
+
...(live.projectId !== undefined ? { projectId: live.projectId } : {}),
|
|
1517
|
+
};
|
|
1518
|
+
},
|
|
1347
1519
|
baseUrl: effectiveBaseUrl,
|
|
1348
1520
|
signal: this.opts.signal,
|
|
1349
1521
|
accountId,
|
|
@@ -1507,29 +1679,45 @@ export class AgentSession {
|
|
|
1507
1679
|
if (isAbortError(err) || this.opts.signal?.aborted) {
|
|
1508
1680
|
return;
|
|
1509
1681
|
}
|
|
1510
|
-
//
|
|
1511
|
-
// billing stop). If the user ALSO configured
|
|
1512
|
-
// the OAuth credential usage-exhausted (honoring the
|
|
1513
|
-
// reset time when present) and retry this turn on the API
|
|
1514
|
-
// stays the preferred credential and resumes automatically once
|
|
1515
|
-
// lapses. A generic 429 is deliberately excluded: it may be a
|
|
1516
|
-
// rate limit and must not silently switch the user to a billed
|
|
1517
|
-
//
|
|
1518
|
-
//
|
|
1519
|
-
|
|
1682
|
+
// A subscription OAuth plan ran out of usage (hard usage-limit stop, or an
|
|
1683
|
+
// HTTP 402 billing stop). If the user ALSO configured that provider's API
|
|
1684
|
+
// key, mark the OAuth credential usage-exhausted (honoring the
|
|
1685
|
+
// provider-stated reset time when present) and retry this turn on the API
|
|
1686
|
+
// key — OAuth stays the preferred credential and resumes automatically once
|
|
1687
|
+
// the mark lapses. A generic 429 is deliberately excluded: it may be a
|
|
1688
|
+
// transient rate limit and must not silently switch the user to a billed
|
|
1689
|
+
// API key.
|
|
1690
|
+
//
|
|
1691
|
+
// Grok adds one case Kimi doesn't have: xAI gates its CLI chat proxy by
|
|
1692
|
+
// subscription tier, so an entitled-looking account can be refused outright
|
|
1693
|
+
// with a 403. That means "OAuth cannot serve this", not a transient error,
|
|
1694
|
+
// so it counts as exhausted too — otherwise a dual-configured user would
|
|
1695
|
+
// hard-fail while holding a perfectly good API key.
|
|
1696
|
+
//
|
|
1697
|
+
// Guarded on the subscription endpoint actually being in use: if the API key
|
|
1698
|
+
// was already active, the same error means BOTH are out and must surface.
|
|
1699
|
+
const dualAuth = dualAuthProvider(this.provider);
|
|
1700
|
+
const onSubscriptionEndpoint = (this.provider === "moonshot" && isKimiCodingEndpoint(creds.baseUrl)) ||
|
|
1701
|
+
(this.provider === "xai" && isGrokCliEndpoint(creds.baseUrl));
|
|
1702
|
+
const tierRefusal = this.provider === "xai" && err instanceof ProviderError && err.statusCode === 403;
|
|
1703
|
+
const oauthIsOut = isUsageLimitError(err) ||
|
|
1704
|
+
(err instanceof ProviderError && err.statusCode === 402) ||
|
|
1705
|
+
tierRefusal;
|
|
1706
|
+
if (dualAuth &&
|
|
1520
1707
|
!this.baseUrl &&
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
(await this.authStorage.hasCredentials(
|
|
1708
|
+
onSubscriptionEndpoint &&
|
|
1709
|
+
oauthIsOut &&
|
|
1710
|
+
(await this.authStorage.hasCredentials(dualAuth.provider))) {
|
|
1524
1711
|
const resetsAt = err instanceof ProviderError ? err.resetsAt : undefined;
|
|
1525
|
-
await this.authStorage.markUsageExhausted(
|
|
1526
|
-
log("WARN", "auth",
|
|
1712
|
+
await this.authStorage.markUsageExhausted(dualAuth.oauthKey, resetsAt);
|
|
1713
|
+
log("WARN", "auth", `${dualAuth.oauthLabel} usage limit reached — retrying this turn on the ${dualAuth.apiKeyLabel}`, { resetsAt: resetsAt !== undefined ? String(resetsAt) : "unknown" });
|
|
1527
1714
|
creds = await this.authStorage.resolveCredentials(this.provider, {
|
|
1528
1715
|
storageKeys: this.currentAuthStorageKeys(),
|
|
1529
1716
|
});
|
|
1530
1717
|
this.lastAccountId = creds.accountId;
|
|
1531
1718
|
// The runAgentLoop closure re-reads `creds`, so the retry picks up the
|
|
1532
|
-
// API key's baseUrl (api.moonshot.ai) and drops the
|
|
1719
|
+
// API key's public baseUrl (api.moonshot.ai / api.x.ai) and drops the
|
|
1720
|
+
// subscription endpoint's client-identity headers.
|
|
1533
1721
|
try {
|
|
1534
1722
|
await runAgentLoop(creds.accessToken, creds.accountId, creds.projectId);
|
|
1535
1723
|
}
|
|
@@ -1544,15 +1732,21 @@ export class AgentSession {
|
|
|
1544
1732
|
else if (err instanceof ProviderError && err.statusCode === 401) {
|
|
1545
1733
|
// Static API-key providers (GLM, Moonshot API key, etc.) have no refresh
|
|
1546
1734
|
// mechanism — retrying with the same key is pointless. Clear the
|
|
1547
|
-
// credential and surface the error so the user re-logins.
|
|
1548
|
-
// (active for `moonshot` when present) is refreshable, so it
|
|
1549
|
-
// through to the force-refresh path below.
|
|
1735
|
+
// credential and surface the error so the user re-logins. Subscription
|
|
1736
|
+
// OAuth (active for `moonshot`/`xai` when present) is refreshable, so it
|
|
1737
|
+
// falls through to the force-refresh path below.
|
|
1550
1738
|
if (await clearInvalidStaticApiKey(err))
|
|
1551
1739
|
throw err;
|
|
1552
1740
|
log("INFO", "auth", "Got 401, force-refreshing token and retrying");
|
|
1553
1741
|
creds = await this.authStorage.resolveCredentials(this.provider, {
|
|
1554
1742
|
forceRefresh: true,
|
|
1555
1743
|
storageKeys: this.currentAuthStorageKeys(),
|
|
1744
|
+
// Name the token the provider actually rejected (which the per-turn
|
|
1745
|
+
// resolver may have rotated since the run started). If disk already
|
|
1746
|
+
// holds a newer one, adopt it instead of minting another — a fresh
|
|
1747
|
+
// refresh would invalidate the token every sibling process is using
|
|
1748
|
+
// and turn one 401 into a cascade of them.
|
|
1749
|
+
rejectedToken: lastResolvedAccessToken,
|
|
1556
1750
|
});
|
|
1557
1751
|
this.lastAccountId = creds.accountId;
|
|
1558
1752
|
await runAgentLoop(creds.accessToken, creds.accountId, creds.projectId);
|
|
@@ -1666,7 +1860,9 @@ export class AgentSession {
|
|
|
1666
1860
|
}
|
|
1667
1861
|
}
|
|
1668
1862
|
// Use getAllMcpServers so user-configured servers survive the reconnect.
|
|
1669
|
-
const servers = await getAllMcpServers(this.provider, apiKey, this.cwd
|
|
1863
|
+
const servers = await getAllMcpServers(this.provider, apiKey, this.cwd, {
|
|
1864
|
+
allowProjectScope: this.settingsManager.isProjectTrusted(this.cwd),
|
|
1865
|
+
});
|
|
1670
1866
|
const mcpTools = await this.mcpManager.connectAll(servers);
|
|
1671
1867
|
// Drop stale MCP tools from both the live set and deferred catalog before
|
|
1672
1868
|
// re-adding. Some tools may already have been promoted out of the catalog.
|
|
@@ -1934,8 +2130,7 @@ export class AgentSession {
|
|
|
1934
2130
|
this.autopilotMarkers = [];
|
|
1935
2131
|
this.appMarkers = [];
|
|
1936
2132
|
this.turnMetrics = [];
|
|
1937
|
-
const basePrompt = this.
|
|
1938
|
-
(await buildSystemPrompt(this.cwd, this.skills, false, undefined, this.tools.map((tool) => tool.name), undefined, this.provider, this.promptEnvironment()));
|
|
2133
|
+
const basePrompt = await this.buildBasePrompt(false, undefined);
|
|
1939
2134
|
this.baseSystemPrompt = basePrompt;
|
|
1940
2135
|
this.messages = [{ role: "system", content: this.withSystemPromptTail(basePrompt) }];
|
|
1941
2136
|
// Fresh conversation — new entries must not chain onto the old DAG's leaf.
|
|
@@ -2070,6 +2265,9 @@ export class AgentSession {
|
|
|
2070
2265
|
this.idealReviewPhase = "idle";
|
|
2071
2266
|
this.reviewCoverage.reset();
|
|
2072
2267
|
}
|
|
2268
|
+
// Suppression flips mid-run (autopilot takes over verification), so a client
|
|
2269
|
+
// holding a draft under a stale arming must be released.
|
|
2270
|
+
this.refreshIdealReviewArmed();
|
|
2073
2271
|
}
|
|
2074
2272
|
/** Queue a user message (optionally with attachments) to be injected mid-run
|
|
2075
2273
|
* as steering. Returns the new queue length. No-op semantics are the caller's
|
|
@@ -2217,6 +2415,17 @@ export class AgentSession {
|
|
|
2217
2415
|
await this.rebuildSystemPromptInPlace();
|
|
2218
2416
|
return { ok: true, root: resolved };
|
|
2219
2417
|
}
|
|
2418
|
+
/**
|
|
2419
|
+
* Names to advertise as available-on-demand. A tool the model already
|
|
2420
|
+
* promoted lives in `this.tools` and carries its own schema, so it drops out
|
|
2421
|
+
* of the index rather than being listed twice.
|
|
2422
|
+
*/
|
|
2423
|
+
deferredToolNamesForPrompt(liveNames) {
|
|
2424
|
+
if (this.deferredBuiltinToolNames.length === 0)
|
|
2425
|
+
return [];
|
|
2426
|
+
const live = new Set(liveNames);
|
|
2427
|
+
return this.deferredBuiltinToolNames.filter((name) => !live.has(name));
|
|
2428
|
+
}
|
|
2220
2429
|
/** Environment facts that vary per session rather than per host. */
|
|
2221
2430
|
promptEnvironment() {
|
|
2222
2431
|
const networkAllow = this.settingsManager.get("networkMode") === "allowlist"
|
|
@@ -2224,11 +2433,37 @@ export class AgentSession {
|
|
|
2224
2433
|
: [];
|
|
2225
2434
|
return { additionalRoots: this.additionalRoots, networkAllow };
|
|
2226
2435
|
}
|
|
2436
|
+
/**
|
|
2437
|
+
* Build the stable system-prompt prefix for the current tool set and state.
|
|
2438
|
+
*
|
|
2439
|
+
* Three modes, in precedence order: a full replacement (`systemPrompt`), a
|
|
2440
|
+
* composed sub-agent prompt (`agentPrompt` — agent body plus Tools, project
|
|
2441
|
+
* context, return contract and Environment), or the standard prompt.
|
|
2442
|
+
*/
|
|
2443
|
+
async buildBasePrompt(planMode, approvedPlanPath) {
|
|
2444
|
+
if (this.customSystemPrompt)
|
|
2445
|
+
return this.customSystemPrompt;
|
|
2446
|
+
const toolNames = this.tools.map((tool) => tool.name);
|
|
2447
|
+
const deferredToolNames = this.deferredToolNamesForPrompt(toolNames);
|
|
2448
|
+
if (this.agentPrompt !== undefined) {
|
|
2449
|
+
return buildSubAgentSystemPrompt(this.agentPrompt, {
|
|
2450
|
+
cwd: this.cwd,
|
|
2451
|
+
toolNames,
|
|
2452
|
+
deferredToolNames,
|
|
2453
|
+
context: this.opts.agentContext,
|
|
2454
|
+
environment: this.promptEnvironment(),
|
|
2455
|
+
});
|
|
2456
|
+
}
|
|
2457
|
+
return buildSystemPrompt(this.cwd, this.skills, planMode, approvedPlanPath, toolNames, undefined, this.provider, this.promptEnvironment(), deferredToolNames);
|
|
2458
|
+
}
|
|
2227
2459
|
/** Rebuild messages[0] from current plan-mode + approved-plan state. */
|
|
2228
2460
|
async rebuildSystemPromptInPlace() {
|
|
2461
|
+
// A full replacement is verbatim by contract — there is nothing to rebuild.
|
|
2462
|
+
// A composed agent prompt still must be: its Tools section has to follow
|
|
2463
|
+
// late-arriving MCP tools, or a compacted child loses tools it can call.
|
|
2229
2464
|
if (this.customSystemPrompt)
|
|
2230
2465
|
return;
|
|
2231
|
-
const rebuilt = await
|
|
2466
|
+
const rebuilt = await this.buildBasePrompt(this.planModeRef.current, this.approvedPlanPath);
|
|
2232
2467
|
this.baseSystemPrompt = rebuilt;
|
|
2233
2468
|
const content = this.withSystemPromptTail(rebuilt);
|
|
2234
2469
|
if (this.messages[0]?.role === "system") {
|