@morlay/dsh-preset 0.0.4 → 0.0.5

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 CHANGED
@@ -6,12 +6,12 @@
6
6
 
7
7
  ## 内容
8
8
 
9
- | 文件 | 作用 |
10
- | -------------------------- | ------------------------------------------------------------------------------------------------------------ |
11
- | `cordis.patch.yml` | bundle patch:禁用官方 preset、注册本包 preset 为默认、声明个人 `llm-pi-ai` route、插入 `prompt-reminder` 行 |
12
- | `tool/generate-presets.ts` | 从上游生成 preset 的模块 + tsdown hooks |
13
- | `dist/presets/standard/` | 构建产物:自定义 preset「标准模式」(由上游 `standard` 生成) |
14
- | `dist/presets/ptc/` | 构建产物:自定义 preset「PTC 模式」(由上游 `ptc` 生成) |
9
+ | 文件 | 作用 |
10
+ | -------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
11
+ | `cordis.patch.yml` | bundle patch:禁用官方 preset、注册本包 preset 为默认、声明个人 `llm-pi-ai` route、覆盖沙箱规则、插入 `prompt-reminder` 行 |
12
+ | `tool/generate-presets.ts` | 从上游生成 preset 的模块 + tsdown hooks |
13
+ | `dist/presets/standard/` | 构建产物:自定义 preset「标准模式」(由上游 `standard` 生成) |
14
+ | `dist/presets/ptc/` | 构建产物:自定义 preset「PTC 模式」(由上游 `ptc` 生成) |
15
15
 
16
16
  `cordis.patch.yml` 里插入的 `prompt-reminder`(`@morlay/dsh-prompt-reminder`)把被
17
17
  裁掉的系统提示词 section 降级为 `<system-reminder>` user 消息,见「工具说明降级为
@@ -156,6 +156,22 @@ row、改字段)都自动跟随,不依赖易碎的文本锚点;上游若
156
156
  2. `pnpm --filter @morlay/dsh-preset run build`(build:done 会重新生成)
157
157
  3. `pnpm exec vitest run packages/preset` 确认无 drift(含 reminder 插件的行为测试)。
158
158
 
159
+ ## 沙箱装配与规则(部署级)
160
+
161
+ 本 bundle 的 `cordis.patch.yml` 里一次做完三件事:禁用官方 `sandbox` / `fs-sandbox`
162
+ 两行、插入 `- id: sandbox-local` 行、写上 `rw` / `r-` / `--` 条目(唯一真源,本 README
163
+ 不复制一份以免两处漂移);条目语法、优先级与各平台表达能力见
164
+ [`@morlay/dsh-sandbox-local` 的 README](../../sandbox/dsh-sandbox-local/README.md)。
165
+
166
+ 放本 bundle 而不是示例 app 的 `cordis.patch.yml`:bundle patch 在 dev(web / desktop)
167
+ 与打包形态都会应用,app 的 patch 只在打包时作为 seed 的 profile patch 生效。
168
+
169
+ 两个前置条件:
170
+
171
+ - **本包的 `dependencies` 必须声明 `@morlay/dsh-sandbox-local`**:插入行的 `name` 要能在
172
+ profile 的依赖树里解析(profile 的 `nodeLinker: hoisted` 由本包的依赖把它带进去)。
173
+ - **规则变化要重启**:profile 在启动时装载,`access` 在插件构造时解析(模板也是)。
174
+
159
175
  ## 装配
160
176
 
161
177
  `agent-presets.roots` 需指向本包的 `dist/presets/`。因为该目录随包分发,
@@ -198,6 +214,10 @@ profile 里把内容物化到该挂载点;`includeShippedRoot: false` 两种
198
214
  - `cordis.patch.yml` 插入的 `@morlay/dsh-prompt-reminder` 必须能被 **profile** 的依赖
199
215
  树解析:示例 app 已在 `dependencies` 声明;换工作区时要一并声明,否则该行加载失败、
200
216
  工具说明会留在系统提示词里。
217
+ - 沙箱装配(禁用官方两行 + 插入 `sandbox-local` 行 + 规则)全在本 bundle 的 patch 里,
218
+ app 的 `dsh.profile.bundles` 不需要额外列 `@morlay/dsh-sandbox-local`;
219
+ `@morlay/dsh-sandbox-local` 自带的 bundle patch 供把该包作为独立 bundle 采用的部署
220
+ 使用,与本 bundle 同时上线会重复插入同一行。
201
221
  - 生成器显式设 `quotingType: '"'`:`yaml.dump` 默认单引号而仓库 oxfmt 偏好双引号,
