@xth26/dsh-plan-build-mode 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,104 @@
1
+ # dsh-plan-build-mode
2
+
3
+ OpenCode-style Plan / Build hard permission model for DeepSeek Harness.
4
+
5
+ This plugin adds an independent Plan/Build mode switch to DSH:
6
+
7
+ - **Plan mode** enforces a `read-only` sandbox and blocks mutating tools (`write`, `edit`).
8
+ - **Build mode** restores `workspace-write` and allows edits.
9
+ - DSH's built-in `/plan` soft-guidance mode is left untouched.
10
+
11
+ The tool denial only takes effect when Plan mode is configured as `read-only`. When the session has not been switched, Build mode is active by default.
12
+
13
+ ## Installation
14
+
15
+ DSH plugins are loaded through a DSH profile. Install the plugin into the profile(s) you use:
16
+
17
+ ```bash
18
+ # For the web profile
19
+ dsh plugin --profile web add @xth26/dsh-plan-build-mode
20
+
21
+ # For the TUI profile
22
+ dsh plugin --profile dsh-tui add @xth26/dsh-plan-build-mode
23
+ ```
24
+
25
+ The plugin ships with a `cordis.patch.yml` that auto-injects the required row
26
+ when the package is loaded by a DSH profile.
27
+
28
+ ## Using the same Plan/Build mode in both web and TUI
29
+
30
+ Plan/Build mode state is stored in the session event log (`sandbox/mode` event). Both `dsh web` and `dsh --profile <name>` use the same session store when they share the same profile and session ID.
31
+
32
+ - **Same profile**: if you run `dsh web --profile web` and `dsh --profile web`, the mode is shared because the session events are shared.
33
+ - **Different profiles**: by default `web` and `dsh-tui` are separate profiles with separate session directories. Switching in one does **not** affect the other.
34
+
35
+ To make web and TUI share the same mode and session history, use the **same profile** for both:
36
+
37
+ ```bash
38
+ # Use the web profile for both interfaces
39
+ dsh web --profile web
40
+ dsh --profile web
41
+ ```
42
+
43
+ Or, if you prefer to keep separate profiles but want to share only the session store, override the session root in each profile's `cordis.patch.yml` to point to the same directory:
44
+
45
+ ```yaml
46
+ - id: session-root
47
+ config:
48
+ root: /path/to/shared/sessions
49
+ ```
50
+
51
+ Note: sharing session directories across profiles requires both profiles to mount compatible service bundles; otherwise event interpretation may differ.
52
+
53
+ ## Local development / link
54
+
55
+ To try the plugin from a local checkout without publishing:
56
+
57
+ ```bash
58
+ # From the plugin checkout
59
+ cd /path/to/dsh-plan-build-mode
60
+ pnpm link --global
61
+
62
+ # From your DSH profile directory
63
+ pnpm link --global @xth26/dsh-plan-build-mode
64
+ ```
65
+
66
+ Then start DSH with that profile. The `dsh.bundle.patch` field in the plugin's
67
+ `package.json` makes the patch apply automatically.
68
+
69
+ ## Usage
70
+
71
+ | Command | Effect |
72
+ |---|---|
73
+ | `/plan-build` | Show the current mode |
74
+ | `/plan-build switch plan` | Enter Plan mode (read-only) |
75
+ | `/plan-build switch build` | Enter Build mode (writable) |
76
+ | `/plan-build switch` | Toggle between plan and build |
77
+
78
+ ## Configuration
79
+
80
+ ```yaml
81
+ - id: plan-build-mode
82
+ name: '@xth26/dsh-plan-build-mode'
83
+ config:
84
+ planSandbox: read-only
85
+ buildSandbox: workspace-write
86
+ denyWriteTools: true
87
+ section: true
88
+ ```
89
+
90
+ ## Local integration check
91
+
92
+ After installing/linking the plugin in a DSH profile:
93
+
94
+ 1. Start DSH with that profile.
95
+ 2. Run `/plan-build switch plan`. You should see a confirmation that Plan mode
96
+ is active.
97
+ 3. Ask the agent to call the `write` tool. It should be denied with a reason.
98
+ 4. Run `/plan-build switch build`. You should see a confirmation that Build mode
99
+ is active.
100
+ 5. Ask the agent to call `write` again. It should now be allowed.
101
+
102
+ ## License
103
+
104
+ MIT
package/README.zh.md ADDED
@@ -0,0 +1,99 @@
1
+ # dsh-plan-build-mode
2
+
3
+ OpenCode 风格的 Plan / Build 硬权限模型插件。
4
+
5
+ 本插件为 DSH 增加一个独立的 Plan/Build 模式切换,不影响 DSH 原生的 `/plan` 软提示模式:
6
+
7
+ - **Plan 模式**:强制 `read-only` 沙箱,并拦截写工具(`write`、`edit`)。
8
+ - **Build 模式**:恢复 `workspace-write`,允许编辑。
9
+
10
+ 写工具拦截仅在 Plan 模式配置为 `read-only` 时生效。首次使用或未切换时,默认处于 Build 模式。
11
+
12
+ ## 安装
13
+
14
+ DSH 插件通过 DSH profile 加载。把它装到你实际使用的 profile 里:
15
+
16
+ ```bash
17
+ # 装到 web profile
18
+ dsh plugin --profile web add @xth26/dsh-plan-build-mode
19
+
20
+ # 装到 TUI profile
21
+ dsh plugin --profile dsh-tui add @xth26/dsh-plan-build-mode
22
+ ```
23
+
24
+ 插件自带的 `cordis.patch.yml` 会在 DSH profile 加载时自动注入。
25
+
26
+ ## 让 Web 和 TUI 共享同一个 Plan/Build 模式
27
+
28
+ Plan/Build 模式状态存在会话事件日志里(`sandbox/mode` 事件)。`dsh web` 和 `dsh --profile <名称>` 只有在共用同一个 profile、同一个 session ID 时,才会读写同一个会话事件流。
29
+
30
+ - **同一个 profile**:比如 `dsh web --profile web` 和 `dsh --profile web` 启动的两个入口,会共享 session 事件,因此模式切换会同步生效。
31
+ - **不同 profile**:默认 `web` 和 `dsh-tui` 是两个独立 profile,会话目录也分开。在一处切换不会影响另一处。
32
+
33
+ 想让 web 和 TUI 共享模式状态,最简单的方法是**两个入口都使用同一个 profile**:
34
+
35
+ ```bash
36
+ # 两个入口都用 web profile
37
+ dsh web --profile web
38
+ dsh --profile web
39
+ ```
40
+
41
+ 如果你确实想用不同 profile,但只想共享会话存储,可以在每个 profile 的 `cordis.patch.yml` 里把 session root 指向同一个目录:
42
+
43
+ ```yaml
44
+ - id: session-root
45
+ config:
46
+ root: /path/to/shared/sessions
47
+ ```
48
+
49
+ 注意:跨 profile 共享会话目录要求两个 profile 挂载的服务组合兼容,否则事件解释可能出现差异。
50
+
51
+ ## 本地开发 / link 试用
52
+
53
+ 想在发布前从本地源码试用:
54
+
55
+ ```bash
56
+ # 在插件目录
57
+ cd /path/to/dsh-plan-build-mode
58
+ pnpm link --global
59
+
60
+ # 在你的 DSH profile 目录
61
+ pnpm link --global @xth26/dsh-plan-build-mode
62
+ ```
63
+
64
+ 然后启动 DSH。插件 `package.json` 里的 `dsh.bundle.patch` 会自动生效。
65
+
66
+ ## 使用
67
+
68
+ | 命令 | 效果 |
69
+ |---|---|
70
+ | `/plan-build` | 显示当前模式 |
71
+ | `/plan-build switch plan` | 进入 Plan 模式(只读) |
72
+ | `/plan-build switch build` | 进入 Build 模式(可写) |
73
+ | `/plan-build switch` | 切换当前模式 |
74
+
75
+ ## 配置
76
+
77
+ ```yaml
78
+ - id: plan-build-mode
79
+ name: '@xth26/dsh-plan-build-mode'
80
+ config:
81
+ planSandbox: read-only
82
+ buildSandbox: workspace-write
83
+ denyWriteTools: true
84
+ section: true
85
+ ```
86
+
87
+ ## 本地集成验证
88
+
89
+ 安装或 link 插件到 DSH profile 后:
90
+
91
+ 1. 启动 DSH。
92
+ 2. 输入 `/plan-build switch plan`,应提示进入 Plan 模式。
93
+ 3. 让 agent 调用 `write` 工具,应被拒绝。
94
+ 4. 输入 `/plan-build switch build`,应提示进入 Build 模式。
95
+ 5. 再次让 agent 调用 `write`,应允许执行。
96
+
97
+ ## 许可证
98
+
99
+ MIT
@@ -0,0 +1,10 @@
1
+ # Profile patch for dsh-plan-build-mode.
2
+ # Loaded automatically when the package is installed in a DSH profile.
3
+ - insert:
4
+ - id: plan-build-mode
5
+ name: '@xth26/dsh-plan-build-mode'
6
+ config:
7
+ planSandbox: read-only
8
+ buildSandbox: workspace-write
9
+ denyWriteTools: true
10
+ section: true
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Pure helpers for OpenCode-style Plan/Build mode switching.
3
+ * @module dsh-plan-build-mode/helpers
4
+ */
5
+ import type { Agent } from '@deepseek-ai/dsh-agent';
6
+ import type { SandboxMode } from '@deepseek-ai/dsh-sandbox';
7
+ import type { SessionEvent } from '@deepseek-ai/dsh-session';
8
+ import type { ToolExecution } from '@deepseek-ai/dsh-tools';
9
+ /** Default sandbox mode while Plan mode is active. */
10
+ export declare const DEFAULT_PLAN_SANDBOX: SandboxMode;
11
+ /** Default sandbox mode while Build mode is active. */
12
+ export declare const DEFAULT_BUILD_SANDBOX: SandboxMode;
13
+ /** Tools forbidden while in Plan mode. */
14
+ export declare const WRITE_TOOLS: Set<string>;
15
+ /**
16
+ * Return the most recently written sandbox mode for a session, or undefined
17
+ * when the session has never switched.
18
+ */
19
+ export declare function currentSandboxMode(events: readonly SessionEvent[]): SandboxMode | undefined;
20
+ /**
21
+ * Whether the session is currently in OpenCode Plan mode.
22
+ * Plan mode is defined as the current sandbox mode matching the configured
23
+ * planSandbox (read-only by default).
24
+ */
25
+ export declare function isPlanModeActive(events: readonly SessionEvent[], planSandbox: SandboxMode): boolean;
26
+ /**
27
+ * Append a `sandbox/mode` event to switch between Plan and Build mode.
28
+ */
29
+ export declare function setPlanBuildMode(agent: Agent, mode: 'plan' | 'build', planSandbox: SandboxMode, buildSandbox: SandboxMode): void;
30
+ /**
31
+ * Compute a denial reason if a tool call should be blocked in Plan mode.
32
+ * Returns `undefined` when the call is allowed.
33
+ *
34
+ * Write tools are denied only when Plan mode is active AND Plan mode is
35
+ * configured as read-only. If Plan mode is configured to a writable sandbox,
36
+ * the plugin still tracks the mode but does not block tools — the real
37
+ * protection is the read-only sandbox.
38
+ */
39
+ export declare function planModeDenial(exec: ToolExecution, planSandbox: SandboxMode, writeTools?: ReadonlySet<string>): string | undefined;
40
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAG3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAE3D,sDAAsD;AACtD,eAAO,MAAM,oBAAoB,EAAE,WAAyB,CAAA;AAE5D,uDAAuD;AACvD,eAAO,MAAM,qBAAqB,EAAE,WAA+B,CAAA;AAEnE,0CAA0C;AAC1C,eAAO,MAAM,WAAW,aAA6B,CAAA;AAErD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,WAAW,GAAG,SAAS,CAQ3F;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAEnG;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,GAAG,IAAI,CAGhI;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,aAAa,EACnB,WAAW,EAAE,WAAW,EACxB,UAAU,GAAE,WAAW,CAAC,MAAM,CAAe,GAC5C,MAAM,GAAG,SAAS,CAQpB"}
package/lib/helpers.js ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Pure helpers for OpenCode-style Plan/Build mode switching.
3
+ * @module dsh-plan-build-mode/helpers
4
+ */
5
+ /** Default sandbox mode while Plan mode is active. */
6
+ export const DEFAULT_PLAN_SANDBOX = 'read-only';
7
+ /** Default sandbox mode while Build mode is active. */
8
+ export const DEFAULT_BUILD_SANDBOX = 'workspace-write';
9
+ /** Tools forbidden while in Plan mode. */
10
+ export const WRITE_TOOLS = new Set(['write', 'edit']);
11
+ /**
12
+ * Return the most recently written sandbox mode for a session, or undefined
13
+ * when the session has never switched.
14
+ */
15
+ export function currentSandboxMode(events) {
16
+ for (let i = events.length - 1; i >= 0; i -= 1) {
17
+ const event = events[i];
18
+ if (event.type === 'sandbox/mode') {
19
+ return event.data.mode;
20
+ }
21
+ }
22
+ return undefined;
23
+ }
24
+ /**
25
+ * Whether the session is currently in OpenCode Plan mode.
26
+ * Plan mode is defined as the current sandbox mode matching the configured
27
+ * planSandbox (read-only by default).
28
+ */
29
+ export function isPlanModeActive(events, planSandbox) {
30
+ return currentSandboxMode(events) === planSandbox;
31
+ }
32
+ /**
33
+ * Append a `sandbox/mode` event to switch between Plan and Build mode.
34
+ */
35
+ export function setPlanBuildMode(agent, mode, planSandbox, buildSandbox) {
36
+ const target = mode === 'plan' ? planSandbox : buildSandbox;
37
+ agent.session.append('sandbox/mode', { mode: target });
38
+ }
39
+ /**
40
+ * Compute a denial reason if a tool call should be blocked in Plan mode.
41
+ * Returns `undefined` when the call is allowed.
42
+ *
43
+ * Write tools are denied only when Plan mode is active AND Plan mode is
44
+ * configured as read-only. If Plan mode is configured to a writable sandbox,
45
+ * the plugin still tracks the mode but does not block tools — the real
46
+ * protection is the read-only sandbox.
47
+ */
48
+ export function planModeDenial(exec, planSandbox, writeTools = WRITE_TOOLS) {
49
+ if (exec.agent === undefined)
50
+ return undefined;
51
+ if (planSandbox !== 'read-only')
52
+ return undefined;
53
+ if (!isPlanModeActive(exec.agent.session.events, planSandbox))
54
+ return undefined;
55
+ if (writeTools.has(exec.name)) {
56
+ return `Tool '${exec.name}' is forbidden in Plan Mode. Leave Plan Mode with /plan-build switch build before editing files.`;
57
+ }
58
+ return undefined;
59
+ }
60
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,sDAAsD;AACtD,MAAM,CAAC,MAAM,oBAAoB,GAAgB,WAAW,CAAA;AAE5D,uDAAuD;AACvD,MAAM,CAAC,MAAM,qBAAqB,GAAgB,iBAAiB,CAAA;AAEnE,0CAA0C;AAC1C,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAA;AAErD;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAA+B;IAChE,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/C,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAE,CAAA;QACxB,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YAClC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAA;QACxB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAA+B,EAAE,WAAwB;IACxF,OAAO,kBAAkB,CAAC,MAAM,CAAC,KAAK,WAAW,CAAA;AACnD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAY,EAAE,IAAsB,EAAE,WAAwB,EAAE,YAAyB;IACxH,MAAM,MAAM,GAAgB,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAA;IACxE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;AACxD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAC5B,IAAmB,EACnB,WAAwB,EACxB,aAAkC,WAAW;IAE7C,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IAC9C,IAAI,WAAW,KAAK,WAAW;QAAE,OAAO,SAAS,CAAA;IACjD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,WAAW,CAAC;QAAE,OAAO,SAAS,CAAA;IAC/E,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,OAAO,SAAS,IAAI,CAAC,IAAI,kGAAkG,CAAA;IAC7H,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Host half of `dsh-plan-build-mode`.
3
+ *
4
+ * Implements an OpenCode-style Plan / Build mode that is independent from
5
+ * DSH's built-in `/plan` soft-guidance mode:
6
+ *
7
+ * - `/plan-build switch plan` -> Plan mode + read-only sandbox
8
+ * - `/plan-build switch build` -> Build mode + workspace-write sandbox
9
+ * - Blocks `write`/`edit` tool calls while in Plan mode
10
+ * - Injects a `plan-build:policy` system prompt section
11
+ *
12
+ * @module dsh-plan-build-mode
13
+ */
14
+ import type { Context } from '@deepseek-ai/cordis';
15
+ import z from '@deepseek-ai/schemastery';
16
+ import type { PlanBuildModeConfig } from './types.ts';
17
+ /** Cordis plugin name. */
18
+ export declare const name = "dsh-plan-build-mode";
19
+ /** Service dependencies for the host half. */
20
+ export declare const inject: readonly ["agents", "tools", "systemPrompt"];
21
+ /** Configuration schema. */
22
+ export declare const Config: z<Schemastery.ObjectS<{
23
+ planSandbox: z<"read-only" | "workspace-write" | "danger-full-access", "read-only" | "workspace-write" | "danger-full-access">;
24
+ buildSandbox: z<"read-only" | "workspace-write" | "danger-full-access", "read-only" | "workspace-write" | "danger-full-access">;
25
+ denyWriteTools: z<boolean, boolean>;
26
+ section: z<boolean, boolean>;
27
+ }>, Schemastery.ObjectT<{
28
+ planSandbox: z<"read-only" | "workspace-write" | "danger-full-access", "read-only" | "workspace-write" | "danger-full-access">;
29
+ buildSandbox: z<"read-only" | "workspace-write" | "danger-full-access", "read-only" | "workspace-write" | "danger-full-access">;
30
+ denyWriteTools: z<boolean, boolean>;
31
+ section: z<boolean, boolean>;
32
+ }>>;
33
+ /**
34
+ * Plugin entry point.
35
+ * @param ctx - Cordis context carrying the injected services.
36
+ * @param config - Validated deployment configuration.
37
+ */
38
+ export declare function apply(ctx: Context, config?: PlanBuildModeConfig): void;
39
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAmBxC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAErD,0BAA0B;AAC1B,eAAO,MAAM,IAAI,wBAAwB,CAAA;AACzC,8CAA8C;AAC9C,eAAO,MAAM,MAAM,8CAA+C,CAAA;AAClE,4BAA4B;AAC5B,eAAO,MAAM,MAAM;;;;;;;;;;GAajB,CAAA;AAEF;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,mBAAwB,GAAG,IAAI,CAkG1E"}
package/lib/index.js ADDED
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Host half of `dsh-plan-build-mode`.
3
+ *
4
+ * Implements an OpenCode-style Plan / Build mode that is independent from
5
+ * DSH's built-in `/plan` soft-guidance mode:
6
+ *
7
+ * - `/plan-build switch plan` -> Plan mode + read-only sandbox
8
+ * - `/plan-build switch build` -> Build mode + workspace-write sandbox
9
+ * - Blocks `write`/`edit` tool calls while in Plan mode
10
+ * - Injects a `plan-build:policy` system prompt section
11
+ *
12
+ * @module dsh-plan-build-mode
13
+ */
14
+ import z from '@deepseek-ai/schemastery';
15
+ import { DEFAULT_BUILD_SANDBOX, DEFAULT_PLAN_SANDBOX, isPlanModeActive, planModeDenial, setPlanBuildMode, WRITE_TOOLS, } from "./helpers.js";
16
+ /** Cordis plugin name. */
17
+ export const name = 'dsh-plan-build-mode';
18
+ /** Service dependencies for the host half. */
19
+ export const inject = ['agents', 'tools', 'systemPrompt'];
20
+ /** Configuration schema. */
21
+ export const Config = z.object({
22
+ planSandbox: z.union([
23
+ z.const('read-only'),
24
+ z.const('workspace-write'),
25
+ z.const('danger-full-access'),
26
+ ]).required(false),
27
+ buildSandbox: z.union([
28
+ z.const('read-only'),
29
+ z.const('workspace-write'),
30
+ z.const('danger-full-access'),
31
+ ]).required(false),
32
+ denyWriteTools: z.boolean().default(true),
33
+ section: z.boolean().default(true),
34
+ });
35
+ /**
36
+ * Plugin entry point.
37
+ * @param ctx - Cordis context carrying the injected services.
38
+ * @param config - Validated deployment configuration.
39
+ */
40
+ export function apply(ctx, config = {}) {
41
+ const planSandbox = config.planSandbox ?? DEFAULT_PLAN_SANDBOX;
42
+ const buildSandbox = config.buildSandbox ?? DEFAULT_BUILD_SANDBOX;
43
+ if (planSandbox === buildSandbox) {
44
+ throw new Error(`planSandbox and buildSandbox must be different, but both are '${planSandbox}'.`);
45
+ }
46
+ const denyWriteTools = config.denyWriteTools !== false;
47
+ const enableSection = config.section !== false;
48
+ ctx.effect(() => {
49
+ const disposers = [];
50
+ // Align existing sessions on load (resumed sessions may already have
51
+ // sandbox/mode events).
52
+ for (const _agent of ctx.agents.list()) {
53
+ // No-op on load: state is already in the log; we only react to commands.
54
+ }
55
+ // Inject a system prompt section describing the current mode.
56
+ if (enableSection) {
57
+ disposers.push(ctx.systemPrompt.section({
58
+ name: 'plan-build:policy',
59
+ order: 56,
60
+ text(context) {
61
+ const agent = context.agent;
62
+ if (agent === undefined)
63
+ return '';
64
+ return isPlanModeActive(agent.session.events, planSandbox)
65
+ ? 'You are in OpenCode Plan Mode. You are READ-ONLY. You may read files, search code, browse directories, and ask questions. You MUST NOT create, modify, or delete files; run commands that change the system; install packages; run tests/builds; or delegate to subagents/workflows. Present a complete plan and use /plan-build switch build before implementing.'
66
+ : 'You are in OpenCode Build Mode. You may edit files, run commands, and execute the approved plan. Make minimal changes, run tests/verification after changes, and ask for confirmation before destructive git operations or system-wide changes.';
67
+ },
68
+ }));
69
+ }
70
+ // Block mutating tool calls while in Plan mode.
71
+ disposers.push(ctx.on('tools/pre-execute', async (exec, next) => {
72
+ if (!denyWriteTools)
73
+ return next();
74
+ const reason = planModeDenial(exec, planSandbox, WRITE_TOOLS);
75
+ if (reason !== undefined)
76
+ return { kind: 'deny', reason };
77
+ return next();
78
+ }));
79
+ // User-facing slash command to check or switch Plan/Build mode.
80
+ // Activates only when a command registry is composed (headless assemblies stay unaffected).
81
+ ctx.inject(['commands'], (commandCtx) => {
82
+ disposers.push(commandCtx.commands.register({
83
+ name: 'plan-build',
84
+ description: 'Switch between OpenCode Plan and Build modes',
85
+ input: { hint: '[switch [plan|build]]' },
86
+ handler: ({ agent, rawInput }) => {
87
+ const arg = rawInput.trim().toLowerCase();
88
+ const active = isPlanModeActive(agent.session.events, planSandbox);
89
+ if (arg === '') {
90
+ return {
91
+ kind: 'success',
92
+ text: active
93
+ ? 'Plan mode is active (read-only). Use /plan-build switch build to enter Build mode.'
94
+ : 'Build mode is active. Use /plan-build switch plan to enter Plan mode.',
95
+ };
96
+ }
97
+ if (!arg.startsWith('switch')) {
98
+ return {
99
+ kind: 'error',
100
+ text: 'Usage: /plan-build, /plan-build switch, /plan-build switch plan, or /plan-build switch build.',
101
+ };
102
+ }
103
+ const target = arg.slice('switch'.length).trim().toLowerCase();
104
+ if (target === '') {
105
+ const next = active ? 'build' : 'plan';
106
+ setPlanBuildMode(agent, next, planSandbox, buildSandbox);
107
+ return { kind: 'success', text: `Switched to ${next} mode.` };
108
+ }
109
+ if (target !== 'plan' && target !== 'build') {
110
+ return {
111
+ kind: 'error',
112
+ text: 'Usage: /plan-build switch plan, or /plan-build switch build.',
113
+ };
114
+ }
115
+ const targetActive = target === 'plan';
116
+ if (active === targetActive) {
117
+ return { kind: 'success', text: `Already in ${target} mode.` };
118
+ }
119
+ setPlanBuildMode(agent, target, planSandbox, buildSandbox);
120
+ return { kind: 'success', text: `Switched to ${target} mode.` };
121
+ },
122
+ }));
123
+ });
124
+ return () => {
125
+ for (const dispose of disposers)
126
+ dispose();
127
+ };
128
+ });
129
+ }
130
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Package-owned invariant companion for `dsh-plan-build-mode`.
3
+ *
4
+ * This plugin stores its state entirely in the existing `sandbox/mode` event
5
+ * (owned by `@deepseek-ai/dsh-sandbox-policy`), so there is no custom event
6
+ * type to validate. The companion is kept as a no-op installer so downstream
7
+ * deployments can still mount `dsh-plan-build-mode/invariant` if desired.
8
+ *
9
+ * @module dsh-plan-build-mode/invariant
10
+ */
11
+ import type { Context } from '@deepseek-ai/cordis';
12
+ /** Cordis companion plugin name. */
13
+ export declare const name = "dsh-plan-build-mode-invariant";
14
+ /** Service required before the companion can reserve package ownership. */
15
+ export declare const inject: readonly ["invariants"];
16
+ /**
17
+ * Register the plan-build-mode invariant companion.
18
+ * @param ctx - Cordis context carrying the invariant service.
19
+ * @returns the installed registration's disposer after setup succeeds.
20
+ */
21
+ export declare const apply: (ctx: Context & {
22
+ invariants: unknown;
23
+ }) => Promise<() => void>;
24
+ //# sourceMappingURL=invariant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invariant.d.ts","sourceRoot":"","sources":["../src/invariant.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,oCAAoC;AACpC,eAAO,MAAM,IAAI,kCAAkC,CAAA;AACnD,2EAA2E;AAC3E,eAAO,MAAM,MAAM,yBAA0B,CAAA;AAO7C;;;;GAIG;AACH,eAAO,MAAM,KAAK,QAAS,OAAO,GAAG;IAAE,UAAU,EAAE,OAAO,CAAA;CAAE,KAAG,OAAO,CAAC,MAAM,IAAI,CAM9E,CAAA"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Package-owned invariant companion for `dsh-plan-build-mode`.
3
+ *
4
+ * This plugin stores its state entirely in the existing `sandbox/mode` event
5
+ * (owned by `@deepseek-ai/dsh-sandbox-policy`), so there is no custom event
6
+ * type to validate. The companion is kept as a no-op installer so downstream
7
+ * deployments can still mount `dsh-plan-build-mode/invariant` if desired.
8
+ *
9
+ * @module dsh-plan-build-mode/invariant
10
+ */
11
+ /** Cordis companion plugin name. */
12
+ export const name = 'dsh-plan-build-mode-invariant';
13
+ /** Service required before the companion can reserve package ownership. */
14
+ export const inject = ['invariants'];
15
+ /** No-op installer: state lives in sandbox/mode, validated by dsh-sandbox-policy. */
16
+ const install = Object.assign(() => {
17
+ // Intentionally empty: this plugin does not introduce new session event types.
18
+ }, { inject: [] });
19
+ /**
20
+ * Register the plan-build-mode invariant companion.
21
+ * @param ctx - Cordis context carrying the invariant service.
22
+ * @returns the installed registration's disposer after setup succeeds.
23
+ */
24
+ export const apply = (ctx) => Promise.resolve(ctx.invariants.register('dsh-plan-build-mode', install));
25
+ //# sourceMappingURL=invariant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invariant.js","sourceRoot":"","sources":["../src/invariant.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,oCAAoC;AACpC,MAAM,CAAC,MAAM,IAAI,GAAG,+BAA+B,CAAA;AACnD,2EAA2E;AAC3E,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,YAAY,CAAU,CAAA;AAE7C,qFAAqF;AACrF,MAAM,OAAO,GAAuB,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE;IACrD,+EAA+E;AACjF,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAA;AAElB;;;;GAIG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,GAAsC,EAAuB,EAAE,CACnF,OAAO,CAAC,OAAO,CACZ,GAAG,CAAC,UAAoF,CAAC,QAAQ,CAChG,qBAAqB,EACrB,OAAO,CACR,CACF,CAAA"}
package/lib/types.d.ts ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Shared types for `dsh-plan-build-mode`.
3
+ * @module dsh-plan-build-mode/types
4
+ */
5
+ import type { SandboxMode } from '@deepseek-ai/dsh-sandbox';
6
+ declare module '@deepseek-ai/dsh-session/types' {
7
+ }
8
+ /**
9
+ * Deployment configuration for the Plan/Build mode plugin.
10
+ */
11
+ export interface PlanBuildModeConfig {
12
+ /**
13
+ * Sandbox mode enforced while Plan mode is active.
14
+ * @default 'read-only'
15
+ */
16
+ planSandbox?: SandboxMode;
17
+ /**
18
+ * Sandbox mode enforced while Build mode is active.
19
+ * @default 'workspace-write'
20
+ */
21
+ buildSandbox?: SandboxMode;
22
+ /**
23
+ * Whether to deny known write tools while in Plan mode + read-only sandbox.
24
+ * @default true
25
+ */
26
+ denyWriteTools?: boolean;
27
+ /**
28
+ * Whether to inject the `plan-build:policy` system prompt section.
29
+ * @default true
30
+ */
31
+ section?: boolean;
32
+ }
33
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAE3D,OAAO,QAAQ,gCAAgC,CAAC;CAG/C;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB;;;OAGG;IACH,YAAY,CAAC,EAAE,WAAW,CAAA;IAC1B;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB"}
package/lib/types.js ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Shared types for `dsh-plan-build-mode`.
3
+ * @module dsh-plan-build-mode/types
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
package/package.json ADDED
@@ -0,0 +1,100 @@
1
+ {
2
+ "name": "@xth26/dsh-plan-build-mode",
3
+ "description": "OpenCode-style Plan / Build hard permission model for DSH",
4
+ "version": "0.1.0",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "type": "module",
9
+ "main": "lib/index.js",
10
+ "types": "lib/types/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./lib/types/index.d.ts",
14
+ "default": "./lib/index.js"
15
+ },
16
+ "./invariant": {
17
+ "types": "./lib/types/invariant.d.ts",
18
+ "default": "./lib/invariant.js"
19
+ },
20
+ "./src/*": "./src/*",
21
+ "./package.json": "./package.json"
22
+ },
23
+ "files": [
24
+ "lib",
25
+ "cordis.patch.yml",
26
+ "README.md",
27
+ "README.zh.md",
28
+ "LICENSE"
29
+ ],
30
+ "dsh": {
31
+ "bundle": {
32
+ "patch": "./cordis.patch.yml"
33
+ }
34
+ },
35
+ "scripts": {
36
+ "build": "tsc -b tsconfig.json",
37
+ "test": "vitest run",
38
+ "typecheck": "tsc --noEmit -p tsconfig.json"
39
+ },
40
+ "license": "MIT",
41
+ "peerDependencies": {
42
+ "@deepseek-ai/cordis": "^4.0.1",
43
+ "@deepseek-ai/dsh-agent": "^0.1.0-rc.8",
44
+ "@deepseek-ai/dsh-commands": "^0.1.0-rc.8",
45
+ "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8",
46
+ "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8",
47
+ "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8",
48
+ "@deepseek-ai/dsh-session": "^0.1.0-rc.8",
49
+ "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8",
50
+ "@deepseek-ai/dsh-tools": "^0.1.0-rc.8",
51
+ "@deepseek-ai/schemastery": "^3.18.1"
52
+ },
53
+ "peerDependenciesMeta": {
54
+ "@deepseek-ai/cordis": {
55
+ "optional": true
56
+ },
57
+ "@deepseek-ai/dsh-agent": {
58
+ "optional": true
59
+ },
60
+ "@deepseek-ai/dsh-commands": {
61
+ "optional": true
62
+ },
63
+ "@deepseek-ai/dsh-invariants": {
64
+ "optional": true
65
+ },
66
+ "@deepseek-ai/dsh-sandbox": {
67
+ "optional": true
68
+ },
69
+ "@deepseek-ai/dsh-sandbox-policy": {
70
+ "optional": true
71
+ },
72
+ "@deepseek-ai/dsh-session": {
73
+ "optional": true
74
+ },
75
+ "@deepseek-ai/dsh-system-prompt": {
76
+ "optional": true
77
+ },
78
+ "@deepseek-ai/dsh-tools": {
79
+ "optional": true
80
+ },
81
+ "@deepseek-ai/schemastery": {
82
+ "optional": true
83
+ }
84
+ },
85
+ "devDependencies": {
86
+ "@deepseek-ai/cordis": "link:../deepseek-harness/vendor/cordis",
87
+ "@deepseek-ai/dsh-agent": "link:../deepseek-harness/packages/core/agent",
88
+ "@deepseek-ai/dsh-commands": "link:../deepseek-harness/packages/interaction/commands",
89
+ "@deepseek-ai/dsh-invariants": "link:../deepseek-harness/packages/runtime-diagnostics/invariants",
90
+ "@deepseek-ai/dsh-sandbox": "link:../deepseek-harness/packages/sandbox/sandbox",
91
+ "@deepseek-ai/dsh-sandbox-policy": "link:../deepseek-harness/packages/sandbox/sandbox-policy",
92
+ "@deepseek-ai/dsh-session": "link:../deepseek-harness/packages/core/session",
93
+ "@deepseek-ai/dsh-system-prompt": "link:../deepseek-harness/packages/core/system-prompt",
94
+ "@deepseek-ai/dsh-tools": "link:../deepseek-harness/packages/core/tools",
95
+ "@deepseek-ai/schemastery": "link:../deepseek-harness/vendor/schemastery",
96
+ "@types/node": "^22.0.0",
97
+ "typescript": "^5.7.0",
98
+ "vitest": "^2.1.0"
99
+ }
100
+ }