@yiln-dsh/dsh-plugin-sandbox-guidance 0.1.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/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # @yiln-dsh/dsh-plugin-sandbox-guidance
2
+
3
+ A Host-only DSH plugin that explains one confusing sandbox failure to the model:
4
+ when a bash call asks for a mode that is not strictly wider than the current
5
+ sandbox mode.
6
+
7
+ It does not change sandbox policy, bypass approval, rewrite tool arguments, or
8
+ replace the built-in bash executor. The native failure remains an error and the
9
+ command remains unexecuted.
10
+
11
+ ## Behavior
12
+
13
+ The plugin adds a `systemPrompt` section that tells the model to omit
14
+ `sandbox_permissions` during ordinary calls and to explain this failure instead
15
+ of repeating it blindly. It also listens to `tools/post-execute` and replaces
16
+ only the matching bash failure text with a diagnostic containing:
17
+
18
+ - the fact that bash did not run;
19
+ - the requested sandbox mode;
20
+ - the current effective mode;
21
+ - whether the retry should omit `sandbox_permissions` or request a genuinely wider mode.
22
+
23
+ Other bash failures pass through unchanged.
24
+
25
+ ## Install
26
+
27
+ The published package is `@yiln-dsh/dsh-plugin-sandbox-guidance@0.1.0`.
28
+
29
+ ```bash
30
+ dsh plugin --profile web add @yiln-dsh/dsh-plugin-sandbox-guidance@latest
31
+ ```
32
+
33
+ Restart `dsh web` after installing the package so the Host composition loads the
34
+ new row.
35
+
36
+ ## Limitations
37
+
38
+ `tools/pre-execute` and `tools/post-execute` receive immutable tool arguments.
39
+ This plugin can explain a failure and guide the next model step, but it cannot
40
+ silently convert an invalid escalation into a valid one. Removing the strict
41
+ sandbox check still requires a DSH core patch or fork.
42
+
43
+ ## Layout
44
+
45
+ | File | Content |
46
+ | --- | --- |
47
+ | `index.js` | Host system prompt section and bash failure diagnostic. |
48
+ | `cordis.patch.yml` | Composition patch that mounts the Host row. |
@@ -0,0 +1,11 @@
1
+ # dsh-plugin-sandbox-guidance bundle patch.
2
+ #
3
+ # Adds a Host-only prompt/result diagnostic; it never changes sandbox policy or
4
+ # replaces the native bash executor.
5
+
6
+ - insert:
7
+ - id: sandbox-guidance
8
+ name: '@yiln-dsh/dsh-plugin-sandbox-guidance'
9
+ inject:
10
+ - tools
11
+ - systemPrompt
package/index.js ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Explains non-widening sandbox errors to the model without changing execution.
3
+ * The native bash tool remains fail-closed; this package only improves recovery
4
+ * guidance when a caller repeats the current sandbox mode.
5
+ */
6
+
7
+ export const name = "sandbox-guidance";
8
+ export const inject = ["tools", "systemPrompt"];
9
+
10
+ const NON_WIDENING_ERROR = /^sandbox escalation to "([^"]+)" is not strictly wider than this call's current "([^"]+)" mode$/u;
11
+
12
+ /**
13
+ * Turn the native sandbox error into a model-facing diagnostic that says what
14
+ * ran, what did not run, and which retry shape is valid.
15
+ */
16
+ export function explainSandboxFailure(message) {
17
+ if (typeof message !== "string") return undefined;
18
+ const match = NON_WIDENING_ERROR.exec(message);
19
+ if (match === null) return undefined;
20
+ const requested = match[1];
21
+ const effective = match[2];
22
+ const sameMode = requested === effective;
23
+ return [
24
+ "Bash was not executed; this failure happened before the command ran.",
25
+ `Cause: sandbox_permissions requested \"${requested}\", but the current effective sandbox mode is \"${effective}\".`,
26
+ sameMode
27
+ ? "The requested mode is already active, so sandbox_permissions must be omitted for the retry."
28
+ : "sandbox_permissions is only valid for a retry that requests a strictly wider mode; do not retry with this mode.",
29
+ "Explain this cause to the user instead of silently repeating the same bash call.",
30
+ ].join(" ");
31
+ }
32
+
33
+ const SYSTEM_PROMPT = [
34
+ "Sandbox escalation recovery:",
35
+ "- Do not include sandbox_permissions in an ordinary bash call.",
36
+ "- Only include it when retrying a call that was actually denied by the sandbox and the requested mode is strictly wider than the effective mode.",
37
+ "- If a bash result says the requested mode is not strictly wider than the current mode, state that the command did not run, explain the requested and effective modes, and retry without sandbox_permissions when the current mode is sufficient.",
38
+ "- If a wider mode is genuinely required, explain why to the user and request approval rather than repeating the failed call.",
39
+ ].join("\n");
40
+
41
+ export function apply(ctx) {
42
+ const order = typeof ctx.systemPrompt.getSectionOrder === "function"
43
+ ? ctx.systemPrompt.getSectionOrder("TOOL_BASH") + 1
44
+ : 105;
45
+ ctx.systemPrompt.section({
46
+ name: "tool:sandbox-guidance",
47
+ order,
48
+ text: SYSTEM_PROMPT,
49
+ });
50
+
51
+ ctx.on("tools/post-execute", (exec, result, next) => {
52
+ if (exec.name !== "bash" || result.isError !== true) return next();
53
+ const explained = explainSandboxFailure(result.error?.message);
54
+ if (explained === undefined) return next();
55
+ return {
56
+ kind: "accept",
57
+ content: [{ type: "text", text: explained }],
58
+ };
59
+ });
60
+ }
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@yiln-dsh/dsh-plugin-sandbox-guidance",
3
+ "version": "0.1.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "description": "DSH Host plugin that explains non-widening sandbox failures to the model and user without changing execution policy.",
8
+ "type": "module",
9
+ "scripts": {
10
+ "test": "node --test test/*.test.js"
11
+ },
12
+ "main": "index.js",
13
+ "exports": {
14
+ ".": "./index.js",
15
+ "./package.json": "./package.json"
16
+ },
17
+ "dsh": {
18
+ "bundle": {
19
+ "patch": "./cordis.patch.yml"
20
+ }
21
+ },
22
+ "files": [
23
+ "index.js",
24
+ "cordis.patch.yml",
25
+ "README.md"
26
+ ],
27
+ "peerDependencies": {
28
+ "@deepseek-ai/cordis": ">=4.0.2",
29
+ "@deepseek-ai/dsh-system-prompt": ">=0.1.2-rc.1",
30
+ "@deepseek-ai/dsh-tools": ">=0.1.2-rc.1"
31
+ },
32
+ "engines": {
33
+ "node": ">=22"
34
+ },
35
+ "license": "MIT"
36
+ }