@shgroup/dsh-serenity-hooks 1.87.2 → 1.87.3
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/dsh.plugin.json +1 -1
- package/lib/{ilink-BMk2w2KY.js → ilink-CsZ-f64q.js} +52 -2
- package/lib/im/ilink.d.ts +26 -0
- package/lib/index.js +7 -5
- package/package.json +1 -1
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-serenity-hooks",
|
|
3
|
-
"version": "1.87.
|
|
3
|
+
"version": "1.87.3",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——14 个工具(container_fs/cognitive_trajectory/dashboard/container_git/msm/praxis/ontology/serenity-skill-creator/cheap-worker/localstore/container_admin;另三个 im-bridge/acc-diag/diagram 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 认知轨迹日志与原地重建 + 网页登录入口/IM 桥/认知轨迹唤醒注册表。轨迹声明 = 轨迹目录下的 trajectory.json(约束面 + 旧标识 uid + CRO 机器绑定 cro.host;旧名 trajectory-constraint.json / skiff.json 仍在读取族里);轨迹提示词 = 轨迹目录下的 PROMPT.md(一条轨迹「是谁、按什么章程工作」,所有轨迹通用,追加在容器层与质量层之后,不替换它们)。适配 DSH 0.1.7-rc.1 / 0.2.0-rc.1 / 0.2.1-rc.1(三档,deepseek-ai/deepseek-harness)。",
|
|
6
6
|
"engines": {
|
|
@@ -20,6 +20,7 @@ import { createCipheriv, createDecipheriv, createHash, randomBytes } from "node:
|
|
|
20
20
|
var ilink_exports = /* @__PURE__ */ __exportAll({
|
|
21
21
|
TypingStatus: () => TypingStatus,
|
|
22
22
|
aes128EcbDecrypt: () => aes128EcbDecrypt,
|
|
23
|
+
buildBaseInfo: () => buildBaseInfo,
|
|
23
24
|
buildClientVersion: () => buildClientVersion,
|
|
24
25
|
buildMediaDownloadUrl: () => buildMediaDownloadUrl,
|
|
25
26
|
downloadMedia: () => downloadMedia,
|
|
@@ -65,6 +66,30 @@ function buildCommonHeaders() {
|
|
|
65
66
|
"iLink-App-ClientVersion": String(CLIENT_VERSION)
|
|
66
67
|
};
|
|
67
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* `base_info` —— **每一个业务 POST 都必须带**(2026-10-22 补齐,完全照官方实现)。
|
|
71
|
+
*
|
|
72
|
+
* ## 🔴 我们漏了这个字段,漏了很久
|
|
73
|
+
*
|
|
74
|
+
* 腾讯官方 `@tencent-weixin/openclaw-weixin` 的 `src/api/api.ts` 里,**九处**业务 POST
|
|
75
|
+
* 全部无条件附加它(`body: JSON.stringify({ ...body, base_info: buildBaseInfo() })`),
|
|
76
|
+
* 而 `buildBaseInfo()` 恒为 `{ channel_version: pkg.version }`。
|
|
77
|
+
*
|
|
78
|
+
* 我们这一侧长期只发 `{ msg: {...} }` —— **`base_info` 完全没有**。
|
|
79
|
+
*
|
|
80
|
+
* ## 症状为什么是「平时能发,隔久了发不出」
|
|
81
|
+
*
|
|
82
|
+
* 缺字段本身不会每次崩:入站带来的**新** `context_token` 给服务端提供了足够上下文,
|
|
83
|
+
* 请求照样成立。等票变旧、服务端进入 `prepare`(准备会话上下文)阶段时,
|
|
84
|
+
* **没有 `channel_version` 可依据** ⇒ 只能回 `ret=-2: prepare failed`。
|
|
85
|
+
* ⇒ 那个报错读作「准备阶段缺参数」,**不是**「会话过期」(后者是 `-14`)。
|
|
86
|
+
*
|
|
87
|
+
* ⚠️ 判据边界:本字段**不修复**「票真的过期」那种失败(那是 `-14`),
|
|
88
|
+
* 它修复的是**票在半旧窗口内、本该能发却被拒**的那一档。
|
|
89
|
+
*/
|
|
90
|
+
function buildBaseInfo() {
|
|
91
|
+
return { channel_version: CHANNEL_VERSION };
|
|
92
|
+
}
|
|
68
93
|
function buildHeaders(token) {
|
|
69
94
|
return {
|
|
70
95
|
"Content-Type": "application/json",
|
|
@@ -95,6 +120,30 @@ async function apiGet(params) {
|
|
|
95
120
|
throw err;
|
|
96
121
|
}
|
|
97
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* 给 POST body 统一附加 `base_info`(**对齐官方做法**)。
|
|
125
|
+
*
|
|
126
|
+
* 官方的九处业务 POST 各自写 `{ ...body, base_info: buildBaseInfo() }`;
|
|
127
|
+
* 我们把它收进 `apiPost` 一处 —— 语义完全相同(每个 POST 都带上),
|
|
128
|
+
* 但**新增调用点不可能漏**(这正是我们当初漏掉它的形态:靠每处手写就会漏)。
|
|
129
|
+
*
|
|
130
|
+
* ⚠️ 只在 body 是 JSON 对象时附加;解析失败就原样发(不为了加字段把请求搞坏)。
|
|
131
|
+
* ⚠️ 已经带 `base_info` 的 body **不覆盖**(以调用方给的为准)。
|
|
132
|
+
*/
|
|
133
|
+
function withBaseInfo(body) {
|
|
134
|
+
try {
|
|
135
|
+
const parsed = JSON.parse(body);
|
|
136
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return body;
|
|
137
|
+
const obj = parsed;
|
|
138
|
+
if (obj.base_info !== void 0) return body;
|
|
139
|
+
return JSON.stringify({
|
|
140
|
+
...obj,
|
|
141
|
+
base_info: buildBaseInfo()
|
|
142
|
+
});
|
|
143
|
+
} catch {
|
|
144
|
+
return body;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
98
147
|
async function apiPost(params) {
|
|
99
148
|
const base = ensureTrailingSlash(params.baseUrl);
|
|
100
149
|
const url = new URL(params.endpoint, base);
|
|
@@ -104,7 +153,7 @@ async function apiPost(params) {
|
|
|
104
153
|
const res = await currentFetch(url.toString(), {
|
|
105
154
|
method: "POST",
|
|
106
155
|
headers: buildHeaders(params.token),
|
|
107
|
-
body: params.body,
|
|
156
|
+
body: withBaseInfo(params.body),
|
|
108
157
|
signal: controller.signal
|
|
109
158
|
});
|
|
110
159
|
clearTimeout(timer);
|
|
@@ -214,7 +263,8 @@ async function sendTextMessage(params) {
|
|
|
214
263
|
type: MessageItemType.TEXT,
|
|
215
264
|
text_item: { text: markdownToPlainText(params.text) }
|
|
216
265
|
}],
|
|
217
|
-
...params.contextToken ? { context_token: params.contextToken } : {}
|
|
266
|
+
...params.contextToken ? { context_token: params.contextToken } : {},
|
|
267
|
+
...params.runId ? { run_id: params.runId } : {}
|
|
218
268
|
} }),
|
|
219
269
|
token: params.token,
|
|
220
270
|
timeoutMs: params.timeoutMs ?? 15e3
|
package/lib/im/ilink.d.ts
CHANGED
|
@@ -16,6 +16,30 @@
|
|
|
16
16
|
*/
|
|
17
17
|
/** 版本号 → ClientVersion 整数:(major<<16)|(minor<<8)|patch */
|
|
18
18
|
export declare function buildClientVersion(version: string): number;
|
|
19
|
+
/**
|
|
20
|
+
* `base_info` —— **每一个业务 POST 都必须带**(2026-10-22 补齐,完全照官方实现)。
|
|
21
|
+
*
|
|
22
|
+
* ## 🔴 我们漏了这个字段,漏了很久
|
|
23
|
+
*
|
|
24
|
+
* 腾讯官方 `@tencent-weixin/openclaw-weixin` 的 `src/api/api.ts` 里,**九处**业务 POST
|
|
25
|
+
* 全部无条件附加它(`body: JSON.stringify({ ...body, base_info: buildBaseInfo() })`),
|
|
26
|
+
* 而 `buildBaseInfo()` 恒为 `{ channel_version: pkg.version }`。
|
|
27
|
+
*
|
|
28
|
+
* 我们这一侧长期只发 `{ msg: {...} }` —— **`base_info` 完全没有**。
|
|
29
|
+
*
|
|
30
|
+
* ## 症状为什么是「平时能发,隔久了发不出」
|
|
31
|
+
*
|
|
32
|
+
* 缺字段本身不会每次崩:入站带来的**新** `context_token` 给服务端提供了足够上下文,
|
|
33
|
+
* 请求照样成立。等票变旧、服务端进入 `prepare`(准备会话上下文)阶段时,
|
|
34
|
+
* **没有 `channel_version` 可依据** ⇒ 只能回 `ret=-2: prepare failed`。
|
|
35
|
+
* ⇒ 那个报错读作「准备阶段缺参数」,**不是**「会话过期」(后者是 `-14`)。
|
|
36
|
+
*
|
|
37
|
+
* ⚠️ 判据边界:本字段**不修复**「票真的过期」那种失败(那是 `-14`),
|
|
38
|
+
* 它修复的是**票在半旧窗口内、本该能发却被拒**的那一档。
|
|
39
|
+
*/
|
|
40
|
+
export declare function buildBaseInfo(): {
|
|
41
|
+
channel_version: string;
|
|
42
|
+
};
|
|
19
43
|
/** fetch 注入点(测试替换;生产 = 全局 fetch) */
|
|
20
44
|
type FetchLike = typeof fetch;
|
|
21
45
|
/** 测试注入:替换全局 fetch 实现(生产零调用) */
|
|
@@ -126,6 +150,8 @@ export declare function sendTextMessage(params: {
|
|
|
126
150
|
text: string;
|
|
127
151
|
contextToken?: string;
|
|
128
152
|
clientId?: string;
|
|
153
|
+
/** 本轮次的运行 id(官方每条出站都带;同一次回复的多条消息共享它) */
|
|
154
|
+
runId?: string;
|
|
129
155
|
timeoutMs?: number;
|
|
130
156
|
}): Promise<void>;
|
|
131
157
|
/**
|
package/lib/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { n as hasSessionLogById, r as sessionsRootDir } from "./cleanup-C-92qnDs
|
|
|
9
9
|
import { n as readSimpleSettings, r as registerSettingsSection } from "./settings-H7TVDayZ.js";
|
|
10
10
|
import { a as readFeishuCredential, c as readWeixinSettings, d as weixinInboundDir, f as weixinSessionIdForTrajectory, i as matchWeixinRoute, n as extractWeixinText, o as readImSettings, r as hasVoiceItem, s as readWeixinCredential, t as extractWeixinMedia, u as sanitizeFileName$1 } from "./route-3OzOAjec.js";
|
|
11
11
|
import { REGISTERED_TOOLS } from "./invariant.js";
|
|
12
|
-
import { c as sendTextMessage, i as getUpdates, l as sendTyping, n as downloadMedia, o as markdownToPlainText, r as getConfig, s as sendFileMessage, t as TypingStatus, u as sniffImageExt } from "./ilink-
|
|
12
|
+
import { c as sendTextMessage, i as getUpdates, l as sendTyping, n as downloadMedia, o as markdownToPlainText, r as getConfig, s as sendFileMessage, t as TypingStatus, u as sniffImageExt } from "./ilink-CsZ-f64q.js";
|
|
13
13
|
import { a as registerImAccountImpl, i as normalizeAccountChannel, n as getImAccountImpl, r as imAccountChannels } from "./accounts-BHQbakUh.js";
|
|
14
14
|
import { createRequire } from "node:module";
|
|
15
15
|
import z from "@deepseek-ai/schemastery";
|
|
@@ -14344,7 +14344,7 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
14344
14344
|
}
|
|
14345
14345
|
const root = chk.root;
|
|
14346
14346
|
if (body.action === "login-start") {
|
|
14347
|
-
const { fetchQRCode } = await import("./ilink-
|
|
14347
|
+
const { fetchQRCode } = await import("./ilink-CsZ-f64q.js").then((n) => n.a);
|
|
14348
14348
|
const { randomUUID } = await import("node:crypto");
|
|
14349
14349
|
for (const [key, v] of weixinLogins) if (Date.now() - v.startedAt > WEIXIN_LOGIN_TTL_MS) weixinLogins.delete(key);
|
|
14350
14350
|
const { readWeixinSettings } = await import("./route-3OzOAjec.js").then((n) => n.l);
|
|
@@ -14478,7 +14478,7 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
14478
14478
|
sendJson$2(res, 200, { status: "expired" });
|
|
14479
14479
|
return;
|
|
14480
14480
|
}
|
|
14481
|
-
const { pollQRStatus } = await import("./ilink-
|
|
14481
|
+
const { pollQRStatus } = await import("./ilink-CsZ-f64q.js").then((n) => n.a);
|
|
14482
14482
|
const { readWeixinSettings } = await import("./route-3OzOAjec.js").then((n) => n.l);
|
|
14483
14483
|
const settings = readWeixinSettings(login.root);
|
|
14484
14484
|
const status = await pollQRStatus({
|
|
@@ -20190,7 +20190,8 @@ async function handleIncoming(ctx, root, accountId, cred, msg, preset) {
|
|
|
20190
20190
|
token: cred.token,
|
|
20191
20191
|
toUserId,
|
|
20192
20192
|
text,
|
|
20193
|
-
contextToken: replyRef
|
|
20193
|
+
contextToken: replyRef,
|
|
20194
|
+
runId: `dsp-run-${randomBytes(6).toString("hex")}`
|
|
20194
20195
|
});
|
|
20195
20196
|
},
|
|
20196
20197
|
typingStart: ({ toUserId, replyRef }) => sendTypingStart(cred, accountId, toUserId, replyRef),
|
|
@@ -20533,7 +20534,8 @@ async function sendProactiveText(input) {
|
|
|
20533
20534
|
token: cred.token,
|
|
20534
20535
|
toUserId,
|
|
20535
20536
|
text: input.text,
|
|
20536
|
-
...contextToken === void 0 ? {} : { contextToken }
|
|
20537
|
+
...contextToken === void 0 ? {} : { contextToken },
|
|
20538
|
+
runId: `dsp-run-${randomBytes(6).toString("hex")}`
|
|
20537
20539
|
});
|
|
20538
20540
|
} catch (err) {
|
|
20539
20541
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shgroup/dsh-serenity-hooks",
|
|
3
|
-
"version": "1.87.
|
|
3
|
+
"version": "1.87.3",
|
|
4
4
|
"description": "宁静号 ACC harness(Native Cordis 插件)——给 DeepSeek Harness 装一个「AI 工作区」:14 个工具(container_fs/cognitive_trajectory/dashboard/container_git/msm/praxis/ontology/serenity-skill-creator/cheap-worker/localstore/container_admin;另三个 im-bridge/acc-diag/diagram 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫/对外输出守卫)+ 认知轨迹日志与原地重建 + 网页登录入口/IM 桥/认知轨迹唤醒注册表。轨迹声明 = 轨迹目录下的 trajectory.json(约束面 + 旧标识 uid + CRO 机器绑定 cro.host;旧名 trajectory-constraint.json / skiff.json 仍在读取族里);轨迹提示词 = 轨迹目录下的 PROMPT.md(一条轨迹「是谁、按什么章程工作」,所有轨迹通用,追加在容器层与质量层之后,不替换它们)。适配 DSH 0.1.7-rc.1 / 0.2.0-rc.1 / 0.2.1-rc.1(三档)。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|