@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,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified tool registry — built-in tools + MCP tools.
|
|
3
|
+
*/
|
|
4
|
+
import type { RegisteredTool, ToolDefinition, ToolResult } from "../types.js";
|
|
5
|
+
import { type BuiltinToolFn } from "./builtin/index.js";
|
|
6
|
+
import type { ToolContext } from "./context.js";
|
|
7
|
+
/**
|
|
8
|
+
* Default execution timeout for any tool that does not declare its own
|
|
9
|
+
* timeoutMs at registration time. Tools that need to run longer (Agent,
|
|
10
|
+
* Arena, Bash, custom long-running tools) should set timeoutMs explicitly.
|
|
11
|
+
*/
|
|
12
|
+
export declare const DEFAULT_TOOL_TIMEOUT_MS = 120000;
|
|
13
|
+
export interface ToolRegistryOptions {
|
|
14
|
+
builtinTools?: readonly string[];
|
|
15
|
+
}
|
|
16
|
+
export declare class ToolRegistry {
|
|
17
|
+
private tools;
|
|
18
|
+
private builtinExecutors;
|
|
19
|
+
constructor(options?: ToolRegistryOptions);
|
|
20
|
+
private registerBuiltins;
|
|
21
|
+
registerTool(tool: RegisteredTool, executor?: BuiltinToolFn): void;
|
|
22
|
+
getToolDefinitions(): ToolDefinition[];
|
|
23
|
+
getTool(name: string): RegisteredTool | undefined;
|
|
24
|
+
hasTool(name: string): boolean;
|
|
25
|
+
executeTool(name: string, args: Record<string, unknown>, options?: {
|
|
26
|
+
timeoutMs?: number;
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
ctx?: ToolContext;
|
|
29
|
+
}): Promise<ToolResult>;
|
|
30
|
+
listTools(): string[];
|
|
31
|
+
listToolsDetailed(): RegisteredTool[];
|
|
32
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified tool registry — built-in tools + MCP tools.
|
|
3
|
+
*/
|
|
4
|
+
import { ConfigError, ToolNotFoundError, ToolExecutionError, ToolTimeoutError } from "../exceptions.js";
|
|
5
|
+
import { BUILTIN_TOOLS } from "./builtin/index.js";
|
|
6
|
+
/**
|
|
7
|
+
* Default execution timeout for any tool that does not declare its own
|
|
8
|
+
* timeoutMs at registration time. Tools that need to run longer (Agent,
|
|
9
|
+
* Arena, Bash, custom long-running tools) should set timeoutMs explicitly.
|
|
10
|
+
*/
|
|
11
|
+
export const DEFAULT_TOOL_TIMEOUT_MS = 120_000;
|
|
12
|
+
export class ToolRegistry {
|
|
13
|
+
tools = new Map();
|
|
14
|
+
builtinExecutors = new Map();
|
|
15
|
+
constructor(options = {}) {
|
|
16
|
+
this.registerBuiltins(options.builtinTools);
|
|
17
|
+
}
|
|
18
|
+
registerBuiltins(selectedBuiltinTools) {
|
|
19
|
+
const availableNames = new Set(BUILTIN_TOOLS.map((tool) => tool.definition.name));
|
|
20
|
+
const selectedNames = selectedBuiltinTools ? new Set(selectedBuiltinTools) : null;
|
|
21
|
+
if (selectedNames) {
|
|
22
|
+
const unknown = [...selectedNames].filter((name) => !availableNames.has(name));
|
|
23
|
+
if (unknown.length > 0) {
|
|
24
|
+
throw new ConfigError(`Unknown built-in tool(s): ${unknown.join(", ")}`, { unknownBuiltinTools: unknown });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
for (const tool of BUILTIN_TOOLS) {
|
|
28
|
+
if (selectedNames && !selectedNames.has(tool.definition.name)) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
this.tools.set(tool.definition.name, tool.definition);
|
|
32
|
+
this.builtinExecutors.set(tool.definition.name, tool.execute);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
registerTool(tool, executor) {
|
|
36
|
+
this.tools.set(tool.name, tool);
|
|
37
|
+
if (executor) {
|
|
38
|
+
this.builtinExecutors.set(tool.name, executor);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
getToolDefinitions() {
|
|
42
|
+
return [...this.tools.values()].map((t) => ({
|
|
43
|
+
name: t.name,
|
|
44
|
+
description: t.description,
|
|
45
|
+
inputSchema: t.inputSchema,
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
getTool(name) {
|
|
49
|
+
return this.tools.get(name);
|
|
50
|
+
}
|
|
51
|
+
hasTool(name) {
|
|
52
|
+
return this.tools.has(name);
|
|
53
|
+
}
|
|
54
|
+
async executeTool(name, args, options) {
|
|
55
|
+
const tool = this.tools.get(name);
|
|
56
|
+
if (!tool) {
|
|
57
|
+
throw new ToolNotFoundError(name);
|
|
58
|
+
}
|
|
59
|
+
const executor = this.builtinExecutors.get(name);
|
|
60
|
+
if (!executor) {
|
|
61
|
+
throw new ToolExecutionError(name, "No executor registered for this tool");
|
|
62
|
+
}
|
|
63
|
+
// Tool timeout precedence:
|
|
64
|
+
// options.timeoutMs (per-call override) > tool.timeoutMs (declared at registration) > default 120s.
|
|
65
|
+
// To run longer, declare timeoutMs on the tool (e.g. Agent/Arena: 30min, Bash: 1h).
|
|
66
|
+
const timeout = options?.timeoutMs ?? tool.timeoutMs ?? DEFAULT_TOOL_TIMEOUT_MS;
|
|
67
|
+
const parentSignal = options?.signal;
|
|
68
|
+
const id = `tool_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
69
|
+
// Check if already aborted before starting
|
|
70
|
+
if (parentSignal?.aborted) {
|
|
71
|
+
return {
|
|
72
|
+
id,
|
|
73
|
+
toolName: name,
|
|
74
|
+
error: `Tool aborted before execution: ${name}`,
|
|
75
|
+
isError: true,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// Create a child AbortController that aborts on timeout OR parent abort
|
|
79
|
+
const childController = new AbortController();
|
|
80
|
+
const timerId = timeout > 0
|
|
81
|
+
? setTimeout(() => childController.abort(new ToolTimeoutError(name, timeout)), timeout)
|
|
82
|
+
: undefined;
|
|
83
|
+
// Cascade parent abort to child
|
|
84
|
+
const onParentAbort = () => childController.abort(parentSignal?.reason);
|
|
85
|
+
parentSignal?.addEventListener("abort", onParentAbort, { once: true });
|
|
86
|
+
// Inject the abort signal into args so tools (like Agent) can use it
|
|
87
|
+
const argsWithSignal = { ...args, __signal: childController.signal };
|
|
88
|
+
// Build per-call ctx: caller's ctx (if any) + this call's signal
|
|
89
|
+
const ctx = options?.ctx
|
|
90
|
+
? { ...options.ctx, signal: childController.signal }
|
|
91
|
+
: undefined;
|
|
92
|
+
try {
|
|
93
|
+
const result = await Promise.race([
|
|
94
|
+
executor(argsWithSignal, ctx),
|
|
95
|
+
new Promise((_, reject) => {
|
|
96
|
+
childController.signal.addEventListener("abort", () => {
|
|
97
|
+
const reason = childController.signal.reason;
|
|
98
|
+
reject(reason instanceof ToolTimeoutError ? reason : new Error("Tool aborted"));
|
|
99
|
+
}, { once: true });
|
|
100
|
+
}),
|
|
101
|
+
]);
|
|
102
|
+
clearTimeout(timerId);
|
|
103
|
+
parentSignal?.removeEventListener("abort", onParentAbort);
|
|
104
|
+
return { id, toolName: name, result };
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
clearTimeout(timerId);
|
|
108
|
+
parentSignal?.removeEventListener("abort", onParentAbort);
|
|
109
|
+
// Always return error as ToolResult, never throw
|
|
110
|
+
let errorMsg;
|
|
111
|
+
const isAbort = err?.name === "AbortError" ||
|
|
112
|
+
parentSignal?.aborted === true;
|
|
113
|
+
if (err instanceof ToolTimeoutError) {
|
|
114
|
+
errorMsg = `Tool timed out after ${timeout}ms: ${name}`;
|
|
115
|
+
}
|
|
116
|
+
else if (isAbort) {
|
|
117
|
+
errorMsg = `Tool aborted: ${name}`;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
errorMsg = err.message;
|
|
121
|
+
}
|
|
122
|
+
return { id, toolName: name, error: errorMsg, isError: true };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
listTools() {
|
|
126
|
+
return [...this.tools.keys()];
|
|
127
|
+
}
|
|
128
|
+
listToolsDetailed() {
|
|
129
|
+
return [...this.tools.values()];
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linux bubblewrap backend.
|
|
3
|
+
*
|
|
4
|
+
* bwrap creates a fresh mount namespace, then bind-mounts only what we tell
|
|
5
|
+
* it. We bind / read-only and overlay writableRoots as read-write. PID,
|
|
6
|
+
* IPC, UTS, cgroup namespaces are unshared. Network is shared unless
|
|
7
|
+
* config.network === "deny".
|
|
8
|
+
*
|
|
9
|
+
* Sensitive directories listed in deniedReads are shadowed with a tmpfs so
|
|
10
|
+
* the inner process literally cannot see them even though `/` is mounted.
|
|
11
|
+
*/
|
|
12
|
+
import type { SandboxBackend, SandboxConfig } from "./index.js";
|
|
13
|
+
export declare function createBwrapBackend(config: SandboxConfig): SandboxBackend;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linux bubblewrap backend.
|
|
3
|
+
*
|
|
4
|
+
* bwrap creates a fresh mount namespace, then bind-mounts only what we tell
|
|
5
|
+
* it. We bind / read-only and overlay writableRoots as read-write. PID,
|
|
6
|
+
* IPC, UTS, cgroup namespaces are unshared. Network is shared unless
|
|
7
|
+
* config.network === "deny".
|
|
8
|
+
*
|
|
9
|
+
* Sensitive directories listed in deniedReads are shadowed with a tmpfs so
|
|
10
|
+
* the inner process literally cannot see them even though `/` is mounted.
|
|
11
|
+
*/
|
|
12
|
+
export function createBwrapBackend(config) {
|
|
13
|
+
return {
|
|
14
|
+
name: "bwrap",
|
|
15
|
+
wrap(command, opts) {
|
|
16
|
+
const args = [];
|
|
17
|
+
args.push("--ro-bind", "/", "/");
|
|
18
|
+
args.push("--dev", "/dev");
|
|
19
|
+
args.push("--proc", "/proc");
|
|
20
|
+
args.push("--tmpfs", "/tmp");
|
|
21
|
+
for (const root of config.writableRoots) {
|
|
22
|
+
args.push("--bind-try", root, root);
|
|
23
|
+
}
|
|
24
|
+
// Shadow each denied path by bind-mounting /dev/null on top. Why this
|
|
25
|
+
// approach instead of `--tmpfs <denied>`:
|
|
26
|
+
// 1. `--tmpfs` requires the destination to exist (mount(2) does), so
|
|
27
|
+
// a missing ~/.aws meant we had to skip the deny entirely — that's
|
|
28
|
+
// a TOCTOU window: if the host creates ~/.aws between wrap-time
|
|
29
|
+
// and spawn-time (or while the child is alive, since --ro-bind /
|
|
30
|
+
// reflects live host state, not a snapshot), the shadow never
|
|
31
|
+
// applies.
|
|
32
|
+
// 2. `--ro-bind-try /dev/null DEST` is no-op when DEST is missing on
|
|
33
|
+
// the host (SRC is always there); when DEST exists, the bind hides
|
|
34
|
+
// whatever was there. A read of the path returns EOF; directory
|
|
35
|
+
// traversal fails (it's a char device, not a dir).
|
|
36
|
+
// The leftover case — DEST didn't exist at wrap-time, then appears on
|
|
37
|
+
// the host mid-run — is mitigated by `--ro-bind / /` making the rest of
|
|
38
|
+
// the filesystem read-only inside the sandbox, so the child can't
|
|
39
|
+
// create the path itself. A host-side concurrent write into a denied
|
|
40
|
+
// path is still visible to the sandbox; document that limitation in
|
|
41
|
+
// index.ts rather than papering over it here.
|
|
42
|
+
for (const denied of config.deniedReads) {
|
|
43
|
+
args.push("--ro-bind-try", "/dev/null", denied);
|
|
44
|
+
}
|
|
45
|
+
args.push("--unshare-pid", "--unshare-ipc", "--unshare-uts", "--unshare-cgroup");
|
|
46
|
+
if (config.network === "deny") {
|
|
47
|
+
args.push("--unshare-net");
|
|
48
|
+
}
|
|
49
|
+
args.push("--die-with-parent");
|
|
50
|
+
args.push("--chdir", opts.cwd);
|
|
51
|
+
args.push(opts.shell, "-c", command);
|
|
52
|
+
return { file: "bwrap", args };
|
|
53
|
+
},
|
|
54
|
+
hintForBlockedOutput(stderr) {
|
|
55
|
+
if (/Permission denied|No such file or directory.*bwrap/i.test(stderr)) {
|
|
56
|
+
return ("\n[sandbox:bwrap] A path access was blocked by the sandbox. " +
|
|
57
|
+
"If this path should be writable, ask the user to update " +
|
|
58
|
+
"sandbox.writableRoots in settings.json.");
|
|
59
|
+
}
|
|
60
|
+
return undefined;
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandbox backends for shell command execution.
|
|
3
|
+
*
|
|
4
|
+
* We wrap Bash-tool commands in an OS-level sandbox so a misbehaving (or
|
|
5
|
+
* prompt-injected) model can't reach beyond the workspace. The sandbox runs
|
|
6
|
+
* the user's command inside an isolated process tree with restricted file
|
|
7
|
+
* and (optionally) network access. The Engine itself is NOT sandboxed; only
|
|
8
|
+
* the spawned shell is. File-editing tools (Edit/Write) keep going through
|
|
9
|
+
* the application-layer permission gate.
|
|
10
|
+
*
|
|
11
|
+
* Backends are platform-specific:
|
|
12
|
+
* - "seatbelt" macOS sandbox-exec, built into macOS, zero install
|
|
13
|
+
* - "bwrap" Linux bubblewrap, requires `apt install bubblewrap`
|
|
14
|
+
* - "off" passthrough, no sandboxing (current behavior)
|
|
15
|
+
*
|
|
16
|
+
* "auto" picks per platform at startup; falls back to "off" with a warning
|
|
17
|
+
* when no sandbox is available.
|
|
18
|
+
*/
|
|
19
|
+
export type SandboxMode = "off" | "auto" | "seatbelt" | "bwrap";
|
|
20
|
+
export type SandboxNetworkPolicy = "allow" | "deny";
|
|
21
|
+
export interface SandboxConfig {
|
|
22
|
+
mode: SandboxMode;
|
|
23
|
+
writableRoots: string[];
|
|
24
|
+
deniedReads: string[];
|
|
25
|
+
network: SandboxNetworkPolicy;
|
|
26
|
+
}
|
|
27
|
+
export interface SandboxBackend {
|
|
28
|
+
/** Resolved backend name — "off" means no sandboxing. */
|
|
29
|
+
name: "off" | "seatbelt" | "bwrap";
|
|
30
|
+
/**
|
|
31
|
+
* Decide the binary + argv that should actually be spawned to run `command`
|
|
32
|
+
* under this sandbox. The shell still interprets `command`; we only swap
|
|
33
|
+
* the outer process.
|
|
34
|
+
*/
|
|
35
|
+
wrap(command: string, opts: {
|
|
36
|
+
cwd: string;
|
|
37
|
+
shell: string;
|
|
38
|
+
}): {
|
|
39
|
+
file: string;
|
|
40
|
+
args: string[];
|
|
41
|
+
/**
|
|
42
|
+
* Optional callback the Bash tool calls after the child process exits.
|
|
43
|
+
* Backends that allocate per-command resources (e.g. seatbelt writes a
|
|
44
|
+
* profile file to a fresh temp dir) hang their cleanup here so a long
|
|
45
|
+
* session doesn't leak hundreds of temp dirs in /tmp.
|
|
46
|
+
*/
|
|
47
|
+
cleanup?: () => void;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* If `stderr` looks like a sandbox denial, return a short hint string that
|
|
51
|
+
* the Bash tool will append to its result so the model understands why.
|
|
52
|
+
*/
|
|
53
|
+
hintForBlockedOutput?(stderr: string): string | undefined;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Detect which sandbox mechanisms are available on the current host. Used by
|
|
57
|
+
* "auto" mode and surfaced to the user via /sandbox status if desired.
|
|
58
|
+
*/
|
|
59
|
+
export declare function detectSandboxCapabilities(): {
|
|
60
|
+
seatbelt: boolean;
|
|
61
|
+
bwrap: boolean;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Expand `~` and `${workspace}` placeholders against the live cwd and home.
|
|
65
|
+
*/
|
|
66
|
+
export declare function expandPath(p: string, cwd: string): string;
|
|
67
|
+
export declare function expandConfig(config: SandboxConfig, cwd: string): SandboxConfig;
|
|
68
|
+
export declare function defaultSandboxConfig(mode?: SandboxMode): SandboxConfig;
|
|
69
|
+
/**
|
|
70
|
+
* Resolve the active backend given user config + the current host.
|
|
71
|
+
*
|
|
72
|
+
* "off" → off backend
|
|
73
|
+
* "seatbelt" → seatbelt if available, else throws (explicit choice)
|
|
74
|
+
* "bwrap" → bwrap if available, else throws
|
|
75
|
+
* "auto" → seatbelt on macOS, bwrap on Linux with bwrap installed,
|
|
76
|
+
* else off + console warning
|
|
77
|
+
*/
|
|
78
|
+
export declare function resolveSandboxBackend(config: SandboxConfig, cwd: string): Promise<SandboxBackend>;
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandbox backends for shell command execution.
|
|
3
|
+
*
|
|
4
|
+
* We wrap Bash-tool commands in an OS-level sandbox so a misbehaving (or
|
|
5
|
+
* prompt-injected) model can't reach beyond the workspace. The sandbox runs
|
|
6
|
+
* the user's command inside an isolated process tree with restricted file
|
|
7
|
+
* and (optionally) network access. The Engine itself is NOT sandboxed; only
|
|
8
|
+
* the spawned shell is. File-editing tools (Edit/Write) keep going through
|
|
9
|
+
* the application-layer permission gate.
|
|
10
|
+
*
|
|
11
|
+
* Backends are platform-specific:
|
|
12
|
+
* - "seatbelt" macOS sandbox-exec, built into macOS, zero install
|
|
13
|
+
* - "bwrap" Linux bubblewrap, requires `apt install bubblewrap`
|
|
14
|
+
* - "off" passthrough, no sandboxing (current behavior)
|
|
15
|
+
*
|
|
16
|
+
* "auto" picks per platform at startup; falls back to "off" with a warning
|
|
17
|
+
* when no sandbox is available.
|
|
18
|
+
*/
|
|
19
|
+
import { accessSync, constants, realpathSync } from "node:fs";
|
|
20
|
+
import { homedir } from "node:os";
|
|
21
|
+
import { SandboxUnavailableError } from "../../exceptions.js";
|
|
22
|
+
/**
|
|
23
|
+
* Detect which sandbox mechanisms are available on the current host. Used by
|
|
24
|
+
* "auto" mode and surfaced to the user via /sandbox status if desired.
|
|
25
|
+
*/
|
|
26
|
+
export function detectSandboxCapabilities() {
|
|
27
|
+
return {
|
|
28
|
+
seatbelt: process.platform === "darwin" && binaryExists("/usr/bin/sandbox-exec"),
|
|
29
|
+
bwrap: process.platform === "linux" && (binaryExists("/usr/bin/bwrap") || binaryExists("/usr/local/bin/bwrap")),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function binaryExists(path) {
|
|
33
|
+
try {
|
|
34
|
+
accessSync(path, constants.X_OK);
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Expand `~` and `${workspace}` placeholders against the live cwd and home.
|
|
43
|
+
*/
|
|
44
|
+
export function expandPath(p, cwd) {
|
|
45
|
+
if (p === "${workspace}")
|
|
46
|
+
return cwd;
|
|
47
|
+
if (p.startsWith("${workspace}/"))
|
|
48
|
+
return cwd + p.slice("${workspace}".length);
|
|
49
|
+
if (p === "~")
|
|
50
|
+
return homedir();
|
|
51
|
+
if (p.startsWith("~/"))
|
|
52
|
+
return homedir() + p.slice(1);
|
|
53
|
+
return p;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Resolve a path through any symlinks. On macOS `/var` and `/tmp` are
|
|
57
|
+
* symlinks to `/private/var` and `/private/tmp`; Seatbelt's `subpath` rules
|
|
58
|
+
* match by canonical (post-resolution) path, so a profile that lists
|
|
59
|
+
* `/var/folders/...` silently doesn't match when the syscall actually
|
|
60
|
+
* hits `/private/var/folders/...`. Resolving up front fixes this.
|
|
61
|
+
*
|
|
62
|
+
* Falls back to the original path when realpath fails (e.g. the path
|
|
63
|
+
* doesn't exist yet — common for deniedReads on hosts without those
|
|
64
|
+
* credential dirs).
|
|
65
|
+
*/
|
|
66
|
+
function canonicalize(path) {
|
|
67
|
+
try {
|
|
68
|
+
return realpathSync(path);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return path;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export function expandConfig(config, cwd) {
|
|
75
|
+
return {
|
|
76
|
+
...config,
|
|
77
|
+
writableRoots: config.writableRoots.map((p) => canonicalize(expandPath(p, cwd))),
|
|
78
|
+
deniedReads: config.deniedReads.map((p) => canonicalize(expandPath(p, cwd))),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Default config when the user hasn't supplied anything. Workspace +
|
|
83
|
+
* /tmp writable; ssh / cloud creds explicitly denied for read; network
|
|
84
|
+
* left open (sandboxing network breaks `npm install`, `git pull`, etc.,
|
|
85
|
+
* and most users find that surprising).
|
|
86
|
+
*/
|
|
87
|
+
/**
|
|
88
|
+
* Emit a one-shot warning when `auto` finds no usable backend. Per-process
|
|
89
|
+
* latch so a long REPL session doesn't repeat the message every Engine run.
|
|
90
|
+
* Suppressible with CODE_SHELL_SANDBOX_QUIET=1 for users who know.
|
|
91
|
+
*/
|
|
92
|
+
let autoDowngradeWarned = false;
|
|
93
|
+
function warnAutoDowngrade() {
|
|
94
|
+
if (autoDowngradeWarned)
|
|
95
|
+
return;
|
|
96
|
+
if (process.env.CODE_SHELL_SANDBOX_QUIET === "1")
|
|
97
|
+
return;
|
|
98
|
+
autoDowngradeWarned = true;
|
|
99
|
+
const platform = process.platform;
|
|
100
|
+
let hint;
|
|
101
|
+
if (platform === "linux") {
|
|
102
|
+
hint = "install bubblewrap (apt install bubblewrap / dnf install bubblewrap)";
|
|
103
|
+
}
|
|
104
|
+
else if (platform === "win32") {
|
|
105
|
+
hint = "run code-shell inside WSL or a Docker container";
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
hint = "this platform does not currently have an OS-level sandbox backend";
|
|
109
|
+
}
|
|
110
|
+
process.stderr.write(`[code-shell] sandbox=auto found no usable backend; shell commands will run unsandboxed. To fix: ${hint}. ` +
|
|
111
|
+
`Set sandbox.mode=off in settings.json to silence, or CODE_SHELL_SANDBOX_QUIET=1.\n`);
|
|
112
|
+
}
|
|
113
|
+
export function defaultSandboxConfig(mode = "auto") {
|
|
114
|
+
return {
|
|
115
|
+
mode,
|
|
116
|
+
writableRoots: ["${workspace}", "/tmp", "/private/tmp", "/var/tmp"],
|
|
117
|
+
deniedReads: [
|
|
118
|
+
"~/.ssh",
|
|
119
|
+
"~/.aws",
|
|
120
|
+
"~/.config/gcloud",
|
|
121
|
+
"~/.code-shell",
|
|
122
|
+
"~/.claude",
|
|
123
|
+
],
|
|
124
|
+
network: "allow",
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Resolve the active backend given user config + the current host.
|
|
129
|
+
*
|
|
130
|
+
* "off" → off backend
|
|
131
|
+
* "seatbelt" → seatbelt if available, else throws (explicit choice)
|
|
132
|
+
* "bwrap" → bwrap if available, else throws
|
|
133
|
+
* "auto" → seatbelt on macOS, bwrap on Linux with bwrap installed,
|
|
134
|
+
* else off + console warning
|
|
135
|
+
*/
|
|
136
|
+
export async function resolveSandboxBackend(config, cwd) {
|
|
137
|
+
const expanded = expandConfig(config, cwd);
|
|
138
|
+
const caps = detectSandboxCapabilities();
|
|
139
|
+
let chosen;
|
|
140
|
+
switch (config.mode) {
|
|
141
|
+
case "off":
|
|
142
|
+
chosen = "off";
|
|
143
|
+
break;
|
|
144
|
+
case "seatbelt":
|
|
145
|
+
if (!caps.seatbelt) {
|
|
146
|
+
throw new SandboxUnavailableError("seatbelt", process.platform, "sandbox.mode=seatbelt requested but sandbox-exec is unavailable (macOS-only). " +
|
|
147
|
+
'Set sandbox.mode to "auto" or "off".');
|
|
148
|
+
}
|
|
149
|
+
chosen = "seatbelt";
|
|
150
|
+
break;
|
|
151
|
+
case "bwrap":
|
|
152
|
+
if (!caps.bwrap) {
|
|
153
|
+
throw new SandboxUnavailableError("bwrap", process.platform, "sandbox.mode=bwrap requested but bubblewrap (bwrap) is not installed. " +
|
|
154
|
+
"Install with `apt install bubblewrap` (Debian/Ubuntu) or `dnf install bubblewrap` (Fedora).");
|
|
155
|
+
}
|
|
156
|
+
chosen = "bwrap";
|
|
157
|
+
break;
|
|
158
|
+
case "auto":
|
|
159
|
+
if (caps.seatbelt)
|
|
160
|
+
chosen = "seatbelt";
|
|
161
|
+
else if (caps.bwrap)
|
|
162
|
+
chosen = "bwrap";
|
|
163
|
+
else {
|
|
164
|
+
chosen = "off";
|
|
165
|
+
warnAutoDowngrade();
|
|
166
|
+
}
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
switch (chosen) {
|
|
170
|
+
case "off": {
|
|
171
|
+
const { createOffBackend } = await import("./off.js");
|
|
172
|
+
return createOffBackend();
|
|
173
|
+
}
|
|
174
|
+
case "seatbelt": {
|
|
175
|
+
const { createSeatbeltBackend } = await import("./seatbelt.js");
|
|
176
|
+
// Same footgun as bwrap below: seatbelt's `(subpath "...")` rule for
|
|
177
|
+
// a non-existent path silently matches nothing, so a typo in
|
|
178
|
+
// writableRoots presents as "my sandbox blocks all writes" with no
|
|
179
|
+
// diagnostic. Warn so the user notices the dropped path up front.
|
|
180
|
+
warnMissingWritableRoots(expanded.writableRoots);
|
|
181
|
+
return createSeatbeltBackend(expanded);
|
|
182
|
+
}
|
|
183
|
+
case "bwrap": {
|
|
184
|
+
const { createBwrapBackend } = await import("./bwrap.js");
|
|
185
|
+
// bwrap's --bind-try silently skips paths that don't exist on the
|
|
186
|
+
// host. That's the right default (e.g. /private/tmp doesn't exist on
|
|
187
|
+
// Linux) but turns into invisible footguns for typos: a user adds
|
|
188
|
+
// "/work/important" to writableRoots, mistypes it as "/wrok/...", and
|
|
189
|
+
// every write looks blocked-by-sandbox with no diagnostic. Warn here
|
|
190
|
+
// so the user sees the path got dropped before the first command.
|
|
191
|
+
warnMissingWritableRoots(expanded.writableRoots);
|
|
192
|
+
return createBwrapBackend(expanded);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Warn once per session for each writableRoot that doesn't exist on the
|
|
198
|
+
* host. Keyed by absolute path so a long session doesn't repeat the same
|
|
199
|
+
* warning across many Engine.run() calls.
|
|
200
|
+
*/
|
|
201
|
+
const missingWritableWarned = new Set();
|
|
202
|
+
function warnMissingWritableRoots(roots) {
|
|
203
|
+
if (process.env.CODE_SHELL_SANDBOX_QUIET === "1")
|
|
204
|
+
return;
|
|
205
|
+
for (const root of roots) {
|
|
206
|
+
if (missingWritableWarned.has(root))
|
|
207
|
+
continue;
|
|
208
|
+
let exists = false;
|
|
209
|
+
try {
|
|
210
|
+
accessSync(root, constants.F_OK);
|
|
211
|
+
exists = true;
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
// doesn't exist
|
|
215
|
+
}
|
|
216
|
+
if (!exists) {
|
|
217
|
+
missingWritableWarned.add(root);
|
|
218
|
+
process.stderr.write(`[code-shell] sandbox.writableRoots includes "${root}" which doesn't exist on this host — ` +
|
|
219
|
+
`writes there will be blocked. Check for typos in settings.json (silence with CODE_SHELL_SANDBOX_QUIET=1).\n`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* macOS Seatbelt backend.
|
|
3
|
+
*
|
|
4
|
+
* Builds a sandbox-exec profile that:
|
|
5
|
+
* - Allows reading most of the filesystem (denying everything breaks tooling)
|
|
6
|
+
* - Denies reads of sensitive credential directories
|
|
7
|
+
* - Restricts writes to the workspace + writableRoots
|
|
8
|
+
* - Optionally denies outbound network
|
|
9
|
+
*
|
|
10
|
+
* The profile is written to a fresh temp file per command (cheap; users can
|
|
11
|
+
* have arbitrary writableRoots so we can't cache). The spawned process and
|
|
12
|
+
* its entire subprocess tree inherit the profile via XNU's sandbox framework.
|
|
13
|
+
*
|
|
14
|
+
* sandbox-exec is technically deprecated by Apple but remains the only
|
|
15
|
+
* working OS-level sandbox on macOS and is what Codex CLI / Cursor use today.
|
|
16
|
+
*/
|
|
17
|
+
import type { SandboxBackend, SandboxConfig } from "./index.js";
|
|
18
|
+
export declare function createSeatbeltBackend(config: SandboxConfig): SandboxBackend;
|