@cjhyy/code-shell-core 0.5.0-rc.1 → 0.6.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -10
- package/dist/agent/agent-definition-registry.d.ts +21 -3
- package/dist/agent/agent-definition-registry.js +49 -18
- package/dist/agent/agent-definition.d.ts +32 -0
- package/dist/agent/agent-definition.js +49 -4
- package/dist/arena/arena.js +11 -12
- package/dist/arena/context/context-tools.js +47 -6
- package/dist/arena/context/within-root.d.ts +7 -0
- package/dist/arena/context/within-root.js +15 -0
- package/dist/arena/iterate/phases/argue.js +8 -2
- package/dist/arena/iterate/phases/revise.js +1 -1
- package/dist/arena/iterate/phases/tournament.js +3 -3
- package/dist/arena/ledger.js +9 -1
- package/dist/arena/phases/adjudication.js +1 -4
- package/dist/arena/phases/build-consensus.js +1 -4
- package/dist/arena/phases/cross-review.js +2 -8
- package/dist/arena/phases/debate-rounds.js +1 -4
- package/dist/arena/phases/participant-research.js +1 -4
- package/dist/arena/phases/planning-detail-expansion.js +8 -10
- package/dist/arena/planner.js +0 -1
- package/dist/arena/providers/docs.d.ts +1 -0
- package/dist/arena/providers/docs.js +5 -2
- package/dist/arena/providers/repo.d.ts +1 -0
- package/dist/arena/providers/repo.js +5 -2
- package/dist/arena/strategies/utils.d.ts +1 -4
- package/dist/arena/strategies/utils.js +7 -51
- package/dist/arena/transitions.d.ts +7 -2
- package/dist/arena/transitions.js +9 -4
- package/dist/arena/types.d.ts +8 -2
- package/dist/automation/cron-expr.d.ts +41 -0
- package/dist/automation/cron-expr.js +169 -0
- package/dist/automation/index.d.ts +41 -0
- package/dist/automation/index.js +39 -0
- package/dist/automation/runner.d.ts +84 -0
- package/dist/automation/runner.js +92 -0
- package/dist/automation/scheduler.d.ts +194 -0
- package/dist/automation/scheduler.js +623 -0
- package/dist/automation/store.d.ts +39 -0
- package/dist/automation/store.js +122 -0
- package/dist/automation/write-policy.d.ts +34 -0
- package/dist/automation/write-policy.js +113 -0
- package/dist/automation/write-run.d.ts +51 -0
- package/dist/automation/write-run.js +38 -0
- package/dist/capability-control/disabled-lists.d.ts +25 -0
- package/dist/capability-control/disabled-lists.js +57 -0
- package/dist/capability-control/index.d.ts +5 -0
- package/dist/capability-control/index.js +3 -0
- package/dist/capability-control/overlay.d.ts +64 -0
- package/dist/capability-control/overlay.js +116 -0
- package/dist/capability-control/project.d.ts +65 -0
- package/dist/capability-control/project.js +147 -0
- package/dist/capability-control/service.d.ts +70 -0
- package/dist/capability-control/service.js +147 -0
- package/dist/capability-control/types.d.ts +62 -0
- package/dist/capability-control/types.js +17 -0
- package/dist/cc-orchestrator/agent-adapter.d.ts +50 -0
- package/dist/cc-orchestrator/agent-adapter.js +133 -0
- package/dist/cc-orchestrator/cc-capability.d.ts +19 -0
- package/dist/cc-orchestrator/cc-capability.js +53 -0
- package/dist/cc-orchestrator/codex-session-discovery.d.ts +24 -0
- package/dist/cc-orchestrator/codex-session-discovery.js +191 -0
- package/dist/cc-orchestrator/codex-session-history.d.ts +25 -0
- package/dist/cc-orchestrator/codex-session-history.js +187 -0
- package/dist/cc-orchestrator/external-agent-changes.d.ts +19 -0
- package/dist/cc-orchestrator/external-agent-changes.js +214 -0
- package/dist/cc-orchestrator/external-agent-driver.d.ts +18 -0
- package/dist/cc-orchestrator/external-agent-driver.js +69 -0
- package/dist/cc-orchestrator/index.d.ts +8 -0
- package/dist/cc-orchestrator/index.js +8 -0
- package/dist/cc-orchestrator/relevance-judge.d.ts +15 -0
- package/dist/cc-orchestrator/relevance-judge.js +29 -0
- package/dist/cc-orchestrator/session-discovery.d.ts +46 -0
- package/dist/cc-orchestrator/session-discovery.js +125 -0
- package/dist/cc-orchestrator/session-history.d.ts +19 -0
- package/dist/cc-orchestrator/session-history.js +67 -0
- package/dist/cli/agent-server-stdio.d.ts +26 -1
- package/dist/cli/agent-server-stdio.js +221 -28
- package/dist/cli/agent-server-tcp.d.ts +20 -0
- package/dist/cli/agent-server-tcp.js +134 -0
- package/dist/cli/graceful-shutdown.d.ts +27 -0
- package/dist/cli/graceful-shutdown.js +30 -0
- package/dist/context/compaction.d.ts +56 -0
- package/dist/context/compaction.js +209 -15
- package/dist/context/manager.d.ts +0 -20
- package/dist/context/manager.js +25 -41
- package/dist/cost-tracker.js +5 -61
- package/dist/credentials/cipher.d.ts +49 -0
- package/dist/credentials/cipher.js +45 -0
- package/dist/credentials/cookie-jar.d.ts +24 -0
- package/dist/credentials/cookie-jar.js +40 -0
- package/dist/credentials/index.d.ts +7 -0
- package/dist/credentials/index.js +5 -0
- package/dist/credentials/inject-credential-tool.d.ts +20 -0
- package/dist/credentials/inject-credential-tool.js +130 -0
- package/dist/credentials/store.d.ts +72 -0
- package/dist/credentials/store.js +184 -0
- package/dist/credentials/types.d.ts +56 -0
- package/dist/credentials/use-credential-tool.d.ts +29 -0
- package/dist/credentials/use-credential-tool.js +205 -0
- package/dist/credentials/use-gate.d.ts +56 -0
- package/dist/credentials/use-gate.js +52 -0
- package/dist/cron/cron-runtime.d.ts +2 -0
- package/dist/cron/cron-runtime.js +2 -0
- package/dist/cron/cron-store.d.ts +2 -0
- package/dist/cron/cron-store.js +2 -0
- package/dist/cron/scheduler.d.ts +5 -32
- package/dist/cron/scheduler.js +5 -113
- package/dist/data/model-metadata.d.ts +77 -0
- package/dist/data/model-metadata.js +56 -0
- package/dist/data/model-metadata.json +216 -0
- package/dist/data/openrouter-models.d.ts +18 -7
- package/dist/data/openrouter-models.js +35 -8
- package/dist/data/openrouter-sync.js +1 -1
- package/dist/engine/aux-key.d.ts +10 -0
- package/dist/engine/aux-key.js +11 -0
- package/dist/engine/dynamic-tool-defs.d.ts +19 -0
- package/dist/engine/dynamic-tool-defs.js +36 -0
- package/dist/engine/engine.d.ts +431 -108
- package/dist/engine/engine.js +1630 -279
- package/dist/engine/friendly-error.d.ts +18 -0
- package/dist/engine/friendly-error.js +63 -0
- package/dist/engine/goal.d.ts +187 -0
- package/dist/engine/goal.js +196 -0
- package/dist/engine/image-compression.d.ts +81 -0
- package/dist/engine/image-compression.js +186 -0
- package/dist/engine/image-policy.d.ts +165 -0
- package/dist/engine/image-policy.js +189 -0
- package/dist/engine/model-connections-pool.d.ts +17 -0
- package/dist/engine/model-connections-pool.js +66 -0
- package/dist/engine/model-facade.d.ts +10 -0
- package/dist/engine/model-facade.js +25 -0
- package/dist/engine/patch-orphaned-tools.js +3 -0
- package/dist/engine/reactive-threshold.d.ts +13 -0
- package/dist/engine/reactive-threshold.js +17 -0
- package/dist/engine/resolve-llm-config.d.ts +16 -0
- package/dist/engine/resolve-llm-config.js +44 -0
- package/dist/engine/runtime.js +9 -1
- package/dist/engine/sandbox-cache-key.d.ts +10 -0
- package/dist/engine/sandbox-cache-key.js +9 -0
- package/dist/engine/sandbox-config.d.ts +31 -0
- package/dist/engine/sandbox-config.js +38 -0
- package/dist/engine/session-title.d.ts +13 -0
- package/dist/engine/session-title.js +34 -0
- package/dist/engine/session-usage.d.ts +19 -0
- package/dist/engine/session-usage.js +25 -0
- package/dist/engine/steer-queue.d.ts +32 -0
- package/dist/engine/steer-queue.js +26 -0
- package/dist/engine/streaming-tool-queue.d.ts +12 -0
- package/dist/engine/streaming-tool-queue.js +50 -10
- package/dist/engine/turn-loop.d.ts +94 -9
- package/dist/engine/turn-loop.js +775 -342
- package/dist/engine/types.d.ts +175 -0
- package/dist/engine/types.js +13 -0
- package/dist/external-agents/config.d.ts +2 -0
- package/dist/external-agents/config.js +15 -0
- package/dist/external-agents/types.d.ts +31 -0
- package/dist/external-agents/types.js +1 -0
- package/dist/git/parse-log.d.ts +13 -0
- package/dist/git/parse-log.js +21 -0
- package/dist/git/utils.d.ts +8 -6
- package/dist/git/utils.js +62 -26
- package/dist/git/worktree.d.ts +48 -0
- package/dist/git/worktree.js +111 -20
- package/dist/hooks/events.d.ts +23 -1
- package/dist/hooks/goal-stop-hook.d.ts +58 -0
- package/dist/hooks/goal-stop-hook.js +279 -0
- package/dist/hooks/hook-output.d.ts +33 -0
- package/dist/hooks/hook-output.js +79 -0
- package/dist/hooks/registry.d.ts +15 -0
- package/dist/hooks/registry.js +57 -1
- package/dist/hooks/shell-runner.d.ts +2 -0
- package/dist/hooks/shell-runner.js +48 -18
- package/dist/index.d.ts +79 -11
- package/dist/index.js +89 -6
- package/dist/llm/capabilities/param-specs.d.ts +14 -0
- package/dist/llm/capabilities/param-specs.js +62 -0
- package/dist/llm/capabilities/reasoning-control.d.ts +24 -0
- package/dist/llm/capabilities/reasoning-control.js +38 -0
- package/dist/llm/capabilities/rules.js +37 -3
- package/dist/llm/capabilities/types.d.ts +32 -2
- package/dist/llm/clamp-max-tokens.d.ts +11 -0
- package/dist/llm/clamp-max-tokens.js +17 -0
- package/dist/llm/client-base.d.ts +69 -5
- package/dist/llm/client-base.js +185 -25
- package/dist/llm/client-factory.d.ts +3 -3
- package/dist/llm/client-factory.js +2 -2
- package/dist/llm/model-cache.js +4 -2
- package/dist/llm/model-pool.d.ts +29 -11
- package/dist/llm/model-pool.js +36 -20
- package/dist/llm/provider-auth.d.ts +41 -0
- package/dist/llm/provider-auth.js +76 -0
- package/dist/llm/provider-catalog.d.ts +6 -2
- package/dist/llm/providers/anthropic.d.ts +32 -2
- package/dist/llm/providers/anthropic.js +207 -18
- package/dist/llm/providers/openai.d.ts +47 -2
- package/dist/llm/providers/openai.js +478 -71
- package/dist/llm/reasoning-setting.d.ts +51 -0
- package/dist/llm/reasoning-setting.js +40 -0
- package/dist/llm/stop-reason.d.ts +13 -0
- package/dist/llm/stop-reason.js +21 -0
- package/dist/llm/stream-watchdog.js +5 -1
- package/dist/llm/strip-vision.d.ts +32 -0
- package/dist/llm/strip-vision.js +94 -0
- package/dist/llm/token-counter.js +9 -2
- package/dist/llm/types.d.ts +9 -6
- package/dist/logging/logger.js +18 -4
- package/dist/logging/sanitize-messages.d.ts +10 -0
- package/dist/logging/sanitize-messages.js +112 -0
- package/dist/lsp/client.js +28 -8
- package/dist/lsp/manager.d.ts +1 -1
- package/dist/lsp/manager.js +42 -11
- package/dist/lsp/root-path.d.ts +9 -0
- package/dist/lsp/root-path.js +12 -0
- package/dist/model-catalog/builtin.d.ts +12 -0
- package/dist/model-catalog/builtin.js +407 -0
- package/dist/model-catalog/gen-connections.d.ts +20 -0
- package/dist/model-catalog/gen-connections.js +28 -0
- package/dist/model-catalog/index.d.ts +41 -0
- package/dist/model-catalog/index.js +90 -0
- package/dist/model-catalog/params.d.ts +20 -0
- package/dist/model-catalog/params.js +45 -0
- package/dist/model-catalog/resolve.d.ts +48 -0
- package/dist/model-catalog/resolve.js +33 -0
- package/dist/model-catalog/save-entry.d.ts +32 -0
- package/dist/model-catalog/save-entry.js +104 -0
- package/dist/model-catalog/types.d.ts +561 -0
- package/dist/model-catalog/types.js +93 -0
- package/dist/model-catalog/upsert.d.ts +9 -0
- package/dist/model-catalog/upsert.js +8 -0
- package/dist/onboarding.d.ts +12 -82
- package/dist/onboarding.js +75 -333
- package/dist/plugins/gitOps.d.ts +53 -0
- package/dist/plugins/gitOps.js +130 -5
- package/dist/plugins/installer/checkUpdate.d.ts +16 -0
- package/dist/plugins/installer/checkUpdate.js +32 -0
- package/dist/plugins/installer/codex/convertAgents.d.ts +7 -0
- package/dist/plugins/installer/codex/convertAgents.js +55 -0
- package/dist/plugins/installer/codex/convertCommands.d.ts +19 -0
- package/dist/plugins/installer/codex/convertCommands.js +46 -0
- package/dist/plugins/installer/codex/convertMcp.d.ts +11 -0
- package/dist/plugins/installer/codex/convertMcp.js +85 -0
- package/dist/plugins/installer/codex/convertSkills.d.ts +12 -0
- package/dist/plugins/installer/codex/convertSkills.js +33 -0
- package/dist/plugins/installer/detectFormat.d.ts +2 -0
- package/dist/plugins/installer/detectFormat.js +6 -0
- package/dist/plugins/installer/install.d.ts +7 -0
- package/dist/plugins/installer/install.js +123 -0
- package/dist/plugins/installer/installFromArchive.d.ts +43 -0
- package/dist/plugins/installer/installFromArchive.js +134 -0
- package/dist/plugins/installer/installFromSource.d.ts +13 -0
- package/dist/plugins/installer/installFromSource.js +51 -0
- package/dist/plugins/installer/list.d.ts +9 -0
- package/dist/plugins/installer/list.js +30 -0
- package/dist/plugins/installer/loadPluginAgents.d.ts +3 -0
- package/dist/plugins/installer/loadPluginAgents.js +27 -0
- package/dist/plugins/installer/loadPluginMcp.d.ts +14 -0
- package/dist/plugins/installer/loadPluginMcp.js +107 -0
- package/dist/plugins/installer/parseSource.d.ts +20 -0
- package/dist/plugins/installer/parseSource.js +74 -0
- package/dist/plugins/installer/paths.d.ts +5 -0
- package/dist/plugins/installer/paths.js +25 -0
- package/dist/plugins/installer/pruneDisabled.d.ts +24 -0
- package/dist/plugins/installer/pruneDisabled.js +73 -0
- package/dist/plugins/installer/types.d.ts +52 -0
- package/dist/plugins/installer/types.js +28 -0
- package/dist/plugins/installer/uninstall.d.ts +2 -0
- package/dist/plugins/installer/uninstall.js +18 -0
- package/dist/plugins/installer/unzip.d.ts +14 -0
- package/dist/plugins/installer/unzip.js +82 -0
- package/dist/plugins/installer/update.d.ts +28 -0
- package/dist/plugins/installer/update.js +97 -0
- package/dist/plugins/loadPluginHooks.d.ts +54 -1
- package/dist/plugins/loadPluginHooks.js +83 -1
- package/dist/plugins/marketplaceManager.d.ts +15 -1
- package/dist/plugins/marketplaceManager.js +58 -4
- package/dist/plugins/pluginCommandHook.js +34 -14
- package/dist/plugins/pluginContent.d.ts +30 -0
- package/dist/plugins/pluginContent.js +83 -0
- package/dist/plugins/pluginInstaller.d.ts +34 -0
- package/dist/plugins/pluginInstaller.js +168 -35
- package/dist/plugins/schemas.js +41 -6
- package/dist/plugins/types.d.ts +10 -0
- package/dist/preset/index.d.ts +7 -1
- package/dist/preset/index.js +112 -6
- package/dist/product/types.d.ts +1 -1
- package/dist/prompt/composer.d.ts +31 -0
- package/dist/prompt/composer.js +95 -25
- package/dist/prompt/instruction-scanner.js +5 -3
- package/dist/prompt/section-loader.js +1 -0
- package/dist/prompt/sections/base.md +1 -0
- package/dist/prompt/sections/browser.md +10 -0
- package/dist/prompt/sections/coding.md +4 -0
- package/dist/prompt/sections/orchestration.md +8 -0
- package/dist/protocol/chat-session-manager.d.ts +15 -2
- package/dist/protocol/chat-session-manager.js +46 -0
- package/dist/protocol/chat-session.d.ts +82 -0
- package/dist/protocol/chat-session.js +121 -1
- package/dist/protocol/client.d.ts +27 -0
- package/dist/protocol/client.js +38 -0
- package/dist/protocol/redact.d.ts +50 -0
- package/dist/protocol/redact.js +71 -0
- package/dist/protocol/server.d.ts +153 -2
- package/dist/protocol/server.js +807 -39
- package/dist/protocol/tcp-transport.d.ts +45 -0
- package/dist/protocol/tcp-transport.js +74 -0
- package/dist/protocol/transport.js +3 -2
- package/dist/protocol/types.d.ts +69 -0
- package/dist/protocol/types.js +22 -0
- package/dist/quota/credentials.d.ts +3 -0
- package/dist/quota/credentials.js +80 -0
- package/dist/quota/index.d.ts +36 -0
- package/dist/quota/index.js +155 -0
- package/dist/quota/types.d.ts +48 -0
- package/dist/quota/types.js +13 -0
- package/dist/remote/bridge.d.ts +11 -2
- package/dist/remote/bridge.js +61 -33
- package/dist/review/review-prompt.d.ts +28 -0
- package/dist/review/review-prompt.js +81 -0
- package/dist/run/ArtifactTracker.js +5 -4
- package/dist/run/EngineRunner.d.ts +27 -1
- package/dist/run/EngineRunner.js +46 -8
- package/dist/run/FileRunStore.js +40 -11
- package/dist/run/RunApprovalBackend.js +25 -5
- package/dist/run/RunLock.d.ts +28 -2
- package/dist/run/RunLock.js +49 -7
- package/dist/run/RunManager.d.ts +12 -0
- package/dist/run/RunManager.js +86 -3
- package/dist/run/RunQueue.d.ts +1 -0
- package/dist/run/RunQueue.js +8 -2
- package/dist/run/factory.d.ts +8 -1
- package/dist/run/factory.js +1 -0
- package/dist/run/index.d.ts +2 -2
- package/dist/run/index.js +1 -1
- package/dist/run/redirect-target.d.ts +7 -0
- package/dist/run/redirect-target.js +13 -0
- package/dist/run/types.js +1 -1
- package/dist/runtime/background-shell.d.ts +139 -0
- package/dist/runtime/background-shell.js +495 -0
- package/dist/runtime/output-clean.d.ts +24 -0
- package/dist/runtime/output-clean.js +41 -0
- package/dist/runtime/ring-file.d.ts +64 -0
- package/dist/runtime/ring-file.js +174 -0
- package/dist/runtime/safe-spawn.js +15 -34
- package/dist/runtime/spawn-common.d.ts +148 -0
- package/dist/runtime/spawn-common.js +303 -0
- package/dist/runtime/truncate-output.d.ts +22 -0
- package/dist/runtime/truncate-output.js +49 -0
- package/dist/runtime/utf8-cut.d.ts +11 -0
- package/dist/runtime/utf8-cut.js +23 -0
- package/dist/services/auto-dream.d.ts +4 -0
- package/dist/services/auto-dream.js +26 -26
- package/dist/services/browser-open.d.ts +13 -0
- package/dist/services/browser-open.js +16 -0
- package/dist/services/diagnostics.d.ts +1 -2
- package/dist/services/diagnostics.js +12 -7
- package/dist/services/dream-consolidation.d.ts +57 -0
- package/dist/services/dream-consolidation.js +151 -0
- package/dist/services/extract-memories.d.ts +14 -1
- package/dist/services/extract-memories.js +45 -6
- package/dist/services/memory-orchestrator.d.ts +21 -0
- package/dist/services/memory-orchestrator.js +125 -32
- package/dist/services/notifier.d.ts +8 -0
- package/dist/services/notifier.js +39 -25
- package/dist/services/oauth.js +5 -7
- package/dist/services/session-memory-sort.d.ts +8 -0
- package/dist/services/session-memory-sort.js +9 -0
- package/dist/services/session-memory.js +30 -19
- package/dist/session/file-history.d.ts +124 -1
- package/dist/session/file-history.js +232 -9
- package/dist/session/memory.d.ts +116 -2
- package/dist/session/memory.js +250 -28
- package/dist/session/session-manager.d.ts +63 -1
- package/dist/session/session-manager.js +186 -5
- package/dist/session/simple-diff.d.ts +23 -0
- package/dist/session/simple-diff.js +84 -0
- package/dist/session/transcript.d.ts +25 -1
- package/dist/session/transcript.js +35 -2
- package/dist/session/undo-target.d.ts +67 -0
- package/dist/session/undo-target.js +144 -0
- package/dist/settings/disk-defaults.d.ts +42 -0
- package/dist/settings/disk-defaults.js +33 -0
- package/dist/settings/feature-flags.d.ts +64 -0
- package/dist/settings/feature-flags.js +61 -0
- package/dist/settings/manager.d.ts +101 -1
- package/dist/settings/manager.js +345 -15
- package/dist/settings/migrate-config.d.ts +45 -0
- package/dist/settings/migrate-config.js +125 -0
- package/dist/settings/personalization.d.ts +19 -0
- package/dist/settings/personalization.js +7 -0
- package/dist/settings/schema-export.d.ts +25 -0
- package/dist/settings/schema-export.js +38 -0
- package/dist/settings/schema.d.ts +1827 -396
- package/dist/settings/schema.js +361 -81
- package/dist/skills/scanner.d.ts +9 -0
- package/dist/skills/scanner.js +30 -2
- package/dist/stt/resolve-transcribe.d.ts +31 -0
- package/dist/stt/resolve-transcribe.js +108 -0
- package/dist/stt/transcribe.d.ts +51 -0
- package/dist/stt/transcribe.js +65 -0
- package/dist/tool-system/browser-bridge.d.ts +226 -0
- package/dist/tool-system/browser-bridge.js +163 -0
- package/dist/tool-system/builtin/add-marketplace.d.ts +12 -0
- package/dist/tool-system/builtin/add-marketplace.js +76 -0
- package/dist/tool-system/builtin/agent-heartbeat.d.ts +49 -0
- package/dist/tool-system/builtin/agent-heartbeat.js +89 -0
- package/dist/tool-system/builtin/agent-notifications.d.ts +12 -3
- package/dist/tool-system/builtin/agent-notifications.js +9 -3
- package/dist/tool-system/builtin/agent-output-file.d.ts +38 -0
- package/dist/tool-system/builtin/agent-output-file.js +72 -0
- package/dist/tool-system/builtin/agent-registry.d.ts +23 -0
- package/dist/tool-system/builtin/agent-registry.js +16 -4
- package/dist/tool-system/builtin/agent.d.ts +50 -11
- package/dist/tool-system/builtin/agent.js +576 -73
- package/dist/tool-system/builtin/apply-patch/applier.js +66 -8
- package/dist/tool-system/builtin/apply-patch/backup-targets.d.ts +10 -0
- package/dist/tool-system/builtin/apply-patch/backup-targets.js +30 -0
- package/dist/tool-system/builtin/apply-patch/index.js +7 -3
- package/dist/tool-system/builtin/arena.js +6 -7
- package/dist/tool-system/builtin/background-jobs.d.ts +76 -0
- package/dist/tool-system/builtin/background-jobs.js +124 -0
- package/dist/tool-system/builtin/background-shell-tools.d.ts +20 -0
- package/dist/tool-system/builtin/background-shell-tools.js +108 -0
- package/dist/tool-system/builtin/background-work.d.ts +67 -0
- package/dist/tool-system/builtin/background-work.js +86 -0
- package/dist/tool-system/builtin/bash-output-style.d.ts +32 -0
- package/dist/tool-system/builtin/bash-output-style.js +40 -0
- package/dist/tool-system/builtin/bash.d.ts +5 -2
- package/dist/tool-system/builtin/bash.js +98 -62
- package/dist/tool-system/builtin/browser-tools.d.ts +33 -0
- package/dist/tool-system/builtin/browser-tools.js +312 -0
- package/dist/tool-system/builtin/cancel-goal.d.ts +31 -0
- package/dist/tool-system/builtin/cancel-goal.js +64 -0
- package/dist/tool-system/builtin/check-quota.d.ts +15 -0
- package/dist/tool-system/builtin/check-quota.js +34 -0
- package/dist/tool-system/builtin/complete-goal.d.ts +25 -0
- package/dist/tool-system/builtin/complete-goal.js +45 -0
- package/dist/tool-system/builtin/config.js +7 -0
- package/dist/tool-system/builtin/cron.d.ts +7 -0
- package/dist/tool-system/builtin/cron.js +105 -9
- package/dist/tool-system/builtin/drive-claude-code.d.ts +30 -0
- package/dist/tool-system/builtin/drive-claude-code.js +157 -0
- package/dist/tool-system/builtin/edit-model-catalog.d.ts +3 -0
- package/dist/tool-system/builtin/edit-model-catalog.js +94 -0
- package/dist/tool-system/builtin/edit.d.ts +2 -1
- package/dist/tool-system/builtin/edit.js +21 -12
- package/dist/tool-system/builtin/eol.d.ts +29 -0
- package/dist/tool-system/builtin/eol.js +37 -0
- package/dist/tool-system/builtin/file-cache.d.ts +6 -0
- package/dist/tool-system/builtin/file-cache.js +8 -0
- package/dist/tool-system/builtin/generate-image.d.ts +60 -0
- package/dist/tool-system/builtin/generate-image.js +374 -0
- package/dist/tool-system/builtin/generate-video.d.ts +55 -0
- package/dist/tool-system/builtin/generate-video.js +361 -0
- package/dist/tool-system/builtin/grep.js +6 -2
- package/dist/tool-system/builtin/image-providers.d.ts +86 -0
- package/dist/tool-system/builtin/image-providers.js +190 -0
- package/dist/tool-system/builtin/image-uploader.d.ts +33 -0
- package/dist/tool-system/builtin/image-uploader.js +74 -0
- package/dist/tool-system/builtin/index.d.ts +24 -1
- package/dist/tool-system/builtin/index.js +310 -25
- package/dist/tool-system/builtin/mcp-tools.js +23 -3
- package/dist/tool-system/builtin/memory.js +45 -7
- package/dist/tool-system/builtin/notebook-edit.d.ts +2 -1
- package/dist/tool-system/builtin/notebook-edit.js +1 -1
- package/dist/tool-system/builtin/powershell.js +4 -1
- package/dist/tool-system/builtin/read.d.ts +2 -1
- package/dist/tool-system/builtin/read.js +11 -3
- package/dist/tool-system/builtin/repl.js +4 -1
- package/dist/tool-system/builtin/skill.js +9 -0
- package/dist/tool-system/builtin/sleep.js +12 -5
- package/dist/tool-system/builtin/task.js +4 -1
- package/dist/tool-system/builtin/tool-search.js +25 -7
- package/dist/tool-system/builtin/update-automation-memory.d.ts +24 -0
- package/dist/tool-system/builtin/update-automation-memory.js +60 -0
- package/dist/tool-system/builtin/video-providers.d.ts +154 -0
- package/dist/tool-system/builtin/video-providers.js +235 -0
- package/dist/tool-system/builtin/view-image.d.ts +18 -0
- package/dist/tool-system/builtin/view-image.js +96 -0
- package/dist/tool-system/builtin/web-fetch.js +12 -2
- package/dist/tool-system/builtin/web-search.d.ts +4 -1
- package/dist/tool-system/builtin/web-search.js +57 -10
- package/dist/tool-system/builtin/worktree.d.ts +2 -1
- package/dist/tool-system/builtin/worktree.js +31 -4
- package/dist/tool-system/builtin/write.d.ts +2 -1
- package/dist/tool-system/builtin/write.js +1 -1
- package/dist/tool-system/context.d.ts +166 -6
- package/dist/tool-system/executor.d.ts +3 -2
- package/dist/tool-system/executor.js +197 -119
- package/dist/tool-system/investigation-guard.d.ts +4 -1
- package/dist/tool-system/investigation-guard.js +20 -4
- package/dist/tool-system/mcp-manager.d.ts +78 -16
- package/dist/tool-system/mcp-manager.js +357 -28
- package/dist/tool-system/path-policy.d.ts +99 -0
- package/dist/tool-system/path-policy.js +578 -0
- package/dist/tool-system/permission.d.ts +36 -1
- package/dist/tool-system/permission.js +322 -117
- package/dist/tool-system/plan-mode-allowlist.d.ts +32 -0
- package/dist/tool-system/plan-mode-allowlist.js +65 -0
- package/dist/tool-system/registry.d.ts +1 -0
- package/dist/tool-system/registry.js +26 -1
- package/dist/tool-system/sandbox/index.d.ts +8 -0
- package/dist/tool-system/sandbox/index.js +7 -2
- package/dist/tool-system/validate-tool-metadata.d.ts +36 -0
- package/dist/tool-system/validate-tool-metadata.js +63 -0
- package/dist/tool-system/validation.d.ts +10 -0
- package/dist/tool-system/validation.js +16 -3
- package/dist/types.d.ts +301 -15
- package/dist/updater.js +20 -9
- package/dist/utils/envUtils.d.ts +0 -9
- package/dist/utils/envUtils.js +3 -28
- package/dist/utils/exec.d.ts +40 -0
- package/dist/utils/exec.js +144 -0
- package/dist/utils/format.js +4 -2
- package/dist/utils/json.d.ts +12 -0
- package/dist/utils/json.js +92 -0
- package/dist/utils/lockfile.js +9 -2
- package/dist/utils/theme.d.ts +7 -1
- package/dist/utils/theme.js +5 -3
- package/dist/utils/toolDisplay.js +0 -1
- package/package.json +14 -7
- package/dist/agent/coordinator.d.ts +0 -49
- package/dist/agent/coordinator.js +0 -77
- package/dist/settings/manager.test.js +0 -73
- package/dist/tool-system/builtin/remote-trigger.d.ts +0 -6
- package/dist/tool-system/builtin/remote-trigger.js +0 -54
- package/dist/tool-system/builtin/send-message.d.ts +0 -6
- package/dist/tool-system/builtin/send-message.js +0 -47
- /package/dist/{settings/manager.test.d.ts → credentials/types.js} +0 -0
package/dist/git/worktree.js
CHANGED
|
@@ -1,9 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Git worktree management — create/remove isolated worktrees for agents.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { execFileSync } from "node:child_process";
|
|
5
5
|
import { existsSync, symlinkSync, lstatSync } from "node:fs";
|
|
6
|
-
import { join, resolve } from "node:path";
|
|
6
|
+
import { join, resolve, dirname } from "node:path";
|
|
7
|
+
import { safeSpawnShell } from "../runtime/safe-spawn.js";
|
|
8
|
+
import { buildSandboxEnv, mergeShellEnv, defaultShellBinary } from "../runtime/spawn-common.js";
|
|
9
|
+
import { resolveExecutable } from "../utils/exec.js";
|
|
10
|
+
// git resolved via PATH×PATHEXT on Windows (.cmd/.exe shim); no-op on POSIX.
|
|
11
|
+
const GIT_BIN = resolveExecutable("git");
|
|
12
|
+
/**
|
|
13
|
+
* Pick the setup/cleanup script for the running platform, falling back to
|
|
14
|
+
* `default`. Empty/whitespace-only scripts are treated as absent so a project
|
|
15
|
+
* can leave a platform key blank without spawning an empty shell. `platform`
|
|
16
|
+
* defaults to `process.platform` so callers usually omit it; tests pass a
|
|
17
|
+
* fixed value.
|
|
18
|
+
*/
|
|
19
|
+
export function selectPlatformScript(scripts, platform = process.platform) {
|
|
20
|
+
if (!scripts)
|
|
21
|
+
return undefined;
|
|
22
|
+
const key = platform === "darwin" ? "macos" : platform === "win32" ? "windows" : "linux";
|
|
23
|
+
// A blank platform key shouldn't shadow a real `default` — fall through.
|
|
24
|
+
const platformScript = scripts[key]?.trim() ? scripts[key] : undefined;
|
|
25
|
+
const candidate = platformScript ?? scripts.default;
|
|
26
|
+
const trimmed = candidate?.trim();
|
|
27
|
+
return trimmed ? candidate : undefined;
|
|
28
|
+
}
|
|
7
29
|
/**
|
|
8
30
|
* Validate worktree slug to prevent path traversal attacks.
|
|
9
31
|
*/
|
|
@@ -19,7 +41,7 @@ export function validateWorktreeSlug(slug) {
|
|
|
19
41
|
* Find the canonical git root (resolves worktree → main repo).
|
|
20
42
|
*/
|
|
21
43
|
export function findGitRoot(cwd) {
|
|
22
|
-
return
|
|
44
|
+
return execFileSync(GIT_BIN, ["rev-parse", "--show-toplevel"], { cwd, encoding: "utf-8", timeout: 5000 }).trim();
|
|
23
45
|
}
|
|
24
46
|
/**
|
|
25
47
|
* Create an isolated git worktree for an agent session.
|
|
@@ -32,7 +54,7 @@ export function createWorktree(cwd, slug, sessionId) {
|
|
|
32
54
|
// Get current branch for later reference
|
|
33
55
|
let originalBranch;
|
|
34
56
|
try {
|
|
35
|
-
originalBranch =
|
|
57
|
+
originalBranch = execFileSync(GIT_BIN, ["branch", "--show-current"], {
|
|
36
58
|
cwd: gitRoot,
|
|
37
59
|
encoding: "utf-8",
|
|
38
60
|
timeout: 5000,
|
|
@@ -41,8 +63,10 @@ export function createWorktree(cwd, slug, sessionId) {
|
|
|
41
63
|
catch {
|
|
42
64
|
// Detached HEAD
|
|
43
65
|
}
|
|
44
|
-
// Create the worktree
|
|
45
|
-
|
|
66
|
+
// Create the worktree. Pre-fix this used a quoted command string; the argv
|
|
67
|
+
// form keeps branchName/worktreePath as literal positional arguments even
|
|
68
|
+
// if a future caller bypasses validateWorktreeSlug.
|
|
69
|
+
execFileSync(GIT_BIN, ["worktree", "add", "-b", branchName, worktreePath], {
|
|
46
70
|
cwd: gitRoot,
|
|
47
71
|
timeout: 30000,
|
|
48
72
|
});
|
|
@@ -58,30 +82,91 @@ export function createWorktree(cwd, slug, sessionId) {
|
|
|
58
82
|
createdAt: Date.now(),
|
|
59
83
|
};
|
|
60
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Run a project's `localEnvironment.setupScripts` once, in the freshly-created
|
|
87
|
+
* worktree's root, right after `git worktree add`. This mirrors Codex's
|
|
88
|
+
* local-environment semantics: setup belongs to the *worktree* lifecycle, not
|
|
89
|
+
* the conversation — it runs when the isolated copy is born so e.g. `bun
|
|
90
|
+
* install` or `cp .env.example .env` happens before the agent works there.
|
|
91
|
+
*
|
|
92
|
+
* Failure is non-fatal by design (Beta decision 2026-06-08, "警告但继续"): a
|
|
93
|
+
* broken setup script shouldn't strand the agent outside a worktree it already
|
|
94
|
+
* created. The caller surfaces `output` as a warning and proceeds. cleanup
|
|
95
|
+
* scripts are intentionally NOT auto-run on exit (same decision).
|
|
96
|
+
*
|
|
97
|
+
* Reuses the same sandbox + env primitives as the Bash tool so the setup
|
|
98
|
+
* command sees the project's `localEnvironment.env` and runs under the same
|
|
99
|
+
* isolation the agent's later commands will.
|
|
100
|
+
*/
|
|
101
|
+
export async function runWorktreeSetup(worktreePath, script, opts = {}) {
|
|
102
|
+
const trimmed = script?.trim();
|
|
103
|
+
if (!trimmed)
|
|
104
|
+
return { skipped: true, ok: true, output: "" };
|
|
105
|
+
const shell = defaultShellBinary();
|
|
106
|
+
const backend = opts.sandbox;
|
|
107
|
+
const baseEnv = backend && backend.name !== "off" ? buildSandboxEnv() : { ...process.env };
|
|
108
|
+
const env = mergeShellEnv(baseEnv, opts.shellEnv);
|
|
109
|
+
const result = await safeSpawnShell(trimmed, {
|
|
110
|
+
cwd: worktreePath,
|
|
111
|
+
env,
|
|
112
|
+
timeoutMs: opts.timeoutMs ?? 120_000,
|
|
113
|
+
maxOutputBytes: 1024 * 1024,
|
|
114
|
+
sandbox: backend,
|
|
115
|
+
shell,
|
|
116
|
+
signal: opts.signal,
|
|
117
|
+
});
|
|
118
|
+
const parts = [];
|
|
119
|
+
if (result.stdout)
|
|
120
|
+
parts.push(result.stdout);
|
|
121
|
+
if (result.stderr)
|
|
122
|
+
parts.push(result.stderr);
|
|
123
|
+
const output = parts.join("\n").trim();
|
|
124
|
+
if (result.aborted)
|
|
125
|
+
return { skipped: false, ok: false, output: output || "setup aborted" };
|
|
126
|
+
if (result.timedOut)
|
|
127
|
+
return { skipped: false, ok: false, output: output || "setup timed out" };
|
|
128
|
+
if (result.spawnFailed) {
|
|
129
|
+
return { skipped: false, ok: false, output: result.error ?? "failed to spawn setup script" };
|
|
130
|
+
}
|
|
131
|
+
return { skipped: false, ok: result.exitCode === 0, output, exitCode: result.exitCode };
|
|
132
|
+
}
|
|
61
133
|
/**
|
|
62
134
|
* Remove a worktree and optionally its branch.
|
|
63
135
|
*/
|
|
64
136
|
export function removeWorktree(worktreePath, removeBranch = false) {
|
|
65
137
|
try {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
});
|
|
138
|
+
// The MAIN repo root, not the worktree's own toplevel. `git rev-parse
|
|
139
|
+
// --show-toplevel` from inside a worktree returns the worktree path, which
|
|
140
|
+
// is about to be deleted; the branch-delete must run from the main repo,
|
|
141
|
+
// which outlives the worktree. Derive it from the common git dir.
|
|
142
|
+
const commonDir = execFileSync(GIT_BIN, ["rev-parse", "--path-format=absolute", "--git-common-dir"], { cwd: worktreePath, encoding: "utf-8", timeout: 5000 }).trim();
|
|
143
|
+
const mainRoot = dirname(commonDir); // <main>/.git → <main>
|
|
144
|
+
// Capture the worktree's branch BEFORE removing the worktree — afterwards
|
|
145
|
+
// the directory is gone and `git branch --show-current` in it would fail
|
|
146
|
+
// (silently, leaving removeBranch a no-op).
|
|
147
|
+
let branch = "";
|
|
71
148
|
if (removeBranch) {
|
|
72
|
-
// Extract branch name from worktree
|
|
73
149
|
try {
|
|
74
|
-
|
|
150
|
+
branch = execFileSync(GIT_BIN, ["branch", "--show-current"], {
|
|
75
151
|
cwd: worktreePath,
|
|
76
152
|
encoding: "utf-8",
|
|
77
153
|
timeout: 5000,
|
|
78
154
|
}).trim();
|
|
79
|
-
if (branch.startsWith("worktree/")) {
|
|
80
|
-
execSync(`git branch -D "${branch}"`, { cwd: gitRoot, timeout: 10000 });
|
|
81
|
-
}
|
|
82
155
|
}
|
|
83
156
|
catch {
|
|
84
|
-
//
|
|
157
|
+
// Detached HEAD or unreadable — nothing to delete.
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
execFileSync(GIT_BIN, ["worktree", "remove", worktreePath, "--force"], {
|
|
161
|
+
cwd: mainRoot,
|
|
162
|
+
timeout: 30000,
|
|
163
|
+
});
|
|
164
|
+
if (removeBranch && branch.startsWith("worktree/")) {
|
|
165
|
+
try {
|
|
166
|
+
execFileSync(GIT_BIN, ["branch", "-D", branch], { cwd: mainRoot, timeout: 10000 });
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// Branch might already be removed.
|
|
85
170
|
}
|
|
86
171
|
}
|
|
87
172
|
}
|
|
@@ -93,7 +178,7 @@ export function removeWorktree(worktreePath, removeBranch = false) {
|
|
|
93
178
|
* List active worktrees.
|
|
94
179
|
*/
|
|
95
180
|
export function listWorktrees(cwd) {
|
|
96
|
-
const raw =
|
|
181
|
+
const raw = execFileSync(GIT_BIN, ["worktree", "list", "--porcelain"], {
|
|
97
182
|
cwd,
|
|
98
183
|
encoding: "utf-8",
|
|
99
184
|
timeout: 10000,
|
|
@@ -124,15 +209,21 @@ export function listWorktrees(cwd) {
|
|
|
124
209
|
*/
|
|
125
210
|
function symlinkLargeDirectories(sourceRoot, worktreePath) {
|
|
126
211
|
const largeDirs = ["node_modules", ".venv", "vendor", ".pnpm-store"];
|
|
212
|
+
// Windows directory symlinks need admin/Developer Mode and throw EPERM for a
|
|
213
|
+
// normal user; NTFS junctions don't and behave the same for our purpose
|
|
214
|
+
// (share node_modules into the worktree). Use "junction" on win32, "dir"
|
|
215
|
+
// elsewhere. Failure stays non-fatal — the worktree just doesn't share dirs.
|
|
216
|
+
const linkType = process.platform === "win32" ? "junction" : "dir";
|
|
127
217
|
for (const dir of largeDirs) {
|
|
128
218
|
const source = join(sourceRoot, dir);
|
|
129
219
|
const target = join(worktreePath, dir);
|
|
130
220
|
if (existsSync(source) && lstatSync(source).isDirectory() && !existsSync(target)) {
|
|
131
221
|
try {
|
|
132
|
-
symlinkSync(source, target,
|
|
222
|
+
symlinkSync(source, target, linkType);
|
|
133
223
|
}
|
|
134
224
|
catch {
|
|
135
|
-
// Symlink might fail on some systems
|
|
225
|
+
// Symlink/junction might fail on some systems — non-fatal, the
|
|
226
|
+
// worktree just won't share this directory (more disk, still works).
|
|
136
227
|
}
|
|
137
228
|
}
|
|
138
229
|
}
|
package/dist/hooks/events.d.ts
CHANGED
|
@@ -23,6 +23,21 @@
|
|
|
23
23
|
* may return `messages` to inject a
|
|
24
24
|
* per-turn reminder appended to the
|
|
25
25
|
* conversation right before the model call.
|
|
26
|
+
* - on_stop (turn-loop.ts) — fires when the model
|
|
27
|
+
* returns no tool calls and the loop is
|
|
28
|
+
* about to return reason "completed". A
|
|
29
|
+
* handler returning `continueSession: true`
|
|
30
|
+
* (with `messages`) BLOCKS termination:
|
|
31
|
+
* the messages are injected as a
|
|
32
|
+
* <system-reminder> and the loop runs
|
|
33
|
+
* another turn instead of stopping. This
|
|
34
|
+
* is the seam Goal mode uses (see
|
|
35
|
+
* goal-stop-hook.ts). Bounded by a
|
|
36
|
+
* consecutive-block cap (maxStopBlocks)
|
|
37
|
+
* and maxTurns. ctx.data carries `goal`,
|
|
38
|
+
* `finalText`, `turnCount`. Distinct from
|
|
39
|
+
* HookResult.stop, which controls the hook
|
|
40
|
+
* CHAIN, not agent termination.
|
|
26
41
|
* - pre_tool_use / post_tool_use (executor.ts) — pre_tool_use honors
|
|
27
42
|
* `decision: "deny"` to short-circuit
|
|
28
43
|
* the call (executor.ts:131).
|
|
@@ -72,7 +87,7 @@
|
|
|
72
87
|
* ContextManager; current implementation only knows
|
|
73
88
|
* after-the-fact (use post_compact instead).
|
|
74
89
|
*/
|
|
75
|
-
export type HookEventName = "on_agent_start" | "on_agent_end" | "on_turn_start" | "on_turn_end" | "on_tool_start" | "on_tool_end" | "on_permission_check" | "on_session_start" | "on_session_end" | "pre_tool_use" | "post_tool_use" | "user_prompt_submit" | "pre_compact" | "post_compact" | "file_changed" | "notification";
|
|
90
|
+
export type HookEventName = "on_agent_start" | "on_agent_end" | "on_turn_start" | "on_turn_end" | "on_stop" | "on_tool_start" | "on_tool_end" | "on_permission_check" | "on_session_start" | "on_session_end" | "pre_tool_use" | "post_tool_use" | "user_prompt_submit" | "pre_compact" | "post_compact" | "file_changed" | "notification";
|
|
76
91
|
export interface HookContext {
|
|
77
92
|
eventName: HookEventName;
|
|
78
93
|
data: Record<string, unknown>;
|
|
@@ -82,6 +97,13 @@ export interface HookContext {
|
|
|
82
97
|
export interface HookResult {
|
|
83
98
|
/** If true, stop the hook chain */
|
|
84
99
|
stop?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* For on_stop: if true, BLOCK agent termination — the loop injects this
|
|
102
|
+
* result's `messages` and runs another turn instead of returning
|
|
103
|
+
* "completed". Distinct from `stop` (which only short-circuits the hook
|
|
104
|
+
* chain). Ignored for non-on_stop events. Bounded by maxStopBlocks.
|
|
105
|
+
*/
|
|
106
|
+
continueSession?: boolean;
|
|
85
107
|
/** Modified data to pass along */
|
|
86
108
|
data?: Record<string, unknown>;
|
|
87
109
|
/** Additional messages to inject */
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { HookHandler } from "./registry.js";
|
|
2
|
+
import type { LLMResponse } from "../types.js";
|
|
3
|
+
import { type GoalConfig } from "../engine/goal.js";
|
|
4
|
+
/** Narrow LLM surface the judge needs — just a one-shot completion. */
|
|
5
|
+
export interface GoalJudgeLLM {
|
|
6
|
+
createMessage(options: {
|
|
7
|
+
systemPrompt: string;
|
|
8
|
+
messages: {
|
|
9
|
+
role: "user" | "assistant" | "system";
|
|
10
|
+
content: string;
|
|
11
|
+
}[];
|
|
12
|
+
stream?: boolean;
|
|
13
|
+
maxTokens?: number;
|
|
14
|
+
recordUsage?: boolean;
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
/** Reasoning control — the judge always asks for it OFF (see call site). */
|
|
17
|
+
reasoning?: import("../llm/reasoning-setting.js").ReasoningSetting;
|
|
18
|
+
}): Promise<LLMResponse>;
|
|
19
|
+
}
|
|
20
|
+
interface GoalLogger {
|
|
21
|
+
info: (msg: string, data?: Record<string, unknown>) => void;
|
|
22
|
+
warn: (msg: string, data?: Record<string, unknown>) => void;
|
|
23
|
+
error: (msg: string, data?: Record<string, unknown>) => void;
|
|
24
|
+
}
|
|
25
|
+
export interface GoalStopHookOptions {
|
|
26
|
+
llm: GoalJudgeLLM;
|
|
27
|
+
log: GoalLogger;
|
|
28
|
+
/** Override the goal instead of reading ctx.data.goal (mainly for tests). */
|
|
29
|
+
goal?: string | GoalConfig;
|
|
30
|
+
/**
|
|
31
|
+
* Re-check whether the session STILL has a live persisted goal, evaluated
|
|
32
|
+
* fresh each time the hook fires. The hook's `goal` above is frozen at
|
|
33
|
+
* creation, so a goal cleared mid-run (user hit 清除 while a long-lived
|
|
34
|
+
* run kept going) would otherwise be judged forever off the stale copy —
|
|
35
|
+
* the unregister path in Engine.clearGoal only fires for the one in-flight
|
|
36
|
+
* hook it tracks, which misses automation / resumed runs. When this returns
|
|
37
|
+
* false the hook allows the stop immediately without calling the judge.
|
|
38
|
+
* Injectable (reads SessionManager on the engine); omit to disable the
|
|
39
|
+
* re-check (tests / non-persistent callers).
|
|
40
|
+
*/
|
|
41
|
+
isGoalActive?: (sessionId: string) => boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Called once when the judge first returns met:true, before this handler
|
|
44
|
+
* returns. The engine uses it to clear the session's persisted activeGoal so
|
|
45
|
+
* a later bare send doesn't re-inherit a satisfied goal. Optional so tests /
|
|
46
|
+
* non-persistent callers can omit it.
|
|
47
|
+
*/
|
|
48
|
+
onMet?: () => void;
|
|
49
|
+
/**
|
|
50
|
+
* Clock source for the current time fed to the judge. Injectable so tests
|
|
51
|
+
* pin a fixed instant (the judge prompt is a fresh sub-call, not part of the
|
|
52
|
+
* cached prefix, so a live clock here has no cache cost). Defaults to
|
|
53
|
+
* `() => new Date()`.
|
|
54
|
+
*/
|
|
55
|
+
now?: () => Date;
|
|
56
|
+
}
|
|
57
|
+
export declare function createGoalStopHook(opts: GoalStopHookOptions): HookHandler;
|
|
58
|
+
export {};
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { normalizeGoal } from "../engine/goal.js";
|
|
2
|
+
import { listRunningBackgroundWork } from "../tool-system/builtin/background-work.js";
|
|
3
|
+
/**
|
|
4
|
+
* Render the current instant for the judge: a human-readable local time plus
|
|
5
|
+
* the numeric UTC offset and IANA zone, so the judge can reason about a
|
|
6
|
+
* wall-clock deadline written into the objective (e.g. "until 12:00"). An LLM
|
|
7
|
+
* has no clock — without this line it can never tell whether a time cutoff has
|
|
8
|
+
* passed. Falls back gracefully if Intl is unavailable.
|
|
9
|
+
*/
|
|
10
|
+
function renderNow(now) {
|
|
11
|
+
const iso = now.toISOString(); // unambiguous UTC anchor
|
|
12
|
+
try {
|
|
13
|
+
const zone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
14
|
+
// e.g. "2026-07-01 12:11:32 GMT+8"
|
|
15
|
+
const local = now.toLocaleString("sv-SE", {
|
|
16
|
+
timeZoneName: "short",
|
|
17
|
+
});
|
|
18
|
+
return `${local} (时区 ${zone};UTC 基准 ${iso})`;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return iso;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const JUDGE_SYSTEM = "你是一个目标完成度裁判。给定一个目标、agent 最近的输出,以及当前在后台运行的任务清单," +
|
|
25
|
+
"判断目标状态。只返回一个 JSON 对象,形如 " +
|
|
26
|
+
'{"met": true|false, "waiting": true|false, "gaps": "若未达成,简述还差什么;达成则空串"}。' +
|
|
27
|
+
"三态语义:" +
|
|
28
|
+
"(1) met:true —— 目标已完全达成。" +
|
|
29
|
+
"(2) waiting:true —— 目标尚未达成,但剩下唯一要做的事就是等一个【会结束的】后台任务完成" +
|
|
30
|
+
"(如下载、视频渲染、会退出的脚本),它完成后系统会自动唤醒你继续。此时应允许停下来等。" +
|
|
31
|
+
"(3) 两者皆 false —— 目标未达成,且还有你能【主动去做】的事。" +
|
|
32
|
+
"关键:【常驻服务】(如 dev server、watch、`npm run dev`/`bun run dev` 这类永不退出的进程)" +
|
|
33
|
+
"不算‘在等的任务’——它永远在跑,目标若不依赖它就照常判断达成与否,绝不要因为它而返回 waiting。" +
|
|
34
|
+
"时间截止:若目标里写了明确的时间截止(如“到 12:00 停”“until 15:00”“干到今晚 22 点”)," +
|
|
35
|
+
"你会拿到【当前时间】(含时区),据此自行判断截止时刻是否已到、目标是否应当结束;解读截止以【当前时间】所在时区为准。" +
|
|
36
|
+
"关键——解读【相对/不完整的时间】(如只说“3点”“今晚”而没写日期):以【目标设定时间】为基准," +
|
|
37
|
+
"取其之后【最近的那个】时点。例如目标设定于 07-01 23:00、说“做到3点”,那就是 07-02 03:00;" +
|
|
38
|
+
"设定于 10:00、说“做到3点”,那就是当天 15:00(下午3点,设定后最近的3点)。" +
|
|
39
|
+
"绝不要因为“当前时间已过那个钟点”就把它顺延到第二天——只要当前时间已过【据设定时间算出的】截止时刻,就应当结束。" +
|
|
40
|
+
"(未提供【目标设定时间】时,退回仅凭当前时间按常理推断。)" +
|
|
41
|
+
"目标没有时间截止时,忽略当前时间,照常按内容判断。" +
|
|
42
|
+
"不要输出任何额外文字。宁可严格:只有确信目标已完全完成时才返回 met:true。";
|
|
43
|
+
/** Pull the first balanced JSON object out of possibly-prose text. */
|
|
44
|
+
function extractJson(text) {
|
|
45
|
+
const start = text.indexOf("{");
|
|
46
|
+
const end = text.lastIndexOf("}");
|
|
47
|
+
if (start === -1 || end === -1 || end <= start)
|
|
48
|
+
return null;
|
|
49
|
+
const slice = text.slice(start, end + 1);
|
|
50
|
+
try {
|
|
51
|
+
const parsed = JSON.parse(slice);
|
|
52
|
+
if (!parsed || typeof parsed !== "object")
|
|
53
|
+
return null;
|
|
54
|
+
const p = parsed;
|
|
55
|
+
if (typeof p.met !== "boolean")
|
|
56
|
+
return null;
|
|
57
|
+
const gaps = typeof p.gaps === "string" ? p.gaps : "";
|
|
58
|
+
const waiting = typeof p.waiting === "boolean" ? p.waiting : false;
|
|
59
|
+
return { met: p.met, waiting, gaps };
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Render the running background tasks for the judge prompt. */
|
|
66
|
+
function renderBackgroundTasks(items) {
|
|
67
|
+
if (items.length === 0)
|
|
68
|
+
return "(无)";
|
|
69
|
+
const kindLabel = {
|
|
70
|
+
subagent: "后台子代理",
|
|
71
|
+
job: "后台任务",
|
|
72
|
+
shell: "后台命令",
|
|
73
|
+
};
|
|
74
|
+
return items
|
|
75
|
+
.map((i) => {
|
|
76
|
+
// A listening port strongly implies a long-lived service (dev server) —
|
|
77
|
+
// tell the judge so it doesn't classify it as a finite task to wait on.
|
|
78
|
+
const portNote = i.detectedPort != null
|
|
79
|
+
? `(在 :${i.detectedPort} 监听端口,疑似常驻服务)`
|
|
80
|
+
: "";
|
|
81
|
+
return `- [${kindLabel[i.kind] ?? i.kind}] ${i.description}${portNote}`;
|
|
82
|
+
})
|
|
83
|
+
.join("\n");
|
|
84
|
+
}
|
|
85
|
+
export function createGoalStopHook(opts) {
|
|
86
|
+
const { llm, log } = opts;
|
|
87
|
+
const now = opts.now ?? (() => new Date());
|
|
88
|
+
// Per-run cache: if the model emits the same final text with the same set of
|
|
89
|
+
// running background tasks twice in a row (it stalls repeating itself), the
|
|
90
|
+
// verdict can't have changed — reuse it instead of paying for another judge
|
|
91
|
+
// call. Keyed on (finalText + rendered task list); a `met` verdict is never
|
|
92
|
+
// cached (it ends the run anyway and triggers the onMet side-effect).
|
|
93
|
+
let lastKey = null;
|
|
94
|
+
let lastResult = null;
|
|
95
|
+
return async (ctx) => {
|
|
96
|
+
// Accept string or GoalConfig from either the override or ctx.data.goal.
|
|
97
|
+
const g = normalizeGoal(opts.goal ?? ctx.data.goal);
|
|
98
|
+
// No goal → not Goal mode → allow stop.
|
|
99
|
+
if (!g)
|
|
100
|
+
return {};
|
|
101
|
+
const goal = g.objective;
|
|
102
|
+
const sessionId = ctx.data.sessionId;
|
|
103
|
+
// Re-check the LIVE goal each turn. `goal` above is frozen at hook creation,
|
|
104
|
+
// so a goal cleared mid-run (清除) on a long-lived run (automation / resumed)
|
|
105
|
+
// would keep being judged off the stale copy — Engine.clearGoal's unregister
|
|
106
|
+
// only reaches the single in-flight hook it tracks. If the persisted goal is
|
|
107
|
+
// gone, allow the stop now and skip the judge call entirely.
|
|
108
|
+
if (opts.isGoalActive &&
|
|
109
|
+
typeof sessionId === "string" &&
|
|
110
|
+
sessionId.length > 0 &&
|
|
111
|
+
!opts.isGoalActive(sessionId)) {
|
|
112
|
+
log.info("goal_stop.cleared_midrun", { cat: "goal" });
|
|
113
|
+
return {};
|
|
114
|
+
}
|
|
115
|
+
// Background work is no longer a mechanical short-circuit. Instead we list
|
|
116
|
+
// what's running and let the judge decide (s-mqe0ox7n-a8d11c26 bug): a
|
|
117
|
+
// boolean "has background work" can't tell a finite download/render (→ wait
|
|
118
|
+
// for the wakeup, allow stop) from a never-ending dev server (→ judge the
|
|
119
|
+
// goal normally). The judge sees each task's kind + command and returns a
|
|
120
|
+
// three-state verdict; `waiting:true` allows the stop without pushing.
|
|
121
|
+
const runningWork = typeof sessionId === "string" && sessionId.length > 0
|
|
122
|
+
? listRunningBackgroundWork(sessionId)
|
|
123
|
+
: [];
|
|
124
|
+
const backgroundTasks = renderBackgroundTasks(runningWork);
|
|
125
|
+
const finalText = typeof ctx.data.finalText === "string" ? ctx.data.finalText : "";
|
|
126
|
+
const nowDate = now();
|
|
127
|
+
const nowLabel = renderNow(nowDate);
|
|
128
|
+
// The goal-set instant (when the user last set/replaced this goal), used by
|
|
129
|
+
// the judge to anchor relative deadlines ("做到3点"). renderNow renders any
|
|
130
|
+
// instant, not just "now". Absent for pre-field goals → line omitted, judge
|
|
131
|
+
// falls back to reasoning from current time alone.
|
|
132
|
+
const setAtLabel = typeof g.setAtMs === "number" && g.setAtMs > 0
|
|
133
|
+
? renderNow(new Date(g.setAtMs))
|
|
134
|
+
: undefined;
|
|
135
|
+
// Verdict cache key: same goal + same final text + same running tasks +
|
|
136
|
+
// same MINUTE ⇒ verdict unchanged; skip the LLM call and replay it.
|
|
137
|
+
// The minute bucket is in the key on purpose: if a goal has a wall-clock
|
|
138
|
+
// deadline and the model stalls repeating identical output, a time-blind
|
|
139
|
+
// key would replay a stale "not met" forever and the deadline would never
|
|
140
|
+
// fire. Bucketing to the minute still absorbs same-minute repeats while
|
|
141
|
+
// re-judging once the clock advances past a cutoff.
|
|
142
|
+
const minuteBucket = nowDate.toISOString().slice(0, 16);
|
|
143
|
+
const cacheKey = `${goal} ${finalText} ${backgroundTasks} ${minuteBucket}`;
|
|
144
|
+
if (lastKey === cacheKey && lastResult) {
|
|
145
|
+
log.info("goal_stop.verdict_cache_hit", { cat: "goal" });
|
|
146
|
+
return lastResult;
|
|
147
|
+
}
|
|
148
|
+
const signal = ctx.data.signal;
|
|
149
|
+
let verdict = null;
|
|
150
|
+
let respText = "";
|
|
151
|
+
let respStopReason;
|
|
152
|
+
try {
|
|
153
|
+
const resp = await llm.createMessage({
|
|
154
|
+
systemPrompt: JUDGE_SYSTEM,
|
|
155
|
+
messages: [
|
|
156
|
+
{
|
|
157
|
+
role: "user",
|
|
158
|
+
content: `目标:\n${goal}\n\n` +
|
|
159
|
+
(setAtLabel ? `目标设定于:${setAtLabel}\n\n` : "") +
|
|
160
|
+
`当前时间:${nowLabel}\n\n` +
|
|
161
|
+
`agent 最近的输出:\n${finalText || "(无文本输出)"}\n\n` +
|
|
162
|
+
`当前在后台运行的任务:\n${backgroundTasks}\n\n` +
|
|
163
|
+
"判断目标状态,按要求只返回 JSON(met / waiting / gaps)。",
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
stream: false,
|
|
167
|
+
// Headroom, not 400. A reasoning-capable aux model (e.g. DeepSeek V4)
|
|
168
|
+
// shares this budget between hidden reasoning tokens and the visible
|
|
169
|
+
// JSON. At 400 the reasoning ate the budget and the JSON got truncated
|
|
170
|
+
// (stopReason:"length") → extractJson returned null → the P0
|
|
171
|
+
// "unparseable" branch kept the run going forever, so a wall-clock
|
|
172
|
+
// deadline in the goal never fired. `reasoning:off` below is the real
|
|
173
|
+
// fix; 1500 is the belt-and-suspenders for models that ignore it.
|
|
174
|
+
maxTokens: 1500,
|
|
175
|
+
// Auxiliary sub-call — keep it out of the session cost/turn stats.
|
|
176
|
+
recordUsage: false,
|
|
177
|
+
// Turn thinking OFF. The judge only emits a tiny JSON verdict; reasoning
|
|
178
|
+
// tokens are pure waste here and (per above) actively caused truncation.
|
|
179
|
+
// On DeepSeek V4 / Anthropic-budget this genuinely disables thinking; on
|
|
180
|
+
// effort/adaptive/unknown models the field is a no-op (never a 400), so
|
|
181
|
+
// it is safe to always send — matching the aux summary/memory calls.
|
|
182
|
+
reasoning: { mode: "off" },
|
|
183
|
+
// Let a user Stop mid-judge abort this call rather than block on it.
|
|
184
|
+
signal,
|
|
185
|
+
});
|
|
186
|
+
respText = resp.text ?? "";
|
|
187
|
+
respStopReason = resp.stopReason;
|
|
188
|
+
verdict = extractJson(respText);
|
|
189
|
+
}
|
|
190
|
+
catch (err) {
|
|
191
|
+
log.warn("goal_stop.judge_failed", {
|
|
192
|
+
cat: "goal",
|
|
193
|
+
error: err.message,
|
|
194
|
+
});
|
|
195
|
+
// P0: do NOT silently allow stop on judge failure — in unattended runs
|
|
196
|
+
// that means the goal silently fails. Nudge to continue instead; the
|
|
197
|
+
// run-scoped budget guardrail (turn-loop) is the real safety backstop
|
|
198
|
+
// that prevents an unsatisfiable goal from looping forever.
|
|
199
|
+
return {
|
|
200
|
+
continueSession: true,
|
|
201
|
+
messages: [
|
|
202
|
+
"继续 —— 目标完成度无法判定,请继续推进直到明确完成(或调用 complete_goal 声明完成)。",
|
|
203
|
+
],
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
if (!verdict) {
|
|
207
|
+
// Record enough to diagnose WHY the verdict didn't parse without having to
|
|
208
|
+
// reproduce it live: stopReason ("length" ⇒ the reply was truncated, the
|
|
209
|
+
// most common cause) plus a short preview of the raw text. Preview is
|
|
210
|
+
// capped so a runaway reply can't bloat the log line.
|
|
211
|
+
log.warn("goal_stop.unparseable", {
|
|
212
|
+
cat: "goal",
|
|
213
|
+
stopReason: respStopReason,
|
|
214
|
+
preview: respText.slice(0, 200),
|
|
215
|
+
});
|
|
216
|
+
// P0: same as the throw path — unparseable judge output must not be
|
|
217
|
+
// treated as "done". Continue instead of silently allowing the stop.
|
|
218
|
+
return {
|
|
219
|
+
continueSession: true,
|
|
220
|
+
messages: [
|
|
221
|
+
"继续 —— 目标完成度无法判定,请继续推进直到明确完成(或调用 complete_goal 声明完成)。",
|
|
222
|
+
],
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
if (verdict.met) {
|
|
226
|
+
log.info("goal_stop.met", { cat: "goal" });
|
|
227
|
+
// Clear the persisted active goal (engine side-effect) so a later bare
|
|
228
|
+
// send doesn't re-inherit a satisfied goal. Isolated so a throwing
|
|
229
|
+
// callback can't block the stop.
|
|
230
|
+
try {
|
|
231
|
+
opts.onMet?.();
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
/* ignore */
|
|
235
|
+
}
|
|
236
|
+
// Surface the verdict so the loop can emit a goal_progress(met) event.
|
|
237
|
+
return { data: { goalVerdict: { met: true, gaps: "" } } };
|
|
238
|
+
}
|
|
239
|
+
// waiting: goal not met, but the only remaining work is a FINITE background
|
|
240
|
+
// task that will wake the session on completion. Allow the stop (no push) —
|
|
241
|
+
// forcing continueSession here is exactly the busy-loop bug. The completion
|
|
242
|
+
// notification wakes the idle session (server maybeWakeIdleSession) and the
|
|
243
|
+
// goal is re-judged on that woken turn.
|
|
244
|
+
//
|
|
245
|
+
// GUARD: only honor `waiting` when real background work is actually running.
|
|
246
|
+
// If the judge hallucinates waiting:true with an empty task list, allowing
|
|
247
|
+
// the stop would silently abandon the goal — NOTHING would ever wake the
|
|
248
|
+
// session (no notification to drain). So a baseless `waiting` falls through
|
|
249
|
+
// to not_met (continueSession), where the model is nudged to keep working.
|
|
250
|
+
if (verdict.waiting && runningWork.length > 0) {
|
|
251
|
+
log.info("goal_stop.waiting_on_background_task", { cat: "goal", sessionId });
|
|
252
|
+
const result = {
|
|
253
|
+
data: { goalVerdict: { met: false, gaps: verdict.gaps.trim() } },
|
|
254
|
+
};
|
|
255
|
+
lastKey = cacheKey;
|
|
256
|
+
lastResult = result;
|
|
257
|
+
return result;
|
|
258
|
+
}
|
|
259
|
+
if (verdict.waiting) {
|
|
260
|
+
log.warn("goal_stop.waiting_without_background_work", { cat: "goal", sessionId });
|
|
261
|
+
}
|
|
262
|
+
log.info("goal_stop.not_met", { cat: "goal", gaps: verdict.gaps });
|
|
263
|
+
const gaps = verdict.gaps.trim();
|
|
264
|
+
const result = {
|
|
265
|
+
continueSession: true,
|
|
266
|
+
messages: [
|
|
267
|
+
gaps
|
|
268
|
+
? `继续 —— 目标尚未达成。还差:${gaps}`
|
|
269
|
+
: "继续 —— 目标尚未达成,请接着完成它。",
|
|
270
|
+
],
|
|
271
|
+
// Structured verdict for the UI — the loop emits goal_progress(not_met)
|
|
272
|
+
// with this `gaps` instead of re-running the judge.
|
|
273
|
+
data: { goalVerdict: { met: false, gaps } },
|
|
274
|
+
};
|
|
275
|
+
lastKey = cacheKey;
|
|
276
|
+
lastResult = result;
|
|
277
|
+
return result;
|
|
278
|
+
};
|
|
279
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared output-handling primitives for hook runners.
|
|
3
|
+
*
|
|
4
|
+
* Two runners spawn child processes that produce HookResult JSON:
|
|
5
|
+
* - hooks/shell-runner.ts (user-configured shell hooks from settings)
|
|
6
|
+
* - plugins/pluginCommandHook.ts (hooks declared by installed plugins)
|
|
7
|
+
*
|
|
8
|
+
* Both need the same defences against:
|
|
9
|
+
* 1. Runaway output (a chatty / malicious handler eating engine RAM).
|
|
10
|
+
* 2. Schema drift (unknown decision values, typo'd top-level keys,
|
|
11
|
+
* non-string messages — silent no-ops are worse than rejections).
|
|
12
|
+
*
|
|
13
|
+
* Keeping the byte cap and validator in one module guarantees the two
|
|
14
|
+
* runners can't accidentally diverge on what counts as "valid".
|
|
15
|
+
*/
|
|
16
|
+
import type { HookResult } from "./events.js";
|
|
17
|
+
/**
|
|
18
|
+
* Cap hook output to avoid runaway logging / OOM. 1 MiB is more than enough
|
|
19
|
+
* for any legitimate HookResult (which is typically < 1 KiB), while still
|
|
20
|
+
* absorbing chatty handlers without truncating their decision/messages
|
|
21
|
+
* payload. Past the cap callers kill the child and treat the hook as failed.
|
|
22
|
+
*/
|
|
23
|
+
export declare const MAX_HOOK_OUTPUT_BYTES: number;
|
|
24
|
+
/**
|
|
25
|
+
* Permissive runtime check that a parsed object matches HookResult.
|
|
26
|
+
* Rejects unknown decision values, non-string/array fields, and unknown
|
|
27
|
+
* top-level keys (signalling a typo or hostile/garbage payload). Returns
|
|
28
|
+
* a normalized HookResult on success or null on failure — caller treats
|
|
29
|
+
* null the same as "no result, drop it".
|
|
30
|
+
*
|
|
31
|
+
* Exported so a unit test can pin the contract without spawning a shell.
|
|
32
|
+
*/
|
|
33
|
+
export declare function validateHookResult(parsed: unknown): HookResult | null;
|