@duke-dsh-plugins/dsh-agent-approval 1.6.0 → 1.7.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 CHANGED
@@ -62,7 +62,7 @@
62
62
  dsh plugin --profile web add /path/to/dsh-agent-approval
63
63
 
64
64
  # 正式发布:从 GitHub Release tarball 安装
65
- dsh plugin --profile web add https://github.com/MoonlitDropOfBlood/dsh-agent-approval/releases/download/v1.6.0/dsh-agent-approval-1.6.0.tgz
65
+ dsh plugin --profile web add https://github.com/MoonlitDropOfBlood/dsh-agent-approval/releases/download/v1.7.0/dsh-agent-approval-1.7.0.tgz
66
66
  ```
67
67
 
68
68
  重启 DSH 后:设置面板出现 **Agent 审批** 页;`/permission` 菜单出现第四项 **Agent 审批**。
@@ -87,10 +87,11 @@ dsh plugin --profile web add https://github.com/MoonlitDropOfBlood/dsh-agent-app
87
87
  ```
88
88
  dsh-agent-approval/
89
89
  ├── index.js # Host 半:AgentApprovalService(审批瀑布抢占 + spawn 审批 Agent + 审计)
90
- ├── client.js # Client 半:设置页「Agent 审批」+ 输入框开关 UI bundle
91
- ├── typert.host.js # Typert Host manifest(agentApproval 6 个方法的描述)
90
+ ├── client.js # Client 半:设置页「Agent 审批」+ 会话「审批」审计标签页 bundle
91
+ ├── typert.host.js # Typert Host manifest(agentApproval 9 个 Remote 方法的描述)
92
92
  ├── cordis.patch.yml # dsh bundle patch(挂载行 + permission 预设表覆盖)
93
93
  ├── scripts/patch-glyph.mjs # 可选:权限菜单图标补丁(标准安装不自动执行)
94
+ ├── scripts/check-typert-manifest.mjs # npm run check 用:双代 Typert codec 契约冒烟
94
95
  ├── .github/workflows/ # GitHub Actions 发布
95
96
  ├── AGENTS.md # 面向 AI agent 的开发指南(含踩坑)
96
97
  └── LICENSE # MIT
@@ -99,11 +100,13 @@ dsh-agent-approval/
99
100
  ## 开发
100
101
 
101
102
  ```bash
102
- npm run check # node --check index.js client.js typert.host.js
103
+ npm run check # node --check 全部脚本 + 双代 Typert 契约冒烟(scripts/check-typert-manifest.mjs)
103
104
  dsh plugin --profile web add /path/to/dsh-agent-approval # 安装/重装到本机 DSH profile
104
105
  npm run patch:glyph # 可选:权限菜单图标
105
106
  ```
106
107
 
108
+ **兼容性**:支持 DSH 0.1.5-rc.3 ~ 0.1.7-rc.1。v1.7.0 起 Typert manifest / Client Remote 描述符的每个 codec 同时携带 `schema`(≤0.1.5 的 zod 契约)与 `create()` 工厂(0.1.7 的新契约),任一宿主代际都能注册;旧版本(≤1.6.0)在 0.1.7 上会被 typert-loader 以 "has no create() factory" 拒绝,Remote 全部失效。
109
+
107
110
  详见 [AGENTS.md](AGENTS.md)——记录了 DSH 正式插件(Host/Client/Typert 三件套)的完整机制、审批瀑布 prepend 抢占与结构化子代理裁决的踩坑。
108
111
 
109
112
  ## License
