@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,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileRunStore — local filesystem implementation of RunStore.
|
|
3
|
+
*
|
|
4
|
+
* Layout:
|
|
5
|
+
* ~/.code-shell/runs/<runId>/
|
|
6
|
+
* run.json — current snapshot
|
|
7
|
+
* events.jsonl — append-only event log
|
|
8
|
+
* checkpoints/<id>.json — structured checkpoints
|
|
9
|
+
* approvals/<id>.json — approval records
|
|
10
|
+
* artifacts/refs.jsonl — artifact reference log
|
|
11
|
+
*/
|
|
12
|
+
import { mkdirSync, existsSync, readFileSync, writeFileSync, appendFileSync, readdirSync, renameSync, rmSync, } from "node:fs";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { homedir } from "node:os";
|
|
15
|
+
export class FileRunStore {
|
|
16
|
+
runsDir;
|
|
17
|
+
constructor(storageDir) {
|
|
18
|
+
this.runsDir = storageDir ?? join(homedir(), ".code-shell", "runs");
|
|
19
|
+
mkdirSync(this.runsDir, { recursive: true });
|
|
20
|
+
}
|
|
21
|
+
// ─── Helpers ───────────────────────────────────────────────────
|
|
22
|
+
runDir(runId) {
|
|
23
|
+
return join(this.runsDir, runId);
|
|
24
|
+
}
|
|
25
|
+
ensureRunDir(runId) {
|
|
26
|
+
const dir = this.runDir(runId);
|
|
27
|
+
mkdirSync(dir, { recursive: true });
|
|
28
|
+
mkdirSync(join(dir, "checkpoints"), { recursive: true });
|
|
29
|
+
mkdirSync(join(dir, "approvals"), { recursive: true });
|
|
30
|
+
mkdirSync(join(dir, "artifacts"), { recursive: true });
|
|
31
|
+
return dir;
|
|
32
|
+
}
|
|
33
|
+
writeJson(filePath, data) {
|
|
34
|
+
const tmp = filePath + ".tmp";
|
|
35
|
+
writeFileSync(tmp, JSON.stringify(data, null, 2), "utf-8");
|
|
36
|
+
// Atomic rename — prevents partial writes on crash
|
|
37
|
+
renameSync(tmp, filePath);
|
|
38
|
+
}
|
|
39
|
+
readJson(filePath) {
|
|
40
|
+
if (!existsSync(filePath))
|
|
41
|
+
return null;
|
|
42
|
+
return JSON.parse(readFileSync(filePath, "utf-8"));
|
|
43
|
+
}
|
|
44
|
+
/** Serializes concurrent JSONL appends per file path. */
|
|
45
|
+
appendLocks = new Map();
|
|
46
|
+
async appendJsonl(filePath, data) {
|
|
47
|
+
// Serialize writes to the same file to prevent interleaved output
|
|
48
|
+
const prev = this.appendLocks.get(filePath) ?? Promise.resolve();
|
|
49
|
+
const current = prev.then(() => {
|
|
50
|
+
appendFileSync(filePath, JSON.stringify(data) + "\n", "utf-8");
|
|
51
|
+
});
|
|
52
|
+
this.appendLocks.set(filePath, current);
|
|
53
|
+
await current;
|
|
54
|
+
}
|
|
55
|
+
readJsonl(filePath) {
|
|
56
|
+
if (!existsSync(filePath))
|
|
57
|
+
return [];
|
|
58
|
+
const content = readFileSync(filePath, "utf-8");
|
|
59
|
+
if (!content)
|
|
60
|
+
return [];
|
|
61
|
+
return content
|
|
62
|
+
.split("\n")
|
|
63
|
+
.filter((line) => line.trim())
|
|
64
|
+
.map((line) => JSON.parse(line));
|
|
65
|
+
}
|
|
66
|
+
// ─── Snapshot ──────────────────────────────────────────────────
|
|
67
|
+
async create(snapshot) {
|
|
68
|
+
const dir = this.ensureRunDir(snapshot.runId);
|
|
69
|
+
this.writeJson(join(dir, "run.json"), snapshot);
|
|
70
|
+
}
|
|
71
|
+
async update(snapshot) {
|
|
72
|
+
const dir = this.runDir(snapshot.runId);
|
|
73
|
+
if (!existsSync(dir)) {
|
|
74
|
+
throw new Error(`Run not found: ${snapshot.runId}`);
|
|
75
|
+
}
|
|
76
|
+
this.writeJson(join(dir, "run.json"), snapshot);
|
|
77
|
+
}
|
|
78
|
+
async get(runId) {
|
|
79
|
+
return this.readJson(join(this.runDir(runId), "run.json"));
|
|
80
|
+
}
|
|
81
|
+
async list(query) {
|
|
82
|
+
if (!existsSync(this.runsDir))
|
|
83
|
+
return [];
|
|
84
|
+
const entries = readdirSync(this.runsDir, { withFileTypes: true });
|
|
85
|
+
const snapshots = [];
|
|
86
|
+
for (const entry of entries) {
|
|
87
|
+
if (!entry.isDirectory())
|
|
88
|
+
continue;
|
|
89
|
+
const snapshot = this.readJson(join(this.runsDir, entry.name, "run.json"));
|
|
90
|
+
if (!snapshot)
|
|
91
|
+
continue;
|
|
92
|
+
// Filter by status
|
|
93
|
+
if (query?.status) {
|
|
94
|
+
const statuses = Array.isArray(query.status) ? query.status : [query.status];
|
|
95
|
+
if (!statuses.includes(snapshot.status))
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
// Filter by tag
|
|
99
|
+
if (query?.tag && !snapshot.tags.includes(query.tag))
|
|
100
|
+
continue;
|
|
101
|
+
snapshots.push(snapshot);
|
|
102
|
+
}
|
|
103
|
+
// Sort by createdAt descending (newest first)
|
|
104
|
+
snapshots.sort((a, b) => b.createdAt - a.createdAt);
|
|
105
|
+
// Pagination
|
|
106
|
+
const offset = query?.offset ?? 0;
|
|
107
|
+
const limit = query?.limit ?? 50;
|
|
108
|
+
return snapshots.slice(offset, offset + limit);
|
|
109
|
+
}
|
|
110
|
+
async delete(runId) {
|
|
111
|
+
const dir = this.runDir(runId);
|
|
112
|
+
if (existsSync(dir)) {
|
|
113
|
+
rmSync(dir, { recursive: true, force: true });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// ─── Events ────────────────────────────────────────────────────
|
|
117
|
+
async appendEvent(event) {
|
|
118
|
+
this.ensureRunDir(event.runId);
|
|
119
|
+
const dir = this.runDir(event.runId);
|
|
120
|
+
await this.appendJsonl(join(dir, "events.jsonl"), event);
|
|
121
|
+
}
|
|
122
|
+
async listEvents(runId) {
|
|
123
|
+
return this.readJsonl(join(this.runDir(runId), "events.jsonl"));
|
|
124
|
+
}
|
|
125
|
+
// ─── Checkpoints ───────────────────────────────────────────────
|
|
126
|
+
async saveCheckpoint(cp) {
|
|
127
|
+
const dir = this.runDir(cp.runId);
|
|
128
|
+
this.writeJson(join(dir, "checkpoints", `${cp.checkpointId}.json`), cp);
|
|
129
|
+
}
|
|
130
|
+
async getLatestCheckpoint(runId) {
|
|
131
|
+
const cpDir = join(this.runDir(runId), "checkpoints");
|
|
132
|
+
if (!existsSync(cpDir))
|
|
133
|
+
return null;
|
|
134
|
+
const files = readdirSync(cpDir).filter((f) => f.endsWith(".json"));
|
|
135
|
+
if (files.length === 0)
|
|
136
|
+
return null;
|
|
137
|
+
// Find the latest by createdAt
|
|
138
|
+
let latest = null;
|
|
139
|
+
for (const file of files) {
|
|
140
|
+
const cp = this.readJson(join(cpDir, file));
|
|
141
|
+
if (cp && (!latest || cp.createdAt > latest.createdAt)) {
|
|
142
|
+
latest = cp;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return latest;
|
|
146
|
+
}
|
|
147
|
+
// ─── Approvals ─────────────────────────────────────────────────
|
|
148
|
+
async saveApproval(approval) {
|
|
149
|
+
const dir = this.runDir(approval.runId);
|
|
150
|
+
this.writeJson(join(dir, "approvals", `${approval.approvalId}.json`), approval);
|
|
151
|
+
}
|
|
152
|
+
async getApproval(runId, approvalId) {
|
|
153
|
+
return this.readJson(join(this.runDir(runId), "approvals", `${approvalId}.json`));
|
|
154
|
+
}
|
|
155
|
+
async getPendingApproval(runId) {
|
|
156
|
+
const approvalDir = join(this.runDir(runId), "approvals");
|
|
157
|
+
if (!existsSync(approvalDir))
|
|
158
|
+
return null;
|
|
159
|
+
const files = readdirSync(approvalDir).filter((f) => f.endsWith(".json"));
|
|
160
|
+
for (const file of files) {
|
|
161
|
+
const approval = this.readJson(join(approvalDir, file));
|
|
162
|
+
if (approval?.status === "pending")
|
|
163
|
+
return approval;
|
|
164
|
+
}
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
// ─── Artifact Refs ─────────────────────────────────────────────
|
|
168
|
+
async appendArtifactRef(ref) {
|
|
169
|
+
this.ensureRunDir(ref.runId);
|
|
170
|
+
const dir = this.runDir(ref.runId);
|
|
171
|
+
await this.appendJsonl(join(dir, "artifacts", "refs.jsonl"), ref);
|
|
172
|
+
}
|
|
173
|
+
async listArtifactRefs(runId) {
|
|
174
|
+
return this.readJsonl(join(this.runDir(runId), "artifacts", "refs.jsonl"));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Heartbeat — periodic timestamp writer for run liveness detection.
|
|
3
|
+
*
|
|
4
|
+
* While a run is executing, the heartbeat writes a timestamp file at regular
|
|
5
|
+
* intervals. Crash recovery uses this to determine if a "running" run is
|
|
6
|
+
* actually alive or if its process died without cleanup.
|
|
7
|
+
*
|
|
8
|
+
* File: ~/.code-shell/runs/<runId>/heartbeat
|
|
9
|
+
* Content: JSON { pid, timestamp, runId }
|
|
10
|
+
*/
|
|
11
|
+
export interface HeartbeatConfig {
|
|
12
|
+
runsDir?: string;
|
|
13
|
+
/** Heartbeat interval in ms. Default: 5_000 (5 seconds) */
|
|
14
|
+
intervalMs?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface HeartbeatData {
|
|
17
|
+
pid: number;
|
|
18
|
+
timestamp: number;
|
|
19
|
+
runId: string;
|
|
20
|
+
}
|
|
21
|
+
export declare class Heartbeat {
|
|
22
|
+
private readonly runsDir;
|
|
23
|
+
private readonly intervalMs;
|
|
24
|
+
private timers;
|
|
25
|
+
constructor(config?: HeartbeatConfig);
|
|
26
|
+
/**
|
|
27
|
+
* Start heartbeat for a run. Writes immediately, then repeats on interval.
|
|
28
|
+
*/
|
|
29
|
+
start(runId: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* Stop heartbeat for a run and remove the heartbeat file.
|
|
32
|
+
*/
|
|
33
|
+
stop(runId: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* Stop all heartbeats.
|
|
36
|
+
*/
|
|
37
|
+
stopAll(): void;
|
|
38
|
+
/**
|
|
39
|
+
* Read the last heartbeat for a run. Returns null if no heartbeat exists.
|
|
40
|
+
*/
|
|
41
|
+
read(runId: string): HeartbeatData | null;
|
|
42
|
+
/**
|
|
43
|
+
* Check if a run's heartbeat is stale (older than threshold).
|
|
44
|
+
* Returns true if stale or missing, false if recent.
|
|
45
|
+
*/
|
|
46
|
+
isStale(runId: string, thresholdMs?: number): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Check if the process that wrote the heartbeat is still alive.
|
|
49
|
+
*/
|
|
50
|
+
isProcessAlive(runId: string): boolean;
|
|
51
|
+
private write;
|
|
52
|
+
private remove;
|
|
53
|
+
private filePath;
|
|
54
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Heartbeat — periodic timestamp writer for run liveness detection.
|
|
3
|
+
*
|
|
4
|
+
* While a run is executing, the heartbeat writes a timestamp file at regular
|
|
5
|
+
* intervals. Crash recovery uses this to determine if a "running" run is
|
|
6
|
+
* actually alive or if its process died without cleanup.
|
|
7
|
+
*
|
|
8
|
+
* File: ~/.code-shell/runs/<runId>/heartbeat
|
|
9
|
+
* Content: JSON { pid, timestamp, runId }
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, readFileSync, writeFileSync, unlinkSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import { homedir } from "node:os";
|
|
14
|
+
export class Heartbeat {
|
|
15
|
+
runsDir;
|
|
16
|
+
intervalMs;
|
|
17
|
+
timers = new Map();
|
|
18
|
+
constructor(config) {
|
|
19
|
+
this.runsDir = config?.runsDir ?? join(homedir(), ".code-shell", "runs");
|
|
20
|
+
this.intervalMs = config?.intervalMs ?? 5_000;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Start heartbeat for a run. Writes immediately, then repeats on interval.
|
|
24
|
+
*/
|
|
25
|
+
start(runId) {
|
|
26
|
+
// Write first heartbeat immediately
|
|
27
|
+
this.write(runId);
|
|
28
|
+
// Schedule periodic heartbeats
|
|
29
|
+
const timer = setInterval(() => this.write(runId), this.intervalMs);
|
|
30
|
+
// Unref so the timer doesn't prevent process exit
|
|
31
|
+
if (typeof timer === "object" && "unref" in timer) {
|
|
32
|
+
timer.unref();
|
|
33
|
+
}
|
|
34
|
+
this.timers.set(runId, timer);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Stop heartbeat for a run and remove the heartbeat file.
|
|
38
|
+
*/
|
|
39
|
+
stop(runId) {
|
|
40
|
+
const timer = this.timers.get(runId);
|
|
41
|
+
if (timer) {
|
|
42
|
+
clearInterval(timer);
|
|
43
|
+
this.timers.delete(runId);
|
|
44
|
+
}
|
|
45
|
+
this.remove(runId);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Stop all heartbeats.
|
|
49
|
+
*/
|
|
50
|
+
stopAll() {
|
|
51
|
+
for (const [runId] of this.timers) {
|
|
52
|
+
this.stop(runId);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Read the last heartbeat for a run. Returns null if no heartbeat exists.
|
|
57
|
+
*/
|
|
58
|
+
read(runId) {
|
|
59
|
+
const filePath = this.filePath(runId);
|
|
60
|
+
if (!existsSync(filePath))
|
|
61
|
+
return null;
|
|
62
|
+
try {
|
|
63
|
+
return JSON.parse(readFileSync(filePath, "utf-8"));
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Check if a run's heartbeat is stale (older than threshold).
|
|
71
|
+
* Returns true if stale or missing, false if recent.
|
|
72
|
+
*/
|
|
73
|
+
isStale(runId, thresholdMs) {
|
|
74
|
+
const threshold = thresholdMs ?? this.intervalMs * 3;
|
|
75
|
+
const data = this.read(runId);
|
|
76
|
+
if (!data)
|
|
77
|
+
return true;
|
|
78
|
+
return Date.now() - data.timestamp > threshold;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Check if the process that wrote the heartbeat is still alive.
|
|
82
|
+
*/
|
|
83
|
+
isProcessAlive(runId) {
|
|
84
|
+
const data = this.read(runId);
|
|
85
|
+
if (!data)
|
|
86
|
+
return false;
|
|
87
|
+
try {
|
|
88
|
+
// Sending signal 0 checks if process exists without actually signaling it
|
|
89
|
+
process.kill(data.pid, 0);
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
write(runId) {
|
|
97
|
+
const data = {
|
|
98
|
+
pid: process.pid,
|
|
99
|
+
timestamp: Date.now(),
|
|
100
|
+
runId,
|
|
101
|
+
};
|
|
102
|
+
try {
|
|
103
|
+
writeFileSync(this.filePath(runId), JSON.stringify(data), "utf-8");
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// Run directory may have been deleted
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
remove(runId) {
|
|
110
|
+
try {
|
|
111
|
+
const filePath = this.filePath(runId);
|
|
112
|
+
if (existsSync(filePath)) {
|
|
113
|
+
unlinkSync(filePath);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Already removed
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
filePath(runId) {
|
|
121
|
+
return join(this.runsDir, runId, "heartbeat");
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RunApprovalBackend — bridges Engine's approval system into Run lifecycle.
|
|
3
|
+
*
|
|
4
|
+
* When Engine requests tool approval:
|
|
5
|
+
* 1. Creates a RunApproval record
|
|
6
|
+
* 2. Notifies RunManager to transition the run to waiting_approval
|
|
7
|
+
* 3. Suspends the Engine's promise until the user resumes the run
|
|
8
|
+
*
|
|
9
|
+
* Similarly for AskUser:
|
|
10
|
+
* 1. Notifies RunManager to transition the run to waiting_input
|
|
11
|
+
* 2. Suspends until the user provides input via resume
|
|
12
|
+
*/
|
|
13
|
+
import type { ApprovalRequest, ApprovalResult } from "../types.js";
|
|
14
|
+
import type { ApprovalBackend } from "../tool-system/permission.js";
|
|
15
|
+
import type { AskUserFn } from "../tool-system/builtin/ask-user.js";
|
|
16
|
+
export interface PendingApproval {
|
|
17
|
+
resolve: (result: ApprovalResult) => void;
|
|
18
|
+
request: ApprovalRequest;
|
|
19
|
+
}
|
|
20
|
+
export interface PendingInput {
|
|
21
|
+
resolve: (answer: string) => void;
|
|
22
|
+
question: string;
|
|
23
|
+
}
|
|
24
|
+
export interface RunLifecycleHooks {
|
|
25
|
+
onApprovalNeeded: (request: ApprovalRequest) => Promise<{
|
|
26
|
+
approvalId: string;
|
|
27
|
+
}>;
|
|
28
|
+
onInputNeeded: (question: string) => Promise<void>;
|
|
29
|
+
onApprovalResolved?: (approvalId: string, result: ApprovalResult) => void;
|
|
30
|
+
onInputResolved?: (answer: string) => void;
|
|
31
|
+
}
|
|
32
|
+
export declare class RunApprovalBackend implements ApprovalBackend {
|
|
33
|
+
private pendingApproval;
|
|
34
|
+
private hooks;
|
|
35
|
+
setHooks(hooks: RunLifecycleHooks): void;
|
|
36
|
+
/** Max time (ms) to wait for approval before auto-rejecting. Default: 24h */
|
|
37
|
+
private timeoutMs;
|
|
38
|
+
setTimeout(ms: number): void;
|
|
39
|
+
requestApproval(request: ApprovalRequest): Promise<ApprovalResult>;
|
|
40
|
+
/**
|
|
41
|
+
* Called by RunManager when the user resumes with an approval decision.
|
|
42
|
+
*/
|
|
43
|
+
resolveApproval(result: ApprovalResult): boolean;
|
|
44
|
+
hasPendingApproval(): boolean;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Creates an AskUserFn that suspends the run when user input is needed.
|
|
48
|
+
*/
|
|
49
|
+
export declare function createRunAskUserFn(hooks: RunLifecycleHooks): {
|
|
50
|
+
askUserFn: AskUserFn;
|
|
51
|
+
resolveInput: (answer: string) => boolean;
|
|
52
|
+
hasPendingInput: () => boolean;
|
|
53
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RunApprovalBackend — bridges Engine's approval system into Run lifecycle.
|
|
3
|
+
*
|
|
4
|
+
* When Engine requests tool approval:
|
|
5
|
+
* 1. Creates a RunApproval record
|
|
6
|
+
* 2. Notifies RunManager to transition the run to waiting_approval
|
|
7
|
+
* 3. Suspends the Engine's promise until the user resumes the run
|
|
8
|
+
*
|
|
9
|
+
* Similarly for AskUser:
|
|
10
|
+
* 1. Notifies RunManager to transition the run to waiting_input
|
|
11
|
+
* 2. Suspends until the user provides input via resume
|
|
12
|
+
*/
|
|
13
|
+
// ─── RunApprovalBackend ──────────────────────────────────────────
|
|
14
|
+
export class RunApprovalBackend {
|
|
15
|
+
pendingApproval = null;
|
|
16
|
+
hooks = null;
|
|
17
|
+
setHooks(hooks) {
|
|
18
|
+
this.hooks = hooks;
|
|
19
|
+
}
|
|
20
|
+
/** Max time (ms) to wait for approval before auto-rejecting. Default: 24h */
|
|
21
|
+
timeoutMs = 24 * 60 * 60 * 1000;
|
|
22
|
+
setTimeout(ms) {
|
|
23
|
+
this.timeoutMs = ms;
|
|
24
|
+
}
|
|
25
|
+
async requestApproval(request) {
|
|
26
|
+
if (!this.hooks) {
|
|
27
|
+
// No hooks wired — fall back to auto-approve (shouldn't happen in practice)
|
|
28
|
+
return { approved: true };
|
|
29
|
+
}
|
|
30
|
+
// Notify RunManager that approval is needed
|
|
31
|
+
const { approvalId } = await this.hooks.onApprovalNeeded(request);
|
|
32
|
+
// Suspend execution until resolved (with timeout safety net)
|
|
33
|
+
return new Promise((resolve) => {
|
|
34
|
+
this.pendingApproval = { resolve, request };
|
|
35
|
+
const timer = setTimeout(() => {
|
|
36
|
+
if (this.pendingApproval?.resolve === resolve) {
|
|
37
|
+
this.pendingApproval = null;
|
|
38
|
+
resolve({ approved: false, reason: "approval timed out" });
|
|
39
|
+
}
|
|
40
|
+
}, this.timeoutMs);
|
|
41
|
+
if (typeof timer === "object" && "unref" in timer) {
|
|
42
|
+
timer.unref();
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Called by RunManager when the user resumes with an approval decision.
|
|
48
|
+
*/
|
|
49
|
+
resolveApproval(result) {
|
|
50
|
+
if (!this.pendingApproval)
|
|
51
|
+
return false;
|
|
52
|
+
const { resolve } = this.pendingApproval;
|
|
53
|
+
this.pendingApproval = null;
|
|
54
|
+
resolve(result);
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
hasPendingApproval() {
|
|
58
|
+
return this.pendingApproval !== null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// ─── RunAskUserAdapter ───────────────────────────────────────────
|
|
62
|
+
/**
|
|
63
|
+
* Creates an AskUserFn that suspends the run when user input is needed.
|
|
64
|
+
*/
|
|
65
|
+
export function createRunAskUserFn(hooks) {
|
|
66
|
+
let pending = null;
|
|
67
|
+
const askUserFn = async (question) => {
|
|
68
|
+
// Notify RunManager
|
|
69
|
+
await hooks.onInputNeeded(question);
|
|
70
|
+
// Suspend execution until user provides input
|
|
71
|
+
return new Promise((resolve) => {
|
|
72
|
+
pending = { resolve, question };
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
const resolveInput = (answer) => {
|
|
76
|
+
if (!pending)
|
|
77
|
+
return false;
|
|
78
|
+
const { resolve } = pending;
|
|
79
|
+
pending = null;
|
|
80
|
+
resolve(answer);
|
|
81
|
+
return true;
|
|
82
|
+
};
|
|
83
|
+
const hasPendingInput = () => pending !== null;
|
|
84
|
+
return { askUserFn, resolveInput, hasPendingInput };
|
|
85
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RunLock — file-based locking to prevent multiple workers from executing
|
|
3
|
+
* the same run concurrently.
|
|
4
|
+
*
|
|
5
|
+
* Uses proper-lockfile (via lazy wrapper) for cross-process safe locking.
|
|
6
|
+
* Each run gets a lock on its run.json file.
|
|
7
|
+
*/
|
|
8
|
+
export interface RunLockConfig {
|
|
9
|
+
/** Base directory for runs. Default: ~/.code-shell/runs */
|
|
10
|
+
runsDir?: string;
|
|
11
|
+
/** Stale lock timeout in ms. Default: 60_000 (1 minute) */
|
|
12
|
+
staleMs?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare class RunLock {
|
|
15
|
+
private readonly runsDir;
|
|
16
|
+
private readonly staleMs;
|
|
17
|
+
private readonly releaseFns;
|
|
18
|
+
constructor(config?: RunLockConfig);
|
|
19
|
+
/**
|
|
20
|
+
* Acquire a lock for a run. Returns true if acquired, false if already held.
|
|
21
|
+
*/
|
|
22
|
+
acquire(runId: string): Promise<boolean>;
|
|
23
|
+
/**
|
|
24
|
+
* Release the lock for a run.
|
|
25
|
+
*/
|
|
26
|
+
release(runId: string): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Check if a run is currently locked by any process.
|
|
29
|
+
*/
|
|
30
|
+
isLocked(runId: string): Promise<boolean>;
|
|
31
|
+
/**
|
|
32
|
+
* Force-unlock a stale lock (e.g., after crash recovery).
|
|
33
|
+
*/
|
|
34
|
+
forceUnlock(runId: string): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Release all locks held by this instance.
|
|
37
|
+
*/
|
|
38
|
+
releaseAll(): Promise<void>;
|
|
39
|
+
private lockTarget;
|
|
40
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RunLock — file-based locking to prevent multiple workers from executing
|
|
3
|
+
* the same run concurrently.
|
|
4
|
+
*
|
|
5
|
+
* Uses proper-lockfile (via lazy wrapper) for cross-process safe locking.
|
|
6
|
+
* Each run gets a lock on its run.json file.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync } from "node:fs";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { homedir } from "node:os";
|
|
11
|
+
import { lock, check, unlock } from "../utils/lockfile.js";
|
|
12
|
+
import { logger } from "../logging/logger.js";
|
|
13
|
+
export class RunLock {
|
|
14
|
+
runsDir;
|
|
15
|
+
staleMs;
|
|
16
|
+
releaseFns = new Map();
|
|
17
|
+
constructor(config) {
|
|
18
|
+
this.runsDir = config?.runsDir ?? join(homedir(), ".code-shell", "runs");
|
|
19
|
+
this.staleMs = config?.staleMs ?? 60_000;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Acquire a lock for a run. Returns true if acquired, false if already held.
|
|
23
|
+
*/
|
|
24
|
+
async acquire(runId) {
|
|
25
|
+
const lockTarget = this.lockTarget(runId);
|
|
26
|
+
if (!existsSync(lockTarget))
|
|
27
|
+
return false;
|
|
28
|
+
try {
|
|
29
|
+
const release = await lock(lockTarget, {
|
|
30
|
+
stale: this.staleMs,
|
|
31
|
+
retries: 0,
|
|
32
|
+
});
|
|
33
|
+
this.releaseFns.set(runId, release);
|
|
34
|
+
logger.info("run.lock.acquired", { runId });
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Lock already held by another process
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Release the lock for a run.
|
|
44
|
+
*/
|
|
45
|
+
async release(runId) {
|
|
46
|
+
const releaseFn = this.releaseFns.get(runId);
|
|
47
|
+
if (releaseFn) {
|
|
48
|
+
try {
|
|
49
|
+
await releaseFn();
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// Lock may already be released (stale cleanup)
|
|
53
|
+
}
|
|
54
|
+
this.releaseFns.delete(runId);
|
|
55
|
+
logger.info("run.lock.released", { runId });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Check if a run is currently locked by any process.
|
|
60
|
+
*/
|
|
61
|
+
async isLocked(runId) {
|
|
62
|
+
const lockTarget = this.lockTarget(runId);
|
|
63
|
+
if (!existsSync(lockTarget))
|
|
64
|
+
return false;
|
|
65
|
+
try {
|
|
66
|
+
return await check(lockTarget, { stale: this.staleMs });
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Force-unlock a stale lock (e.g., after crash recovery).
|
|
74
|
+
*/
|
|
75
|
+
async forceUnlock(runId) {
|
|
76
|
+
const lockTarget = this.lockTarget(runId);
|
|
77
|
+
if (!existsSync(lockTarget))
|
|
78
|
+
return;
|
|
79
|
+
try {
|
|
80
|
+
await unlock(lockTarget);
|
|
81
|
+
logger.info("run.lock.force_unlocked", { runId });
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// Already unlocked
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Release all locks held by this instance.
|
|
89
|
+
*/
|
|
90
|
+
async releaseAll() {
|
|
91
|
+
for (const [runId] of this.releaseFns) {
|
|
92
|
+
await this.release(runId);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
lockTarget(runId) {
|
|
96
|
+
return join(this.runsDir, runId, "run.json");
|
|
97
|
+
}
|
|
98
|
+
}
|