@shgroup/dsh-serenity-hooks 1.34.0 → 1.34.2

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.
Files changed (96) hide show
  1. package/README.md +1 -0
  2. package/dsh.plugin.json +1 -1
  3. package/lib/acp-core.d.ts +2 -22
  4. package/lib/acp-http.d.ts +8 -0
  5. package/lib/api.d.ts +12 -4
  6. package/lib/autopilot-chain.d.ts +76 -0
  7. package/lib/autopilot-core-DCRkiWEe.js +229 -0
  8. package/lib/autopilot-core.d.ts +132 -0
  9. package/lib/autopilot-ops.d.ts +48 -0
  10. package/lib/autopilot-trajectory-D9Znxo75.js +782 -0
  11. package/lib/autopilot-trajectory.d.ts +64 -97
  12. package/lib/ccc-roots-Bd_SjEs7.js +152 -0
  13. package/lib/ccc-roots.d.ts +105 -0
  14. package/lib/ccc.d.ts +3 -6
  15. package/lib/client.js +2 -2
  16. package/lib/clock-runtime.d.ts +197 -0
  17. package/lib/config-ops.d.ts +9 -14
  18. package/lib/constants.d.ts +0 -2
  19. package/lib/container-status.d.ts +183 -0
  20. package/lib/diag-ops.d.ts +25 -10
  21. package/lib/face-host.d.ts +110 -0
  22. package/lib/fs-ops.d.ts +3 -2
  23. package/lib/gateway-auth.d.ts +2 -5
  24. package/lib/gateway.d.ts +0 -34
  25. package/lib/git-ops.d.ts +3 -2
  26. package/lib/handyman-ops.d.ts +3 -2
  27. package/lib/handyman-preset-inherit.d.ts +2 -1
  28. package/lib/host/access.d.ts +8 -7
  29. package/lib/host/contract.d.ts +29 -6
  30. package/lib/host/type-contract.d.ts +1 -2
  31. package/lib/im-bridge.d.ts +6 -5
  32. package/lib/index.js +8336 -5607
  33. package/lib/invariant.d.ts +0 -15
  34. package/lib/invariant.js +1 -1
  35. package/lib/kit-ops.d.ts +11 -31
  36. package/lib/localstore-ops.d.ts +3 -17
  37. package/lib/msm-ops.d.ts +34 -52
  38. package/lib/opencode-provider.d.ts +4 -5
  39. package/lib/output-guard-seam.d.ts +0 -3
  40. package/lib/output-guard.d.ts +12 -3
  41. package/lib/ports.d.ts +59 -0
  42. package/lib/rebuild.d.ts +1 -1
  43. package/lib/seams/bootstrap.d.ts +4 -3
  44. package/lib/seams/compact.d.ts +2 -1
  45. package/lib/seams/context.d.ts +2 -4
  46. package/lib/seams/env.d.ts +2 -1
  47. package/lib/seams/guards.d.ts +4 -43
  48. package/lib/seams/keeper.d.ts +1 -1
  49. package/lib/seams/system-prompt.d.ts +1 -5
  50. package/lib/session-cleanup.d.ts +3 -2
  51. package/lib/{settings-section-BuPGQv_H.js → settings-section-DTYZjwUs.js} +65 -9
  52. package/lib/settings-section.d.ts +3 -31
  53. package/lib/skiff-core.d.ts +4 -9
  54. package/lib/skiff-debug.d.ts +15 -21
  55. package/lib/skiff-registry-FTjoWQTQ.js +25 -0
  56. package/lib/skiff-registry.d.ts +2 -1
  57. package/lib/{skiff-role-DAfPb6YQ.js → skiff-role-CEHL5cek.js} +1 -1
  58. package/lib/skiff-role.d.ts +2 -2
  59. package/lib/skills/opencode-scan.d.ts +3 -2
  60. package/lib/skills-discovery.d.ts +15 -2
  61. package/lib/status.d.ts +2 -1
  62. package/lib/tools/cce.d.ts +1 -2
  63. package/lib/tools/container-admin.d.ts +7 -3
  64. package/lib/tools/eap.d.ts +2 -3
  65. package/lib/tools/handyman.d.ts +0 -29
  66. package/lib/tools/msm.d.ts +0 -4
  67. package/lib/tools/neat.d.ts +1 -2
  68. package/lib/tools/praxis.d.ts +0 -1
  69. package/lib/tools/skiff-admin.d.ts +2 -2
  70. package/lib/tools/trajectory.d.ts +7 -15
  71. package/lib/totp.d.ts +0 -4
  72. package/lib/trajectory-assistant.d.ts +2 -1
  73. package/lib/trajectory-bound-Cax1p9ut.js +190 -0
  74. package/lib/trajectory-bound.d.ts +3 -4
  75. package/lib/{trajectory-bound-C8DUxi6_.js → trajectory-ops-mrXK0H0I.js} +2 -159
  76. package/lib/trajectory-ops.d.ts +4 -9
  77. package/lib/trajectory-skills.d.ts +71 -0
  78. package/lib/{wake-registry-D0Vj0WXb.js → wake-registry-CYxIb484.js} +7 -20
  79. package/lib/wake-registry.d.ts +3 -11
  80. package/lib/wake-scheduler.d.ts +13 -49
  81. package/lib/web-fetch-provider.d.ts +0 -21
  82. package/lib/{weixin-api-PjEhmjlZ.js → weixin-api-CtFYm53S.js} +3 -9
  83. package/lib/weixin-api.d.ts +6 -37
  84. package/lib/weixin-bridge.d.ts +5 -24
  85. package/lib/weixin-hook.d.ts +6 -12
  86. package/lib/weixin-output-guard.d.ts +2 -1
  87. package/lib/{weixin-route-D1ND823E.js → weixin-route-B2ajFypI.js} +4 -5
  88. package/lib/weixin-route.d.ts +0 -2
  89. package/lib/weixin-send-api.d.ts +15 -6
  90. package/package.json +2 -4
  91. package/experiments/autopilot-trajectory/SKILL.md +0 -115
  92. package/experiments/autopilot-trajectory/scripts/autopilot-trajectory.ts +0 -546
  93. package/lib/autopilot-script.d.ts +0 -40
  94. package/lib/skiff-debug-D83-Njy7.js +0 -2867
  95. package/lib/{ccc-eu_IPF94.js → ccc-NlLr_sxy.js} +1 -1
  96. package/lib/{session-cleanup-CMT4mHWt.js → session-cleanup-B6IHZgww.js} +1 -1