package/client.js CHANGED
@@ -92,7 +92,7 @@ window.__ModuleLoader__.load({
92
92
  draws the same shield + AI-star glyph patch-glyph.mjs used, as a
93
93
  currentColor mask so hover/selected/disabled colors all follow the shell.
94
94
  Scope guard: only menus that already render the official glyph set
95
- (sibling rows carry span._itemIcon_*) qualify — the composer /permission
95
+ (sibling rows carry the Menu primitive's itemIcon span) qualify — the composer /permission
96
96
  menu does; the settings PermissionRow dropdown (settings.general 权限 row,
97
97
  portaled to <body>) renders NO icons for any preset, so an icon there
98
98
  would be an uninvited extra and is deliberately left unmarked. */
@@ -156,17 +156,20 @@ window.__ModuleLoader__.load({
156
156
  // inside button[role=menuitem]; an icon-less row starts at the label.
157
157
  // Glyph-set guard: only mark our row in menus where the official
158
158
  // presets already render their permissionGlyphs (sibling rows carry
159
- // span[class*="_itemIcon_"] — the CSS-modules build keeps the source
160
- // class name as a substring). The composer /permission menu
161
- // qualifies; the settings PermissionRow dropdown (portaled to
162
- // <body>, no item icons for any preset) does NOT, so the glyph no
163
- // longer leaks into the settings page. (The selected-row checkmark
164
- // svg is class "_check_", not "_itemIcon_", so it cannot fake the
165
- // guard.)
159
+ // the Menu primitive's icon span). The class-name substring is
160
+ // "itemIcon" (v1.7.0, widened from "_itemIcon_"): CSS-modules compiles
161
+ // the source name differently across host generations
162
+ // (`_itemIcon_<hash>_` vs `<hash>_itemIcon`), and the Menu moved from
163
+ // dsh-client-ui-conversation to dsh-client-ui-permission-presets in
164
+ // 0.1.7-rc.1. The composer /permission menu qualifies; the settings
165
+ // PermissionRow dropdown (portaled to <body>, no item icons for any
166
+ // preset) does NOT, so the glyph no longer leaks into the settings
167
+ // page. (The selected-row checkmark svg is class "_check_", not
168
+ // "itemIcon", so it cannot fake the guard.)
166
169
  const menus = document.querySelectorAll('[role="menu"]');
167
170
  const glyphMenus = [];
168
171
  for (let i = 0; i < menus.length; i++) {
169
- if (menus[i].querySelector('span[class*="_itemIcon_"]') !== null) glyphMenus.push(menus[i]);
172
+ if (menus[i].querySelector('span[class*="itemIcon"]') !== null) glyphMenus.push(menus[i]);
170
173
  }
171
174
  const items = document.querySelectorAll('[role="menu"] button[role="menuitem"]');
172
175
  for (let i = 0; i < items.length; i++) {
@@ -220,22 +223,25 @@ window.__ModuleLoader__.load({
220
223
  // client assembly mounts only the official namespaces, so a plugin must
221
224
  // mount its own. Mirrors the invocations in typert.host.js (id,
222
225
  // service/namespace/method). zod is not requirable in the browser module
223
- // loader, so codecs use passthrough schemas — the runtime contract only
224
- // requires typeSymbol + schema.parse().
226
+ // loader, so codecs use passthrough schemas. The wire contract spans two
227
+ // host generations (v1.7.0): the client Remote registry validates
228
+ // `codec.schema.parse` on DSH ≤ 0.1.5-rc.3 but a `codec.create()` factory
229
+ // on 0.1.7-rc.1+ ("strict codec has no create() factory" kills the mount),
230
+ // so every codec carries BOTH fields over the same passthrough schema.
225
231
  const passthrough = () => ({ parse: (v) => v });
232
+ const strictCodec = (typeSymbol) => {
233
+ const schema = passthrough();
234
+ return { mode: "strict", typeSymbol, schema, create: () => schema };
235
+ };
226
236
  const param = (typeSymbol) => [
227
237
  {
228
238
  name: "request",
229
239
  wire: "request",
230
240
  source: "json",
231
- codec: { mode: "strict", typeSymbol, schema: passthrough() },
241
+ codec: strictCodec(typeSymbol),
232
242
  },
233
243
  ];
234
- const result = (typeSymbol) => ({
235
- mode: "strict",
236
- typeSymbol,
237
- schema: passthrough(),
238
- });
244
+ const result = (typeSymbol) => strictCodec(typeSymbol);
239
245
  const CLIENT_REMOTE = {
240
246
  package: "dsh-agent-approval",
241
247
  descriptors: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duke-dsh-plugins/dsh-agent-approval",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "Agent-decided approvals for DeepSeek Harness: a workspace-write base permission mode where an independent approval judge (an isolated subagent, or the TypeSafe Jev decision model via direct API) evaluates every sandbox escalation (risky operations are rejected), with a configurable approval model and a per-session audit trail in the conversation window's 审批 tab.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -36,13 +36,13 @@
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@deepseek-ai/cordis": "^4.0.1",
39
- "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7"
39
+ "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.7 || ^0.1.7-rc.1"
40
40
  },
41
41
  "dependencies": {
42
42
  "zod": "^4.4.3"
43
43
  },
44
44
  "scripts": {
45
45
  "patch:glyph": "node scripts/patch-glyph.mjs",
46
- "check": "node --check index.js && node --check client.js && node --check typert.host.js && node --check scripts/patch-glyph.mjs"
46
+ "check": "node --check index.js && node --check client.js && node --check typert.host.js && node --check scripts/patch-glyph.mjs && node --check scripts/check-typert-manifest.mjs && node scripts/check-typert-manifest.mjs"
47
47
  }
48
48
  }
package/typert.host.js CHANGED
@@ -12,6 +12,17 @@
12
12
  *
13
13
  * Result schemas are STRICT: every Host return value must match exactly
14
14
  * (fields present, types correct), or the gateway validation fails.
15
+ *
16
+ * Codec wire format spans two host generations (v1.7.0): DSH ≤ 0.1.5-rc.3
17
+ * validates and parses through `codec.schema` (a zod v4 instance — the
18
+ * typert-loader checked `"_zod" in schema`, the gateway called
19
+ * `codec.schema.parse`), while DSH 0.1.7-rc.1+ replaced that contract with a
20
+ * `codec.create()` FACTORY (the loader now rejects any codec "with no create()
21
+ * factory"; the gateway calls `codec.create().parse`). Every codec below
22
+ * therefore carries BOTH fields: `schema` keeps 0.1.5 loading, `create` keeps
23
+ * 0.1.7 loading, and both generations parse through the same zod instance.
24
+ * Removing either field breaks one generation at startup (the typert-loader
25
+ * throw is why 0.1.7 refused this manifest before v1.7.0).
15
26
  */
16
27
 
17
28
  import { z } from "zod";
@@ -230,6 +241,7 @@ export const TYPERT = {
230
241
  mode: "strict",
231
242
  typeSymbol: "dsh-agent-approval#AgentApprovalStateResult",
232
243
  schema: stateResultSchema,
244
+ create: () => stateResultSchema,
233
245
  },
234
246
  sourceLocation: { file: "index.js", line: 1, column: 1 },
235
247
  },
@@ -248,6 +260,7 @@ export const TYPERT = {
248
260
  mode: "strict",
249
261
  typeSymbol: "dsh-agent-approval#AgentApprovalSetModelRequest",
250
262
  schema: _agentApproval_setModel_parameter_0$schema,
263
+ create: () => _agentApproval_setModel_parameter_0$schema,
251
264
  },
252
265
  },
253
266
  ],
@@ -255,6 +268,7 @@ export const TYPERT = {
255
268
  mode: "strict",
256
269
  typeSymbol: "dsh-agent-approval#AgentApprovalSetModelResult",
257
270
  schema: setModelResultSchema,
271
+ create: () => setModelResultSchema,
258
272
  },
259
273
  sourceLocation: { file: "index.js", line: 1, column: 1 },
260
274
  },
@@ -273,6 +287,7 @@ export const TYPERT = {
273
287
  mode: "strict",
274
288
  typeSymbol: "dsh-agent-approval#AgentApprovalSetJevRequest",
275
289
  schema: _agentApproval_setJevConfig_parameter_0$schema,
290
+ create: () => _agentApproval_setJevConfig_parameter_0$schema,
276
291
  },
277
292
  },
278
293
  ],
@@ -280,6 +295,7 @@ export const TYPERT = {
280
295
  mode: "strict",
281
296
  typeSymbol: "dsh-agent-approval#AgentApprovalSetJevResult",
282
297
  schema: setJevResultSchema,
298
+ create: () => setJevResultSchema,
283
299
  },
284
300
  sourceLocation: { file: "index.js", line: 1, column: 1 },
285
301
  },
@@ -298,6 +314,7 @@ export const TYPERT = {
298
314
  mode: "strict",
299
315
  typeSymbol: "dsh-agent-approval#AgentApprovalSetTimeoutRequest",
300
316
  schema: _agentApproval_setApprovalTimeout_parameter_0$schema,
317
+ create: () => _agentApproval_setApprovalTimeout_parameter_0$schema,
301
318
  },
302
319
  },
