@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 +104 -0
- package/README.zh.md +99 -0
- package/cordis.patch.yml +10 -0
- package/lib/helpers.d.ts +40 -0
- package/lib/helpers.d.ts.map +1 -0
- package/lib/helpers.js +60 -0
- package/lib/helpers.js.map +1 -0
- package/lib/index.d.ts +39 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +130 -0
- package/lib/index.js.map +1 -0
- package/lib/invariant.d.ts +24 -0
- package/lib/invariant.d.ts.map +1 -0
- package/lib/invariant.js +25 -0
- package/lib/invariant.js.map +1 -0
- package/lib/types.d.ts +33 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +6 -0
- package/lib/types.js.map +1 -0
- package/package.json +100 -0
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
|
package/cordis.patch.yml
ADDED
|
@@ -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
|
package/lib/helpers.d.ts
ADDED
|
@@ -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
|
package/lib/index.js.map
ADDED
|
@@ -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"}
|
package/lib/invariant.js
ADDED
|
@@ -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
package/lib/types.js.map
ADDED
|
@@ -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
|
+
}
|