@@ -52,7 +52,7 @@ export declare const ACK_SKIP_PREFIX = "TRAJECTORY-ASSISTANT-skipped";
52
52
  */
53
53
  export declare const IN_FLIGHT_HEADING = "## In-flight (rebuild handover)";
54
54
  /** 风格档位:plain(默认,精确文本)/ metaphor(借星舰词——产品隐喻非游戏词) */
55
- export type TrajectoryStyle = 'plain' | 'metaphor';
55
+ type TrajectoryStyle = 'plain' | 'metaphor';
56
56
  /**
57
57
  * 按风格生成前缀 token。plain = eventToken()(原样);metaphor 仅当有
58
58
  * 星舰化变体时替换用词(当前等价保留——星舰词库隐喻域的既有措辞即
@@ -65,3 +65,4 @@ export declare function styledToken(event: keyof typeof EVENT_LABEL, style?: Tra
65
65
  * 尚无可靠自动检测(D2 用户拍板记录为未解问题),实现留待仪式落地。
66
66
  */
67
67
  export declare function onSettlement(_cb: (sessionId: string) => void): void;
68
+ export {};
@@ -0,0 +1,190 @@
1
+ import { r as cccRootForCwd } from "./ccc-roots-Bd_SjEs7.js";
2
+ import { c as getLastActiveSessionInfo, p as sessionEvents, s as getActiveSessionInfo } from "./trajectory-ops-mrXK0H0I.js";
3
+ import { dirname, join } from "node:path";
4
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
5
+ //#region src/trajectory-bound.ts
6
+ /**
7
+ * trajectory-bound.ts — SESSION 绑定持久化(CCC 内 `AGENT_SESSIONS/.bindings.json`)
8
+ *
9
+ * 目标(S142 用户拍板,方案 v1.0):让「dsh 会话(载体)↔ SESSION(宁静号轨迹)」
10
+ * 的绑定坚固——LLM 不能因智力因素(幻觉/理解偏差)在过程中或 container_trajectory rebuild 后
11
+ * 自行更换 SESSION。
12
+ *
13
+ * 存储形态(v1.30.6 起,S142 review F-01):绑定**不再写入 dsh 会话日志**。
14
+ * 原因(宿主契约实证):dsp 的自定义事件 `serenity/bound` 既不在宿主的
15
+ * `KNOWN_SESSION_EVENT_TYPES`(生成静态集,明确说明 out-of-repo 插件事件不在其中),
16
+ * 而 `Session.append` 构造事件时只写 `{type,seq,time,data,surfaceOp?,sourceEventSeqs?}`
17
+ * ——**没有写入 envelope `ignorable` 标记的通道**;宿主的 `assertEventsSupported`
18
+ * (session-persistence/coordinator.ts:1248-1252,调用点含恢复/HMR 路径)会拒绝任何
19
+ * "未知且非 ignorable" 的事件 → 含该事件的会话在冷加载时可能抛
20
+ * `SessionFormatUnsupportedError`。v1.29.1~v1.30.5 的设计文档虽写明要带
21
+ * `ignorable: true`(docs/session-binding-hardening-research.md:53),但类型层声明
22
+ * 不等于持久层标记,实际从未落盘。
23
+ *
24
+ * 现形态:每 CCC 一个 JSON 文件 `AGENT_SESSIONS/.bindings.json`(原子写:tmp + rename),
25
+ * 以 dsh 会话 id 为键,latest-wins 覆盖。**向后兼容**:读取时若文件中无该会话记录,
26
+ * 仍回落到扫描会话日志中的旧 `serenity/bound` 事件(老会话的绑定不丢)。
27
+ *
28
+ * 编码无关(U4):绑定锚 = **完整 AGENT_SESSIONS 目录名**(磁盘唯一存在),
29
+ * sessionId(S###/apaas-xxx/自定义)仅是派生展示字段——绝不假设 S 前缀。
30
+ */
31
+ /** 旧形态事件类型(v1.29.1~v1.30.5 写入会话日志;v1.30.6 起只读不写——兼容存量绑定) */
32
+ const SESSION_BOUND_EVENT = "serenity/bound";
33
+ /** 绑定文件相对 CCC 根的路径 */
34
+ const BINDINGS_REL_PATH = "AGENT_SESSIONS/.bindings.json";
35
+ const BINDINGS_VERSION = 1;
36
+ function sessionHeader(session) {
37
+ const header = session?.header;
38
+ if (!header || typeof header !== "object") return null;
39
+ return header;
40
+ }
41
+ /** 绑定文件绝对路径(由会话 cwd 上溯 .serenity 定位 CCC 根);无法定位返回 null */
42
+ function bindingsPathFor(session) {
43
+ const header = sessionHeader(session);
44
+ if (typeof header?.cwd !== "string") return null;
45
+ const root = cccRootForCwd(header.cwd);
46
+ if (!root) return null;
47
+ return join(root, BINDINGS_REL_PATH);
48
+ }
49
+ function readBindingsFile(path) {
50
+ if (!existsSync(path)) return {
51
+ version: BINDINGS_VERSION,
52
+ sessions: {}
53
+ };
54
+ try {
55
+ const sessions = JSON.parse(readFileSync(path, "utf-8")).sessions;
56
+ if (!sessions || typeof sessions !== "object") return {
57
+ version: BINDINGS_VERSION,
58
+ sessions: {}
59
+ };
60
+ return {
61
+ version: BINDINGS_VERSION,
62
+ sessions
63
+ };
64
+ } catch {
65
+ return {
66
+ version: BINDINGS_VERSION,
67
+ sessions: {}
68
+ };
69
+ }
70
+ }
71
+ /** 原子写:同目录 tmp + rename(避免半写文件被后续读取) */
72
+ function writeBindingsFile(path, data) {
73
+ mkdirSync(dirname(path), { recursive: true });
74
+ const tmp = `${path}.tmp`;
75
+ writeFileSync(tmp, `${JSON.stringify(data, null, 2)}\n`, "utf-8");
76
+ renameSync(tmp, path);
77
+ }
78
+ /** 记录形状校验(容忍手改/旧数据) */
79
+ function asBoundRecord(value) {
80
+ const r = value;
81
+ if (!r || typeof r.dirName !== "string" || typeof r.mdPath !== "string") return null;
82
+ return r;
83
+ }
84
+ /** 旧形态:从会话日志扫最后一条 `serenity/bound`(兼容 v1.30.5 及更早写入的绑定) */
85
+ function readLegacyBoundFromEvents(session) {
86
+ const events = sessionEvents(session);
87
+ for (let i = events.length - 1; i >= 0; i--) {
88
+ const ev = events[i];
89
+ if (!ev || ev.type !== SESSION_BOUND_EVENT) continue;
90
+ const rec = asBoundRecord(ev.data);
91
+ if (rec) return rec;
92
+ }
93
+ return null;
94
+ }
95
+ /**
96
+ * 读取会话当前绑定(权威,latest-wins):文件记录优先,无则回落旧事件形态。
97
+ * 无绑定返回 null。
98
+ */
99
+ function readLastBound(session) {
100
+ const path = bindingsPathFor(session);
101
+ const id = sessionHeader(session)?.id;
102
+ if (path && typeof id === "string") {
103
+ const rec = asBoundRecord(readBindingsFile(path).sessions[id]);
104
+ if (rec) return rec;
105
+ }
106
+ return readLegacyBoundFromEvents(session);
107
+ }
108
+ /** 目录名 → 轨迹标签(`--S###--` 命中取 `S###`;未命中原样返回——编码无关 U4) */
109
+ function trajectoryLabel(dirName) {
110
+ const m = dirName.match(/--S(\d{3,})--/);
111
+ return m ? `S${m[1]}` : dirName;
112
+ }
113
+ /**
114
+ * **调用方自身**所属 trajectory 的标签(审计字段 `createdBy` 的唯一正解)。
115
+ *
116
+ * 三级来源,逐级回退(R↓:为什么不用单一来源):
117
+ * 1. `readLastBound(session)` —— **持久 bound**,权威(重启存活、不受别的会话激活污染)
118
+ * 2. `getActiveSessionInfo(scope)` —— 本 dsh 会话的**内存**激活(按 scope 隔离)
119
+ * 3. `getLastActiveSessionInfo()` —— **全局**最近激活指针(无绑定的会话兼容回退)
120
+ *
121
+ * ⚠️ 为何单列成本函数(S142 §30.12.1 实测缺陷):唤醒注册表的 `createdBy` 原先直接取第 3 级
122
+ * 全局指针,而它记录的是"**进程内最近一次被激活的 trajectory**"——多会话并发时必然张冠李戴
123
+ * (实测:S142 登记唤醒被写成 `by=S060`)。`createdBy` 是 D60「以可审计替代入口栅」的**唯一凭证**,
124
+ * 失真即替代控制失效 ⇒ 必须以"调用方自己是谁"为准,全局指针只作最后兜底。
125
+ *
126
+ * @param session 调用方 dsh 会话对象(需 `header.id` + `header.cwd`)
127
+ * @param scope 调用方 dsh 会话 id(取不到传空串)
128
+ * @returns 轨迹标签(`S###` 或完整目录名);三级全落空 → 空串(渲染为 `?`)
129
+ */
130
+ function resolveSessionTrajectoryLabel(session, scope) {
131
+ const bound = session ? readLastBound(session) : null;
132
+ if (bound?.dirName) return trajectoryLabel(bound.dirName);
133
+ const scoped = scope !== "" ? getActiveSessionInfo(scope) : null;
134
+ if (scoped) return scoped.sessionId;
135
+ return getLastActiveSessionInfo()?.sessionId ?? "";
136
+ }
137
+ /**
138
+ * 反向查:绑定到某 trajectory 目录名的 dsh 会话 id(**按绑定时间倒序,最新在前**)。
139
+ *
140
+ * 用途(wake-scheduler 冷唤醒):.bindings.json 以 **sessionId 为键**,而唤醒条目的
141
+ * target 是**目录名**——需要值侧扫描做反向索引。冷会话被唤醒时必须先知道"哪个 dsh
142
+ * 会话承载这条轨迹",这是唯一的权威来源(标题只作回退,见 v1.29.2 R2)。
143
+ *
144
+ * @param root CCC 根
145
+ * @param dirName AGENT_SESSIONS 目录名(完整名,如 `2026-09-01--S151--x--auto`)
146
+ * @returns 会话 id 列表(最新绑定在前);无绑定 → `[]`
147
+ */
148
+ function listBoundSessionIds(root, dirName) {
149
+ const file = readBindingsFile(join(root, BINDINGS_REL_PATH));
150
+ const hits = [];
151
+ for (const [id, raw] of Object.entries(file.sessions)) {
152
+ const rec = asBoundRecord(raw);
153
+ if (!rec || rec.dirName !== dirName) continue;
154
+ hits.push({
155
+ id,
156
+ at: typeof rec.at === "number" ? rec.at : 0
157
+ });
158
+ }
159
+ return hits.sort((a, b) => b.at - a.at).map((h) => h.id);
160
+ }
161
+ /**
162
+ * 写入绑定(latest-wins 覆盖该会话记录)。
163
+ *
164
+ * 绑定持久化尽力而为:无法定位 CCC 根 / 无会话 id / 写盘失败 → 返回 false,不阻断主流程。
165
+ * @param session 目标 dsh 会话(需 `header.id` + `header.cwd` 可定位 CCC 根)
166
+ * @param action 绑定动作
167
+ * @param rec 绑定记录(dirName + mdPath 必填;sessionId 可选展示码)
168
+ */
169
+ function appendBound(session, action, rec) {
170
+ const path = bindingsPathFor(session);
171
+ const id = sessionHeader(session)?.id;
172
+ if (!path || typeof id !== "string") return false;
173
+ try {
174
+ const file = readBindingsFile(path);
175
+ file.sessions[id] = {
176
+ dirName: rec.dirName,
177
+ mdPath: rec.mdPath,
178
+ ...rec.sessionId ? { sessionId: rec.sessionId } : {},
179
+ action,
180
+ at: Date.now(),
181
+ ...rec.note ? { note: rec.note } : {}
182
+ };
183
+ writeBindingsFile(path, file);
184
+ return true;
185
+ } catch {
186
+ return false;
187
+ }
188
+ }
189
+ //#endregion
190
+ export { resolveSessionTrajectoryLabel as i, listBoundSessionIds as n, readLastBound as r, appendBound as t };
@@ -23,8 +23,8 @@
23
23
  * 编码无关(U4):绑定锚 = **完整 AGENT_SESSIONS 目录名**(磁盘唯一存在),