303
320
  ],
@@ -305,6 +322,7 @@ export const TYPERT = {
305
322
  mode: "strict",
306
323
  typeSymbol: "dsh-agent-approval#AgentApprovalSetTimeoutResult",
307
324
  schema: setTimeoutResultSchema,
325
+ create: () => setTimeoutResultSchema,
308
326
  },
309
327
  sourceLocation: { file: "index.js", line: 1, column: 1 },
310
328
  },
@@ -323,6 +341,7 @@ export const TYPERT = {
323
341
  mode: "strict",
324
342
  typeSymbol: "dsh-agent-approval#AgentApprovalToggleRequest",
325
343
  schema: _agentApproval_toggle_parameter_0$schema,
344
+ create: () => _agentApproval_toggle_parameter_0$schema,
326
345
  },
327
346
  },
328
347
  ],
@@ -330,6 +349,7 @@ export const TYPERT = {
330
349
  mode: "strict",
331
350
  typeSymbol: "dsh-agent-approval#AgentApprovalToggleResult",
332
351
  schema: toggleResultSchema,
352
+ create: () => toggleResultSchema,
333
353
  },
334
354
  sourceLocation: { file: "index.js", line: 1, column: 1 },
335
355
  },
@@ -348,6 +368,7 @@ export const TYPERT = {
348
368
  mode: "strict",
349
369
  typeSymbol: "dsh-agent-approval#AgentApprovalAddRuleRequest",
350
370
  schema: _agentApproval_addRule_parameter_0$schema,
371
+ create: () => _agentApproval_addRule_parameter_0$schema,
351
372
  },
