@cjhyy/code-shell-core 0.5.0-rc.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/LICENSE +21 -0
- package/README.md +162 -0
- package/dist/agent/coordinator.d.ts +49 -0
- package/dist/agent/coordinator.js +77 -0
- package/dist/arena/arena.d.ts +43 -0
- package/dist/arena/arena.js +334 -0
- package/dist/arena/context/context-tools.d.ts +16 -0
- package/dist/arena/context/context-tools.js +231 -0
- package/dist/arena/detect-mode.d.ts +20 -0
- package/dist/arena/detect-mode.js +78 -0
- package/dist/arena/digest-builder.d.ts +25 -0
- package/dist/arena/digest-builder.js +120 -0
- package/dist/arena/index.d.ts +29 -0
- package/dist/arena/index.js +29 -0
- package/dist/arena/iterate/convergence.d.ts +25 -0
- package/dist/arena/iterate/convergence.js +103 -0
- package/dist/arena/iterate/formats/index.d.ts +22 -0
- package/dist/arena/iterate/formats/index.js +283 -0
- package/dist/arena/iterate/index.d.ts +11 -0
- package/dist/arena/iterate/index.js +9 -0
- package/dist/arena/iterate/iterative-arena.d.ts +23 -0
- package/dist/arena/iterate/iterative-arena.js +237 -0
- package/dist/arena/iterate/parse.d.ts +42 -0
- package/dist/arena/iterate/parse.js +123 -0
- package/dist/arena/iterate/phases/argue.d.ts +22 -0
- package/dist/arena/iterate/phases/argue.js +159 -0
- package/dist/arena/iterate/phases/revise.d.ts +16 -0
- package/dist/arena/iterate/phases/revise.js +62 -0
- package/dist/arena/iterate/phases/tournament.d.ts +34 -0
- package/dist/arena/iterate/phases/tournament.js +113 -0
- package/dist/arena/iterate/tools/web-tools.d.ts +13 -0
- package/dist/arena/iterate/tools/web-tools.js +54 -0
- package/dist/arena/iterate/types.d.ts +152 -0
- package/dist/arena/iterate/types.js +8 -0
- package/dist/arena/ledger.d.ts +47 -0
- package/dist/arena/ledger.js +151 -0
- package/dist/arena/lenses/architecture.d.ts +5 -0
- package/dist/arena/lenses/architecture.js +22 -0
- package/dist/arena/lenses/engineering.d.ts +5 -0
- package/dist/arena/lenses/engineering.js +22 -0
- package/dist/arena/lenses/general.d.ts +5 -0
- package/dist/arena/lenses/general.js +20 -0
- package/dist/arena/lenses/index.d.ts +16 -0
- package/dist/arena/lenses/index.js +47 -0
- package/dist/arena/lenses/product.d.ts +5 -0
- package/dist/arena/lenses/product.js +22 -0
- package/dist/arena/model-presets.d.ts +23 -0
- package/dist/arena/model-presets.js +44 -0
- package/dist/arena/phases/adjudication.d.ts +24 -0
- package/dist/arena/phases/adjudication.js +144 -0
- package/dist/arena/phases/build-consensus.d.ts +29 -0
- package/dist/arena/phases/build-consensus.js +86 -0
- package/dist/arena/phases/claim-registry.d.ts +26 -0
- package/dist/arena/phases/claim-registry.js +60 -0
- package/dist/arena/phases/cross-review.d.ts +45 -0
- package/dist/arena/phases/cross-review.js +224 -0
- package/dist/arena/phases/debate-rounds.d.ts +27 -0
- package/dist/arena/phases/debate-rounds.js +162 -0
- package/dist/arena/phases/participant-research.d.ts +38 -0
- package/dist/arena/phases/participant-research.js +317 -0
- package/dist/arena/phases/planning-detail-expansion.d.ts +38 -0
- package/dist/arena/phases/planning-detail-expansion.js +121 -0
- package/dist/arena/planner.d.ts +27 -0
- package/dist/arena/planner.js +312 -0
- package/dist/arena/providers/docs.d.ts +6 -0
- package/dist/arena/providers/docs.js +108 -0
- package/dist/arena/providers/git.d.ts +8 -0
- package/dist/arena/providers/git.js +174 -0
- package/dist/arena/providers/index.d.ts +32 -0
- package/dist/arena/providers/index.js +132 -0
- package/dist/arena/providers/none.d.ts +7 -0
- package/dist/arena/providers/none.js +11 -0
- package/dist/arena/providers/repo.d.ts +6 -0
- package/dist/arena/providers/repo.js +255 -0
- package/dist/arena/render/session.d.ts +17 -0
- package/dist/arena/render/session.js +190 -0
- package/dist/arena/render/terminal.d.ts +34 -0
- package/dist/arena/render/terminal.js +286 -0
- package/dist/arena/strategies/discussion.d.ts +25 -0
- package/dist/arena/strategies/discussion.js +143 -0
- package/dist/arena/strategies/index.d.ts +15 -0
- package/dist/arena/strategies/index.js +28 -0
- package/dist/arena/strategies/language-wrapper.d.ts +17 -0
- package/dist/arena/strategies/language-wrapper.js +102 -0
- package/dist/arena/strategies/lens-wrapper.d.ts +16 -0
- package/dist/arena/strategies/lens-wrapper.js +236 -0
- package/dist/arena/strategies/planning.d.ts +30 -0
- package/dist/arena/strategies/planning.js +225 -0
- package/dist/arena/strategies/review.d.ts +26 -0
- package/dist/arena/strategies/review.js +168 -0
- package/dist/arena/strategies/utils.d.ts +39 -0
- package/dist/arena/strategies/utils.js +647 -0
- package/dist/arena/tools/selector.d.ts +17 -0
- package/dist/arena/tools/selector.js +61 -0
- package/dist/arena/transitions.d.ts +48 -0
- package/dist/arena/transitions.js +92 -0
- package/dist/arena/types.d.ts +508 -0
- package/dist/arena/types.js +27 -0
- package/dist/cli/agent-server-stdio.d.ts +32 -0
- package/dist/cli/agent-server-stdio.js +116 -0
- package/dist/colorizer.d.ts +23 -0
- package/dist/colorizer.js +12 -0
- package/dist/context/compaction.d.ts +116 -0
- package/dist/context/compaction.js +534 -0
- package/dist/context/manager.d.ts +145 -0
- package/dist/context/manager.js +423 -0
- package/dist/context/token-counter.d.ts +27 -0
- package/dist/context/token-counter.js +91 -0
- package/dist/context/tool-result-storage.d.ts +96 -0
- package/dist/context/tool-result-storage.js +296 -0
- package/dist/cost-tracker.d.ts +64 -0
- package/dist/cost-tracker.js +314 -0
- package/dist/cron/scheduler.d.ts +34 -0
- package/dist/cron/scheduler.js +115 -0
- package/dist/data/deepseek-models.json +46 -0
- package/dist/data/gemini-models.json +67 -0
- package/dist/data/openai-models.json +175 -0
- package/dist/data/openrouter-models.d.ts +35 -0
- package/dist/data/openrouter-models.js +36 -0
- package/dist/data/openrouter-models.json +4626 -0
- package/dist/data/openrouter-sync.d.ts +16 -0
- package/dist/data/openrouter-sync.js +53 -0
- package/dist/data/static-catalogs.d.ts +25 -0
- package/dist/data/static-catalogs.js +26 -0
- package/dist/data/zai-models.json +56 -0
- package/dist/engine/cost-store.d.ts +22 -0
- package/dist/engine/cost-store.js +15 -0
- package/dist/engine/engine.d.ts +295 -0
- package/dist/engine/engine.js +1467 -0
- package/dist/engine/model-facade.d.ts +24 -0
- package/dist/engine/model-facade.js +194 -0
- package/dist/engine/parse-task.d.ts +59 -0
- package/dist/engine/parse-task.js +135 -0
- package/dist/engine/patch-orphaned-tools.d.ts +52 -0
- package/dist/engine/patch-orphaned-tools.js +95 -0
- package/dist/engine/query.d.ts +50 -0
- package/dist/engine/query.js +107 -0
- package/dist/engine/runtime.d.ts +50 -0
- package/dist/engine/runtime.js +59 -0
- package/dist/engine/streaming-tool-queue.d.ts +34 -0
- package/dist/engine/streaming-tool-queue.js +61 -0
- package/dist/engine/token-budget.d.ts +22 -0
- package/dist/engine/token-budget.js +40 -0
- package/dist/engine/tool-summary.d.ts +13 -0
- package/dist/engine/tool-summary.js +35 -0
- package/dist/engine/turn-loop.d.ts +122 -0
- package/dist/engine/turn-loop.js +602 -0
- package/dist/engine/turn-state.d.ts +20 -0
- package/dist/engine/turn-state.js +17 -0
- package/dist/exceptions.d.ts +61 -0
- package/dist/exceptions.js +116 -0
- package/dist/git/utils.d.ts +35 -0
- package/dist/git/utils.js +98 -0
- package/dist/git/worktree.d.ts +36 -0
- package/dist/git/worktree.js +139 -0
- package/dist/hooks/events.d.ts +114 -0
- package/dist/hooks/events.js +4 -0
- package/dist/hooks/inject.d.ts +19 -0
- package/dist/hooks/inject.js +29 -0
- package/dist/hooks/registry.d.ts +15 -0
- package/dist/hooks/registry.js +84 -0
- package/dist/hooks/shell-runner.d.ts +45 -0
- package/dist/hooks/shell-runner.js +173 -0
- package/dist/index.d.ts +117 -0
- package/dist/index.js +145 -0
- package/dist/llm/api-key-sanitize.d.ts +22 -0
- package/dist/llm/api-key-sanitize.js +81 -0
- package/dist/llm/capabilities/index.d.ts +20 -0
- package/dist/llm/capabilities/index.js +39 -0
- package/dist/llm/capabilities/rules.d.ts +26 -0
- package/dist/llm/capabilities/rules.js +215 -0
- package/dist/llm/capabilities/types.d.ts +114 -0
- package/dist/llm/capabilities/types.js +24 -0
- package/dist/llm/client-base.d.ts +29 -0
- package/dist/llm/client-base.js +137 -0
- package/dist/llm/client-factory.d.ts +10 -0
- package/dist/llm/client-factory.js +29 -0
- package/dist/llm/model-cache.d.ts +21 -0
- package/dist/llm/model-cache.js +46 -0
- package/dist/llm/model-fetcher.d.ts +29 -0
- package/dist/llm/model-fetcher.js +282 -0
- package/dist/llm/model-pool.d.ts +95 -0
- package/dist/llm/model-pool.js +246 -0
- package/dist/llm/provider-catalog.d.ts +32 -0
- package/dist/llm/provider-catalog.js +50 -0
- package/dist/llm/provider-kinds.d.ts +21 -0
- package/dist/llm/provider-kinds.js +132 -0
- package/dist/llm/providers/anthropic.d.ts +19 -0
- package/dist/llm/providers/anthropic.js +267 -0
- package/dist/llm/providers/openai.d.ts +64 -0
- package/dist/llm/providers/openai.js +606 -0
- package/dist/llm/retry.d.ts +12 -0
- package/dist/llm/retry.js +17 -0
- package/dist/llm/stream-watchdog.d.ts +42 -0
- package/dist/llm/stream-watchdog.js +70 -0
- package/dist/llm/token-counter.d.ts +17 -0
- package/dist/llm/token-counter.js +36 -0
- package/dist/llm/types.d.ts +37 -0
- package/dist/llm/types.js +4 -0
- package/dist/logging/logger.d.ts +109 -0
- package/dist/logging/logger.js +390 -0
- package/dist/logging/sanitize-messages.d.ts +42 -0
- package/dist/logging/sanitize-messages.js +150 -0
- package/dist/logging/session-recorder.d.ts +90 -0
- package/dist/logging/session-recorder.js +304 -0
- package/dist/lsp/client.d.ts +41 -0
- package/dist/lsp/client.js +166 -0
- package/dist/lsp/manager.d.ts +40 -0
- package/dist/lsp/manager.js +124 -0
- package/dist/lsp/servers.d.ts +16 -0
- package/dist/lsp/servers.js +60 -0
- package/dist/migrate-models.d.ts +45 -0
- package/dist/migrate-models.js +179 -0
- package/dist/onboarding.d.ts +189 -0
- package/dist/onboarding.js +625 -0
- package/dist/plugins/gitOps.d.ts +32 -0
- package/dist/plugins/gitOps.js +62 -0
- package/dist/plugins/installedPlugins.d.ts +15 -0
- package/dist/plugins/installedPlugins.js +56 -0
- package/dist/plugins/knownMarketplaces.d.ts +10 -0
- package/dist/plugins/knownMarketplaces.js +46 -0
- package/dist/plugins/loadPluginHooks.d.ts +52 -0
- package/dist/plugins/loadPluginHooks.js +162 -0
- package/dist/plugins/marketplaceManager.d.ts +49 -0
- package/dist/plugins/marketplaceManager.js +142 -0
- package/dist/plugins/parseMarketplaceInput.d.ts +16 -0
- package/dist/plugins/parseMarketplaceInput.js +73 -0
- package/dist/plugins/pluginCommandHook.d.ts +54 -0
- package/dist/plugins/pluginCommandHook.js +180 -0
- package/dist/plugins/pluginCommandsLoader.d.ts +25 -0
- package/dist/plugins/pluginCommandsLoader.js +114 -0
- package/dist/plugins/pluginInstaller.d.ts +36 -0
- package/dist/plugins/pluginInstaller.js +228 -0
- package/dist/plugins/schemas.d.ts +9 -0
- package/dist/plugins/schemas.js +136 -0
- package/dist/plugins/types.d.ts +75 -0
- package/dist/plugins/types.js +7 -0
- package/dist/plugins/varRewrite.d.ts +42 -0
- package/dist/plugins/varRewrite.js +129 -0
- package/dist/preset/index.d.ts +60 -0
- package/dist/preset/index.js +159 -0
- package/dist/product/define.d.ts +60 -0
- package/dist/product/define.js +123 -0
- package/dist/product/index.d.ts +5 -0
- package/dist/product/index.js +4 -0
- package/dist/product/types.d.ts +111 -0
- package/dist/product/types.js +21 -0
- package/dist/prompt/composer.d.ts +49 -0
- package/dist/prompt/composer.js +168 -0
- package/dist/prompt/instruction-scanner.d.ts +54 -0
- package/dist/prompt/instruction-scanner.js +187 -0
- package/dist/prompt/section-cache.d.ts +15 -0
- package/dist/prompt/section-cache.js +31 -0
- package/dist/prompt/section-loader.d.ts +26 -0
- package/dist/prompt/section-loader.js +53 -0
- package/dist/prompt/sections/base.md +35 -0
- package/dist/prompt/sections/coding.md +31 -0
- package/dist/prompt/sections/orchestration.md +16 -0
- package/dist/prompt/sections/tone.md +9 -0
- package/dist/protocol/chat-session-manager.d.ts +33 -0
- package/dist/protocol/chat-session-manager.js +65 -0
- package/dist/protocol/chat-session.d.ts +49 -0
- package/dist/protocol/chat-session.js +86 -0
- package/dist/protocol/client.d.ts +104 -0
- package/dist/protocol/client.js +260 -0
- package/dist/protocol/factories.d.ts +93 -0
- package/dist/protocol/factories.js +64 -0
- package/dist/protocol/helpers.d.ts +42 -0
- package/dist/protocol/helpers.js +55 -0
- package/dist/protocol/index.d.ts +4 -0
- package/dist/protocol/index.js +4 -0
- package/dist/protocol/server.d.ts +80 -0
- package/dist/protocol/server.js +855 -0
- package/dist/protocol/transport.d.ts +37 -0
- package/dist/protocol/transport.js +85 -0
- package/dist/protocol/types.d.ts +221 -0
- package/dist/protocol/types.js +61 -0
- package/dist/remote/bridge.d.ts +37 -0
- package/dist/remote/bridge.js +103 -0
- package/dist/run/ArtifactTracker.d.ts +38 -0
- package/dist/run/ArtifactTracker.js +132 -0
- package/dist/run/CheckpointWriter.d.ts +53 -0
- package/dist/run/CheckpointWriter.js +135 -0
- package/dist/run/EngineRunner.d.ts +72 -0
- package/dist/run/EngineRunner.js +119 -0
- package/dist/run/Evaluator.d.ts +56 -0
- package/dist/run/Evaluator.js +62 -0
- package/dist/run/FileRunStore.d.ts +39 -0
- package/dist/run/FileRunStore.js +176 -0
- package/dist/run/Heartbeat.d.ts +54 -0
- package/dist/run/Heartbeat.js +123 -0
- package/dist/run/RunApprovalBackend.d.ts +53 -0
- package/dist/run/RunApprovalBackend.js +85 -0
- package/dist/run/RunLock.d.ts +40 -0
- package/dist/run/RunLock.js +98 -0
- package/dist/run/RunManager.d.ts +82 -0
- package/dist/run/RunManager.js +587 -0
- package/dist/run/RunQueue.d.ts +27 -0
- package/dist/run/RunQueue.js +73 -0
- package/dist/run/RunStore.d.ts +25 -0
- package/dist/run/RunStore.js +9 -0
- package/dist/run/factory.d.ts +63 -0
- package/dist/run/factory.js +51 -0
- package/dist/run/index.d.ts +17 -0
- package/dist/run/index.js +23 -0
- package/dist/run/types.d.ts +136 -0
- package/dist/run/types.js +28 -0
- package/dist/runtime/safe-spawn.d.ts +118 -0
- package/dist/runtime/safe-spawn.js +268 -0
- package/dist/services/analytics.d.ts +29 -0
- package/dist/services/analytics.js +84 -0
- package/dist/services/auto-dream.d.ts +49 -0
- package/dist/services/auto-dream.js +124 -0
- package/dist/services/diagnostics.d.ts +41 -0
- package/dist/services/diagnostics.js +99 -0
- package/dist/services/extract-memories.d.ts +31 -0
- package/dist/services/extract-memories.js +71 -0
- package/dist/services/index.d.ts +11 -0
- package/dist/services/index.js +17 -0
- package/dist/services/memory-orchestrator.d.ts +60 -0
- package/dist/services/memory-orchestrator.js +133 -0
- package/dist/services/notifier.d.ts +25 -0
- package/dist/services/notifier.js +69 -0
- package/dist/services/oauth.d.ts +27 -0
- package/dist/services/oauth.js +153 -0
- package/dist/services/session-memory.d.ts +37 -0
- package/dist/services/session-memory.js +81 -0
- package/dist/session/file-history.d.ts +41 -0
- package/dist/session/file-history.js +115 -0
- package/dist/session/memory.d.ts +104 -0
- package/dist/session/memory.js +310 -0
- package/dist/session/session-manager.d.ts +41 -0
- package/dist/session/session-manager.js +261 -0
- package/dist/session/transcript.d.ts +39 -0
- package/dist/session/transcript.js +186 -0
- package/dist/settings/manager.d.ts +36 -0
- package/dist/settings/manager.js +187 -0
- package/dist/settings/schema.d.ts +1219 -0
- package/dist/settings/schema.js +246 -0
- package/dist/skills/frontmatter.d.ts +13 -0
- package/dist/skills/frontmatter.js +70 -0
- package/dist/skills/index.d.ts +7 -0
- package/dist/skills/index.js +6 -0
- package/dist/skills/scanner.d.ts +31 -0
- package/dist/skills/scanner.js +171 -0
- package/dist/state.d.ts +160 -0
- package/dist/state.js +267 -0
- package/dist/tool-system/builtin/agent-notifications.d.ts +84 -0
- package/dist/tool-system/builtin/agent-notifications.js +197 -0
- package/dist/tool-system/builtin/agent-registry.d.ts +67 -0
- package/dist/tool-system/builtin/agent-registry.js +126 -0
- package/dist/tool-system/builtin/agent-transcript-translator.d.ts +22 -0
- package/dist/tool-system/builtin/agent-transcript-translator.js +160 -0
- package/dist/tool-system/builtin/agent.d.ts +16 -0
- package/dist/tool-system/builtin/agent.js +364 -0
- package/dist/tool-system/builtin/apply-patch/applier.d.ts +26 -0
- package/dist/tool-system/builtin/apply-patch/applier.js +250 -0
- package/dist/tool-system/builtin/apply-patch/index.d.ts +20 -0
- package/dist/tool-system/builtin/apply-patch/index.js +101 -0
- package/dist/tool-system/builtin/apply-patch/parser.d.ts +17 -0
- package/dist/tool-system/builtin/apply-patch/parser.js +212 -0
- package/dist/tool-system/builtin/apply-patch/seek-sequence.d.ts +18 -0
- package/dist/tool-system/builtin/apply-patch/seek-sequence.js +123 -0
- package/dist/tool-system/builtin/apply-patch/types.d.ts +49 -0
- package/dist/tool-system/builtin/apply-patch/types.js +13 -0
- package/dist/tool-system/builtin/arena.d.ts +31 -0
- package/dist/tool-system/builtin/arena.js +416 -0
- package/dist/tool-system/builtin/ask-user.d.ts +20 -0
- package/dist/tool-system/builtin/ask-user.js +99 -0
- package/dist/tool-system/builtin/bash.d.ts +21 -0
- package/dist/tool-system/builtin/bash.js +149 -0
- package/dist/tool-system/builtin/brief.d.ts +6 -0
- package/dist/tool-system/builtin/brief.js +41 -0
- package/dist/tool-system/builtin/config.d.ts +6 -0
- package/dist/tool-system/builtin/config.js +67 -0
- package/dist/tool-system/builtin/cron.d.ts +10 -0
- package/dist/tool-system/builtin/cron.js +61 -0
- package/dist/tool-system/builtin/edit.d.ts +6 -0
- package/dist/tool-system/builtin/edit.js +100 -0
- package/dist/tool-system/builtin/file-cache.d.ts +11 -0
- package/dist/tool-system/builtin/file-cache.js +39 -0
- package/dist/tool-system/builtin/glob.d.ts +7 -0
- package/dist/tool-system/builtin/glob.js +76 -0
- package/dist/tool-system/builtin/grep.d.ts +7 -0
- package/dist/tool-system/builtin/grep.js +150 -0
- package/dist/tool-system/builtin/index.d.ts +20 -0
- package/dist/tool-system/builtin/index.js +449 -0
- package/dist/tool-system/builtin/lsp.d.ts +6 -0
- package/dist/tool-system/builtin/lsp.js +141 -0
- package/dist/tool-system/builtin/mcp-tools.d.ts +10 -0
- package/dist/tool-system/builtin/mcp-tools.js +102 -0
- package/dist/tool-system/builtin/memory.d.ts +26 -0
- package/dist/tool-system/builtin/memory.js +226 -0
- package/dist/tool-system/builtin/notebook-edit.d.ts +6 -0
- package/dist/tool-system/builtin/notebook-edit.js +124 -0
- package/dist/tool-system/builtin/plan.d.ts +15 -0
- package/dist/tool-system/builtin/plan.js +55 -0
- package/dist/tool-system/builtin/powershell.d.ts +11 -0
- package/dist/tool-system/builtin/powershell.js +64 -0
- package/dist/tool-system/builtin/read.d.ts +6 -0
- package/dist/tool-system/builtin/read.js +70 -0
- package/dist/tool-system/builtin/remote-trigger.d.ts +6 -0
- package/dist/tool-system/builtin/remote-trigger.js +54 -0
- package/dist/tool-system/builtin/repl.d.ts +11 -0
- package/dist/tool-system/builtin/repl.js +82 -0
- package/dist/tool-system/builtin/send-message.d.ts +6 -0
- package/dist/tool-system/builtin/send-message.js +47 -0
- package/dist/tool-system/builtin/skill-prompt.d.ts +20 -0
- package/dist/tool-system/builtin/skill-prompt.js +52 -0
- package/dist/tool-system/builtin/skill.d.ts +9 -0
- package/dist/tool-system/builtin/skill.js +55 -0
- package/dist/tool-system/builtin/sleep.d.ts +6 -0
- package/dist/tool-system/builtin/sleep.js +33 -0
- package/dist/tool-system/builtin/task.d.ts +48 -0
- package/dist/tool-system/builtin/task.js +139 -0
- package/dist/tool-system/builtin/tool-search.d.ts +11 -0
- package/dist/tool-system/builtin/tool-search.js +90 -0
- package/dist/tool-system/builtin/web-fetch.d.ts +10 -0
- package/dist/tool-system/builtin/web-fetch.js +328 -0
- package/dist/tool-system/builtin/web-search.d.ts +25 -0
- package/dist/tool-system/builtin/web-search.js +174 -0
- package/dist/tool-system/builtin/worktree.d.ts +10 -0
- package/dist/tool-system/builtin/worktree.js +95 -0
- package/dist/tool-system/builtin/write.d.ts +6 -0
- package/dist/tool-system/builtin/write.js +36 -0
- package/dist/tool-system/context.d.ts +165 -0
- package/dist/tool-system/context.js +18 -0
- package/dist/tool-system/executor.d.ts +49 -0
- package/dist/tool-system/executor.js +495 -0
- package/dist/tool-system/investigation-guard.d.ts +46 -0
- package/dist/tool-system/investigation-guard.js +155 -0
- package/dist/tool-system/mcp-manager.d.ts +67 -0
- package/dist/tool-system/mcp-manager.js +249 -0
- package/dist/tool-system/permission.d.ts +111 -0
- package/dist/tool-system/permission.js +774 -0
- package/dist/tool-system/registry.d.ts +32 -0
- package/dist/tool-system/registry.js +131 -0
- package/dist/tool-system/sandbox/bwrap.d.ts +13 -0
- package/dist/tool-system/sandbox/bwrap.js +63 -0
- package/dist/tool-system/sandbox/index.d.ts +78 -0
- package/dist/tool-system/sandbox/index.js +222 -0
- package/dist/tool-system/sandbox/off.d.ts +2 -0
- package/dist/tool-system/sandbox/off.js +8 -0
- package/dist/tool-system/sandbox/seatbelt.d.ts +18 -0
- package/dist/tool-system/sandbox/seatbelt.js +109 -0
- package/dist/tool-system/task-guard.d.ts +29 -0
- package/dist/tool-system/task-guard.js +70 -0
- package/dist/tool-system/validation.d.ts +5 -0
- package/dist/tool-system/validation.js +39 -0
- package/dist/types.d.ts +376 -0
- package/dist/types.js +4 -0
- package/dist/updater.d.ts +65 -0
- package/dist/updater.js +405 -0
- package/dist/utils/debug.d.ts +41 -0
- package/dist/utils/debug.js +110 -0
- package/dist/utils/earlyInput.d.ts +43 -0
- package/dist/utils/earlyInput.js +166 -0
- package/dist/utils/env.d.ts +24 -0
- package/dist/utils/env.js +104 -0
- package/dist/utils/envUtils.d.ts +51 -0
- package/dist/utils/envUtils.js +135 -0
- package/dist/utils/execFileNoThrow.d.ts +39 -0
- package/dist/utils/execFileNoThrow.js +74 -0
- package/dist/utils/format.d.ts +44 -0
- package/dist/utils/format.js +236 -0
- package/dist/utils/intl.d.ts +22 -0
- package/dist/utils/intl.js +83 -0
- package/dist/utils/lockfile.d.ts +15 -0
- package/dist/utils/lockfile.js +30 -0
- package/dist/utils/memoize.d.ts +19 -0
- package/dist/utils/memoize.js +14 -0
- package/dist/utils/semver.d.ts +6 -0
- package/dist/utils/semver.js +13 -0
- package/dist/utils/sliceAnsi.d.ts +12 -0
- package/dist/utils/sliceAnsi.js +62 -0
- package/dist/utils/systemTheme.d.ts +40 -0
- package/dist/utils/systemTheme.js +108 -0
- package/dist/utils/task-sanitizer.d.ts +6 -0
- package/dist/utils/task-sanitizer.js +24 -0
- package/dist/utils/theme.d.ts +93 -0
- package/dist/utils/theme.js +544 -0
- package/dist/utils/toolDisplay.d.ts +31 -0
- package/dist/utils/toolDisplay.js +188 -0
- package/package.json +72 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RunManager — the top-level coordinator for managed agent runs.
|
|
3
|
+
*
|
|
4
|
+
* It does NOT replace Engine. It wraps Engine.run() to provide:
|
|
5
|
+
* - Submit / queue / start / resume / cancel lifecycle
|
|
6
|
+
* - State machine validation
|
|
7
|
+
* - Event sourcing (append-only run events)
|
|
8
|
+
* - Checkpoint and approval coordination
|
|
9
|
+
* - Waiting states: waiting_input / waiting_approval with suspend/resume
|
|
10
|
+
* - Attach (live stream subscription)
|
|
11
|
+
* - Run locking, heartbeat, and crash recovery (Phase 4)
|
|
12
|
+
*/
|
|
13
|
+
import type { RunStore } from "./RunStore.js";
|
|
14
|
+
import { type EngineRunnerConfig, type RunExecutor } from "./EngineRunner.js";
|
|
15
|
+
import { type Evaluator } from "./Evaluator.js";
|
|
16
|
+
import type { RunSnapshot, RunEvent, SubmitRunInput, ResumeRunInput, ListRunsQuery, RunStreamCallback, DetachFn } from "./types.js";
|
|
17
|
+
export interface RunManagerConfig {
|
|
18
|
+
store: RunStore;
|
|
19
|
+
/**
|
|
20
|
+
* Execution backend. Two ways to provide:
|
|
21
|
+
* - `EngineRunnerConfig` object → creates built-in EngineRunner (calls LLM Engine)
|
|
22
|
+
* - `RunExecutor` instance → custom executor (any backend: CI/CD, ETL, etc.)
|
|
23
|
+
*/
|
|
24
|
+
executor: RunExecutor | EngineRunnerConfig;
|
|
25
|
+
concurrency?: number;
|
|
26
|
+
/** Base directory for runs (used by lock and heartbeat). */
|
|
27
|
+
runsDir?: string;
|
|
28
|
+
/** Heartbeat interval in ms. Default: 5000 */
|
|
29
|
+
heartbeatIntervalMs?: number;
|
|
30
|
+
/** Stale lock timeout in ms. Default: 60000 */
|
|
31
|
+
staleLockMs?: number;
|
|
32
|
+
/** Optional evaluator to run on completion. Default: NoopEvaluator */
|
|
33
|
+
evaluator?: Evaluator;
|
|
34
|
+
/** Tags applied to every submitted run unless already present. */
|
|
35
|
+
defaultTags?: string[];
|
|
36
|
+
/** Metadata merged into every submitted run. Submit input wins on conflicts. */
|
|
37
|
+
defaultMetadata?: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
export declare class RunManager {
|
|
40
|
+
private readonly store;
|
|
41
|
+
private readonly queue;
|
|
42
|
+
private readonly runner;
|
|
43
|
+
private readonly lock;
|
|
44
|
+
private readonly heartbeat;
|
|
45
|
+
private readonly evaluator;
|
|
46
|
+
private readonly defaultTags;
|
|
47
|
+
private readonly defaultMetadata;
|
|
48
|
+
private readonly subscribers;
|
|
49
|
+
private readonly abortControllers;
|
|
50
|
+
/** Active execution handles — used to resolve pending approvals/input while Engine is suspended */
|
|
51
|
+
private readonly executionHandles;
|
|
52
|
+
constructor(config: RunManagerConfig);
|
|
53
|
+
submit(input: SubmitRunInput): Promise<RunSnapshot>;
|
|
54
|
+
start(runId: string): Promise<void>;
|
|
55
|
+
resume(runId: string, input?: ResumeRunInput): Promise<void>;
|
|
56
|
+
cancel(runId: string, reason?: string): Promise<void>;
|
|
57
|
+
get(runId: string): Promise<RunSnapshot | null>;
|
|
58
|
+
list(query?: ListRunsQuery): Promise<RunSnapshot[]>;
|
|
59
|
+
getEvents(runId: string): Promise<RunEvent[]>;
|
|
60
|
+
attach(runId: string, cb: RunStreamCallback): DetachFn;
|
|
61
|
+
/**
|
|
62
|
+
* Scan for runs stuck in "running" state and recover them.
|
|
63
|
+
*
|
|
64
|
+
* Call this on process startup. For each "running" run:
|
|
65
|
+
* - If heartbeat is stale AND process is dead → reset to "queued" or "blocked"
|
|
66
|
+
* - If heartbeat is recent OR process is alive → skip (still executing)
|
|
67
|
+
*
|
|
68
|
+
* Returns the IDs of recovered runs.
|
|
69
|
+
*/
|
|
70
|
+
recover(): Promise<string[]>;
|
|
71
|
+
/**
|
|
72
|
+
* Graceful shutdown — stop all heartbeats and release all locks.
|
|
73
|
+
*/
|
|
74
|
+
shutdown(): Promise<void>;
|
|
75
|
+
private executeRun;
|
|
76
|
+
private handleApprovalNeeded;
|
|
77
|
+
private handleInputNeeded;
|
|
78
|
+
private transition;
|
|
79
|
+
private emitRunEvent;
|
|
80
|
+
private notifySubscribers;
|
|
81
|
+
private getOrThrow;
|
|
82
|
+
}
|
|
@@ -0,0 +1,587 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RunManager — the top-level coordinator for managed agent runs.
|
|
3
|
+
*
|
|
4
|
+
* It does NOT replace Engine. It wraps Engine.run() to provide:
|
|
5
|
+
* - Submit / queue / start / resume / cancel lifecycle
|
|
6
|
+
* - State machine validation
|
|
7
|
+
* - Event sourcing (append-only run events)
|
|
8
|
+
* - Checkpoint and approval coordination
|
|
9
|
+
* - Waiting states: waiting_input / waiting_approval with suspend/resume
|
|
10
|
+
* - Attach (live stream subscription)
|
|
11
|
+
* - Run locking, heartbeat, and crash recovery (Phase 4)
|
|
12
|
+
*/
|
|
13
|
+
import { nanoid } from "nanoid";
|
|
14
|
+
import { logger } from "../logging/logger.js";
|
|
15
|
+
import { RunQueue } from "./RunQueue.js";
|
|
16
|
+
import { EngineRunner } from "./EngineRunner.js";
|
|
17
|
+
import { CheckpointWriter } from "./CheckpointWriter.js";
|
|
18
|
+
import { ArtifactTracker } from "./ArtifactTracker.js";
|
|
19
|
+
import { RunLock } from "./RunLock.js";
|
|
20
|
+
import { Heartbeat } from "./Heartbeat.js";
|
|
21
|
+
import { NoopEvaluator } from "./Evaluator.js";
|
|
22
|
+
import { VALID_TRANSITIONS } from "./types.js";
|
|
23
|
+
export class RunManager {
|
|
24
|
+
store;
|
|
25
|
+
queue;
|
|
26
|
+
runner;
|
|
27
|
+
lock;
|
|
28
|
+
heartbeat;
|
|
29
|
+
evaluator;
|
|
30
|
+
defaultTags;
|
|
31
|
+
defaultMetadata;
|
|
32
|
+
subscribers = new Map();
|
|
33
|
+
abortControllers = new Map();
|
|
34
|
+
/** Active execution handles — used to resolve pending approvals/input while Engine is suspended */
|
|
35
|
+
executionHandles = new Map();
|
|
36
|
+
constructor(config) {
|
|
37
|
+
this.store = config.store;
|
|
38
|
+
this.queue = new RunQueue({ concurrency: config.concurrency ?? 1 });
|
|
39
|
+
// Accept either a RunExecutor instance or an EngineRunnerConfig
|
|
40
|
+
this.runner = isRunExecutor(config.executor)
|
|
41
|
+
? config.executor
|
|
42
|
+
: new EngineRunner(config.executor);
|
|
43
|
+
this.lock = new RunLock({
|
|
44
|
+
runsDir: config.runsDir,
|
|
45
|
+
staleMs: config.staleLockMs,
|
|
46
|
+
});
|
|
47
|
+
this.heartbeat = new Heartbeat({
|
|
48
|
+
runsDir: config.runsDir,
|
|
49
|
+
intervalMs: config.heartbeatIntervalMs,
|
|
50
|
+
});
|
|
51
|
+
this.evaluator = config.evaluator ?? new NoopEvaluator();
|
|
52
|
+
this.defaultTags = config.defaultTags ?? [];
|
|
53
|
+
this.defaultMetadata = config.defaultMetadata ?? {};
|
|
54
|
+
// Wire queue executor
|
|
55
|
+
this.queue.setExecutor((runId) => this.executeRun(runId));
|
|
56
|
+
}
|
|
57
|
+
// ─── Submit ────────────────────────────────────────────────────
|
|
58
|
+
async submit(input) {
|
|
59
|
+
const now = Date.now();
|
|
60
|
+
const runId = nanoid(16);
|
|
61
|
+
const snapshot = {
|
|
62
|
+
runId,
|
|
63
|
+
objective: input.objective,
|
|
64
|
+
preset: input.preset ?? "terminal-coding",
|
|
65
|
+
cwd: input.cwd ?? process.cwd(),
|
|
66
|
+
status: "queued",
|
|
67
|
+
createdAt: now,
|
|
68
|
+
updatedAt: now,
|
|
69
|
+
startedAt: null,
|
|
70
|
+
finishedAt: null,
|
|
71
|
+
parentRunId: input.parentRunId ?? null,
|
|
72
|
+
sessionId: null,
|
|
73
|
+
childSessionIds: [],
|
|
74
|
+
attemptCount: 0,
|
|
75
|
+
latestCheckpointId: null,
|
|
76
|
+
latestApprovalId: null,
|
|
77
|
+
summary: null,
|
|
78
|
+
error: null,
|
|
79
|
+
tags: [...new Set([...this.defaultTags, ...(input.tags ?? [])])],
|
|
80
|
+
metadata: { ...this.defaultMetadata, ...(input.metadata ?? {}) },
|
|
81
|
+
};
|
|
82
|
+
await this.store.create(snapshot);
|
|
83
|
+
await this.emitRunEvent(runId, "run_created", { objective: input.objective });
|
|
84
|
+
await this.emitRunEvent(runId, "run_queued", {});
|
|
85
|
+
logger.info("run.submitted", { runId, objective: input.objective.slice(0, 120) });
|
|
86
|
+
// Enqueue for execution
|
|
87
|
+
this.queue.enqueue(runId);
|
|
88
|
+
return snapshot;
|
|
89
|
+
}
|
|
90
|
+
// ─── Start (manual, bypasses queue) ────────────────────────────
|
|
91
|
+
async start(runId) {
|
|
92
|
+
const run = await this.getOrThrow(runId);
|
|
93
|
+
if (run.status !== "queued") {
|
|
94
|
+
throw new Error(`Cannot start run ${runId}: current status is ${run.status}`);
|
|
95
|
+
}
|
|
96
|
+
if (!this.queue.isPending(runId) && !this.queue.isActive(runId)) {
|
|
97
|
+
this.queue.enqueue(runId);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// ─── Resume ────────────────────────────────────────────────────
|
|
101
|
+
async resume(runId, input) {
|
|
102
|
+
const run = await this.getOrThrow(runId);
|
|
103
|
+
if (run.status !== "waiting_input" &&
|
|
104
|
+
run.status !== "waiting_approval" &&
|
|
105
|
+
run.status !== "blocked") {
|
|
106
|
+
throw new Error(`Cannot resume run ${runId}: current status is ${run.status}`);
|
|
107
|
+
}
|
|
108
|
+
const handle = this.executionHandles.get(runId);
|
|
109
|
+
// Case 1: Engine is still suspended (in-process waiting)
|
|
110
|
+
// Resolve the pending promise so Engine continues
|
|
111
|
+
if (handle) {
|
|
112
|
+
if (run.status === "waiting_approval" && input?.approvalDecision) {
|
|
113
|
+
const { approvalId, approved, reason } = input.approvalDecision;
|
|
114
|
+
// Persist the approval decision
|
|
115
|
+
const approval = await this.store.getApproval(runId, approvalId);
|
|
116
|
+
if (approval && approval.status === "pending") {
|
|
117
|
+
approval.status = approved ? "approved" : "rejected";
|
|
118
|
+
approval.resolvedAt = Date.now();
|
|
119
|
+
await this.store.saveApproval(approval);
|
|
120
|
+
await this.emitRunEvent(runId, "approval_resolved", {
|
|
121
|
+
approvalId,
|
|
122
|
+
approved,
|
|
123
|
+
reason,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
// Transition back to running and resolve the suspended Engine
|
|
127
|
+
await this.transition(run, "queued");
|
|
128
|
+
await this.transition(run, "running");
|
|
129
|
+
await this.emitRunEvent(runId, "run_resumed", {});
|
|
130
|
+
handle.resolveApproval(approved, reason);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (run.status === "waiting_input" && input?.userInput) {
|
|
134
|
+
await this.transition(run, "queued");
|
|
135
|
+
await this.transition(run, "running");
|
|
136
|
+
await this.emitRunEvent(runId, "run_resumed", { userInput: input.userInput });
|
|
137
|
+
handle.resolveInput(input.userInput);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Case 2: No active handle (process restarted, or blocked state)
|
|
142
|
+
// Re-queue the run for a fresh execution attempt
|
|
143
|
+
if (input?.approvalDecision) {
|
|
144
|
+
const { approvalId, approved, reason } = input.approvalDecision;
|
|
145
|
+
const approval = await this.store.getApproval(runId, approvalId);
|
|
146
|
+
if (approval && approval.status === "pending") {
|
|
147
|
+
approval.status = approved ? "approved" : "rejected";
|
|
148
|
+
approval.resolvedAt = Date.now();
|
|
149
|
+
await this.store.saveApproval(approval);
|
|
150
|
+
await this.emitRunEvent(runId, "approval_resolved", {
|
|
151
|
+
approvalId,
|
|
152
|
+
approved,
|
|
153
|
+
reason,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
await this.transition(run, "queued");
|
|
158
|
+
await this.emitRunEvent(runId, "run_resumed", {
|
|
159
|
+
userInput: input?.userInput,
|
|
160
|
+
});
|
|
161
|
+
this.queue.enqueue(runId);
|
|
162
|
+
}
|
|
163
|
+
// ─── Cancel ────────────────────────────────────────────────────
|
|
164
|
+
async cancel(runId, reason) {
|
|
165
|
+
const run = await this.getOrThrow(runId);
|
|
166
|
+
if (run.status === "completed" || run.status === "failed" || run.status === "cancelled") {
|
|
167
|
+
throw new Error(`Cannot cancel run ${runId}: already in terminal state ${run.status}`);
|
|
168
|
+
}
|
|
169
|
+
// Abort active execution
|
|
170
|
+
const ac = this.abortControllers.get(runId);
|
|
171
|
+
if (ac)
|
|
172
|
+
ac.abort();
|
|
173
|
+
// If Engine is suspended on approval/input, reject it so the promise resolves
|
|
174
|
+
const handle = this.executionHandles.get(runId);
|
|
175
|
+
if (handle) {
|
|
176
|
+
if (handle.hasPendingApproval()) {
|
|
177
|
+
handle.resolveApproval(false, "run cancelled");
|
|
178
|
+
}
|
|
179
|
+
if (handle.hasPendingInput()) {
|
|
180
|
+
handle.resolveInput("(run cancelled)");
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Remove from pending queue
|
|
184
|
+
this.queue.cancel(runId);
|
|
185
|
+
await this.transition(run, "cancelled");
|
|
186
|
+
run.finishedAt = Date.now();
|
|
187
|
+
await this.store.update(run);
|
|
188
|
+
await this.emitRunEvent(runId, "run_cancelled", { reason });
|
|
189
|
+
logger.info("run.cancelled", { runId, reason });
|
|
190
|
+
}
|
|
191
|
+
// ─── Query ─────────────────────────────────────────────────────
|
|
192
|
+
async get(runId) {
|
|
193
|
+
return this.store.get(runId);
|
|
194
|
+
}
|
|
195
|
+
async list(query) {
|
|
196
|
+
return this.store.list(query);
|
|
197
|
+
}
|
|
198
|
+
async getEvents(runId) {
|
|
199
|
+
return this.store.listEvents(runId);
|
|
200
|
+
}
|
|
201
|
+
// ─── Attach (live stream) ──────────────────────────────────────
|
|
202
|
+
attach(runId, cb) {
|
|
203
|
+
if (!this.subscribers.has(runId)) {
|
|
204
|
+
this.subscribers.set(runId, new Set());
|
|
205
|
+
}
|
|
206
|
+
this.subscribers.get(runId).add(cb);
|
|
207
|
+
return () => {
|
|
208
|
+
const subs = this.subscribers.get(runId);
|
|
209
|
+
if (subs) {
|
|
210
|
+
subs.delete(cb);
|
|
211
|
+
if (subs.size === 0)
|
|
212
|
+
this.subscribers.delete(runId);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
// ─── Crash Recovery ─────────────────────────────────────────────
|
|
217
|
+
/**
|
|
218
|
+
* Scan for runs stuck in "running" state and recover them.
|
|
219
|
+
*
|
|
220
|
+
* Call this on process startup. For each "running" run:
|
|
221
|
+
* - If heartbeat is stale AND process is dead → reset to "queued" or "blocked"
|
|
222
|
+
* - If heartbeat is recent OR process is alive → skip (still executing)
|
|
223
|
+
*
|
|
224
|
+
* Returns the IDs of recovered runs.
|
|
225
|
+
*/
|
|
226
|
+
async recover() {
|
|
227
|
+
const runs = await this.store.list({ status: "running" });
|
|
228
|
+
const recovered = [];
|
|
229
|
+
for (const run of runs) {
|
|
230
|
+
const processAlive = this.heartbeat.isProcessAlive(run.runId);
|
|
231
|
+
const stale = this.heartbeat.isStale(run.runId);
|
|
232
|
+
if (processAlive && !stale) {
|
|
233
|
+
// Still actively running in another process — leave it alone
|
|
234
|
+
logger.info("run.recover.skip", { runId: run.runId, reason: "process alive" });
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
// Process is dead or heartbeat is stale — recover
|
|
238
|
+
logger.info("run.recover.resetting", {
|
|
239
|
+
runId: run.runId,
|
|
240
|
+
processAlive,
|
|
241
|
+
stale,
|
|
242
|
+
});
|
|
243
|
+
// Force-unlock the stale lock
|
|
244
|
+
await this.lock.forceUnlock(run.runId);
|
|
245
|
+
// Decide recovery action based on attempt count
|
|
246
|
+
if (run.attemptCount >= 3) {
|
|
247
|
+
// Too many retries — mark as blocked
|
|
248
|
+
run.error = "Exceeded max recovery attempts (3)";
|
|
249
|
+
run.status = "blocked";
|
|
250
|
+
run.updatedAt = Date.now();
|
|
251
|
+
await this.store.update(run);
|
|
252
|
+
await this.emitRunEvent(run.runId, "run_blocked", {
|
|
253
|
+
error: run.error,
|
|
254
|
+
recovered: true,
|
|
255
|
+
});
|
|
256
|
+
logger.warn("run.recover.blocked", { runId: run.runId });
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
// Re-queue for retry
|
|
260
|
+
run.status = "queued";
|
|
261
|
+
run.updatedAt = Date.now();
|
|
262
|
+
await this.store.update(run);
|
|
263
|
+
await this.emitRunEvent(run.runId, "run_resumed", { recovered: true });
|
|
264
|
+
this.queue.enqueue(run.runId);
|
|
265
|
+
logger.info("run.recover.requeued", { runId: run.runId });
|
|
266
|
+
}
|
|
267
|
+
recovered.push(run.runId);
|
|
268
|
+
}
|
|
269
|
+
// Also check waiting runs with stale heartbeats (process died while waiting)
|
|
270
|
+
for (const status of ["waiting_input", "waiting_approval"]) {
|
|
271
|
+
const waitingRuns = await this.store.list({ status });
|
|
272
|
+
for (const run of waitingRuns) {
|
|
273
|
+
const stale = this.heartbeat.isStale(run.runId);
|
|
274
|
+
if (stale && !this.heartbeat.isProcessAlive(run.runId)) {
|
|
275
|
+
// The process died while the run was waiting — it stays in waiting
|
|
276
|
+
// state but we clean up the lock so it can be resumed
|
|
277
|
+
await this.lock.forceUnlock(run.runId);
|
|
278
|
+
logger.info("run.recover.unlock_waiting", { runId: run.runId, status });
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return recovered;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Graceful shutdown — stop all heartbeats and release all locks.
|
|
286
|
+
*/
|
|
287
|
+
async shutdown() {
|
|
288
|
+
this.heartbeat.stopAll();
|
|
289
|
+
await this.lock.releaseAll();
|
|
290
|
+
logger.info("run.shutdown");
|
|
291
|
+
}
|
|
292
|
+
// ─── Internal: Execute a run ───────────────────────────────────
|
|
293
|
+
async executeRun(runId) {
|
|
294
|
+
const run = await this.getOrThrow(runId);
|
|
295
|
+
// Acquire run lock — prevents concurrent execution by multiple workers
|
|
296
|
+
const acquired = await this.lock.acquire(runId);
|
|
297
|
+
if (!acquired) {
|
|
298
|
+
logger.warn("run.lock.failed", { runId, reason: "already locked by another worker" });
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
// Start heartbeat so crash recovery can detect liveness
|
|
302
|
+
this.heartbeat.start(runId);
|
|
303
|
+
// Transition to running
|
|
304
|
+
await this.transition(run, "running");
|
|
305
|
+
run.startedAt = run.startedAt ?? Date.now();
|
|
306
|
+
run.attemptCount += 1;
|
|
307
|
+
await this.store.update(run);
|
|
308
|
+
await this.emitRunEvent(runId, "run_started", { attempt: run.attemptCount });
|
|
309
|
+
// Create abort controller for this execution
|
|
310
|
+
const ac = new AbortController();
|
|
311
|
+
this.abortControllers.set(runId, ac);
|
|
312
|
+
// Create checkpoint writer and artifact tracker
|
|
313
|
+
const checkpointWriter = new CheckpointWriter({
|
|
314
|
+
runId,
|
|
315
|
+
objective: run.objective,
|
|
316
|
+
store: this.store,
|
|
317
|
+
});
|
|
318
|
+
const artifactTracker = new ArtifactTracker({ runId, store: this.store });
|
|
319
|
+
// Build lifecycle hooks so Engine can notify us about approval/input needs
|
|
320
|
+
const lifecycleHooks = {
|
|
321
|
+
onApprovalNeeded: async (request) => {
|
|
322
|
+
return this.handleApprovalNeeded(runId, request);
|
|
323
|
+
},
|
|
324
|
+
onInputNeeded: async (question) => {
|
|
325
|
+
await this.handleInputNeeded(runId, question);
|
|
326
|
+
},
|
|
327
|
+
};
|
|
328
|
+
const context = {
|
|
329
|
+
signal: ac.signal,
|
|
330
|
+
onStream: async (event) => {
|
|
331
|
+
// Feed events to checkpoint writer and artifact tracker
|
|
332
|
+
await checkpointWriter.onStreamEvent(event);
|
|
333
|
+
await artifactTracker.onStreamEvent(event);
|
|
334
|
+
// Forward to run subscribers
|
|
335
|
+
this.notifySubscribers(runId, { type: "engine_stream", event });
|
|
336
|
+
},
|
|
337
|
+
};
|
|
338
|
+
try {
|
|
339
|
+
const { result, handle } = await this.runner.execute(run, context, lifecycleHooks,
|
|
340
|
+
// Store handle BEFORE Engine.run() awaits, so resume() can resolve
|
|
341
|
+
// pending approvals/input while Engine is suspended
|
|
342
|
+
(h) => this.executionHandles.set(runId, h));
|
|
343
|
+
// Refresh run state (may have been updated during execution)
|
|
344
|
+
const current = await this.getOrThrow(runId);
|
|
345
|
+
// If the run was moved to a waiting state during execution, don't finalize
|
|
346
|
+
if (current.status === "waiting_input" ||
|
|
347
|
+
current.status === "waiting_approval" ||
|
|
348
|
+
current.status === "cancelled") {
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
// Link session
|
|
352
|
+
if (result.sessionId && current.sessionId !== result.sessionId) {
|
|
353
|
+
current.sessionId = result.sessionId;
|
|
354
|
+
checkpointWriter.setSessionId(result.sessionId);
|
|
355
|
+
await this.emitRunEvent(runId, "session_linked", {
|
|
356
|
+
sessionId: result.sessionId,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
// Write final checkpoint with accumulated data from writer/tracker
|
|
360
|
+
const checkpoint = {
|
|
361
|
+
checkpointId: nanoid(12),
|
|
362
|
+
runId,
|
|
363
|
+
createdAt: Date.now(),
|
|
364
|
+
phase: "final",
|
|
365
|
+
objective: current.objective,
|
|
366
|
+
summary: result.text.slice(0, 500),
|
|
367
|
+
nextAction: null,
|
|
368
|
+
linkedSessionId: result.sessionId,
|
|
369
|
+
touchedTools: checkpointWriter.getTouchedTools(),
|
|
370
|
+
touchedArtifacts: artifactTracker.getRecordedPaths(),
|
|
371
|
+
waitingFor: null,
|
|
372
|
+
evaluator: null,
|
|
373
|
+
metadata: { turnCount: result.turnCount, reason: result.reason },
|
|
374
|
+
};
|
|
375
|
+
await this.store.saveCheckpoint(checkpoint);
|
|
376
|
+
current.latestCheckpointId = checkpoint.checkpointId;
|
|
377
|
+
await this.emitRunEvent(runId, "checkpoint_written", {
|
|
378
|
+
checkpointId: checkpoint.checkpointId,
|
|
379
|
+
phase: "final",
|
|
380
|
+
});
|
|
381
|
+
// Run evaluator on the final checkpoint
|
|
382
|
+
const artifacts = await this.store.listArtifactRefs(runId);
|
|
383
|
+
const evalContext = { run: current, checkpoint, artifacts };
|
|
384
|
+
try {
|
|
385
|
+
const evalResult = await this.evaluator.evaluate(evalContext);
|
|
386
|
+
checkpoint.evaluator = {
|
|
387
|
+
status: evalResult.verdict === "passed" ? "passed" : "failed",
|
|
388
|
+
findings: evalResult.findings,
|
|
389
|
+
};
|
|
390
|
+
await this.store.saveCheckpoint(checkpoint);
|
|
391
|
+
}
|
|
392
|
+
catch (evalErr) {
|
|
393
|
+
logger.warn("run.evaluator_error", {
|
|
394
|
+
runId,
|
|
395
|
+
error: evalErr instanceof Error ? evalErr.message : String(evalErr),
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
// Determine terminal state — evaluator verdict can override
|
|
399
|
+
const engineSuccess = result.reason === "completed";
|
|
400
|
+
const evalFailed = checkpoint.evaluator?.status === "failed";
|
|
401
|
+
const isSuccess = engineSuccess && !evalFailed;
|
|
402
|
+
current.summary = result.text.slice(0, 500);
|
|
403
|
+
if (isSuccess) {
|
|
404
|
+
await this.transition(current, "completed");
|
|
405
|
+
current.finishedAt = Date.now();
|
|
406
|
+
await this.store.update(current);
|
|
407
|
+
await this.emitRunEvent(runId, "run_completed", {
|
|
408
|
+
turnCount: result.turnCount,
|
|
409
|
+
reason: result.reason,
|
|
410
|
+
evaluator: checkpoint.evaluator,
|
|
411
|
+
});
|
|
412
|
+
logger.info("run.completed", { runId, turnCount: result.turnCount });
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
current.error = evalFailed
|
|
416
|
+
? `Evaluator failed: ${checkpoint.evaluator?.findings.join("; ")}`
|
|
417
|
+
: `Engine terminated: ${result.reason}`;
|
|
418
|
+
await this.transition(current, "failed");
|
|
419
|
+
current.finishedAt = Date.now();
|
|
420
|
+
await this.store.update(current);
|
|
421
|
+
await this.emitRunEvent(runId, "run_failed", {
|
|
422
|
+
reason: evalFailed ? "evaluator_failed" : result.reason,
|
|
423
|
+
error: current.error,
|
|
424
|
+
evaluator: checkpoint.evaluator,
|
|
425
|
+
});
|
|
426
|
+
logger.warn("run.failed", { runId, reason: evalFailed ? "evaluator" : result.reason });
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
catch (err) {
|
|
430
|
+
const current = await this.store.get(runId);
|
|
431
|
+
if (!current)
|
|
432
|
+
return;
|
|
433
|
+
// If aborted (cancelled), state is already handled
|
|
434
|
+
if (ac.signal.aborted)
|
|
435
|
+
return;
|
|
436
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
437
|
+
current.error = errorMsg;
|
|
438
|
+
await this.transition(current, "blocked");
|
|
439
|
+
await this.store.update(current);
|
|
440
|
+
await this.emitRunEvent(runId, "run_blocked", { error: errorMsg });
|
|
441
|
+
logger.error("run.blocked", { runId, error: errorMsg });
|
|
442
|
+
}
|
|
443
|
+
finally {
|
|
444
|
+
this.abortControllers.delete(runId);
|
|
445
|
+
this.executionHandles.delete(runId);
|
|
446
|
+
this.heartbeat.stop(runId);
|
|
447
|
+
await this.lock.release(runId);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
// ─── Lifecycle: Approval Needed ────────────────────────────────
|
|
451
|
+
async handleApprovalNeeded(runId, request) {
|
|
452
|
+
const approvalId = nanoid(12);
|
|
453
|
+
const run = await this.getOrThrow(runId);
|
|
454
|
+
// Create approval record
|
|
455
|
+
const approval = {
|
|
456
|
+
approvalId,
|
|
457
|
+
runId,
|
|
458
|
+
createdAt: Date.now(),
|
|
459
|
+
resolvedAt: null,
|
|
460
|
+
status: "pending",
|
|
461
|
+
category: "tool",
|
|
462
|
+
title: `Approve: ${request.toolName}`,
|
|
463
|
+
description: request.description,
|
|
464
|
+
payload: { toolName: request.toolName, args: request.args, riskLevel: request.riskLevel },
|
|
465
|
+
};
|
|
466
|
+
await this.store.saveApproval(approval);
|
|
467
|
+
run.latestApprovalId = approvalId;
|
|
468
|
+
// Write waiting checkpoint
|
|
469
|
+
const checkpoint = {
|
|
470
|
+
checkpointId: nanoid(12),
|
|
471
|
+
runId,
|
|
472
|
+
createdAt: Date.now(),
|
|
473
|
+
phase: "waiting_approval",
|
|
474
|
+
objective: run.objective,
|
|
475
|
+
summary: `Awaiting approval for ${request.toolName}: ${request.description}`,
|
|
476
|
+
nextAction: null,
|
|
477
|
+
linkedSessionId: run.sessionId,
|
|
478
|
+
touchedTools: [],
|
|
479
|
+
touchedArtifacts: [],
|
|
480
|
+
waitingFor: { kind: "approval", approvalId },
|
|
481
|
+
evaluator: null,
|
|
482
|
+
metadata: {},
|
|
483
|
+
};
|
|
484
|
+
await this.store.saveCheckpoint(checkpoint);
|
|
485
|
+
run.latestCheckpointId = checkpoint.checkpointId;
|
|
486
|
+
// Transition to waiting_approval
|
|
487
|
+
await this.transition(run, "waiting_approval");
|
|
488
|
+
await this.emitRunEvent(runId, "approval_requested", {
|
|
489
|
+
approvalId,
|
|
490
|
+
toolName: request.toolName,
|
|
491
|
+
description: request.description,
|
|
492
|
+
riskLevel: request.riskLevel,
|
|
493
|
+
});
|
|
494
|
+
await this.emitRunEvent(runId, "checkpoint_written", {
|
|
495
|
+
checkpointId: checkpoint.checkpointId,
|
|
496
|
+
phase: "waiting_approval",
|
|
497
|
+
});
|
|
498
|
+
logger.info("run.waiting_approval", { runId, approvalId, tool: request.toolName });
|
|
499
|
+
return { approvalId };
|
|
500
|
+
}
|
|
501
|
+
// ─── Lifecycle: Input Needed ───────────────────────────────────
|
|
502
|
+
async handleInputNeeded(runId, question) {
|
|
503
|
+
const run = await this.getOrThrow(runId);
|
|
504
|
+
// Write waiting checkpoint
|
|
505
|
+
const checkpoint = {
|
|
506
|
+
checkpointId: nanoid(12),
|
|
507
|
+
runId,
|
|
508
|
+
createdAt: Date.now(),
|
|
509
|
+
phase: "waiting_input",
|
|
510
|
+
objective: run.objective,
|
|
511
|
+
summary: `Awaiting user input: ${question.slice(0, 200)}`,
|
|
512
|
+
nextAction: null,
|
|
513
|
+
linkedSessionId: run.sessionId,
|
|
514
|
+
touchedTools: [],
|
|
515
|
+
touchedArtifacts: [],
|
|
516
|
+
waitingFor: { kind: "input", prompt: question },
|
|
517
|
+
evaluator: null,
|
|
518
|
+
metadata: {},
|
|
519
|
+
};
|
|
520
|
+
await this.store.saveCheckpoint(checkpoint);
|
|
521
|
+
run.latestCheckpointId = checkpoint.checkpointId;
|
|
522
|
+
// Transition to waiting_input
|
|
523
|
+
await this.transition(run, "waiting_input");
|
|
524
|
+
await this.emitRunEvent(runId, "checkpoint_written", {
|
|
525
|
+
checkpointId: checkpoint.checkpointId,
|
|
526
|
+
phase: "waiting_input",
|
|
527
|
+
question,
|
|
528
|
+
});
|
|
529
|
+
logger.info("run.waiting_input", { runId, question: question.slice(0, 120) });
|
|
530
|
+
}
|
|
531
|
+
// ─── State Machine ─────────────────────────────────────────────
|
|
532
|
+
async transition(run, to) {
|
|
533
|
+
const allowed = VALID_TRANSITIONS[run.status];
|
|
534
|
+
if (!allowed.includes(to)) {
|
|
535
|
+
throw new Error(`Invalid run state transition: ${run.status} -> ${to} (run ${run.runId})`);
|
|
536
|
+
}
|
|
537
|
+
run.status = to;
|
|
538
|
+
run.updatedAt = Date.now();
|
|
539
|
+
await this.store.update(run);
|
|
540
|
+
this.notifySubscribers(run.runId, {
|
|
541
|
+
type: "run_status_changed",
|
|
542
|
+
run: { ...run },
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
// ─── Event Sourcing ────────────────────────────────────────────
|
|
546
|
+
async emitRunEvent(runId, type, data) {
|
|
547
|
+
const event = {
|
|
548
|
+
eventId: nanoid(12),
|
|
549
|
+
runId,
|
|
550
|
+
type,
|
|
551
|
+
timestamp: Date.now(),
|
|
552
|
+
data,
|
|
553
|
+
};
|
|
554
|
+
await this.store.appendEvent(event);
|
|
555
|
+
this.notifySubscribers(runId, { type: "run_event", event });
|
|
556
|
+
}
|
|
557
|
+
// ─── Subscribers ───────────────────────────────────────────────
|
|
558
|
+
notifySubscribers(runId, event) {
|
|
559
|
+
const subs = this.subscribers.get(runId);
|
|
560
|
+
if (!subs)
|
|
561
|
+
return;
|
|
562
|
+
for (const cb of subs) {
|
|
563
|
+
try {
|
|
564
|
+
cb(event);
|
|
565
|
+
}
|
|
566
|
+
catch (err) {
|
|
567
|
+
// Remove broken subscriber to prevent repeated errors
|
|
568
|
+
subs.delete(cb);
|
|
569
|
+
logger.warn("run.subscriber_error", {
|
|
570
|
+
runId,
|
|
571
|
+
error: err instanceof Error ? err.message : String(err),
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
// ─── Helpers ───────────────────────────────────────────────────
|
|
577
|
+
async getOrThrow(runId) {
|
|
578
|
+
const run = await this.store.get(runId);
|
|
579
|
+
if (!run)
|
|
580
|
+
throw new Error(`Run not found: ${runId}`);
|
|
581
|
+
return run;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
// ─── Type guard ─────────────────────────────────────────────────
|
|
585
|
+
function isRunExecutor(obj) {
|
|
586
|
+
return obj != null && typeof obj.execute === "function";
|
|
587
|
+
}
|