24
24
  * sessionId(S###/apaas-xxx/自定义)仅是派生展示字段——绝不假设 S 前缀。
25
25
  */
26
- export type SessionBoundAction = 'activate' | 'switch' | 'create' | 'rebuild' | 'reconcile' | 'release';
27
- export interface SessionBoundRecord {
26
+ type SessionBoundAction = 'activate' | 'switch' | 'create' | 'rebuild' | 'reconcile' | 'release';
27
+ interface SessionBoundRecord {
28
28
  dirName: string;
29
29
  mdPath: string;
30
30
  sessionId?: string;
@@ -32,8 +32,6 @@ export interface SessionBoundRecord {
32
32
  at: number;
33
33
  note?: string;
34
34
  }
35
- /** 旧形态事件类型(v1.29.1~v1.30.5 写入会话日志;v1.30.6 起只读不写——兼容存量绑定) */
36
- export declare const SESSION_BOUND_EVENT: "serenity/bound";
37
35
  /** 绑定文件相对 CCC 根的路径 */
38
36
  export declare const BINDINGS_REL_PATH = "AGENT_SESSIONS/.bindings.json";
39
37
  /** 绑定文件绝对路径(由会话 cwd 上溯 .serenity 定位 CCC 根);无法定位返回 null */
@@ -89,3 +87,4 @@ export declare function appendBound(session: unknown, action: SessionBoundAction
89
87
  sessionId?: string;
90
88
  note?: string;
91
89
  }): boolean;
90
+ export {};
@@ -1,6 +1,5 @@
1
- import { a as findSerenityRoot } from "./ccc-eu_IPF94.js";
2
- import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "node:fs";
3
1
  import { basename, dirname, join } from "node:path";
2
+ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
4
3
  //#region src/trajectory-ops.ts
5
4
  /**
6
5
  * trajectory-ops.ts — 轨迹工具纯操作层(零 DSH 依赖,可独立单测)
@@ -407,161 +406,5 @@ function summarize(root) {
407
406
  if (stale > 0) lines.push("", "⚠ Warning: stale trajectories present (no activity > 7d) — see the list above for detail.");
408
407
  return lines.join("\n");
409
408
  }
410
- /** 绑定文件相对 CCC 根的路径 */
411
- const BINDINGS_REL_PATH = "AGENT_SESSIONS/.bindings.json";
412
- const BINDINGS_VERSION = 1;
413
- function sessionHeader(session) {
414
- const header = session?.header;
415
- if (!header || typeof header !== "object") return null;
416
- return header;
417
- }
418
- /** 绑定文件绝对路径(由会话 cwd 上溯 .serenity 定位 CCC 根);无法定位返回 null */
419
- function bindingsPathFor(session) {
420
- const header = sessionHeader(session);
421
- if (typeof header?.cwd !== "string") return null;
422
- const root = findSerenityRoot(header.cwd);
423
- if (!root) return null;
424
- return join(root, BINDINGS_REL_PATH);
425
- }
426
- function readBindingsFile(path) {
427
- if (!existsSync(path)) return {
428
- version: BINDINGS_VERSION,
429
- sessions: {}
430
- };
431
- try {
432
- const sessions = JSON.parse(readFileSync(path, "utf-8")).sessions;
433
- if (!sessions || typeof sessions !== "object") return {
434
- version: BINDINGS_VERSION,
435
- sessions: {}
436
- };
437
- return {
438
- version: BINDINGS_VERSION,
439
- sessions
440
- };
441
- } catch {
442
- return {
443
- version: BINDINGS_VERSION,
444
- sessions: {}
445
- };
446
- }
447
- }
448
- /** 原子写:同目录 tmp + rename(避免半写文件被后续读取) */
449
- function writeBindingsFile(path, data) {
450
- mkdirSync(dirname(path), { recursive: true });
451
- const tmp = `${path}.tmp`;
452
- writeFileSync(tmp, `${JSON.stringify(data, null, 2)}\n`, "utf-8");
453
- renameSync(tmp, path);
454
- }
455
- /** 记录形状校验(容忍手改/旧数据) */
456
- function asBoundRecord(value) {
457
- const r = value;
458
- if (!r || typeof r.dirName !== "string" || typeof r.mdPath !== "string") return null;
459
- return r;
460
- }
461
- /** 旧形态:从会话日志扫最后一条 `serenity/bound`(兼容 v1.30.5 及更早写入的绑定) */
462
- function readLegacyBoundFromEvents(session) {
463
- const events = sessionEvents(session);
464
- for (let i = events.length - 1; i >= 0; i--) {
465
- const ev = events[i];
466
- if (!ev || ev.type !== "serenity/bound") continue;
467
- const rec = asBoundRecord(ev.data);
468
- if (rec) return rec;
469
- }
470
- return null;
471
- }
472
- /**
473
- * 读取会话当前绑定(权威,latest-wins):文件记录优先,无则回落旧事件形态。
474
- * 无绑定返回 null。
475
- */
476
- function readLastBound(session) {
477
- const path = bindingsPathFor(session);
478
- const id = sessionHeader(session)?.id;
479
- if (path && typeof id === "string") {
480
- const rec = asBoundRecord(readBindingsFile(path).sessions[id]);
481
- if (rec) return rec;
482
- }
483
- return readLegacyBoundFromEvents(session);
484
- }
485
- /** 目录名 → 轨迹标签(`--S###--` 命中取 `S###`;未命中原样返回——编码无关 U4) */
486
- function trajectoryLabel(dirName) {
487
- const m = dirName.match(/--S(\d{3,})--/);
488
- return m ? `S${m[1]}` : dirName;
489
- }
490
- /**
491
- * **调用方自身**所属 trajectory 的标签(审计字段 `createdBy` 的唯一正解)。
492
- *
493
- * 三级来源,逐级回退(R↓:为什么不用单一来源):
494
- * 1. `readLastBound(session)` —— **持久 bound**,权威(重启存活、不受别的会话激活污染)
495
- * 2. `getActiveSessionInfo(scope)` —— 本 dsh 会话的**内存**激活(按 scope 隔离)
496
- * 3. `getLastActiveSessionInfo()` —— **全局**最近激活指针(无绑定的会话兼容回退)
497
- *
498
- * ⚠️ 为何单列成本函数(S142 §30.12.1 实测缺陷):唤醒注册表的 `createdBy` 原先直接取第 3 级
499
- * 全局指针,而它记录的是"**进程内最近一次被激活的 trajectory**"——多会话并发时必然张冠李戴
500
- * (实测:S142 登记唤醒被写成 `by=S060`)。`createdBy` 是 D60「以可审计替代入口栅」的**唯一凭证**,
501
- * 失真即替代控制失效 ⇒ 必须以"调用方自己是谁"为准,全局指针只作最后兜底。
502
- *
503
- * @param session 调用方 dsh 会话对象(需 `header.id` + `header.cwd`)
504
- * @param scope 调用方 dsh 会话 id(取不到传空串)
505
- * @returns 轨迹标签(`S###` 或完整目录名);三级全落空 → 空串(渲染为 `?`)
506
- */
507
- function resolveSessionTrajectoryLabel(session, scope) {
508
- const bound = session ? readLastBound(session) : null;
509
- if (bound?.dirName) return trajectoryLabel(bound.dirName);
510
- const scoped = scope !== "" ? getActiveSessionInfo(scope) : null;
511
- if (scoped) return scoped.sessionId;
512
- return getLastActiveSessionInfo()?.sessionId ?? "";
513
- }
514
- /**
515
- * 反向查:绑定到某 trajectory 目录名的 dsh 会话 id(**按绑定时间倒序,最新在前**)。
516
- *
517
- * 用途(wake-scheduler 冷唤醒):.bindings.json 以 **sessionId 为键**,而唤醒条目的
518
- * target 是**目录名**——需要值侧扫描做反向索引。冷会话被唤醒时必须先知道"哪个 dsh
519
- * 会话承载这条轨迹",这是唯一的权威来源(标题只作回退,见 v1.29.2 R2)。
520
- *
521
- * @param root CCC 根
522
- * @param dirName AGENT_SESSIONS 目录名(完整名,如 `2026-09-01--S151--x--auto`)
523
- * @returns 会话 id 列表(最新绑定在前);无绑定 → `[]`
524
- */
525
- function listBoundSessionIds(root, dirName) {
526
- const file = readBindingsFile(join(root, BINDINGS_REL_PATH));
527
- const hits = [];
528
- for (const [id, raw] of Object.entries(file.sessions)) {
529
- const rec = asBoundRecord(raw);
530
- if (!rec || rec.dirName !== dirName) continue;
531
- hits.push({
532
- id,
533
- at: typeof rec.at === "number" ? rec.at : 0
534
- });
535
- }
536
- return hits.sort((a, b) => b.at - a.at).map((h) => h.id);
537
- }
538
- /**
539
- * 写入绑定(latest-wins 覆盖该会话记录)。
540
- *
541
- * 绑定持久化尽力而为:无法定位 CCC 根 / 无会话 id / 写盘失败 → 返回 false,不阻断主流程。
542
- * @param session 目标 dsh 会话(需 `header.id` + `header.cwd` 可定位 CCC 根)
543
- * @param action 绑定动作
544
- * @param rec 绑定记录(dirName + mdPath 必填;sessionId 可选展示码)
545
- */
546
- function appendBound(session, action, rec) {
547
- const path = bindingsPathFor(session);
548
- const id = sessionHeader(session)?.id;
549
- if (!path || typeof id !== "string") return false;
550
- try {
551
- const file = readBindingsFile(path);
552
- file.sessions[id] = {
553
- dirName: rec.dirName,
554
- mdPath: rec.mdPath,
555
- ...rec.sessionId ? { sessionId: rec.sessionId } : {},
556
- action,
557
- at: Date.now(),
558
- ...rec.note ? { note: rec.note } : {}
559
- };
560
- writeBindingsFile(path, file);
561
- return true;
562
- } catch {
563
- return false;
564
- }
565
- }
566
409
  //#endregion
567
- export { sessionsRoot as _, DEFAULT_SESSION_SCOPE as a, summarize as b, createSession as c, getActiveSessionInfo as d, listSessions as f, sessionEvents as g, resolveSessionByTitle as h, resolveSessionTrajectoryLabel as i, extractSessionMdPathFromText as l, readActiveSessionMd as m, listBoundSessionIds as n, TRAJECTORY_ACTIONS as o, parseSessionContextFromEvents as p, readLastBound as r, clearActiveSessionInfo as s, appendBound as t, findSession as u, setActiveSessionInfo as v, useSession as x, showSession as y };
410
+ export { summarize as _, extractSessionMdPathFromText as a, getLastActiveSessionInfo as c, readActiveSessionMd as d, resolveSessionByTitle as f, showSession as g, setActiveSessionInfo as h, createSession as i, listSessions as l, sessionsRoot as m, TRAJECTORY_ACTIONS as n, findSession as o, sessionEvents as p, clearActiveSessionInfo as r, getActiveSessionInfo as s, DEFAULT_SESSION_SCOPE as t, parseSessionContextFromEvents as u, useSession as v };
@@ -11,7 +11,6 @@
11
11
  * list(含 summarize 仪表盘)、show、use(激活 + 绑定)、以及供 list 用的 summarize。
12
12
  * 「完成」不再由 close 写入,而是从 SESSION.md 的 `[x]` 推导;归档走 `container_fs mv`。
13
13
  */
14
- import type { JsonValue } from './json.js';
15
14
  /**
16
15
  * `container_trajectory` 工具的动作集合(v1.33,S142 §32 用户裁决后的收敛结果)。
17
16
  *
@@ -22,7 +21,7 @@ import type { JsonValue } from './json.js';
22
21
  * hook-develop-guide 并进 container_admin msm guide|autopilot 面归 container_admin 的 autopilot 域|
23
22
  * wake-add/list/rm 收敛为 wake-later。
24
23
  */
25
- export type TrajectoryAction = 'list' | 'show' | 'create' | 'use' | 'rebuild' | 'wake-later';
24
+ type TrajectoryAction = 'list' | 'show' | 'create' | 'use' | 'rebuild' | 'wake-later';
26
25
  export declare const TRAJECTORY_ACTIONS: readonly TrajectoryAction[];
27
26
  /**
28
27
  * 读取 Session 事件序列(v1.28.1 适配 0.1.2-rc.1 补齐):rc.1 起官方 Session 类
@@ -41,7 +40,7 @@ interface SessionStatus {
41
40
  /** 「完成」的判据 = SESSION.md 里出现 `[x]`(v1.33 起不再由 close 动作写入) */
42
41
  completed: boolean;
43
42
  }
44
- export interface SessionEntry {
43
+ interface SessionEntry {
45
44
  dirName: string;
46
45
  path: string;
47
46
  mtime: Date;
@@ -56,7 +55,7 @@ export declare function findSession(sessionsDir: string, key: string): SessionEn
56
55
  export declare function listSessions(root: string, activeId?: string): string;
57
56
  /** show 子命令(对齐 osp showSession:`# dirName\n\n` + SESSION.md 内容) */
58
57
  export declare function showSession(root: string, key: string): string;
59
- export interface CreateSessionOptions {
58
+ interface CreateSessionOptions {
60
59
  root: string;
61
60
  /** --desc 模式的描述(与 issue 互斥) */
62
61
  desc?: string;
@@ -71,9 +70,6 @@ export interface CreateSessionResult {
71
70
  sessionPath: string;
72
71
  sessionId: string;
73
72
  }
74
- /** create 子命令(对齐 osp createSession:--desc/--issue 二选一 + dry-run + 长度限制) */
75
- /** 目录名脱敏(Windows 审计问题 10):非法字符 → '-', 去尾点/空格, 保留名(CON/NUL 等)加前缀 */
76
- export declare function sanitizeDirName(s: string): string;
77
73
  export declare function createSession(opts: CreateSessionOptions): CreateSessionResult;
78
74
  /**
79
75
  * 活动会话跟踪(S134 v1.16.14 内存化,对齐 osp active-state):
@@ -143,5 +139,4 @@ export declare function resolveSessionByTitle(title: string, sessionsDir: string
143
139
  export declare function findLatestActiveSessionMd(root: string): string | null;
144
140
  /** summary 仪表盘(供 `list` 动作拼接;v1.33 起独立 `summary` 动作已撤,并入 list) */
145
141
  export declare function summarize(root: string): string;
146
- export type SessionInfo = SessionEntry;
147
- export type { JsonValue };
142
+ export {};
@@ -0,0 +1,71 @@
1
+ /**
2
+ * trajectory-skills.ts — 轨迹 skill 声明解析 + 注入内容装配(纯逻辑,零 DSH 依赖)
3
+ *
4
+ * 接口真相源:`docs/trajectory-skill-injection.md` v1.0(§2 数据契约 / §3 注入契约)。
5
+ * 一句话:**轨迹自己声明它要挂哪些 skill**(`SESSION.md` 顶部 YAML frontmatter 的 `skills:`),
6
+ * ACC 在**绑定期间**把这些 skill 的 `SKILL.md` 全文注入系统提示词。
7
+ *
8
+ * 分工(R↓:为什么解析与注册分开):
9
+ * · 本模块 = **纯文本层**(解析 / 装配 / 安全判定)——可脱离 DSH 单测;
10
+ * · `seams/system-prompt.ts` 的 `registerTrajectorySkillSection` = **宿主接入层**
11
+ * (per-agent `ctx.systemPrompt.section`),只做门与注册,不再解析文本。
12
+ *
13
+ * 边界(规格 §2.2):**不解析** `skills` 以外任何键的语义(CCC 可自由使用,ACC 视而不见);
14
+ * **不改写** frontmatter(ACC 只读)。
15
+ */
16
+ /** 全文注入总长上限(字符数;规格 §3「缺省 32 KB」——防上下文爆炸) */
17
+ export declare const TRAJECTORY_SKILLS_MAX_CHARS: number;
18
+ /** 缺失标记(规格 §3/§6-3 的验收锚点:任何"拿不到全文"的情况都必须带它,绝不静默) */
19
+ export declare const SKILL_MISSING_MARK = "[\u7F3A\u5931]";
20
+ /**
21
+ * 抽取文件顶部 YAML frontmatter 区(规格 §2.1)。
22
+ *
23
+ * 规则:**第一行必须是 `---`**;到下一个 `---` 行为止是 frontmatter 区。
24
+ * 首行不是 `---`,或没有闭合 `---` ⇒ 视为**无 frontmatter**(返回 null)。
25
+ * 边界判断(R↓):未闭合块按"无 frontmatter"处理而非吞掉整个文件——半个声明块是格式错误,
26
+ * 猜它的意图等于把坏数据当好消息(宁可零注入,也不注入来路不明的半截列表)。
27
+ *
28
+ * @param content SESSION.md 全文
29
+ * @returns frontmatter 区各行(不含两条 `---` 定界行);无 → null
30
+ */
31
+ export declare function extractFrontmatter(content: string): string[] | null;
32
+ /**
33
+ * 解析声明(规格 §2.1,**最小实现,不引 YAML 依赖**)。
34
+ *
35
+ * 只认 `skills:` 键;未知键一律忽略(向前兼容,不报错)。两种值形态都支持:
36
+ * ① 行内数组 `skills: [home-rhetoric, acc-eap]`
37
+ * ② 缩进列表(`skills:` 后各起一行 ` - a`)
38
+ * 名字:去首尾空白、空项丢弃、**保持书写顺序**(注入顺序 = 书写顺序)、同名去重(保留首次位置)。
39
+ *
40
+ * 未定义形态(不在规格的两种值形态内,如 `skills: a` 裸标量)⇒ **视为无声明**:
41
+ * 本函数只认契约里写明的两种形态,猜第三种等于自造契约(规格 §2.1 只列了 ①②)。
42
+ *
43
+ * @param sessionMd SESSION.md 全文
44
+ * @returns 声明的 skill 名(按书写顺序去重);无 frontmatter / 无 `skills` 键 / 值为空 → `[]`
45
+ */
46
+ export declare function parseDeclaredSkills(sessionMd: string): string[];
47
+ /**
48
+ * 注册门(规格 §3「无绑定 / 无声明 ⇒ 完全不注册该 section」)。
49
+ *
50
+ * 返回 true 的两种情况:
51
+ * · 文件在且**有非空声明** → 注册(有内容可注入)
52
+ * · 文件**不在 / 读不到** → 同样注册——此时 section 文本是响亮的 `[缺失]` 提示
53
+ * (规格 §6-6 要求"不静默";不注册就等于静默)
54
+ * 其余(文件在但无 frontmatter / 无 `skills` 键 / 值为空)⇒ false,不注册、不产生噪声。
55
+ */
56
+ export declare function hasTrajectorySkillsDeclaration(root: string, mdPath: string): boolean;
57
+ /**
58
+ * 装配注入正文(规格 §3):按声明顺序拼接各 skill 的 `SKILL.md` 全文,每段带来源抬头
59
+ * `=== skill: <name> ===`;拿不到全文的一律以 `[缺失]` 响亮提示占位(**不静默**)。
60
+ *
61
+ * 安全(规格 §3 🔒):名字来自 CCC 数据(frontmatter)⇒ **先过 `isSafeSkillName`**;
62
+ * 不安全 ⇒ 按缺失处理,且不调用 `findSkillMd` ⇒ **不发生任何以该名拼出的 fs 访问**。
63
+ *
64
+ * 长度守卫:复用已导出的 `truncateContent`,超限截断并在末尾写明 `truncated`。
65
+ *
66
+ * @param root CCC 根
67
+ * @param mdPath 轨迹的 SESSION.md 路径(**来自绑定的 `mdPath`**,不用 label 拼)
68
+ * @param maxChars 总长上限(字符)
69
+ * @returns 注入正文;无声明 → `''`(空串 = 宿主不产出该 section 块);SESSION.md 缺失 → 响亮提示
70
+ */
71
+ export declare function buildTrajectorySkillsSection(root: string, mdPath: string, maxChars?: number): string;
@@ -1,6 +1,5 @@
1
- import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
3
1
  import { dirname, join } from "node:path";
2
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
4
3
  //#region src/wake-registry.ts
5
4
  /**
6
5
  * wake-registry.ts — trajectory 唤醒注册表(D58,S142 2026-09-13)
@@ -16,22 +15,10 @@ import { dirname, join } from "node:path";
16
15
  *
17
16
  * 调度与投递在 `wake-scheduler.ts`(需要 ctx),本模块保持纯净。
18
17
  */
19
- var wake_registry_exports = /* @__PURE__ */ __exportAll({
20
- WAKE_CATCH_UP_MS: () => WAKE_CATCH_UP_MS,
21
- WAKE_REGISTRY_REL_PATH: () => WAKE_REGISTRY_REL_PATH,
22
- WAKE_REGISTRY_VERSION: () => 1,
23
- addWake: () => addWake,
24
- listWakes: () => listWakes,
25
- loadWakeRegistry: () => loadWakeRegistry,
26
- newWakeId: () => newWakeId,
27
- parseWakeAt: () => parseWakeAt,
28
- saveWakeRegistry: () => saveWakeRegistry,
29
- splitDueWakes: () => splitDueWakes,
30
- updateWake: () => updateWake,
31
- wakeRegistryPath: () => wakeRegistryPath
32
- });
33
18
  /** 注册表相对 CCC 根的路径(与 `.bindings.json` 同居 AGENT_SESSIONS/) */
34
19
  const WAKE_REGISTRY_REL_PATH = "AGENT_SESSIONS/wake-registry.json";
20
+ /** 注册表格式版本(结构变更时 +1;读取端只接受本版本) */
21
+ const WAKE_REGISTRY_VERSION = 1;
35
22
  /**
36
23
  * 补跑窗口(缺省 2h):dsh 停机期间到期的条目,若迟到不超过本窗口则补投,
37
24
  * 超过则置 `missed` 留痕(不补投——避免"半夜该做的事早上突然连环跑")。
@@ -44,7 +31,7 @@ function wakeRegistryPath(root) {
44
31
  /** 空注册表 */
45
32
  function emptyRegistry() {
46
33
  return {
47
- version: 1,
34
+ version: WAKE_REGISTRY_VERSION,
48
35
  entries: []
49
36
  };
50
37
  }
@@ -88,7 +75,7 @@ function loadWakeRegistry(root) {
88
75
  }
89
76
  return {
90
77
  registry: {
91
- version: 1,
78
+ version: WAKE_REGISTRY_VERSION,
92
79
  entries
93
80
  },
94
81
  error: null
@@ -107,7 +94,7 @@ function saveWakeRegistry(root, registry) {
107
94
  mkdirSync(dirname(path), { recursive: true });
108
95
  const tmp = `${path}.tmp`;
109
96
  writeFileSync(tmp, `${JSON.stringify({
110
- version: 1,
97
+ version: WAKE_REGISTRY_VERSION,
111
98
  entries: registry.entries
112
99
  }, null, 2)}\n`, "utf-8");
113
100
  renameSync(tmp, path);
@@ -267,4 +254,4 @@ function listWakes(root, opts = {}) {
267
254
  };
268
255
  }
269
256
  //#endregion
270
- export { splitDueWakes as a, loadWakeRegistry as i, addWake as n, updateWake as o, listWakes as r, wake_registry_exports as s, WAKE_CATCH_UP_MS as t };
257
+ export { splitDueWakes as a, loadWakeRegistry as i, addWake as n, updateWake as o, listWakes as r, WAKE_CATCH_UP_MS as t };
@@ -12,17 +12,13 @@
12
12
  *
13
13
  * 调度与投递在 `wake-scheduler.ts`(需要 ctx),本模块保持纯净。
14
14
  */
15
- /** 注册表相对 CCC 根的路径(与 `.bindings.json` 同居 AGENT_SESSIONS/) */
16
- export declare const WAKE_REGISTRY_REL_PATH = "AGENT_SESSIONS/wake-registry.json";
17
- /** 注册表格式版本(结构变更时 +1;读取端只接受本版本) */
18
- export declare const WAKE_REGISTRY_VERSION = 1;
19
15
  /**
20
16
  * 补跑窗口(缺省 2h):dsh 停机期间到期的条目,若迟到不超过本窗口则补投,
21
17
  * 超过则置 `missed` 留痕(不补投——避免"半夜该做的事早上突然连环跑")。
22
18
  */
23
19
  export declare const WAKE_CATCH_UP_MS: number;
24
20
  /** 条目状态:一次性唤醒只有这四种归宿 */
25
- export type WakeState = 'pending' | 'delivered' | 'missed' | 'cancelled';
21
+ type WakeState = 'pending' | 'delivered' | 'missed' | 'cancelled';
26
22
  /** 一条唤醒条目 */
27
23
  export interface WakeEntry {
28
24
  /** 稳定 id(不复用;`w-<UTC 到分钟>-<4 hex>`) */
@@ -47,7 +43,7 @@ export interface WakeEntry {
47
43
  deliveredAt: string | null;
48
44
  }
49
45
  /** 注册表文件形态 */
50
- export interface WakeRegistry {
46
+ interface WakeRegistry {
51
47
  version: number;
52
48
  entries: WakeEntry[];
53
49
  }
@@ -62,11 +58,6 @@ export declare function loadWakeRegistry(root: string): {
62
58
  registry: WakeRegistry;
63
59
  error: string | null;
64
60
  };
65
- /** 原子写(tmp + rename;与 .bindings.json 同款形态) */
66
- export declare function saveWakeRegistry(root: string, registry: WakeRegistry): {
67
- ok: boolean;
68
- error: string | null;
69
- };
70
61
  /** 条目 id:`w-<UTC 到分钟>-<4 hex>`(可读 + 低碰撞;不复用由"物理移除"保证) */
71
62
  export declare function newWakeId(nowMs: number, rand?: () => number): string;
72
63
  /**
@@ -144,3 +135,4 @@ export declare function listWakes(root: string, opts?: {
144
135
  entries: WakeEntry[];
145
136
  error: string | null;
146
137
  };
138
+ export {};