202
222
  不指定会让生成器与 formatter 来回改;产物在 gitignore 的 dist 里,本就不参与 fmt。
203
223
  - **dev 模式需要先构建**:`just dev` / `just desktop` / `just bundle` 都先跑
package/cordis.patch.yml CHANGED
@@ -58,6 +58,30 @@
58
58
  high: high
59
59
  max: max
60
60
 
61
+ # 沙箱装配(唯一真源,就地完成):官方 `sandbox`(ctx.sandbox)与 `fs-sandbox`
62
+ # (ctx.fs)两行在这里禁用,由 `@morlay/dsh-sandbox-local` 注册同名服务;规则随本
63
+ # insert 行一起写死,不再依赖任何额外 bundle 层(漏装配时规则会静默失效,只剩
64
+ # workspace + /tmp 可写)。
65
+ - id: sandbox
66
+ disabled: true
67
+
68
+ - id: fs-sandbox
69
+ disabled: true
70
+
71
+ # 沙箱规则:`rw <path>` 追加工作区之外的可写根,`-- <pattern>` 拒绝访问(读 + 写)。
72
+ - insert:
73
+ - id: sandbox-local
74
+ name: "@morlay/dsh-sandbox-local"
75
+ config:
76
+ access: |-
77
+ rw /tmp
78
+ rw {{ env.XDG_CACHE_HOME }}
79
+ rw {{ env.XDG_STATE_HOME }}
80
+ rw {{ env.XDG_DATA_HOME }}
81
+ r- {{ env.XDG_CONFIG_HOME }}
82
+ -- mise.*.toml
83
+ -- **/*.pem
84
+
61
85
  # 提示词分层:系统提示词只留上面的 persona,工具说明 / Agent Teams 规则 / plan
62
86
  # 规则等由该插件降级为 <system-reminder> user 消息。部署级策略,在这里定义一次
63
87
  # 即覆盖全部 preset(含子 agent),preset composition 不再各自带这一行。
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@morlay/dsh-preset",
3
- "version": "0.0.4",
4
- "description": "Personal dsh profile bundle: disables the shipped agent presets, builds generated standard / ptc presets into dist, and declares personal llm-pi-ai provider routes.",
3
+ "version": "0.0.5",
4
+ "description": "Personal dsh profile bundle: disables the shipped agent presets, builds generated standard / ptc presets into dist, declares personal llm-pi-ai provider routes, and carries the deployment sandbox access rules.",
5
5
  "keywords": [
6
6
  "dsh",
7
7
  "dsh-bundle",
@@ -26,7 +26,8 @@
26
26
  "./cordis.patch.yml": "./cordis.patch.yml"
27
27
  },
28
28
  "dependencies": {
29
- "@morlay/dsh-prompt-reminder": "^0.0.1"
29
+ "@morlay/dsh-prompt-reminder": "^0.0.2",
30
+ "@morlay/dsh-sandbox-local": "^0.0.2"
30
31
  },
31
32
  "devDependencies": {
32
33
  "@deepseek-ai/cordis-plugin-include": "^1.0.7",
@@ -1,6 +1,10 @@
1
1
  // 装配守卫:prompt-reminder 是 host plane 的唯一装配点。被误删 / 改名时提示词分层
2
2
  // 静默失效(工具说明回到系统提示词),这里 fail loud;persona 是 keep 名单的唯一
3
3
  // 提供者,删掉它系统提示词会变空。
4
+ //
5
+ // 沙箱同理:官方 `sandbox` / `fs-sandbox` 的禁用与本包 `sandbox-local` 行的插入必须在
6
+ // 同一层——官方行还在时 `ctx.sandbox` / `ctx.fs` 由官方实现提供,access 规则没有生效点,
7
+ // 命令照跑但规则全部失效(只剩 workspace + /tmp 可写),且没有任何报错。
4
8
 
5
9
  import { readFileSync } from "node:fs";
6
10
  import { join } from "node:path";
@@ -9,12 +13,17 @@ import yaml from "js-yaml";
9
13
  import { describe, expect, it } from "vitest";
10
14
 
11
15
  const PATCH_PATH = join(process.cwd(), "packages/preset/dsh-preset/cordis.patch.yml");
16
+ const UPSTREAM_BASE_PATCH = join(
17
+ process.cwd(),
18
+ "vendor/deepseek-harness/packages/bundle/base/cordis.patch.yml",
19
+ );
12
20
 
13
- /** patch 的一行;只用到覆盖目标与 insert 的新增行。 */
21
+ /** patch 的一行;只用到覆盖目标、禁用与 insert 的新增行。 */
14
22
  interface PatchRow {
15
23
  id?: string;
24
+ disabled?: boolean;
16
25
  config?: Record<string, unknown>;
17
- insert?: { id?: string; name?: string }[];
26
+ insert?: { id?: string; name?: string; config?: Record<string, unknown> }[];
18
27
  }
