muonroi-cli 1.7.2 → 1.8.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 -21
- package/README.md +122 -122
- package/dist/packages/agent-harness-core/src/event-filter.js +1 -0
- package/dist/packages/agent-harness-core/src/event-redact.js +8 -0
- package/dist/packages/agent-harness-core/src/mcp-server.d.ts +16 -0
- package/dist/packages/agent-harness-core/src/mcp-server.js +88 -10
- package/dist/packages/agent-harness-core/src/protocol.d.ts +15 -0
- package/dist/packages/agent-harness-core/src/selector.js +2 -2
- package/dist/packages/agent-harness-core/src/transports/sidechannel.js +1 -1
- package/dist/packages/agent-harness-opentui/src/agent-mode.js +1 -1
- package/dist/packages/agent-harness-opentui/src/install.js +1 -1
- package/dist/src/__test-stubs__/vitest-setup.js +4 -0
- package/dist/src/agent-harness/__tests__/mock-model.spec.js +54 -0
- package/dist/src/agent-harness/mock-model.d.ts +1 -1
- package/dist/src/agent-harness/mock-model.js +32 -3
- package/dist/src/agent-harness/test-spawn.js +3 -1
- package/dist/src/chat/chat-keychain.js +9 -1
- package/dist/src/cli/cost-forensics.js +12 -12
- package/dist/src/cli/keys.d.ts +2 -2
- package/dist/src/cli/keys.js +107 -28
- package/dist/src/cli/usage-report.js +2 -2
- package/dist/src/council/__tests__/abort-threading.test.d.ts +1 -0
- package/dist/src/council/__tests__/abort-threading.test.js +193 -0
- package/dist/src/council/__tests__/clarification-prompt.test.js +21 -1
- package/dist/src/council/__tests__/council-turn-length-emit.test.d.ts +1 -0
- package/dist/src/council/__tests__/council-turn-length-emit.test.js +130 -0
- package/dist/src/council/__tests__/debate-round-budget.test.d.ts +1 -0
- package/dist/src/council/__tests__/debate-round-budget.test.js +45 -0
- package/dist/src/council/__tests__/evaluator-metrics.test.js +3 -0
- package/dist/src/council/__tests__/post-debate-recommendation.test.d.ts +1 -0
- package/dist/src/council/__tests__/post-debate-recommendation.test.js +58 -0
- package/dist/src/council/__tests__/research-tools.test.js +4 -0
- package/dist/src/council/__tests__/round-tools.test.js +6 -0
- package/dist/src/council/clarifier-question-cap.test.d.ts +12 -0
- package/dist/src/council/clarifier-question-cap.test.js +73 -0
- package/dist/src/council/clarifier.d.ts +29 -1
- package/dist/src/council/clarifier.js +64 -1
- package/dist/src/council/debate-planner.d.ts +2 -1
- package/dist/src/council/debate-planner.js +5 -3
- package/dist/src/council/debate.d.ts +9 -0
- package/dist/src/council/debate.js +88 -8
- package/dist/src/council/index.d.ts +46 -1
- package/dist/src/council/index.js +125 -19
- package/dist/src/council/llm.js +41 -13
- package/dist/src/council/prompts.js +56 -21
- package/dist/src/council/types.d.ts +14 -1
- package/dist/src/ee/__tests__/export-transcripts.test.js +1 -1
- package/dist/src/ee/bridge.d.ts +3 -1
- package/dist/src/ee/bridge.js +9 -3
- package/dist/src/ee/bridge.test.js +1 -2
- package/dist/src/ee/client.js +15 -2
- package/dist/src/ee/recall-ledger.d.ts +20 -0
- package/dist/src/ee/recall-ledger.js +40 -1
- package/dist/src/ee/search.d.ts +25 -0
- package/dist/src/ee/search.js +73 -0
- package/dist/src/ee/types.d.ts +15 -1
- package/dist/src/ee/who-am-i.d.ts +41 -0
- package/dist/src/ee/who-am-i.js +143 -0
- package/dist/src/ee/who-am-i.test.d.ts +1 -0
- package/dist/src/ee/who-am-i.test.js +101 -0
- package/dist/src/generated/version.d.ts +1 -1
- package/dist/src/generated/version.js +1 -1
- package/dist/src/headless/council-answers.js +1 -0
- package/dist/src/headless/output.d.ts +30 -1
- package/dist/src/headless/output.js +180 -0
- package/dist/src/headless/output.test.js +61 -1
- package/dist/src/hooks/index.js +48 -2
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +55 -60
- package/dist/src/lsp/client-normalize.test.d.ts +12 -0
- package/dist/src/lsp/client-normalize.test.js +34 -0
- package/dist/src/lsp/client.d.ts +1 -0
- package/dist/src/lsp/client.js +10 -2
- package/dist/src/lsp/manager.d.ts +1 -1
- package/dist/src/lsp/manager.js +2 -2
- package/dist/src/lsp/manager.test.js +2 -2
- package/dist/src/lsp/runtime.d.ts +1 -1
- package/dist/src/lsp/runtime.js +2 -2
- package/dist/src/maintain/__tests__/gh-create-pr.test.js +7 -3
- package/dist/src/maintain/__tests__/pr-builder.test.js +7 -3
- package/dist/src/mcp/__tests__/client-pool.spec.js +3 -3
- package/dist/src/mcp/__tests__/ee-tools.test.js +42 -14
- package/dist/src/mcp/__tests__/forensics-tools.test.js +3 -3
- package/dist/src/mcp/__tests__/lsp-tools.test.js +4 -4
- package/dist/src/mcp/client-pool.d.ts +1 -1
- package/dist/src/mcp/client-pool.js +25 -9
- package/dist/src/mcp/ee-tools.d.ts +10 -0
- package/dist/src/mcp/ee-tools.js +34 -0
- package/dist/src/mcp/oauth-callback.js +2 -2
- package/dist/src/mcp/parse-headers.test.js +14 -14
- package/dist/src/mcp/self-verify-jobs.js +1 -3
- package/dist/src/mcp/setup-guide-text.js +74 -74
- package/dist/src/mcp/smoke.test.js +43 -43
- package/dist/src/models/catalog-gemini.test.js +12 -10
- package/dist/src/models/catalog.json +106 -38
- package/dist/src/ops/doctor.js +7 -7
- package/dist/src/orchestrator/__tests__/auto-commit.test.d.ts +1 -0
- package/dist/src/orchestrator/__tests__/auto-commit.test.js +142 -0
- package/dist/src/orchestrator/__tests__/batch-turn-runner.test.js +2 -0
- package/dist/src/orchestrator/__tests__/delegations.test.d.ts +1 -0
- package/dist/src/orchestrator/__tests__/delegations.test.js +96 -0
- package/dist/src/orchestrator/__tests__/message-processor.test.js +1 -0
- package/dist/src/orchestrator/__tests__/stream-runner.test.js +29 -0
- package/dist/src/orchestrator/agent.test.js +5 -2
- package/dist/src/orchestrator/auto-commit.d.ts +110 -0
- package/dist/src/orchestrator/auto-commit.js +364 -0
- package/dist/src/orchestrator/batch-turn-runner.d.ts +3 -2
- package/dist/src/orchestrator/batch-turn-runner.js +2 -1
- package/dist/src/orchestrator/compaction-proposer-prompt.d.ts +8 -0
- package/dist/src/orchestrator/compaction-proposer-prompt.js +43 -0
- package/dist/src/orchestrator/compaction.d.ts +22 -0
- package/dist/src/orchestrator/compaction.js +42 -0
- package/dist/src/orchestrator/delegations.d.ts +1 -0
- package/dist/src/orchestrator/delegations.js +41 -0
- package/dist/src/orchestrator/error-utils.js +27 -2
- package/dist/src/orchestrator/message-processor.d.ts +21 -5
- package/dist/src/orchestrator/message-processor.js +219 -2573
- package/dist/src/orchestrator/orchestrator.d.ts +8 -2
- package/dist/src/orchestrator/orchestrator.js +187 -34
- package/dist/src/orchestrator/preprocessor.d.ts +13 -0
- package/dist/src/orchestrator/preprocessor.js +145 -0
- package/dist/src/orchestrator/prompts.d.ts +8 -0
- package/dist/src/orchestrator/prompts.js +76 -60
- package/dist/src/orchestrator/safety-askcard.d.ts +66 -0
- package/dist/src/orchestrator/safety-askcard.js +74 -0
- package/dist/src/orchestrator/sandbox.test.js +8 -5
- package/dist/src/orchestrator/scope-ceiling.js +1 -1
- package/dist/src/orchestrator/stall-watchdog.d.ts +47 -0
- package/dist/src/orchestrator/stall-watchdog.js +23 -0
- package/dist/src/orchestrator/stall-watchdog.test.js +36 -1
- package/dist/src/orchestrator/stream-runner.js +52 -30
- package/dist/src/orchestrator/sub-agent-model-tier.js +1 -1
- package/dist/src/orchestrator/subagent-compactor.d.ts +14 -0
- package/dist/src/orchestrator/subagent-compactor.js +83 -10
- package/dist/src/orchestrator/subagent-compactor.spec.js +132 -0
- package/dist/src/orchestrator/text-tool-call-detector.d.ts +9 -5
- package/dist/src/orchestrator/text-tool-call-detector.js +16 -12
- package/dist/src/orchestrator/text-tool-call-detector.test.js +66 -8
- package/dist/src/orchestrator/tool-args-repair.js +1 -1
- package/dist/src/orchestrator/tool-engine.d.ts +151 -0
- package/dist/src/orchestrator/tool-engine.js +3079 -0
- package/dist/src/orchestrator/turn-runner-deps.d.ts +1 -0
- package/dist/src/pil/__tests__/discovery-types.test.js +15 -4
- package/dist/src/pil/__tests__/discovery.test.js +89 -145
- package/dist/src/pil/__tests__/dual-run.test.js +2 -0
- package/dist/src/pil/__tests__/layer1-intent-trace.test.js +3 -0
- package/dist/src/pil/__tests__/layer1-intent.test.js +3 -0
- package/dist/src/pil/__tests__/layer16-clarity.test.js +35 -32
- package/dist/src/pil/__tests__/layer18-acceptance.test.js +1 -78
- package/dist/src/pil/__tests__/layer2_5-ponytail.test.d.ts +1 -0
- package/dist/src/pil/__tests__/layer2_5-ponytail.test.js +53 -0
- package/dist/src/pil/__tests__/layer3-ee-injection.test.js +67 -4
- package/dist/src/pil/__tests__/layer3-injected-chunk.test.js +14 -2
- package/dist/src/pil/__tests__/layer4-gsd.test.js +30 -0
- package/dist/src/pil/__tests__/layer5-context.test.js +39 -1
- package/dist/src/pil/__tests__/layer6-output.test.js +30 -2
- package/dist/src/pil/__tests__/orchestrator-integration.test.js +3 -1
- package/dist/src/pil/__tests__/pipeline.test.js +11 -8
- package/dist/src/pil/__tests__/response-tools.test.js +52 -0
- package/dist/src/pil/agent-operating-contract.d.ts +1 -1
- package/dist/src/pil/agent-operating-contract.js +5 -3
- package/dist/src/pil/agent-operating-contract.test.js +2 -2
- package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
- package/dist/src/pil/cheap-model-playbook.js +1 -1
- package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
- package/dist/src/pil/cheap-model-workbooks.js +1 -1
- package/dist/src/pil/config.d.ts +20 -0
- package/dist/src/pil/config.js +35 -0
- package/dist/src/pil/discovery-types.d.ts +32 -9
- package/dist/src/pil/discovery.d.ts +3 -3
- package/dist/src/pil/discovery.js +138 -244
- package/dist/src/pil/index.d.ts +1 -1
- package/dist/src/pil/index.js +1 -1
- package/dist/src/pil/layer1-intent.d.ts +9 -1
- package/dist/src/pil/layer1-intent.js +99 -44
- package/dist/src/pil/layer1-intent.test.js +112 -2
- package/dist/src/pil/layer15-context-scan.js +1 -1
- package/dist/src/pil/layer16-clarity.d.ts +21 -25
- package/dist/src/pil/layer16-clarity.js +52 -88
- package/dist/src/pil/layer18-acceptance.d.ts +13 -3
- package/dist/src/pil/layer18-acceptance.js +1 -75
- package/dist/src/pil/layer2-personality.js +7 -8
- package/dist/src/pil/layer2_5-ponytail.d.ts +2 -0
- package/dist/src/pil/layer2_5-ponytail.js +41 -0
- package/dist/src/pil/layer3-ee-injection.js +180 -14
- package/dist/src/pil/layer4-gsd.js +22 -8
- package/dist/src/pil/layer5-context.d.ts +1 -0
- package/dist/src/pil/layer5-context.js +26 -11
- package/dist/src/pil/layer6-output.js +23 -5
- package/dist/src/pil/llm-classify.js +3 -3
- package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
- package/dist/src/pil/native-capabilities-workbook.js +4 -3
- package/dist/src/pil/pipeline.js +15 -1
- package/dist/src/pil/response-tools.d.ts +16 -0
- package/dist/src/pil/response-tools.js +41 -0
- package/dist/src/pil/schema.d.ts +8 -0
- package/dist/src/pil/schema.js +24 -3
- package/dist/src/pil/task-tier-map.js +7 -7
- package/dist/src/pil/types.d.ts +9 -3
- package/dist/src/product-loop/__tests__/discovery-interview.test.js +103 -1
- package/dist/src/product-loop/__tests__/gather-selectable-alts.test.js +34 -0
- package/dist/src/product-loop/__tests__/sprint-self-verify.test.js +12 -12
- package/dist/src/product-loop/discovery-interview.d.ts +20 -0
- package/dist/src/product-loop/discovery-interview.js +121 -7
- package/dist/src/product-loop/done-gate.js +3 -3
- package/dist/src/product-loop/gather.js +19 -5
- package/dist/src/product-loop/loop-driver.js +20 -20
- package/dist/src/product-loop/progress-snapshot.js +4 -4
- package/dist/src/product-loop/sprint-self-verify.js +2 -2
- package/dist/src/providers/__tests__/reasoning-roundtrip.test.js +12 -0
- package/dist/src/providers/auth/__tests__/gemini-oauth.test.d.ts +1 -5
- package/dist/src/providers/auth/__tests__/gemini-oauth.test.js +1 -5
- package/dist/src/providers/auth/gcloud.d.ts +28 -0
- package/dist/src/providers/auth/gcloud.js +102 -0
- package/dist/src/providers/auth/gemini-oauth.d.ts +46 -19
- package/dist/src/providers/auth/gemini-oauth.js +292 -105
- package/dist/src/providers/auth/grok-oauth.d.ts +1 -1
- package/dist/src/providers/auth/grok-oauth.js +1 -1
- package/dist/src/providers/auth/registry.js +28 -6
- package/dist/src/providers/gemini.d.ts +1 -1
- package/dist/src/providers/gemini.js +10 -3
- package/dist/src/providers/keychain.d.ts +2 -2
- package/dist/src/providers/keychain.js +20 -2
- package/dist/src/providers/mcp-vision-bridge.js +48 -48
- package/dist/src/providers/openai.js +5 -1
- package/dist/src/providers/runtime.d.ts +1 -1
- package/dist/src/providers/runtime.js +11 -2
- package/dist/src/providers/siliconflow-sse-repair.js +1 -1
- package/dist/src/providers/strategies/google.strategy.d.ts +9 -2
- package/dist/src/providers/strategies/google.strategy.js +159 -9
- package/dist/src/providers/strategies/thinking-mode.js +19 -6
- package/dist/src/providers/types.d.ts +1 -1
- package/dist/src/reporter/index.js +1 -1
- package/dist/src/router/decide.test.js +40 -8
- package/dist/src/router/step-router.d.ts +20 -0
- package/dist/src/router/step-router.js +73 -0
- package/dist/src/scaffold/bb-ecosystem-apply.js +47 -47
- package/dist/src/scaffold/bb-quality-gate.js +5 -5
- package/dist/src/scaffold/continuation-prompt.js +60 -60
- package/dist/src/scaffold/init-new.js +453 -453
- package/dist/src/self-qa/__tests__/scenario-planner.test.js +3 -3
- package/dist/src/self-qa/agentic-loop.js +19 -19
- package/dist/src/self-qa/orchestrator.js +5 -5
- package/dist/src/self-qa/scenario-planner.js +1 -1
- package/dist/src/self-qa/spec-emitter.js +4 -4
- package/dist/src/storage/__tests__/migrations.test.js +2 -2
- package/dist/src/storage/index.d.ts +1 -1
- package/dist/src/storage/index.js +1 -1
- package/dist/src/storage/interaction-log.js +5 -5
- package/dist/src/storage/migrations.js +122 -122
- package/dist/src/storage/session-experience-store.js +4 -4
- package/dist/src/storage/sessions.js +43 -43
- package/dist/src/storage/transcript-view.js +7 -1
- package/dist/src/storage/transcript.d.ts +1 -0
- package/dist/src/storage/transcript.js +55 -0
- package/dist/src/storage/ui-interaction-log.d.ts +17 -0
- package/dist/src/storage/usage.js +14 -14
- package/dist/src/storage/workspaces.js +12 -12
- package/dist/src/tools/__tests__/native-tools.test.js +6 -0
- package/dist/src/tools/bash.d.ts +36 -23
- package/dist/src/tools/bash.js +59 -301
- package/dist/src/tools/bash.test.js +2 -257
- package/dist/src/tools/file-tracker.d.ts +5 -0
- package/dist/src/tools/file-tracker.js +14 -0
- package/dist/src/tools/file.js +2 -0
- package/dist/src/tools/git-safety.d.ts +38 -1
- package/dist/src/tools/git-safety.js +94 -4
- package/dist/src/tools/git-safety.test.js +45 -1
- package/dist/src/tools/native-tools.d.ts +1 -1
- package/dist/src/tools/native-tools.js +56 -0
- package/dist/src/tools/registry-bash-empty-command.test.js +4 -3
- package/dist/src/tools/registry-git-safety.test.js +17 -6
- package/dist/src/tools/registry.d.ts +5 -0
- package/dist/src/tools/registry.js +185 -11
- package/dist/src/types/index.d.ts +7 -1
- package/dist/src/ui/app.d.ts +1 -0
- package/dist/src/ui/app.js +0 -0
- package/dist/src/ui/components/council-question-card.js +1 -0
- package/dist/src/ui/components/message-view.js +37 -3
- package/dist/src/ui/components/structured-response-view.js +7 -0
- package/dist/src/ui/components/task-list-panel.js +3 -12
- package/dist/src/ui/containers/chat-feed.d.ts +40 -0
- package/dist/src/ui/containers/chat-feed.js +66 -0
- package/dist/src/ui/containers/modals-layer.d.ts +87 -0
- package/dist/src/ui/containers/modals-layer.js +18 -0
- package/dist/src/ui/slash/__tests__/menu-parity.test.d.ts +1 -0
- package/dist/src/ui/slash/__tests__/menu-parity.test.js +1 -0
- package/dist/src/ui/slash/__tests__/ponytail.test.d.ts +1 -0
- package/dist/src/ui/slash/__tests__/ponytail.test.js +37 -0
- package/dist/src/ui/slash/council-inspect.js +4 -4
- package/dist/src/ui/slash/export.js +16 -1
- package/dist/src/ui/slash/menu-items.js +1 -0
- package/dist/src/ui/slash/ponytail.d.ts +2 -0
- package/dist/src/ui/slash/ponytail.js +19 -0
- package/dist/src/ui/status-bar/store.js +0 -1
- package/dist/src/ui/status-bar/store.test.js +2 -2
- package/dist/src/ui/use-app-logic.d.ts +26 -0
- package/dist/src/ui/use-app-logic.js +0 -0
- package/dist/src/ui/utils/relaunch.js +1 -1
- package/dist/src/ui/utils/text.d.ts +11 -0
- package/dist/src/ui/utils/text.js +21 -1
- package/dist/src/ui/utils/text.test.js +25 -1
- package/dist/src/ui/utils/tools.js +3 -1
- package/dist/src/usage/cost-log.js +2 -2
- package/dist/src/usage/estimator.d.ts +14 -0
- package/dist/src/usage/estimator.js +22 -0
- package/dist/src/utils/__tests__/compaction-caps.test.d.ts +21 -0
- package/dist/src/utils/__tests__/compaction-caps.test.js +187 -0
- package/dist/src/utils/__tests__/llm-deadline-abort.test.d.ts +1 -0
- package/dist/src/utils/__tests__/llm-deadline-abort.test.js +33 -0
- package/dist/src/utils/clipboard-image.js +23 -23
- package/dist/src/utils/llm-deadline.d.ts +9 -1
- package/dist/src/utils/llm-deadline.js +31 -2
- package/dist/src/utils/permission-mode.d.ts +33 -0
- package/dist/src/utils/permission-mode.js +164 -3
- package/dist/src/utils/permission-mode.test.js +92 -1
- package/dist/src/utils/settings.d.ts +27 -31
- package/dist/src/utils/settings.js +100 -109
- package/dist/src/utils/side-question.js +2 -2
- package/dist/src/utils/skills.js +3 -3
- package/dist/src/verify/__tests__/coverage-parsers.test.js +30 -30
- package/package.json +1 -1
package/dist/src/tools/bash.js
CHANGED
|
@@ -4,7 +4,7 @@ import { mkdtemp, rm, stat, unlink } from "fs/promises";
|
|
|
4
4
|
import os from "os";
|
|
5
5
|
import path from "path";
|
|
6
6
|
import { executeEventHooks } from "../hooks/index.js";
|
|
7
|
-
import {
|
|
7
|
+
import { checkCatastrophicCommand } from "../utils/permission-mode.js";
|
|
8
8
|
import { posixToNative, resolveShell } from "../utils/shell.js";
|
|
9
9
|
import { nextBashRunId, recordBashRun, stripAnsi } from "./bash-output-cache.js";
|
|
10
10
|
const MAX_TAIL_BYTES = 8_192;
|
|
@@ -14,17 +14,27 @@ export class BashTool {
|
|
|
14
14
|
cwd;
|
|
15
15
|
bgProcesses = new Map();
|
|
16
16
|
tmpDir = null;
|
|
17
|
-
sandboxMode;
|
|
18
|
-
sandboxSettings;
|
|
19
17
|
shellSettings;
|
|
20
18
|
resolvedShell;
|
|
21
|
-
|
|
19
|
+
sandboxSettings = {};
|
|
22
20
|
constructor(initialCwd = process.cwd(), options = {}) {
|
|
23
21
|
this.cwd = initialCwd;
|
|
24
|
-
this.sandboxMode = options.sandboxMode ?? "off";
|
|
25
|
-
this.sandboxSettings = options.sandboxSettings ?? {};
|
|
26
22
|
this.shellSettings = options.shellSettings ?? {};
|
|
27
23
|
this.resolvedShell = resolveShell(this.shellSettings);
|
|
24
|
+
this.sandboxSettings = options.sandboxSettings ?? {};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Sandbox has been removed. Always returns "off".
|
|
28
|
+
* Kept for backward compatibility with orchestrator / stream-runner callers.
|
|
29
|
+
*/
|
|
30
|
+
getSandboxMode() {
|
|
31
|
+
return "off";
|
|
32
|
+
}
|
|
33
|
+
getSandboxSettings() {
|
|
34
|
+
return this.sandboxSettings;
|
|
35
|
+
}
|
|
36
|
+
setSandboxSettings(settings) {
|
|
37
|
+
this.sandboxSettings = settings;
|
|
28
38
|
}
|
|
29
39
|
async ensureTmpDir() {
|
|
30
40
|
if (!this.tmpDir) {
|
|
@@ -35,19 +45,6 @@ export class BashTool {
|
|
|
35
45
|
async execute(command, timeout = 30_000, abortSignal) {
|
|
36
46
|
try {
|
|
37
47
|
if (command.startsWith("cd ")) {
|
|
38
|
-
// Parse "cd <dir>" with optional "&&|||;" chained remainder.
|
|
39
|
-
// Without this split, `cd D:\foo && gh run list` was passed wholesale
|
|
40
|
-
// to stat() → ENOENT → agents retried with different shell syntaxes
|
|
41
|
-
// and burned hundreds of tool calls (session 127140a47b56: 248 bash
|
|
42
|
-
// calls all hit this bug).
|
|
43
|
-
// Path token = quoted string or bare word stopping at first unquoted
|
|
44
|
-
// shell separator. The regex deliberately excludes `&|;<>` from the
|
|
45
|
-
// bare-word class so chained commands split correctly.
|
|
46
|
-
// Strip cmd.exe-style DOS flags (e.g. `cd /d D:\path` — `/d` enables
|
|
47
|
-
// drive-change, irrelevant in our cwd tracker). Without this, agents
|
|
48
|
-
// using `cd /d <path>` (session 7dcf8fd7d6a4 caller still does this
|
|
49
|
-
// habitually) parse as dir="/d" → resolve fails. Drop the flag and
|
|
50
|
-
// continue parsing.
|
|
51
48
|
const afterCd = command
|
|
52
49
|
.substring(3)
|
|
53
50
|
.trim()
|
|
@@ -57,18 +54,10 @@ export class BashTool {
|
|
|
57
54
|
const rawDir = parsed?.[1] ?? afterCd;
|
|
58
55
|
const chainOp = parsed?.[2];
|
|
59
56
|
const remainder = parsed?.[3]?.trim() || null;
|
|
60
|
-
const dir = rawDir
|
|
61
|
-
.replace(/^["']|["']$/g, "")
|
|
62
|
-
// Strip a trailing backslash that was an escaped quote in the shell
|
|
63
|
-
// parse (e.g. cd "C:\foo\" && cmd → C:\foo). Only strip on Windows
|
|
64
|
-
// because on POSIX a trailing backslash is a valid path continuation.
|
|
65
|
-
.replace(process.platform === "win32" ? /\\$/ : /(?!x)x/, "");
|
|
57
|
+
const dir = rawDir.replace(/^["']|["']$/g, "").replace(process.platform === "win32" ? /\\$/ : /(?!x)x/, "");
|
|
66
58
|
let cdSucceeded = false;
|
|
67
59
|
let cdError = null;
|
|
68
60
|
try {
|
|
69
|
-
// Translate POSIX-style absolute paths (e.g. /d/sources/x, ~/foo)
|
|
70
|
-
// when the active shell understands them, so cwd tracking matches
|
|
71
|
-
// what the shell would actually resolve.
|
|
72
61
|
const translated = this.resolvedShell.isPosix ? posixToNative(dir) : dir;
|
|
73
62
|
const nextCwd = path.resolve(this.cwd, translated);
|
|
74
63
|
const info = await stat(nextCwd);
|
|
@@ -92,14 +81,9 @@ export class BashTool {
|
|
|
92
81
|
const msg = err instanceof Error ? err.message : String(err);
|
|
93
82
|
cdError = { success: false, error: `Cannot change directory: ${msg}` };
|
|
94
83
|
}
|
|
95
|
-
// No chained command — return the cd outcome as before.
|
|
96
84
|
if (!remainder) {
|
|
97
85
|
return cdSucceeded ? { success: true, output: `Changed directory to: ${this.cwd}` } : cdError;
|
|
98
86
|
}
|
|
99
|
-
// Chained command — respect shell semantics:
|
|
100
|
-
// `&&` runs remainder only if cd succeeded
|
|
101
|
-
// `||` runs remainder only if cd failed
|
|
102
|
-
// `;` runs remainder unconditionally
|
|
103
87
|
const shouldRunRemainder = chainOp === ";" || (chainOp === "&&" && cdSucceeded) || (chainOp === "||" && !cdSucceeded);
|
|
104
88
|
if (!shouldRunRemainder) {
|
|
105
89
|
return cdSucceeded ? { success: true, output: `Changed directory to: ${this.cwd}` } : cdError;
|
|
@@ -133,18 +117,12 @@ export class BashTool {
|
|
|
133
117
|
timeout,
|
|
134
118
|
maxBuffer: 10 * 1024 * 1024,
|
|
135
119
|
env: { ...process.env, FORCE_COLOR: "0" },
|
|
136
|
-
// Route through the resolved shell so POSIX syntax
|
|
137
|
-
// (`2>&1 &`, `$()`, single-quotes, `&&` as logical AND, …)
|
|
138
|
-
// works on Windows instead of falling back to cmd.exe.
|
|
139
120
|
...(this.resolvedShell.binary ? { shell: this.resolvedShell.binary } : {}),
|
|
140
121
|
}, (err, stdoutRaw, stderrRaw) => {
|
|
141
122
|
if (aborted || abortSignal?.aborted) {
|
|
142
123
|
finish({ success: false, error: "[Cancelled]" });
|
|
143
124
|
return;
|
|
144
125
|
}
|
|
145
|
-
// ANSI strip — FORCE_COLOR=0 covers cooperating children, but
|
|
146
|
-
// vitest / bun emit cursor-control sequences regardless, so we
|
|
147
|
-
// strip post-process before the output ever leaves this module.
|
|
148
126
|
const stdout = stripAnsi(stdoutRaw);
|
|
149
127
|
const stderr = stripAnsi(stderrRaw);
|
|
150
128
|
const exitCode = err && typeof err.code === "number" ? err.code : err ? 1 : 0;
|
|
@@ -159,11 +137,6 @@ export class BashTool {
|
|
|
159
137
|
const totalChars = stdout.length + stderr.length;
|
|
160
138
|
const output = stdout + (stderr ? `\nSTDERR: ${stderr}` : "");
|
|
161
139
|
if (err) {
|
|
162
|
-
const sandboxError = this.formatSandboxRuntimeError(output, err.message);
|
|
163
|
-
if (sandboxError) {
|
|
164
|
-
finish({ success: false, error: sandboxError, bashRunId: runId, bashTotalChars: totalChars });
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
140
|
if (output.trim()) {
|
|
168
141
|
finish({ success: false, error: output.trim(), bashRunId: runId, bashTotalChars: totalChars });
|
|
169
142
|
return;
|
|
@@ -309,10 +282,10 @@ export class BashTool {
|
|
|
309
282
|
].join("\n"),
|
|
310
283
|
};
|
|
311
284
|
}
|
|
312
|
-
catch {
|
|
285
|
+
catch (err) {
|
|
313
286
|
return {
|
|
314
|
-
success:
|
|
315
|
-
output: `
|
|
287
|
+
success: false,
|
|
288
|
+
output: `Failed to read logs for process ${id}: ${err instanceof Error ? err.message : String(err)}`,
|
|
316
289
|
};
|
|
317
290
|
}
|
|
318
291
|
}
|
|
@@ -322,36 +295,18 @@ export class BashTool {
|
|
|
322
295
|
return { success: false, output: `No background process with id ${id}.` };
|
|
323
296
|
}
|
|
324
297
|
if (!entry.alive) {
|
|
325
|
-
return {
|
|
326
|
-
success: true,
|
|
327
|
-
output: `Process ${id} already exited (code ${entry.exitCode ?? "unknown"}).`,
|
|
328
|
-
};
|
|
298
|
+
return { success: false, output: `Process ${id} is already stopped.` };
|
|
329
299
|
}
|
|
330
300
|
try {
|
|
331
301
|
entry.child.kill("SIGTERM");
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
try {
|
|
335
|
-
entry.child.kill("SIGKILL");
|
|
336
|
-
}
|
|
337
|
-
catch {
|
|
338
|
-
/* already dead */
|
|
339
|
-
}
|
|
340
|
-
resolve();
|
|
341
|
-
}, 3_000);
|
|
342
|
-
entry.child.on("exit", () => {
|
|
343
|
-
clearTimeout(timeout);
|
|
344
|
-
resolve();
|
|
345
|
-
});
|
|
346
|
-
});
|
|
347
|
-
return {
|
|
348
|
-
success: true,
|
|
349
|
-
output: `Process ${id} (pid ${entry.pid}) stopped.`,
|
|
350
|
-
};
|
|
302
|
+
entry.alive = false;
|
|
303
|
+
return { success: true, output: `Process ${id} terminated.` };
|
|
351
304
|
}
|
|
352
305
|
catch (err) {
|
|
353
|
-
|
|
354
|
-
|
|
306
|
+
return {
|
|
307
|
+
success: false,
|
|
308
|
+
output: `Failed to stop process ${id}: ${err instanceof Error ? err.message : String(err)}`,
|
|
309
|
+
};
|
|
355
310
|
}
|
|
356
311
|
}
|
|
357
312
|
listProcesses() {
|
|
@@ -408,52 +363,7 @@ export class BashTool {
|
|
|
408
363
|
}
|
|
409
364
|
this.cwd = next;
|
|
410
365
|
}
|
|
411
|
-
getSandboxMode() {
|
|
412
|
-
return this.sandboxMode;
|
|
413
|
-
}
|
|
414
|
-
setSandboxMode(mode) {
|
|
415
|
-
this.sandboxMode = mode;
|
|
416
|
-
}
|
|
417
|
-
/**
|
|
418
|
-
* The sandbox mode that actually takes effect. When "shuru" is configured but
|
|
419
|
-
* the current platform cannot run Shuru (non-macOS/arm64), the sandbox is
|
|
420
|
-
* inert: every wrapped command would fail with the macOS-only error, and the
|
|
421
|
-
* tool description would still advertise a `/workspace` mount that does not
|
|
422
|
-
* exist — so the model `cd`s into a phantom dir and abandons verification.
|
|
423
|
-
* Degrade to "off" (host execution) with a one-time warning so bash keeps
|
|
424
|
-
* working and the description reflects reality. A stale checked-in project
|
|
425
|
-
* `sandboxMode: "shuru"` therefore no longer bricks the shell off-platform.
|
|
426
|
-
*/
|
|
427
|
-
effectiveSandboxMode() {
|
|
428
|
-
if (this.sandboxMode === "shuru" && getSandboxUnsupportedReason() !== null) {
|
|
429
|
-
if (!this.sandboxUnsupportedWarned) {
|
|
430
|
-
this.sandboxUnsupportedWarned = true;
|
|
431
|
-
console.error(`[bash] sandboxMode "shuru" is configured but ${getSandboxUnsupportedReason()} ` +
|
|
432
|
-
'Falling back to host execution for this platform. Set sandboxMode to "off" to silence this.');
|
|
433
|
-
}
|
|
434
|
-
return "off";
|
|
435
|
-
}
|
|
436
|
-
return this.sandboxMode;
|
|
437
|
-
}
|
|
438
|
-
getSandboxSettings() {
|
|
439
|
-
return this.sandboxSettings;
|
|
440
|
-
}
|
|
441
|
-
setSandboxSettings(settings) {
|
|
442
|
-
this.sandboxSettings = settings;
|
|
443
|
-
}
|
|
444
366
|
getToolDescription() {
|
|
445
|
-
if (this.effectiveSandboxMode() === "shuru") {
|
|
446
|
-
const s = this.sandboxSettings;
|
|
447
|
-
const netStatus = s.allowNet
|
|
448
|
-
? s.allowedHosts?.length
|
|
449
|
-
? `network is restricted to: ${s.allowedHosts.join(", ")}`
|
|
450
|
-
: "network access is enabled"
|
|
451
|
-
: "network is disabled";
|
|
452
|
-
const hostBrowserNote = s.hostBrowserCommandsOnHost
|
|
453
|
-
? " Commands that invoke agent-browser run on the host instead of inside Shuru so they can interact with forwarded localhost services."
|
|
454
|
-
: "";
|
|
455
|
-
return `Execute a bash command inside a Shuru sandbox. Use for find, ls, git inspection, build tools, test runners, and other shell commands that should stay isolated. For content search, prefer the dedicated grep tool. The current workspace is mounted inside the sandbox at /workspace, ${netStatus}, and shell-side workspace file changes do not persist back to the host in this version, so prefer the dedicated file tools for durable edits.${hostBrowserNote} Set background=true for long-running processes like dev servers or watchers.`;
|
|
456
|
-
}
|
|
457
367
|
return "Execute a bash command. Use for find, ls, git, build tools, package managers, running tests, and any other shell command. For content search, prefer the dedicated grep tool. Set background=true for long-running processes like dev servers, watchers, or anything that should keep running while you continue working. For file read/write/edit, prefer the dedicated file tools instead.";
|
|
458
368
|
}
|
|
459
369
|
getResolvedShell() {
|
|
@@ -474,48 +384,44 @@ export class BashTool {
|
|
|
474
384
|
// cmd.exe or unknown
|
|
475
385
|
return { binary: shell.binary, args: ["/d", "/s", "/c", command] };
|
|
476
386
|
}
|
|
477
|
-
// No explicit binary: rely on platform default the same way exec() does.
|
|
478
387
|
if (process.platform === "win32") {
|
|
479
388
|
return { binary: process.env.ComSpec || "cmd.exe", args: ["/d", "/s", "/c", command] };
|
|
480
389
|
}
|
|
481
390
|
return { binary: "/bin/sh", args: ["-c", command] };
|
|
482
391
|
}
|
|
392
|
+
/**
|
|
393
|
+
* Pre-execution command preparation.
|
|
394
|
+
*
|
|
395
|
+
* Layer 1 — Catastrophic hard-block: checks the command against
|
|
396
|
+
* CATASTROPHIC_PATTERNS in permission-mode.ts. These are irreversible or
|
|
397
|
+
* severely dangerous operations that are blocked regardless of permission
|
|
398
|
+
* mode (safe / auto-edit / yolo) and regardless of sandbox state.
|
|
399
|
+
*
|
|
400
|
+
* Layer 2 — Future sandbox: when a new sandbox is wired in, wrap the
|
|
401
|
+
* command here before returning.
|
|
402
|
+
*/
|
|
403
|
+
/**
|
|
404
|
+
* Pre-execution command preparation with two-layer safety.
|
|
405
|
+
*
|
|
406
|
+
* Layer 1 — Catastrophic hard-block: checks the command against
|
|
407
|
+
* CATASTROPHIC_PATTERNS in permission-mode.ts. Returns structured block
|
|
408
|
+
* result so callers can route to askcard approval flow.
|
|
409
|
+
*
|
|
410
|
+
* Layer 2 — Future sandbox: when a new sandbox is wired in, wrap the
|
|
411
|
+
* command here before returning.
|
|
412
|
+
*/
|
|
483
413
|
prepareCommand(command) {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
}
|
|
494
|
-
const blockedReason = getSandboxMutationBlockReason(command, this.sandboxSettings);
|
|
495
|
-
if (blockedReason) {
|
|
496
|
-
return { ok: false, error: blockedReason };
|
|
497
|
-
}
|
|
498
|
-
const wrapped = wrapCommandForShuru(this.cwd, command, this.sandboxSettings);
|
|
499
|
-
appendAudit({
|
|
500
|
-
kind: "permission-override",
|
|
501
|
-
tool: "bash",
|
|
502
|
-
mode: "safe",
|
|
503
|
-
context: { command, shuru: true, settings: this.sandboxSettings },
|
|
504
|
-
ts: Date.now(),
|
|
505
|
-
});
|
|
506
|
-
return { ok: true, command: wrapped };
|
|
507
|
-
}
|
|
508
|
-
formatSandboxRuntimeError(output, fallbackMessage) {
|
|
509
|
-
if (this.effectiveSandboxMode() !== "shuru") {
|
|
510
|
-
return null;
|
|
511
|
-
}
|
|
512
|
-
if (output.includes("shuru: command not found") || output.includes("sh: shuru: not found")) {
|
|
513
|
-
return "Shuru sandbox mode is enabled, but the `shuru` CLI is not installed or not on PATH. Install Shuru or disable sandbox mode.";
|
|
514
|
-
}
|
|
515
|
-
if (output.includes("Apple Silicon") || fallbackMessage.includes("Apple Silicon")) {
|
|
516
|
-
return "Shuru sandbox mode requires macOS on Apple Silicon.";
|
|
414
|
+
const catBlock = checkCatastrophicCommand(command);
|
|
415
|
+
if (catBlock) {
|
|
416
|
+
return {
|
|
417
|
+
ok: false,
|
|
418
|
+
error: `BLOCKED (${catBlock.kind}): ${catBlock.reason}\n` +
|
|
419
|
+
"This command is blocked by the safety filter. " +
|
|
420
|
+
"Use the safety_override tool or ask the user for approval.",
|
|
421
|
+
block: catBlock,
|
|
422
|
+
};
|
|
517
423
|
}
|
|
518
|
-
return
|
|
424
|
+
return { ok: true, command };
|
|
519
425
|
}
|
|
520
426
|
}
|
|
521
427
|
function truncCmd(cmd, max) {
|
|
@@ -532,155 +438,7 @@ function formatAge(start) {
|
|
|
532
438
|
const hr = Math.floor(min / 60);
|
|
533
439
|
return `${hr}h${min % 60}m`;
|
|
534
440
|
}
|
|
535
|
-
export function wrapCommandForShuru(cwd, command, settings = {}) {
|
|
536
|
-
const parts = ["shuru", "run"];
|
|
537
|
-
if (settings.cpus)
|
|
538
|
-
parts.push("--cpus", String(settings.cpus));
|
|
539
|
-
if (settings.memory)
|
|
540
|
-
parts.push("--memory", String(settings.memory));
|
|
541
|
-
if (settings.diskSize)
|
|
542
|
-
parts.push("--disk-size", String(settings.diskSize));
|
|
543
|
-
if (settings.allowNet)
|
|
544
|
-
parts.push("--allow-net");
|
|
545
|
-
if (settings.allowedHosts) {
|
|
546
|
-
for (const host of settings.allowedHosts)
|
|
547
|
-
parts.push("--allow-host", host);
|
|
548
|
-
}
|
|
549
|
-
if (settings.ports) {
|
|
550
|
-
for (const port of settings.ports)
|
|
551
|
-
parts.push("-p", port);
|
|
552
|
-
}
|
|
553
|
-
if (settings.secrets) {
|
|
554
|
-
for (const s of settings.secrets) {
|
|
555
|
-
parts.push("--secret", `${s.name}=${s.fromEnv}@${s.hosts.join(",")}`);
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
if (settings.from)
|
|
559
|
-
parts.push("--from", settings.from);
|
|
560
|
-
const mountArg = `${cwd}:/workspace`;
|
|
561
|
-
parts.push("--mount", shellQuote(mountArg));
|
|
562
|
-
const shellInit = buildShellInitScript(settings);
|
|
563
|
-
const guestPrelude = buildGuestWorkspacePrelude(settings);
|
|
564
|
-
const guestSteps = [
|
|
565
|
-
shellInit,
|
|
566
|
-
guestPrelude,
|
|
567
|
-
`cd ${shellPathForScript(settings.guestWorkdir || "/workspace")}`,
|
|
568
|
-
command,
|
|
569
|
-
].filter(Boolean);
|
|
570
|
-
const guestCommand = guestSteps.join(" && ");
|
|
571
|
-
parts.push("--", "sh", "-lc", shellQuote(guestCommand));
|
|
572
|
-
return parts.join(" ");
|
|
573
|
-
}
|
|
574
|
-
const HOST_SAFE_SEGMENT_RE = /^\s*(?:(?:npx(?:\s+-y)?|bunx)\s+)?agent-browser\b|^\s*mkdir\s|^\s*sleep\s|^\s*echo\s|^\s*true\s*$|^\s*$/;
|
|
575
|
-
export function shouldRunOnHostInSandboxMode(command, settings = {}) {
|
|
576
|
-
if (!settings.hostBrowserCommandsOnHost) {
|
|
577
|
-
return false;
|
|
578
|
-
}
|
|
579
|
-
if (!/\bagent-browser\b/.test(command)) {
|
|
580
|
-
return false;
|
|
581
|
-
}
|
|
582
|
-
if (/\$\(|`/.test(command)) {
|
|
583
|
-
return false;
|
|
584
|
-
}
|
|
585
|
-
const segments = command.split(/\s*(?:&&|\|\||;|\|[^|]|>>?)\s*/);
|
|
586
|
-
return segments.every((segment) => HOST_SAFE_SEGMENT_RE.test(segment));
|
|
587
|
-
}
|
|
588
441
|
export function wrapHostBrowserCommand(command) {
|
|
589
|
-
|
|
590
|
-
.replace(/\bbunx\s+agent-browser\b/g, "__muonroi_ab")
|
|
591
|
-
.replace(/\bnpx(?:\s+-y)?\s+agent-browser\b/g, "__muonroi_ab")
|
|
592
|
-
.replace(/\bagent-browser\b/g, "__muonroi_ab");
|
|
593
|
-
return [
|
|
594
|
-
"__muonroi_ab() {",
|
|
595
|
-
" if command -v agent-browser >/dev/null 2>&1; then",
|
|
596
|
-
' command agent-browser "$@"',
|
|
597
|
-
" elif command -v bunx >/dev/null 2>&1; then",
|
|
598
|
-
' bunx agent-browser "$@"',
|
|
599
|
-
" elif command -v npx >/dev/null 2>&1; then",
|
|
600
|
-
' npx -y agent-browser "$@"',
|
|
601
|
-
" else",
|
|
602
|
-
' echo "agent-browser: not found (no bunx/npx fallback)" >&2',
|
|
603
|
-
" return 127",
|
|
604
|
-
" fi",
|
|
605
|
-
"}",
|
|
606
|
-
normalized,
|
|
607
|
-
].join("\n");
|
|
608
|
-
}
|
|
609
|
-
function shellQuote(value) {
|
|
610
|
-
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
611
|
-
}
|
|
612
|
-
function shellPathForScript(value) {
|
|
613
|
-
return /^[A-Za-z0-9_./-]+$/.test(value) ? value : shellQuote(value);
|
|
614
|
-
}
|
|
615
|
-
function buildGuestWorkspacePrelude(settings) {
|
|
616
|
-
if (!settings.guestWorkdir || !settings.syncHostWorkspace) {
|
|
617
|
-
return "";
|
|
618
|
-
}
|
|
619
|
-
const guest = shellQuote(settings.guestWorkdir);
|
|
620
|
-
const exclusions = [
|
|
621
|
-
".git",
|
|
622
|
-
"node_modules",
|
|
623
|
-
".venv",
|
|
624
|
-
".next",
|
|
625
|
-
"dist",
|
|
626
|
-
"build",
|
|
627
|
-
"target",
|
|
628
|
-
".pytest_cache",
|
|
629
|
-
".mypy_cache",
|
|
630
|
-
];
|
|
631
|
-
const tarExcludes = exclusions.map((entry) => `--exclude=${shellQuote(entry)}`).join(" ");
|
|
632
|
-
return [
|
|
633
|
-
`mkdir -p ${guest}`,
|
|
634
|
-
`find ${guest} -mindepth 1 -maxdepth 1 ${exclusions
|
|
635
|
-
.map((entry) => `! -name ${shellQuote(entry)}`)
|
|
636
|
-
.join(" ")} -exec rm -rf {} + 2>/dev/null || true`,
|
|
637
|
-
`tar -C /workspace ${tarExcludes} -cf - . | tar -C ${guest} -xf -`,
|
|
638
|
-
].join(" && ");
|
|
639
|
-
}
|
|
640
|
-
function buildShellInitScript(settings) {
|
|
641
|
-
return (settings.shellInit ?? []).filter(Boolean).join(" && ");
|
|
642
|
-
}
|
|
643
|
-
function getSandboxUnsupportedReason() {
|
|
644
|
-
if (process.platform !== "darwin" || process.arch !== "arm64") {
|
|
645
|
-
return "Shuru sandbox mode currently requires macOS on Apple Silicon.";
|
|
646
|
-
}
|
|
647
|
-
return null;
|
|
648
|
-
}
|
|
649
|
-
export function getSandboxMutationBlockReason(command, settings = {}) {
|
|
650
|
-
const trimmed = command.trim();
|
|
651
|
-
if (!trimmed)
|
|
652
|
-
return null;
|
|
653
|
-
if (/\bgit\s+/.test(trimmed) && !/\bgit\s+(status|diff|log|show|rev-parse|grep|ls-files)\b/.test(trimmed)) {
|
|
654
|
-
return [
|
|
655
|
-
"Sandbox mode blocks git commands that mutate repository state because Shuru guest-side workspace changes do not persist back to the host.",
|
|
656
|
-
"Disable sandbox mode to run persistent git mutations on the real workspace.",
|
|
657
|
-
].join(" ");
|
|
658
|
-
}
|
|
659
|
-
const blockedPatterns = [
|
|
660
|
-
{
|
|
661
|
-
pattern: /\b(?:prettier\s+--write|eslint\b.*--fix|biome\s+check\b.*--write|ruff\s+check\b.*--fix|gofmt\s+-w|rustfmt\b|clang-format\b.*-i)\b/,
|
|
662
|
-
reason: "Shell-driven formatters that rewrite files are blocked in sandbox mode because those file changes would not persist back to the host workspace.",
|
|
663
|
-
},
|
|
664
|
-
];
|
|
665
|
-
if (!settings.allowEphemeralInstall) {
|
|
666
|
-
const installPatterns = [
|
|
667
|
-
{
|
|
668
|
-
pattern: /\b(?:npm|pnpm|yarn|bun)\s+(?:add|install|remove|unlink|update|upgrade)\b/,
|
|
669
|
-
reason: "Package-manager installs are blocked in sandbox mode because workspace changes like lockfile updates would stay inside the Shuru guest overlay.",
|
|
670
|
-
},
|
|
671
|
-
{
|
|
672
|
-
pattern: /\b(?:pip|pip3)\s+install\b|\bpoetry\s+add\b|\buv\s+add\b|\bcargo\s+add\b/,
|
|
673
|
-
reason: "Dependency install commands are blocked in sandbox mode because resulting workspace changes would not persist back to the host.",
|
|
674
|
-
},
|
|
675
|
-
];
|
|
676
|
-
const installMatch = installPatterns.find(({ pattern }) => pattern.test(trimmed));
|
|
677
|
-
if (installMatch) {
|
|
678
|
-
return `${installMatch.reason} Use read_file/edit_file/write_file for durable edits, or disable sandbox mode for host-persistent shell changes.`;
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
const matched = blockedPatterns.find(({ pattern }) => pattern.test(trimmed));
|
|
682
|
-
if (!matched)
|
|
683
|
-
return null;
|
|
684
|
-
return `${matched.reason} Use read_file/edit_file/write_file for durable edits, or disable sandbox mode for host-persistent shell changes.`;
|
|
442
|
+
return command;
|
|
685
443
|
}
|
|
686
444
|
//# sourceMappingURL=bash.js.map
|