@shgroup/dsh-serenity-hooks 1.31.7 → 1.31.9
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 +2 -2
- package/dsh.plugin.json +1 -1
- package/lib/client.js +6 -6
- package/lib/host/contract.d.ts +1 -1
- package/lib/host/type-contract.d.ts +44 -0
- package/lib/index.js +19 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -317,7 +317,7 @@ AI 一次能"记住"的内容有上限。满了不用你手动开新会话:
|
|
|
317
317
|
|
|
318
318
|
```bash
|
|
319
319
|
pnpm typecheck # 类型检查(node + 浏览器端两套)
|
|
320
|
-
pnpm test # 全量测试(当前
|
|
320
|
+
pnpm test # 全量测试(当前 80 个文件 / 1176 个用例)
|
|
321
321
|
pnpm build # 打包(lib/index.js + client.js)
|
|
322
322
|
```
|
|
323
323
|
|
|
@@ -381,4 +381,4 @@ pnpm build # 打包(lib/index.js + client.js)
|
|
|
381
381
|
|
|
382
382
|
MIT(见 [LICENSE](https://github.com/tellmewhattodo/dsh-serenity-plugin/blob/master/LICENSE))
|
|
383
383
|
|
|
384
|
-
> **版本**:v1.31.
|
|
384
|
+
> **版本**:v1.31.9 | **前置**:DSH 0.1.5-rc.1+ / Node ≥ 20 或 bun | **测试**:80 个文件 / 1176 个用例
|
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-serenity-hooks",
|
|
3
|
-
"version": "1.31.
|
|
3
|
+
"version": "1.31.9",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——11 个工具(container_fs/logbook/dashboard/container_git/msm/praxis/handyman/localstore/container_admin/autopilot-trajectory/im-bridge)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 工作日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/自主巡航。适配 DSH 0.1.5-rc.1(deepseek-ai/deepseek-harness)。",
|
|
6
6
|
"engines": {
|
package/lib/client.js
CHANGED
|
@@ -461,22 +461,22 @@ window.__ModuleLoader__.load({
|
|
|
461
461
|
const inputActions = props.inputActions;
|
|
462
462
|
const handlingRef = (0, react.useRef)(false);
|
|
463
463
|
const promptError = session?.promptError?.error;
|
|
464
|
-
const
|
|
464
|
+
const attachmentIds = input?.attachmentIds ?? [];
|
|
465
465
|
(0, react.useEffect)(() => {
|
|
466
466
|
if (handlingRef.current || !isImageFallbackTrigger(promptError?.code, promptError?.details?.reason)) return;
|
|
467
|
-
if (
|
|
467
|
+
if (attachmentIds.length === 0) return;
|
|
468
468
|
handlingRef.current = true;
|
|
469
469
|
(async () => {
|
|
470
470
|
try {
|
|
471
|
-
const files = await getDraftFiles(String(sessionId),
|
|
471
|
+
const files = await getDraftFiles(String(sessionId), attachmentIds);
|
|
472
472
|
if (files.length === 0) throw new Error("no draft image files");
|
|
473
473
|
const saved = [];
|
|
474
474
|
for (const file of files) saved.push(await uploadImage(file, String(sessionId)));
|
|
475
475
|
const note = imageNoteTemplate(saved);
|
|
476
476
|
const draft = input?.draft ?? "";
|
|
477
477
|
const text = draft === "" ? note : `${draft}\n${note}`;
|
|
478
|
-
if (inputActions?.
|
|
479
|
-
for (const id of
|
|
478
|
+
if (inputActions?.removeAttachment !== void 0 && inputActions.setDraft !== void 0 && inputActions.submit !== void 0) {
|
|
479
|
+
for (const id of attachmentIds) inputActions.removeAttachment(id);
|
|
480
480
|
inputActions.setDraft(text);
|
|
481
481
|
inputActions.submit();
|
|
482
482
|
} else await resendText(String(sessionId), text);
|
|
@@ -488,7 +488,7 @@ window.__ModuleLoader__.load({
|
|
|
488
488
|
})();
|
|
489
489
|
}, [
|
|
490
490
|
promptError,
|
|
491
|
-
|
|
491
|
+
attachmentIds,
|
|
492
492
|
sessionId,
|
|
493
493
|
uploadImage,
|
|
494
494
|
getDraftFiles,
|
package/lib/host/contract.d.ts
CHANGED
|
@@ -55,7 +55,7 @@ export interface HostEventContract {
|
|
|
55
55
|
* 在名字写错/宿主改名时**编译失败**(v1.30.7,review F-04/F-05)。
|
|
56
56
|
* 该 import 为 type-only,编译期擦除,不产生运行时依赖。
|
|
57
57
|
*/
|
|
58
|
-
export declare const HOST_EVENT_NAMES: readonly ["agent/session-start", "agent/pre-step", "agent/turn-stopping", "agent/status", "agent/inbox/inserted", "session/event", "session/created", "tools/pre-execute", "tools/post-execute", "system-prompt/assemble"];
|
|
58
|
+
export declare const HOST_EVENT_NAMES: readonly ["agent/session-start", "agent/pre-step", "agent/turn-stopping", "agent/status", "agent/inbox/inserted", "agent/disposed", "session/event", "session/created", "session/disposed", "settings/updated", "tools/pre-execute", "tools/post-execute", "system-prompt/assemble"];
|
|
59
59
|
export type HostEventName = (typeof HOST_EVENT_NAMES)[number];
|
|
60
60
|
/**
|
|
61
61
|
* dsp 订阅的宿主事件清单(与 HOST_EVENT_NAMES 同源;impact/site 供 health 报告与文档)。
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* host/type-contract.ts — 宿主**类型**契约(编译期反证层,v1.31.8,S142 全量 review 产物)
|
|
3
|
+
*
|
|
4
|
+
* ## 为什么存在(R↓)
|
|
5
|
+
*
|
|
6
|
+
* dsp 用**结构化断言**隔离宿主(手写 interface + `as` / `as never`,零宿主运行时 import),
|
|
7
|
+
* 换来 peer-only 打包与"不随宿主版本耦合"的灵活度;代价是**类型检查对宿主漂移失明**:
|
|
8
|
+
* 宿主把成员改名、改返回形状,dsp 侧拿不到任何编译期信号,只能靠**人读宿主源码**发现。
|
|
9
|
+
*
|
|
10
|
+
* 历史已三次静默失效:
|
|
11
|
+
* - `Session.events` → `snapshotEvents()`(v1.28.0)
|
|
12
|
+
* - `conversation.draftImages()` → `resolveDraftAttachments()`(v1.31.6)
|
|
13
|
+
* - `sessionPersistence.list()` 返回形状 `SessionHeader[]`(`h.cwd`)→
|
|
14
|
+
* `SessionPersistenceSnapshot[]`(`h.header.cwd`)(v1.31.6)
|
|
15
|
+
* 后两条是升级 0.1.5-rc.1 时**逐文件人读**才挖出来的——不是机制发现的。
|
|
16
|
+
*
|
|
17
|
+
* ## 既有三道防线的盲区(2026-09-10 全量 review 结论)
|
|
18
|
+
*
|
|
19
|
+
* | 防线 | 覆盖 | 盲区 |
|
|
20
|
+
* |------|------|------|
|
|
21
|
+
* | `contract.ts` 的 `satisfies keyof Events` | 事件**名** | payload 形状 |
|
|
22
|
+
* | `probeHostContract`(运行期) | 服务**名** + 成员**存在性** | 成员**签名**、**返回形状** |
|
|
23
|
+
* | `tests/**` | —— | **完全不参与类型检查**(tsconfig `include: ["src"]`)→ 写在测试里的"真实宿主类型断言"从未生效 |
|
|
24
|
+
*
|
|
25
|
+
* ## 本模块补的那一格:用宿主真实类型反证 dsp 的形状假设
|
|
26
|
+
*
|
|
27
|
+
* 机制:
|
|
28
|
+
* ① `import type {} from '<宿主包>'` 把该包的 `declare module '@deepseek-ai/cordis'` 声明增强
|
|
29
|
+
* 拉进 program(**空类型 import,编译期擦除 → 零运行时依赖**,peer-only 打包不受影响;
|
|
30
|
+
* 与 `src/client/index.ts` 引 `dsh-client-ui-session` 同款手法)
|
|
31
|
+
* ② 每条 `Expect<Extends<宿主真相, dsp 假设>>` 是一道**编译期闸门**:宿主改名/改形状 →
|
|
32
|
+
* `dsh-develop typecheck` 当场红,升级当天报警,而不是等线上静默失效
|
|
33
|
+
* ③ 换宿主版本时 `dsh-develop typecheck-host <ver>` 会对**解包的新宿主**跑同一批断言
|
|
34
|
+
*
|
|
35
|
+
* ## 维护纪律(强制)
|
|
36
|
+
*
|
|
37
|
+
* **新增一处对宿主的形状依赖 → 在此加一条对应闸门**(断言旁注明 dsp 消费点与后果)。
|
|
38
|
+
* 断言只表达 dsp **真正依赖**的那部分(不求与宿主全等)→ 宿主新增字段/放宽类型不会误报,
|
|
39
|
+
* 只有"dsp 依赖的东西没了或变了"才红。
|
|
40
|
+
*
|
|
41
|
+
* 注:本文件**没有任何运行时语句**,编译产物只有 `export {}`,不影响包体行为。
|
|
42
|
+
*/
|
|
43
|
+
/** 哨兵:确保本模块不是空文件被 tree-shake 掉(无运行时副作用,值为类型) */
|
|
44
|
+
export type HostTypeContractSatisfied = true;
|
package/lib/index.js
CHANGED
|
@@ -8623,10 +8623,22 @@ async function queueRebuild(ctx, opts) {
|
|
|
8623
8623
|
function performRebuild(session, pending, meter) {
|
|
8624
8624
|
const nodes = [...session.surface.nodes];
|
|
8625
8625
|
if (nodes.length === 0) return false;
|
|
8626
|
+
/**
|
|
8627
|
+
* v1.31.8 二次修正(0.1.5-rc.1 实证,diag 原文):
|
|
8628
|
+
* `surface replace: node 0 holds the system prompt and may be rewritten only by a
|
|
8629
|
+
* system/message over exactly that node`(宿主 `dsh-session/lib/types/surface.js`
|
|
8630
|
+
* `assertSystemHeadRewrite`)。
|
|
8631
|
+
*
|
|
8632
|
+
* → **surface node 0 是系统提示节点且被宿主保护**;而重建的语义恰恰是"保留系统提示、
|
|
8633
|
+
* 只清对话历史",故替换范围必须从 **node 1** 起。(旧实现整体替换 `nodes[0..last]`,
|
|
8634
|
+
* 在 0.1.5 上必被拒——这是 §14 之后的第二条 rebuild 阻断规则。)
|
|
8635
|
+
*/
|
|
8636
|
+
const targets = nodes.slice(1);
|
|
8637
|
+
if (targets.length === 0) return false;
|
|
8626
8638
|
if (meter) {
|
|
8627
8639
|
let shadowedTokenCount = 0;
|
|
8628
8640
|
const events = sessionEvents(session);
|
|
8629
|
-
for (const seq of
|
|
8641
|
+
for (const seq of targets) {
|
|
8630
8642
|
const event = events[seq];
|
|
8631
8643
|
if (!event) continue;
|
|
8632
8644
|
const message = deriveEventMessage(event);
|
|
@@ -8634,10 +8646,10 @@ function performRebuild(session, pending, meter) {
|
|
|
8634
8646
|
}
|
|
8635
8647
|
session.append("compaction/prune", {
|
|
8636
8648
|
shadowedRange: {
|
|
8637
|
-
start:
|
|
8638
|
-
end:
|
|
8649
|
+
start: targets[0],
|
|
8650
|
+
end: targets[targets.length - 1]
|
|
8639
8651
|
},
|
|
8640
|
-
shadowedSeqs:
|
|
8652
|
+
shadowedSeqs: targets,
|
|
8641
8653
|
shadowedTokenCount
|
|
8642
8654
|
});
|
|
8643
8655
|
}
|
|
@@ -8650,10 +8662,10 @@ function performRebuild(session, pending, meter) {
|
|
|
8650
8662
|
}, {
|
|
8651
8663
|
surfaceOp: {
|
|
8652
8664
|
op: "replace",
|
|
8653
|
-
|
|
8654
|
-
|
|
8665
|
+
startSeq: targets[0],
|
|
8666
|
+
endSeq: targets[targets.length - 1]
|
|
8655
8667
|
},
|
|
8656
|
-
sourceEventSeqs:
|
|
8668
|
+
sourceEventSeqs: targets
|
|
8657
8669
|
});
|
|
8658
8670
|
return true;
|
|
8659
8671
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shgroup/dsh-serenity-hooks",
|
|
3
|
-
"version": "1.31.
|
|
3
|
+
"version": "1.31.9",
|
|
4
4
|
"description": "宁静号 ACC harness(Native Cordis 插件)——给 DeepSeek Harness 装一个「AI 工作区」:11 个工具(container_fs/logbook/dashboard/container_git/msm/praxis/handyman/localstore/container_admin/autopilot-trajectory/im-bridge)+ 机械约束(安全模式/工作区围墙/密钥守卫/对外输出守卫)+ 工作日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/自主巡航。适配 DSH 0.1.5-rc.1。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|