19
28
 
20
29
  // 用 include 的 entry schema 解析:patch 里含 `!!js` 表达式,默认 schema 会拒绝。
@@ -22,14 +31,18 @@ const rows = yaml.load(readFileSync(PATCH_PATH, "utf8"), {
22
31
  schema: entryListSchema,
23
32
  }) as PatchRow[];
24
33
 
34
+ /** 本层 insert 出来的行。 */
35
+ const inserted = rows.flatMap((row) => row.insert ?? []);
36
+
37
+ /** 本层的 `sandbox-local` 行(装配沙箱替换的那个)。 */
38
+ const sandboxRow = inserted.find((row) => row.id === "sandbox-local");
39
+
25
40
  describe("dsh-preset patch wiring", () => {
26
41
  it("declares the prompt-reminder row exactly once, on the local plugin", () => {
27
- const inserted = rows
28
- .flatMap((row) => row.insert ?? [])
29
- .filter((row) => row.id === "prompt-reminder");
42
+ const reminders = inserted.filter((row) => row.id === "prompt-reminder");
30
43
 
31
- expect(inserted).toHaveLength(1);
32
- expect(inserted[0]?.name).toBe("@morlay/dsh-prompt-reminder");
44
+ expect(reminders).toHaveLength(1);
45
+ expect(reminders[0]?.name).toBe("@morlay/dsh-prompt-reminder");
33
46
  });
34
47
 
35
48
  it("keeps the deployment persona the reminder keeps in the system prompt", () => {
@@ -38,4 +51,46 @@ describe("dsh-preset patch wiring", () => {
38
51
  expect(config?.personaPrefix).toBeTruthy();
39
52
  expect(config?.personaSuffix).toBeTruthy();
40
53
  });
54
+
55
+ it("disables the shipped sandbox rows and mounts the replacement in one layer", () => {
56
+ expect(rows.filter((row) => row.disabled === true).map((row) => row.id)).toEqual([
57
+ "sandbox",
58
+ "fs-sandbox",
59
+ ]);
60
+ expect(inserted.filter((row) => row.id === "sandbox-local")).toHaveLength(1);
61
+ expect(sandboxRow?.name).toBe("@morlay/dsh-sandbox-local");
62
+ });
63
+
64
+ it("names rows that still exist in the shipped base bundle", () => {
65
+ // 上游改名或移动这两行时,本层的 disabled 会被 include 静默跳过(warn+skip),
66
+ // 沙箱替换随之失效;这里对着 vendor 里的 base patch 校验一次。
67
+ const upstreamIds = new Set(
68
+ [...readFileSync(UPSTREAM_BASE_PATCH, "utf8").matchAll(/^\s*- id: (\S+)$/gm)].map(
69
+ (match) => match[1]!,
70
+ ),
71
+ );
72
+
73
+ for (const id of ["sandbox", "fs-sandbox"]) {
74
+ expect(upstreamIds.has(id), `missing upstream row: ${id}`).toBe(true);
75
+ }
76
+ });
77
+
78
+ it("carries the deployment sandbox rules on the inserted row", () => {
79
+ // 规则随本 bundle 分发(跨 dev / 打包形态一致),不再依赖另一层 bundle。
80
+ const access = sandboxRow?.config?.access;
81
+
82
+ expect(typeof access).toBe("string");
83
+ expect(String(access)).toContain("rw {{ env.XDG_CACHE_HOME }}");
84
+ expect(String(access)).toContain("rw {{ env.XDG_DATA_HOME }}");
85
+ expect(String(access)).toContain("-- mise.*.toml");
86
+ expect(String(access)).toContain("-- **/*.pem");
87
+ });
88
+
89
+ it("depends on the bundle whose service classes the inserted row mounts", () => {
90
+ const manifest = JSON.parse(
91
+ readFileSync(join(process.cwd(), "packages/preset/dsh-preset/package.json"), "utf8"),
92
+ ) as { dependencies?: Record<string, string> };
93
+
94
+ expect(manifest.dependencies?.["@morlay/dsh-sandbox-local"]).toBeTruthy();
95
+ });
41
96
  });