352
373
  },
353
374
  ],
@@ -355,6 +376,7 @@ export const TYPERT = {
355
376
  mode: "strict",
356
377
  typeSymbol: "dsh-agent-approval#AgentApprovalRulesResult",
357
378
  schema: addRuleResultSchema,
379
+ create: () => addRuleResultSchema,
358
380
  },
359
381
  sourceLocation: { file: "index.js", line: 1, column: 1 },
360
382
  },
@@ -373,6 +395,7 @@ export const TYPERT = {
373
395
  mode: "strict",
374
396
  typeSymbol: "dsh-agent-approval#AgentApprovalRemoveRuleRequest",
375
397
  schema: _agentApproval_removeRule_parameter_0$schema,
398
+ create: () => _agentApproval_removeRule_parameter_0$schema,
376
399
  },
377
400
  },
378
401
  ],
@@ -380,6 +403,7 @@ export const TYPERT = {
380
403
  mode: "strict",
381
404
  typeSymbol: "dsh-agent-approval#AgentApprovalRulesResult",
382
405
  schema: removeRuleResultSchema,
406
+ create: () => removeRuleResultSchema,
383
407
  },
384
408
  sourceLocation: { file: "index.js", line: 1, column: 1 },
385
409
  },
@@ -398,6 +422,7 @@ export const TYPERT = {
398
422
  mode: "strict",
399
423
  typeSymbol: "dsh-agent-approval#AgentApprovalSessionRecordsRequest",
400
424
  schema: _agentApproval_sessionRecords_parameter_0$schema,
425
+ create: () => _agentApproval_sessionRecords_parameter_0$schema,
401
426
  },
402
427
  },
403
428
  ],
@@ -405,6 +430,7 @@ export const TYPERT = {
405
430
  mode: "strict",
406
431
  typeSymbol: "dsh-agent-approval#AgentApprovalSessionRecordsResult",
407
432
  schema: sessionRecordsResultSchema,
433
+ create: () => sessionRecordsResultSchema,
408
434
  },
409
435
  sourceLocation: { file: "index.js", line: 1, column: 1 },
410
436
  },
@@ -419,6 +445,7 @@ export const TYPERT = {
419
445
  mode: "strict",
420
446
  typeSymbol: "dsh-agent-approval#AgentApprovalDirectoryResult",
421
447
  schema: directoryResultSchema,
448
+ create: () => directoryResultSchema,
422
449
  },
423
450
  sourceLocation: { file: "index.js", line: 1, column: 1 },
424
451
  },