@shgroup/dsh-serenity-hooks 1.26.11 → 1.26.13

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
@@ -1,8 +1,8 @@
1
1
  # @shgroup/dsh-serenity-hooks
2
2
 
3
- 宁静号 ACC(Abstract Cognitive Container)harness — **DeepSeek Harness 原生 Cordis 插件**。
3
+ 宁静号 ACC(Abstract Cognitive Container)harness — **DeepSeek Harness 原生 Cordis 插件**(npm 发布单元,v1.26.11)。
4
4
 
5
- 为 DSH 会话提供认知容器基础设施:真实 DSH 工具(9 个)+ 拦截缝机械约束(safe-mode / 路径守卫 / 会话落盘)+ 系统提示词注入(ACC/CCE/Constraints/SKILL/Session 五块,对齐 opencode-serenity-plugin)+ WebUI 状态徽章。
5
+ 为 DSH 会话提供认知容器基础设施:真实 DSH 工具(12 个)+ 拦截缝机械约束(safe-mode / 路径守卫 / 凭据守卫 / 输出守卫)+ 系统提示词注入(8 块,对齐 opencode-serenity-plugin)+ WebUI 状态胶囊 + 外部访问(双端口网关 / Skiff 问答 / ACP+建议问答页)。
6
6
 
7
7
  ## 安装
8
8
 
@@ -12,29 +12,34 @@ dsh plugin --profile web add @shgroup/dsh-serenity-hooks
12
12
 
13
13
  安装后重启 dsh web。在带 `.serenity` 标记的 CCC 目录中的会话自动获得全部能力。
14
14
 
15
- ## 工具
15
+ ## 工具(12)
16
16
 
17
- `cc_fs` / `session` / `acc_kit` / `cc_git` / `acc_msm` / `eap` / `neat` / `cce` / `handyman`
17
+ `cc_fs` / `session` / `acc_kit` / `cc_git` / `acc_msm` / `eap` / `neat` / `cce` / `handyman` / `session_rebuild` / `localstore` / `skiff_admin`
18
18
 
19
- ## 系统提示词
19
+ ## 系统提示词(8 块)
20
20
 
21
- 五块注入(`systemPrompt.section`,order -50):`=== Serenity ACC ===` / `=== Serenity CCE ===` / `=== Serenity Constraints ===` / 顶层入口 skill 全文(按 `.serenity` 记号发现)/ `=== Serenity Session ===` —— 平台无关文本与 [opencode-serenity-plugin](https://github.com/tellmewhattodo/opencode-serenity-plugin) 逐字节对齐;同一 CCC 可任意换用 osp / dsh 运行时。
21
+ `systemPrompt.section`(order -50):`=== Serenity ACC ===`(身份+工具清单)/ `=== Serenity Metaphor ===`(世界模型三层隐喻)/ `=== Serenity Principles ===`(认知容器本体论 + MSM 原则)/ `=== Serenity CCE ===`(5 行为约束)/ `=== Serenity EAP ===`(E↑R↓S↑ 自检)/ 状态块(Safe Mode / Localstore)/ 顶层入口 skill 全文(按 `.serenity` 记号发现)/ `=== Serenity Session ===`(活跃会话 + Trajectory Steward 预声明)—— 平台无关文本与 [opencode-serenity-plugin](https://github.com/tellmewhattodo/opencode-serenity-plugin) 逐字节对齐;同一 CCC 可任意换用 osp / dsh 运行时。
22
22
 
23
23
  ## 配置
24
24
 
25
- `.dsh/serenity.json`(回退 `.opencode/serenity.json`):
25
+ `.opencode/serenity.json`(CCC 级):
26
26
 
27
27
  ```jsonc
28
28
  {
29
29
  "handyman": { "models": ["provider/model"], "defaultModel": "provider/model" },
30
30
  "sessionKeeper": { "threshold": 100 },
31
- "safeMode": { "blacklist": [".secrets/", "regex:\\.env$"] }
31
+ "safeMode": { "blacklist": [".secrets/", "regex:\\.env$"] },
32
+ "skiff": { "roles": { "qa": { "msms": [], "tools": [], "systemPrompt": "" } } }
32
33
  }
33
34
  ```
34
35
 
36
+ plugin 级配置(账号/开关/阈值)在 DSH 设置面板 + `~/.dsh/serenity-hooks.json`(0600)。
37
+
35
38
  ## 文档
36
39
 
37
- 完整文档见仓库 [README](https://github.com/tellmewhattodo/dsh-serenity-plugin)
40
+ - 完整文档:仓库 [README](https://github.com/tellmewhattodo/dsh-serenity-plugin)(能力为主)
41
+ - 理论叙述:`docs/cognitive-container-theory.md`
42
+ - 设计决策与架构:`CHANGELOG.md` + 维护 skill(`dsh-serenity-plugin-development`)
38
43
 
39
44
  ## 许可
40
45
 
package/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-serenity-hooks",
3
- "version": "1.26.11",
3
+ "version": "1.26.13",
4
4
  "main": "lib/index.js",
5
5
  "description": "宁静号 ACC harness(Native Cordis 插件):真实 DSH 工具 cc_fs/session/acc_msm/eap/neat/cce/handyman/session_rebuild/skiff_admin + 拦截缝机械约束(safe-mode/路径守卫)+ 高级设定面板(双端口网关/账号管理)+ Skiff 认知子集角色(实验性)。适配 DSH 公开版(0.1.0-rc,deepseek-ai/deepseek-harness)。",
6
6
  "engines": {
@@ -0,0 +1,106 @@
1
+ ---
2
+ name: autotrajectory-experiment
3
+ description: 自主轨迹实验(Self-Sustaining Trajectory Experiment)参与 skill。本 skill 让 CCC 完整理解实验的背景(人类 waiting 是 trajectory 速度瓶颈)、目的(验证"无人等待的 trajectory"能否加速认知推进)、方式(时钟唤起 + 先验偏见 + 前台运行),并提供一站式实验管理 MSM(autotrajectory-exp:无参全报告 / init 初始化 / random 验证偏见内容)。任何希望参与实验的 CCC 复制本目录到 .opencode/skills/ 即可开始。
4
+ ---
5
+
6
+ # Skill: autotrajectory-experiment
7
+
8
+ > 本 skill 是自主轨迹实验的 **CCC 参与入口**——加载本 skill 即完整理解实验的**背景、目的、方式**。
9
+ > 实验管理:`acc_msm exec autotrajectory-exp <doc|check|status|guide>`
10
+ > 理论依据:serenity-acc-specs `docs/self-sustaining-trajectory-hypothesis.md`(v0.1 猜想)
11
+
12
+ ## 触发条件/何时加载
13
+
14
+ - CCC 被选为自主轨迹实验对象时(用户指定)
15
+ - 需要理解"无人等待的 trajectory"实验的背景/目的/参与方式时
16
+ - 需要预检/查看实验配置时
17
+
18
+ ---
19
+
20
+ ## 1. 背景:为什么有这个实验
21
+
22
+ 认知容器理论(specs §0)确立:**Trajectory 是主体**(Agent 可替换、Session 载体可重建、LLM 是认知介质);认知容器 = 发生/存储/再发生的地方。
23
+
24
+ 由此观察到**结构性瓶颈**:
25
+
26
+ > **人类 waiting 拖慢 trajectory**:当轨迹以"等待人类"为推进条件时,其事件序列时间被人类响应间隔(钟表时间)锚定。等待人类 = 轨迹空转——人类响应越慢,轨迹运转越慢。
27
+
28
+ **猜想**:设计"无人等待"的 trajectory——不依赖人类输入而自动唤起,唤起时携带先验偏见(自主动机)。若成立,轨迹运转速度提升,更快产生让人类满意的效果。
29
+
30
+ ## 2. 实验目的(验证什么)
31
+
32
+ | 命题 | 内容 |
33
+ |------|------|
34
+ | P4 | 无人等待的 trajectory 可以时钟驱动自动唤起并携带先验偏见(自生+随机) |
35
+ | P5 | 轨迹运转速度提升 → 更快产生让人类满意的效果 |
36
+ | 反证 | 熵增失控 / 自我确认循环 / 随机噪音化 / 资源无界 / 反馈脱节——任一显著 → 猜想不成立 |
37
+
38
+ ## 3. 参与方式(CCC 侧三步——第一步可一键 init)
39
+
40
+ ### ① 初始化(一键):`acc_msm exec autotrajectory-exp init`
41
+
42
+ 自动完成:写配置(`.opencode/serenity.json` autotrajectory 段)+ 生成偏见提供者脚本模板(CCC 根 `autotrajectory-bias.ts`)。
43
+
44
+ ```jsonc
45
+ // 写入的配置(init 后可在 .opencode/serenity.json 查看/调整)
46
+ {
47
+ "autotrajectory": {
48
+ "enabled": true, // 总开关(缺省 false,默认关零资源占用)
49
+ "intervalHours": 12, // 无人类活动 N 小时后唤起(缺省 12)
50
+ "biasProvider": "autotrajectory-bias.ts", // 偏见内容提供者脚本(CCC 根下)
51
+ "avoidWakeHours": { "start": 8, "end": 18 } // 可选:避开北京高峰(缺省 8~18 省钱)
52
+ }
53
+ }
54
+ ```
55
+
56
+ ### ② 实现偏见内容提供者(`autotrajectory-bias.ts`)
57
+
58
+ CCC 根目录下一个脚本,**stdout 输出本轮唤起注入的偏见内容**(反事实问题/探索方向/任何让轨迹偏离既有路径的输入)。**偏见内容归 CCC**——用本 CCC 自己的反馈信息来源保证"足够随机"。`acc_msm exec autotrajectory-exp random` 可验证输出。
59
+
60
+ ### ③ 标记目标会话(可选自生动机段)
61
+
62
+ - 目标会话目录名加 `--auto` 后缀:`AGENT_SESSIONS/<date>--<desc>--auto/`——**只有带标志的轨迹走自主形态**,同 CCC 其他会话不受影响
63
+ - 可选:该 SESSION.md 写「下一轮动机」段(上一轮预写 → 下一轮唤起的自生偏见)
64
+
65
+ ## 4. 机制运行(dsp 侧,CCC 无需干预)
66
+
67
+ ```
68
+ 定时器(每 10min)→ 唤起条件全满足 →
69
+ ① 运行 <biasProvider> 脚本 → stdout = 偏见内容(CCC 自定)
70
+ ② 读 SESSION.md「下一轮动机」段 → 自生动机
71
+ ③ 定位活跃会话 agent → 注入唤起消息(前台运行——用户全程可见、随时可介入)
72
+ → 模型自动继续:探索/反事实检验 → 产出落 SESSION.md「自主探索日志」+ 预写「下一轮动机」
73
+ ```
74
+
75
+ **唤起条件**(全部满足):① enabled ② 会话目录 `--auto` ③ SESSION.md mtime 距今 > intervalHours ④ 北京时间非高峰(缺省避开 8~18)⑤ 无运行中的唤起轮。**偏见提供者脚本缺失 → 唤起中止并报错要求实现**(不静默)。
76
+
77
+ **人类角色**:不触发、不中断;回复/评价天然并入(同一前台会话);轨迹不等人类。
78
+
79
+ ## 5. 实验管理(autotrajectory-exp MSM)——一站式
80
+
81
+ | 用法 | 功能 |
82
+ |------|------|
83
+ | `acc_msm exec autotrajectory-exp`(**推荐,无参**) | **一站式全报告**:背景摘要 + 就绪度检查 + 当前状态 + 下一步指引 + 步骤——CCC agent 看一次即完整理解并知道怎么开始 |
84
+ | `acc_msm exec autotrajectory-exp init` | **一键初始化**:写配置 + 生成偏见提供者脚本模板(CCC 根 autotrajectory-bias.ts) |
85
+ | `acc_msm exec autotrajectory-exp random` | 运行偏见提供者脚本,输出当前偏见内容(验证) |
86
+ | `acc_msm exec autotrajectory-exp doc` | 实验定义说明全文(本 SKILL.md) |
87
+ | `acc_msm exec autotrajectory-exp check` | 仅就绪度检查(配置/偏见提供者/--auto 标志/动机段) |
88
+ | `acc_msm exec autotrajectory-exp status` | 仅当前状态(配置快照/目标会话/距上次活动/唤起窗口/可唤起性) |
89
+ | `acc_msm exec autotrajectory-exp guide` | 仅步骤指引 |
90
+
91
+ ## 6. 观察与验证
92
+
93
+ - **观察**:无人类活动满 intervalHours 且非高峰 → 前台会话自动出现 `[自主轨迹唤起]` 消息(可见可介入)
94
+ - **验证阶段**:A 机制可行性(3~5 轮)→ B 速度对比(72h 有/无等待)→ C 质量与熵(人类评审 + H_op)→ D 长期(数周,检验自我确认/熵增)
95
+ - **成功判据**:自主轮产出有意义的比例 ≥ 阈值,且 H_op 维持可运转
96
+
97
+ ## 7. 边界
98
+
99
+ - 本实验**非标准条款**——不修改 Serenity-ACC 标准正文;验证成立后才评估进入标准演化议程
100
+ - 默认关闭;未配置 = 零资源占用;不触碰 CCC 其他会话/机制
101
+
102
+ ## 相关
103
+
104
+ - 猜想全文:serenity-acc-specs `docs/self-sustaining-trajectory-hypothesis.md`
105
+ - 机制定义:dsh-serenity-plugin `docs/autotrajectory-experiment.md`
106
+ - 标准理论:serenity-acc-specs README §0
@@ -0,0 +1,383 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * autotrajectory-exp.ts — 自主轨迹实验管理 MSM(Mech,纯 TS 零 LLM 决策)——一站式
4
+ *
5
+ * 一个 tool 整合实验全部所需:
6
+ * acc_msm exec autotrajectory-exp → 一站式全报告(背景 + 就绪 + 状态 + 下一步)
7
+ * acc_msm exec autotrajectory-exp init → 初始化实验(写配置 + 生成偏见提供者脚本模板)
8
+ * acc_msm exec autotrajectory-exp random → 运行偏见提供者脚本,输出当前偏见内容(验证)
9
+ * acc_msm exec autotrajectory-exp doc → 实验定义说明全文(SKILL.md)
10
+ * acc_msm exec autotrajectory-exp check → 仅就绪度检查
11
+ * acc_msm exec autotrajectory-exp status → 仅当前状态
12
+ * acc_msm exec autotrajectory-exp guide → 仅步骤指引
13
+ *
14
+ * 概念(用户拍板命名):偏见内容提供者(bias provider)——CCC 根目录下一个脚本,
15
+ * stdout 输出本轮唤起要注入的偏见内容(反事实方向/探索动机等)。tool 直接运行它;
16
+ * 脚本缺失 → 报错要求实现(不再经 mech-registry 注册 MSM)。
17
+ *
18
+ * 零 DSH 依赖,任何 CCC 可运行。环境:SERENITY_ROOT(acc_msm exec 注入)或 cwd 上溯 .serenity。
19
+ */
20
+
21
+ import { existsSync, readFileSync, statSync, readdirSync, writeFileSync, mkdirSync } from 'node:fs'
22
+ import { join, resolve, basename, dirname } from 'node:path'
23
+ import { spawnSync } from 'node:child_process'
24
+
25
+ const DEFAULT_BIAS_PROVIDER = 'autotrajectory-bias.ts'
26
+ const AUTO_SUFFIX = '--auto'
27
+ const MOTIVATION_MARKER = '下一轮动机'
28
+ const CONFIG_PATHS = ['.opencode/serenity.json', '.dsh/serenity.json']
29
+
30
+ /** 偏见内容提供者脚本脚手架模板(init 生成;CCC 按自己的反馈信息来源改写) */
31
+ const BIAS_TEMPLATE = `#!/usr/bin/env bun
32
+ /**
33
+ * autotrajectory-bias.ts — 自主轨迹偏见内容提供者(CCC 实现)
34
+ *
35
+ * stdout 输出一行/一段文本 = 本轮唤起注入的偏见内容(反事实问题 / 探索方向 /
36
+ * 任何让轨迹偏离既有路径的输入)。偏见内容归 CCC——用本 CCC 自己的反馈信息来源
37
+ * 保证"足够随机"(历史会话 / 技能 / 文档 / 外部信息 / 真随机源……)。
38
+ *
39
+ * 本文件为脚手架——请按本 CCC 的信息来源改写。
40
+ */
41
+ const sources = [
42
+ 'AGENT_SESSIONS 中的历史会话',
43
+ '.opencode/skills 技能目录',
44
+ 'docs/ 设计文档',
45
+ '…(CCC 自己的信息来源)',
46
+ ]
47
+ const pick = sources[Math.floor(Math.random() * sources.length)]
48
+ console.log(\`反事实:如果「\${pick}」换个做法会怎样?\`)
49
+ `
50
+
51
+ /** 背景摘要(一站式的第一节——CCC agent 快速理解"为什么/验证什么") */
52
+ const BACKGROUND = [
53
+ '═══ 自主轨迹实验(Self-Sustaining Trajectory)═══',
54
+ '背景:Trajectory 是主体(Agent 可替换、Session 载体可重建)。瓶颈 = 人类 waiting——',
55
+ ' 轨迹以"等待人类"为推进条件时,事件序列时间被人类响应间隔锚定,运转被拖慢。',
56
+ '猜想:无人等待的 trajectory——时钟自动唤起 + 先验偏见(自生动机 + 偏见内容)→ 运转加速。',
57
+ '验证:P4 可自动唤起并携带偏见 / P5 速度提升→更快产生满意效果;反证=熵增失控/自我确认/噪音化。',
58
+ '理论:specs §0.7 记录器→校准器(预测加工)。完整定义:doc(SKILL.md)。',
59
+ '',
60
+ ].join('\n')
61
+
62
+ interface AutoConfig {
63
+ enabled?: boolean
64
+ intervalHours?: number
65
+ biasProvider?: string
66
+ session?: string
67
+ avoidWakeHours?: { start?: number; end?: number }
68
+ }
69
+
70
+ // ── 基础设施 ──
71
+
72
+ function findRoot(): string | null {
73
+ const fromEnv = process.env.SERENITY_ROOT
74
+ if (fromEnv && existsSync(join(fromEnv, '.serenity'))) return fromEnv
75
+ let cur = resolve(process.cwd())
76
+ while (true) {
77
+ if (existsSync(join(cur, '.serenity'))) return cur
78
+ const parent = dirname(cur)
79
+ if (parent === cur) return null
80
+ cur = parent
81
+ }
82
+ }
83
+
84
+ function readUtf8(p: string): string {
85
+ return readFileSync(p, 'utf-8').replace(/^\uFEFF/, '')
86
+ }
87
+
88
+ function loadConfig(root: string): AutoConfig | null {
89
+ for (const rel of CONFIG_PATHS) {
90
+ const p = join(root, rel)
91
+ if (!existsSync(p)) continue
92
+ try {
93
+ const cfg = JSON.parse(readUtf8(p)) as { autotrajectory?: AutoConfig }
94
+ return cfg.autotrajectory ?? null
95
+ } catch {
96
+ return null
97
+ }
98
+ }
99
+ return null
100
+ }
101
+
102
+ /** 偏见提供者脚本绝对路径(根内强制——逃逸拒绝) */
103
+ function biasProviderPath(root: string, providerRel: string): string {
104
+ const rootAbs = resolve(root)
105
+ const abs = resolve(root, providerRel)
106
+ if (abs !== rootAbs && !abs.startsWith(rootAbs + '/')) {
107
+ throw new Error(`biasProvider 路径逃逸(须在 CCC 根内): ${providerRel}`)
108
+ }
109
+ return abs
110
+ }
111
+
112
+ /** 运行偏见提供者脚本(bun 优先,node 兜底),返回偏见内容或错误信息 */
113
+ function runBiasProvider(root: string, providerRel: string): { text: string | null; error: string | null } {
114
+ let scriptAbs: string
115
+ try {
116
+ scriptAbs = biasProviderPath(root, providerRel)
117
+ } catch (e) {
118
+ return { text: null, error: String((e as Error).message) }
119
+ }
120
+ if (!existsSync(scriptAbs)) {
121
+ return { text: null, error: `请在 CCC 根目录实现偏见内容提供者脚本: ${providerRel}(acc_msm exec autotrajectory-exp init 可生成模板)` }
122
+ }
123
+ for (const cmd of ['bun', process.execPath]) {
124
+ try {
125
+ const r = spawnSync(cmd, [scriptAbs], { encoding: 'utf-8', timeout: 600_000, stdio: ['ignore', 'pipe', 'pipe'] })
126
+ if (r.status === 0) {
127
+ const text = (r.stdout ?? '').trim()
128
+ return { text: text || null, error: null }
129
+ }
130
+ if ((r.error as NodeJS.ErrnoException | undefined)?.code === 'ENOENT') continue
131
+ return { text: null, error: `偏见内容提供者脚本执行失败(exit ${r.status ?? '?'}): ${r.stderr?.trim() || r.stdout?.trim() || ''}` }
132
+ } catch {
133
+ continue
134
+ }
135
+ }
136
+ return { text: null, error: '偏见内容提供者脚本无法运行(bun 与 node 均不可用)' }
137
+ }
138
+
139
+ /** 目标 SESSION.md:**session 必填**(S###/目录名匹配)——自动唤起不默认任何会话(CCC 日常多轨迹并行);未配置/未命中 → null */
140
+ function resolveTargetMd(root: string, cfg: AutoConfig): string | null {
141
+ if (!cfg?.session) return null
142
+ const sessionsDir = join(root, 'AGENT_SESSIONS')
143
+ if (!existsSync(sessionsDir)) return null
144
+ const dirs = readdirSync(sessionsDir, { withFileTypes: true })
145
+ .filter((d) => d.isDirectory())
146
+ .map((d) => join(sessionsDir, d.name))
147
+ for (const d of dirs) {
148
+ const md = join(d, 'SESSION.md')
149
+ if (existsSync(md) && basename(d).includes(cfg.session)) return md
150
+ }
151
+ return null
152
+ }
153
+
154
+ function beijingHour(nowMs: number): number {
155
+ return Math.floor(((nowMs + 8 * 3600_000) % 86400_000) / 3600_000)
156
+ }
157
+
158
+ function inAllowedWindow(nowMs: number, avoid?: { start?: number; end?: number }): boolean {
159
+ const start = avoid?.start ?? 8
160
+ const end = avoid?.end ?? 18
161
+ const h = beijingHour(nowMs)
162
+ if (start <= end) return h < start || h >= end
163
+ return h >= end && h < start
164
+ }
165
+
166
+ // ── 子命令实现 ──
167
+
168
+ function doc(root: string): string {
169
+ const p = join(dirname(process.argv[1] ?? ''), '..', 'SKILL.md')
170
+ if (existsSync(p)) return readUtf8(p)
171
+ return `SKILL.md 未找到(${p})——实验定义见 serenity-acc-specs docs/self-sustaining-trajectory-hypothesis.md §7.1`
172
+ }
173
+
174
+ function check(root: string): string {
175
+ const cfg = loadConfig(root)
176
+ const lines: string[] = [`[autotrajectory-exp] 实验就绪度检查(CCC: ${basename(root)})`, '']
177
+ const fail: string[] = []
178
+
179
+ if (!cfg) {
180
+ lines.push('✗ 未配置 autotrajectory(.opencode/serenity.json 缺段)——acc_msm exec autotrajectory-exp init 一键初始化')
181
+ fail.push('config')
182
+ } else if (!cfg.enabled) {
183
+ lines.push('✗ autotrajectory.enabled = false(未开启)')
184
+ fail.push('enabled')
185
+ } else {
186
+ lines.push(`✓ enabled = true`)
187
+ lines.push(` intervalHours = ${cfg.intervalHours ?? 12}`)
188
+ lines.push(` biasProvider = ${cfg.biasProvider?.trim() || DEFAULT_BIAS_PROVIDER}`)
189
+ if (cfg.session) lines.push(` session = ${cfg.session}`)
190
+ const avoid = cfg.avoidWakeHours
191
+ lines.push(` 唤起窗口避开北京 ${avoid?.start ?? 8}~${avoid?.end ?? 18} 点(用量峰谷省钱)`)
192
+ }
193
+
194
+ const provider = cfg?.biasProvider?.trim() || DEFAULT_BIAS_PROVIDER
195
+ if (cfg?.enabled) {
196
+ const bias = runBiasProvider(root, provider)
197
+ if (bias.error) {
198
+ lines.push(`✗ 偏见内容提供者未就绪: ${bias.error}`)
199
+ fail.push('biasProvider')
200
+ } else {
201
+ lines.push(`✓ 偏见内容提供者可运行(输出示例: ${bias.text ?? '(空输出)'})`)
202
+ }
203
+ }
204
+
205
+ const md = resolveTargetMd(root, cfg ?? {})
206
+ if (!cfg?.session) {
207
+ lines.push('✗ 未配置 session(必填——自动唤起不默认任何会话,CCC 日常多轨迹并行)')
208
+ fail.push('session')
209
+ } else if (md) {
210
+ const flag = basename(dirname(md)).endsWith(AUTO_SUFFIX)
211
+ lines.push(`${flag ? '✓' : '✗'} 目标会话目录${flag ? '带' : '未带'} --auto 标志:${basename(dirname(md))}`)
212
+ if (!flag) {
213
+ lines.push(` → 目录名需以 --auto 结尾(AGENT_SESSIONS/<date>--<desc>--auto/)`)
214
+ fail.push('autoFlag')
215
+ }
216
+ const content = readUtf8(md)
217
+ if (content.includes(MOTIVATION_MARKER)) {
218
+ lines.push(`✓ SESSION.md 含「下一轮动机」段(自生偏见)`)
219
+ } else {
220
+ lines.push(`· SESSION.md 无「下一轮动机」段(可选——纯偏见内容亦可)`)
221
+ }
222
+ } else {
223
+ lines.push(`✗ 目标会话未命中:${cfg.session}(AGENT_SESSIONS 无匹配目录)`)
224
+ fail.push('session')
225
+ }
226
+
227
+ lines.push('')
228
+ lines.push(fail.length === 0 ? '✅ 实验就绪——等待时钟唤起(前台可见)' : `⚠️ 未就绪:${fail.join(', ')}`)
229
+ return lines.join('\n')
230
+ }
231
+
232
+ function status(root: string): string {
233
+ const cfg = loadConfig(root)
234
+ const now = Date.now()
235
+ const lines: string[] = [`[autotrajectory-exp] 实验状态(CCC: ${basename(root)},北京 ${beijingHour(now)} 点)`, '']
236
+ if (!cfg?.enabled) {
237
+ lines.push('autotrajectory 未启用(enabled=false 或未配置)——零资源占用')
238
+ return lines.join('\n')
239
+ }
240
+ lines.push(`配置: intervalHours=${cfg.intervalHours ?? 12} | biasProvider=${cfg.biasProvider?.trim() || DEFAULT_BIAS_PROVIDER}${cfg.session ? ` | session=${cfg.session}` : ''}`)
241
+ const md = resolveTargetMd(root, cfg)
242
+ if (!md) {
243
+ lines.push('目标会话:未找到')
244
+ return lines.join('\n')
245
+ }
246
+ const mtime = statSync(md).mtimeMs
247
+ const idleHours = (now - mtime) / 3600_000
248
+ const interval = Math.max(1, cfg.intervalHours ?? 12)
249
+ lines.push(`目标会话:${basename(dirname(md))}${basename(dirname(md)).endsWith(AUTO_SUFFIX) ? '(--auto ✓)' : '(无 --auto 标志)'}`)
250
+ lines.push(`上次轨迹活动:${idleHours.toFixed(1)} 小时前(阈值 ${interval}h)`)
251
+ lines.push(`唤起窗口:${inAllowedWindow(now, cfg.avoidWakeHours) ? '✅ 允许唤起' : '⏸ 高峰避开中(北京 8~18)'}`)
252
+ const wakeable = inAllowedWindow(now, cfg.avoidWakeHours) && idleHours >= interval
253
+ lines.push(`是否可唤起:${wakeable ? '✅ 是(等待下一个 10min tick)' : idleHours < interval ? `否——距上次活动不足 ${interval}h` : '否——高峰避开中'}`)
254
+ return lines.join('\n')
255
+ }
256
+
257
+ function guide(): string {
258
+ return [
259
+ '[autotrajectory-exp] 实验步骤指引',
260
+ '',
261
+ '① 初始化(一键):acc_msm exec autotrajectory-exp init',
262
+ ' ——写配置(.opencode/serenity.json autotrajectory 段)+ 生成偏见提供者脚本模板(CCC 根 autotrajectory-bias.ts)',
263
+ '② 实现偏见内容提供者:编辑 autotrajectory-bias.ts,stdout 输出偏见内容(反事实方向/探索动机,',
264
+ ' 用本 CCC 自己的信息来源保证"足够随机");acc_msm exec autotrajectory-exp random 验证',
265
+ '③ 标记目标会话:目录名加 --auto 后缀 AGENT_SESSIONS/<date>--<desc>--auto/',
266
+ ' (可选)该 SESSION.md 写「下一轮动机」段作自生偏见',
267
+ '④ 验证就绪:acc_msm exec autotrajectory-exp(一站式报告应为 ✅)',
268
+ '⑤ 观察:无人类活动满 intervalHours 且北京非高峰 → 前台会话自动出现 [自主轨迹唤起]',
269
+ ' 产出落 SESSION.md「自主探索日志」+ 预写「下一轮动机」',
270
+ '',
271
+ '完整定义见 SKILL.md(acc_msm exec autotrajectory-exp doc)',
272
+ ].join('\n')
273
+ }
274
+
275
+ /** 初始化:合并写配置(不覆盖其他段)+ 生成偏见提供者脚本模板(已存在则跳过) */
276
+ function init(root: string): string {
277
+ const out: string[] = ['[autotrajectory-exp] 初始化实验', '']
278
+
279
+ // ① 写配置
280
+ let cfgPath = join(root, CONFIG_PATHS[0]!)
281
+ if (!existsSync(cfgPath)) {
282
+ const alt = join(root, CONFIG_PATHS[1]!)
283
+ cfgPath = existsSync(alt) ? alt : cfgPath
284
+ }
285
+ mkdirSync(dirname(cfgPath), { recursive: true })
286
+ let merged: Record<string, unknown> = {}
287
+ if (existsSync(cfgPath)) {
288
+ try {
289
+ merged = JSON.parse(readUtf8(cfgPath)) as Record<string, unknown>
290
+ } catch {
291
+ /* 损坏则重建 */
292
+ }
293
+ }
294
+ const at = (merged.autotrajectory as Record<string, unknown> | undefined) ?? {}
295
+ merged.autotrajectory = {
296
+ enabled: true,
297
+ intervalHours: 12,
298
+ biasProvider: DEFAULT_BIAS_PROVIDER,
299
+ ...at,
300
+ }
301
+ writeFileSync(cfgPath, `${JSON.stringify(merged, null, 2)}\n`)
302
+ out.push(`✓ 配置写入: ${cfgPath}`)
303
+ out.push(` autotrajectory = ${JSON.stringify(merged.autotrajectory)}`)
304
+
305
+ // ② 生成偏见提供者脚本模板
306
+ const scriptAbs = biasProviderPath(root, DEFAULT_BIAS_PROVIDER)
307
+ if (existsSync(scriptAbs)) {
308
+ out.push(`· 偏见提供者脚本已存在(保留): ${DEFAULT_BIAS_PROVIDER}`)
309
+ } else {
310
+ writeFileSync(scriptAbs, BIAS_TEMPLATE)
311
+ out.push(`✓ 已生成偏见提供者脚本模板: ${DEFAULT_BIAS_PROVIDER}(编辑它,stdout 输出偏见内容)`)
312
+ }
313
+
314
+ out.push('', '下一步:③ 标记目标会话 --auto 后缀 → ④ acc_msm exec autotrajectory-exp 验证就绪')
315
+ return out.join('\n')
316
+ }
317
+
318
+ /** random:运行偏见提供者脚本,输出当前偏见内容(验证) */
319
+ function random(root: string): string {
320
+ const cfg = loadConfig(root)
321
+ const provider = cfg?.biasProvider?.trim() || DEFAULT_BIAS_PROVIDER
322
+ const bias = runBiasProvider(root, provider)
323
+ if (bias.error) return `[autotrajectory-exp] ✗ ${bias.error}`
324
+ return `[autotrajectory-exp] 当前偏见内容(${provider}):\n${bias.text ?? '(空输出)'}`
325
+ }
326
+
327
+ /** 一站式全报告:背景 + 就绪检查 + 状态 + 下一步 + 指引(CCC agent 看一次即懂并知道下一步) */
328
+ function all(root: string): string {
329
+ const cfg = loadConfig(root)
330
+ const ready = check(root)
331
+ const stat = status(root)
332
+ const next: string[] = ['═══ 下一步 ═══']
333
+ if (!cfg) {
334
+ next.push('→ 本 CCC 尚未配置 autotrajectory。开始实验:acc_msm exec autotrajectory-exp init 一键初始化。')
335
+ } else if (!cfg.enabled) {
336
+ next.push('→ autotrajectory.enabled 为 false——置 true 开启实验(或 init 重新初始化)。')
337
+ } else if (ready.includes('✗')) {
338
+ next.push('→ 存在未就绪项(见上)。补齐后重跑本命令确认 ✅。')
339
+ } else {
340
+ next.push('→ 已就绪 ✅。保持会话空闲满 intervalHours 且北京非高峰 → 自动唤起(前台可见)。')
341
+ next.push('→ 之后可随时 acc_msm exec autotrajectory-exp status 查看距下次唤起的进度。')
342
+ }
343
+ return [BACKGROUND, ready, '', stat, '', next.join('\n'), '', guide()].join('\n')
344
+ }
345
+
346
+ function main(): void {
347
+ const cmd = process.argv[2] ?? 'all'
348
+ const root = findRoot()
349
+ if (!root) {
350
+ console.error('[autotrajectory-exp] ✗ 未找到 CCC 根(无 .serenity;acc_msm exec 会自动注入 SERENITY_ROOT)')
351
+ process.exit(1)
352
+ }
353
+ switch (cmd) {
354
+ case 'all':
355
+ console.log(all(root))
356
+ break
357
+ case 'init':
358
+ console.log(init(root))
359
+ break
360
+ case 'random':
361
+ console.log(random(root))
362
+ break
363
+ case 'doc':
364
+ console.log(doc(root))
365
+ break
366
+ case 'check':
367
+ console.log(check(root))
368
+ break
369
+ case 'status':
370
+ console.log(status(root))
371
+ break
372
+ case 'guide':
373
+ console.log(guide())
374
+ break
375
+ default:
376
+ console.error(`[autotrajectory-exp] 未知子命令: ${cmd}(可用: 无参一站式 / init / random / doc / check / status / guide)`)
377
+ process.exit(2)
378
+ }
379
+ }
380
+
381
+ if (import.meta.main) {
382
+ main()
383
+ }
package/lib/index.js CHANGED
@@ -522,10 +522,10 @@ function runCcFs(root, args) {
522
522
  * 进程内注册(取代 v0.1 的 bash spawn runner):zod/schemastery 参数校验、
523
523
  * 规范 JSON 输出、纯 render 投影。逻辑在 fs-ops.ts(可单测)。
524
524
  */
525
- function agentCwd$9(exec) {
525
+ function agentCwd$10(exec) {
526
526
  return exec.agent?.session?.header?.cwd ?? process.cwd();
527
527
  }
528
- function renderText$11(value) {
528
+ function renderText$12(value) {
529
529
  return [{
530
530
  type: "text",
531
531
  text: typeof value === "string" ? value : JSON.stringify(value, null, 2)
@@ -597,10 +597,10 @@ const ccFsTool = defineTool({
597
597
  },
598
598
  output: {
599
599
  schema: { type: "json" },
600
- render: (args, value) => renderText$11(value)
600
+ render: (args, value) => renderText$12(value)
601
601
  },
602
602
  async execute(args, exec) {
603
- const root = findSerenityRoot(agentCwd$9(exec));
603
+ const root = findSerenityRoot(agentCwd$10(exec));
604
604
  if (!root) throw new Error("No CCC found: no .serenity file from agent cwd");
605
605
  return runCcFs(root, args);
606
606
  }
@@ -1128,10 +1128,10 @@ async function runKit(root, args) {
1128
1128
  /**
1129
1129
  * kit.ts — acc_kit 真实 DSH 工具定义(defineTool)
1130
1130
  */
1131
- function agentCwd$8(exec) {
1131
+ function agentCwd$9(exec) {
1132
1132
  return exec.agent?.session?.header?.cwd ?? process.cwd();
1133
1133
  }
1134
- function renderText$10(value) {
1134
+ function renderText$11(value) {
1135
1135
  return [{
1136
1136
  type: "text",
1137
1137
  text: typeof value === "string" ? value : JSON.stringify(value, null, 2)
@@ -1154,10 +1154,10 @@ const kitTool = defineTool({
1154
1154
  },
1155
1155
  output: {
1156
1156
  schema: { type: "json" },
1157
- render: (args, value) => renderText$10(value)
1157
+ render: (args, value) => renderText$11(value)
1158
1158
  },
1159
1159
  async execute(args, exec) {
1160
- return await runKit(findSerenityRoot(agentCwd$8(exec)), args);
1160
+ return await runKit(findSerenityRoot(agentCwd$9(exec)), args);
1161
1161
  }
1162
1162
  });
1163
1163
  //#endregion
@@ -1617,10 +1617,10 @@ function runGit(root, args) {
1617
1617
  /**
1618
1618
  * git.ts — cc_git 真实 DSH 工具定义(defineTool)
1619
1619
  */
1620
- function agentCwd$7(exec) {
1620
+ function agentCwd$8(exec) {
1621
1621
  return exec.agent?.session?.header?.cwd ?? process.cwd();
1622
1622
  }
1623
- function renderText$9(value) {
1623
+ function renderText$10(value) {
1624
1624
  return [{
1625
1625
  type: "text",
1626
1626
  text: typeof value === "string" ? value : JSON.stringify(value, null, 2)
@@ -1659,10 +1659,10 @@ const gitTool = defineTool({
1659
1659
  },
1660
1660
  output: {
1661
1661
  schema: { type: "json" },
1662
- render: (args, value) => renderText$9(value)
1662
+ render: (args, value) => renderText$10(value)
1663
1663
  },
1664
1664
  async execute(args, exec) {
1665
- const root = findSerenityRoot(agentCwd$7(exec));
1665
+ const root = findSerenityRoot(agentCwd$8(exec));
1666
1666
  if (!root) throw new Error("No CCC found: no .serenity file from agent cwd");
1667
1667
  return runGit(root, args);
1668
1668
  }
@@ -2407,7 +2407,7 @@ function listActiveHandymen(root) {
2407
2407
  }
2408
2408
  //#endregion
2409
2409
  //#region src/skiff-core.ts
2410
- const PLUGIN_SOURCE$4 = {
2410
+ const PLUGIN_SOURCE$5 = {
2411
2411
  kind: "plugin",
2412
2412
  plugin: "dsh-serenity-hooks"
2413
2413
  };
@@ -2577,7 +2577,7 @@ async function askSkiff(ctx, agent, question, eventsStart, options) {
2577
2577
  type: "text",
2578
2578
  text: question
2579
2579
  }],
2580
- source: PLUGIN_SOURCE$4
2580
+ source: PLUGIN_SOURCE$5
2581
2581
  }));
2582
2582
  await waitIdle$1(ctx, agent);
2583
2583
  const answer = lastAssistantText$2(agent);
@@ -2622,13 +2622,13 @@ function skiffMsmGate(root, sessionId, action, name) {
2622
2622
  /**
2623
2623
  * msm.ts — acc_msm 真实 DSH 工具定义(defineTool)
2624
2624
  */
2625
- function agentCwd$6(exec) {
2625
+ function agentCwd$7(exec) {
2626
2626
  return exec.agent?.session?.header?.cwd ?? process.cwd();
2627
2627
  }
2628
2628
  function agentSessionId$1(exec) {
2629
2629
  return exec.agent?.session?.id ?? "";
2630
2630
  }
2631
- function renderText$8(value) {
2631
+ function renderText$9(value) {
2632
2632
  return [{
2633
2633
  type: "text",
2634
2634
  text: typeof value === "string" ? value : JSON.stringify(value, null, 2)
@@ -2680,10 +2680,10 @@ const msmTool = defineTool({
2680
2680
  },
2681
2681
  output: {
2682
2682
  schema: { type: "json" },
2683
- render: (args, value) => renderText$8(value)
2683
+ render: (args, value) => renderText$9(value)
2684
2684
  },
2685
2685
  async execute(args, exec) {
2686
- const root = findSerenityRoot(agentCwd$6(exec));
2686
+ const root = findSerenityRoot(agentCwd$7(exec));
2687
2687
  if (!root) throw new Error("No CCC found: no .serenity file from agent cwd");
2688
2688
  const gate = skiffMsmGate(root, agentSessionId$1(exec), args.action, args.name);
2689
2689
  if (gate.reject) throw new Error(gate.reject);
@@ -2733,7 +2733,7 @@ CCC (home-serenity etc.) encodes cognitive content as skills/SESSIONs/design doc
2733
2733
 
2734
2734
  ## Reference
2735
2735
  https://github.com/tellmewhattodo/theory-eap`;
2736
- function renderText$7(value) {
2736
+ function renderText$8(value) {
2737
2737
  return [{
2738
2738
  type: "text",
2739
2739
  text: typeof value === "string" ? value : JSON.stringify(value, null, 2)
@@ -2753,7 +2753,7 @@ const eapTool = defineTool({
2753
2753
  } },
2754
2754
  output: {
2755
2755
  schema: { type: "string" },
2756
- render: (_args, value) => renderText$7(value)
2756
+ render: (_args, value) => renderText$8(value)
2757
2757
  },
2758
2758
  async execute(args) {
2759
2759
  if (args.section === "variables") return EAP_CONTENT.split("## Pre-Output Self-Check Checklist")[0];
@@ -2794,7 +2794,7 @@ Requirements → Scope → Solution → Interface → Implementation
2794
2794
  2. Wait for confirmation or correction (small step)
2795
2795
  3. After confirmation, record the decision (into session SESSION.md or a design doc)
2796
2796
  4. Move to the next decision point`;
2797
- function renderText$6(value) {
2797
+ function renderText$7(value) {
2798
2798
  return [{
2799
2799
  type: "text",
2800
2800
  text: typeof value === "string" ? value : JSON.stringify(value, null, 2)
@@ -2810,7 +2810,7 @@ const neatTool = defineTool({
2810
2810
  } },
2811
2811
  output: {
2812
2812
  schema: { type: "string" },
2813
- render: (_args, value) => renderText$6(value)
2813
+ render: (_args, value) => renderText$7(value)
2814
2814
  },
2815
2815
  async execute(args) {
2816
2816
  if (args.section === "rules") return NEAT_CONTENT.match(/## Four Iron Rules[\s\S]*?(?=## )/)?.[0] ?? NEAT_CONTENT;
@@ -2873,7 +2873,7 @@ CCE answers "how structured knowledge should keep evolving across time without l
2873
2873
  ## Relationship with Serenity
2874
2874
  Serenity's session system, session tracking, and entropy management mechanisms (SQC quality loop) are all engineering implementations of CCE;
2875
2875
  the behavioral constraints embedded in CCC system prompts come from CCE.`;
2876
- function renderText$5(value) {
2876
+ function renderText$6(value) {
2877
2877
  return [{
2878
2878
  type: "text",
2879
2879
  text: typeof value === "string" ? value : JSON.stringify(value, null, 2)
@@ -2894,7 +2894,7 @@ const cceTool = defineTool({
2894
2894
  } },
2895
2895
  output: {
2896
2896
  schema: { type: "string" },
2897
- render: (_args, value) => renderText$5(value)
2897
+ render: (_args, value) => renderText$6(value)
2898
2898
  },
2899
2899
  async execute(args) {
2900
2900
  const section = args.section;
@@ -2965,10 +2965,10 @@ function handymanPresetInheritance(parentCtx) {
2965
2965
  * preset 继承 + 工具收窄:setup 钩子里对子 agent 执行 agentPresets.composeFrom(对齐
2966
2966
  * subagent 先例)+ tools.restrict deny handyman(worker 内部看不到 handyman 工具)。
2967
2967
  */
2968
- function agentCwd$5(exec) {
2968
+ function agentCwd$6(exec) {
2969
2969
  return (exec.agent?.session)?.header?.cwd ?? process.cwd();
2970
2970
  }
2971
- function renderText$4(value) {
2971
+ function renderText$5(value) {
2972
2972
  return [{
2973
2973
  type: "text",
2974
2974
  text: typeof value === "string" ? value : JSON.stringify(value, null, 2)
@@ -3185,11 +3185,11 @@ function createHandymanTool(ctx) {
3185
3185
  },
3186
3186
  output: {
3187
3187
  schema: { type: "json" },
3188
- render: (_args, value) => renderText$4(value)
3188
+ render: (_args, value) => renderText$5(value)
3189
3189
  },
3190
3190
  async execute(args, exec) {
3191
3191
  if (args.guide) return { guide: HANDYMAN_GUIDE };
3192
- const root = findSerenityRoot(agentCwd$5(exec));
3192
+ const root = findSerenityRoot(agentCwd$6(exec));
3193
3193
  if (!root) throw new Error("No CCC found: no .serenity file from agent cwd");
3194
3194
  const hc = readHandymanConfig(root, DEFAULT_SERENITY_CONFIG_PATHS);
3195
3195
  if (hc === null) throw new Error("handyman requires a model whitelist: configure .opencode/serenity.json \"handyman.models\" (e.g. {\"handyman\": {\"models\": [\"minimax-cn-coding-plan/MiniMax-M3\"], \"defaultModel\": \"minimax-cn-coding-plan/MiniMax-M3\"}})");
@@ -5987,7 +5987,7 @@ function qaCheck(root, key) {
5987
5987
  * 同步把当前 dsh 会话重命名为该 SESSION 目录名**(sessionTitle.rename,user source
5988
5988
  * pin 住标题)。非创建时预命名。
5989
5989
  */
5990
- function agentCwd$4(exec) {
5990
+ function agentCwd$5(exec) {
5991
5991
  return exec.agent?.session?.header?.cwd ?? process.cwd();
5992
5992
  }
5993
5993
  /** 当前 dsh 会话 id(use/close 按会话隔离的 scope) */
@@ -6087,7 +6087,7 @@ function renameDshSessionForActive(ctx, exec, info) {
6087
6087
  console.warn(`[serenity-hooks] dsh 会话重命名异常: ${String(err?.message ?? err)}`);
6088
6088
  }
6089
6089
  }
6090
- function renderText$3(value) {
6090
+ function renderText$4(value) {
6091
6091
  return [{
6092
6092
  type: "text",
6093
6093
  text: typeof value === "string" ? value : JSON.stringify(value, null, 2)
@@ -6221,10 +6221,10 @@ function createSessionTool(ctx) {
6221
6221
  },
6222
6222
  output: {
6223
6223
  schema: { type: "json" },
6224
- render: (args, value) => renderText$3(value)
6224
+ render: (args, value) => renderText$4(value)
6225
6225
  },
6226
6226
  async execute(args, exec) {
6227
- const root = findSerenityRoot(agentCwd$4(exec));
6227
+ const root = findSerenityRoot(agentCwd$5(exec));
6228
6228
  if (!root) throw new Error("No CCC found: no .serenity file from agent cwd");
6229
6229
  const entries = loadMsmEntries(root);
6230
6230
  const hasSessionTool = entries.some((e) => e.name === "session-tool");
@@ -6584,7 +6584,7 @@ function registerBootstrap(ctx) {
6584
6584
  }
6585
6585
  //#endregion
6586
6586
  //#region src/rebuild.ts
6587
- const PLUGIN_SOURCE$3 = {
6587
+ const PLUGIN_SOURCE$4 = {
6588
6588
  kind: "plugin",
6589
6589
  plugin: "dsh-serenity-hooks"
6590
6590
  };
@@ -6770,7 +6770,7 @@ function registerRebuildTurnHook(ctx) {
6770
6770
  type: "text",
6771
6771
  text: "[TRAJECTORY-REBUILD] The conversation has been cleared and rebuilt. Follow the anchor instructions above now: read the persistent trajectory (SESSION.md) and continue the work automatically from the last checkpoint."
6772
6772
  }],
6773
- source: PLUGIN_SOURCE$3
6773
+ source: PLUGIN_SOURCE$4
6774
6774
  }));
6775
6775
  console.log(`[serenity-hooks] session_rebuild executed with auto-continue (turn ${payload.turn ?? "?"} ended): ${id}`);
6776
6776
  }
@@ -6796,13 +6796,13 @@ function registerRebuildTurnHook(ctx) {
6796
6796
  * (turn 结束前所有 tool/result 已 append → 无孤儿;S141 INVALID_REQUEST 根治)。
6797
6797
  * 服务端逻辑在 ../rebuild.ts(queueRebuild/performRebuild/registerRebuildTurnHook)。
6798
6798
  */
6799
- function agentCwd$3(exec) {
6799
+ function agentCwd$4(exec) {
6800
6800
  return exec.agent?.session?.header?.cwd ?? process.cwd();
6801
6801
  }
6802
6802
  function agentSessionId(exec) {
6803
6803
  return exec.agent?.session?.id ?? "";
6804
6804
  }
6805
- function renderText$2(value) {
6805
+ function renderText$3(value) {
6806
6806
  return [{
6807
6807
  type: "text",
6808
6808
  text: typeof value === "string" ? value : JSON.stringify(value, null, 2)
@@ -6819,17 +6819,17 @@ function createRebuildTool(ctx) {
6819
6819
  } },
6820
6820
  output: {
6821
6821
  schema: { type: "json" },
6822
- render: (args, value) => renderText$2(value)
6822
+ render: (args, value) => renderText$3(value)
6823
6823
  },
6824
6824
  async execute(args, exec) {
6825
- const root = findSerenityRoot(agentCwd$3(exec));
6825
+ const root = findSerenityRoot(agentCwd$4(exec));
6826
6826
  if (!root) throw new Error("No CCC found: no .serenity file from agent cwd");
6827
6827
  const dshSessionId = agentSessionId(exec);
6828
6828
  if (!dshSessionId) throw new Error("Unable to determine the current dsh session id");
6829
6829
  const result = await queueRebuild(ctx, {
6830
6830
  root,
6831
6831
  note: args.note,
6832
- agentCwd: agentCwd$3(exec),
6832
+ agentCwd: agentCwd$4(exec),
6833
6833
  dshSessionId
6834
6834
  });
6835
6835
  return {
@@ -6859,10 +6859,10 @@ const ACTIONS = [
6859
6859
  "show",
6860
6860
  "doc"
6861
6861
  ];
6862
- function agentCwd$2(exec) {
6862
+ function agentCwd$3(exec) {
6863
6863
  return exec.agent?.session?.header?.cwd ?? process.cwd();
6864
6864
  }
6865
- function renderText$1(value) {
6865
+ function renderText$2(value) {
6866
6866
  return [{
6867
6867
  type: "text",
6868
6868
  text: typeof value === "string" ? value : JSON.stringify(value, null, 2)
@@ -6894,10 +6894,10 @@ const localstoreTool = defineTool({
6894
6894
  },
6895
6895
  output: {
6896
6896
  schema: { type: "json" },
6897
- render: (args, value) => renderText$1(value)
6897
+ render: (args, value) => renderText$2(value)
6898
6898
  },
6899
6899
  async execute(args, exec) {
6900
- const root = findSerenityRoot(agentCwd$2(exec));
6900
+ const root = findSerenityRoot(agentCwd$3(exec));
6901
6901
  if (!root) throw new Error("No CCC found: no .serenity file from agent cwd");
6902
6902
  return runLocalStore(root, args);
6903
6903
  }
@@ -6912,10 +6912,10 @@ const localstoreTool = defineTool({
6912
6912
  *
6913
6913
  * 归属:ACC 机制工具(教会 + 校验),角色内容仍归 CCC 配置(.opencode/serenity.json skiff.roles)。
6914
6914
  */
6915
- function agentCwd$1(exec) {
6915
+ function agentCwd$2(exec) {
6916
6916
  return exec.agent?.session?.header?.cwd ?? process.cwd();
6917
6917
  }
6918
- function renderText(value) {
6918
+ function renderText$1(value) {
6919
6919
  return [{
6920
6920
  type: "text",
6921
6921
  text: typeof value === "string" ? value : JSON.stringify(value, null, 2)
@@ -7070,10 +7070,10 @@ const skiffAdminTool = defineTool({
7070
7070
  } },
7071
7071
  output: {
7072
7072
  schema: { type: "json" },
7073
- render: (args, value) => renderText(value)
7073
+ render: (args, value) => renderText$1(value)
7074
7074
  },
7075
7075
  async execute(args, exec) {
7076
- const root = findSerenityRoot(agentCwd$1(exec));
7076
+ const root = findSerenityRoot(agentCwd$2(exec));
7077
7077
  if (!root) throw new Error("No CCC found: no .serenity file from agent cwd");
7078
7078
  switch (args.action) {
7079
7079
  case "guide": return { guide: SKIFF_GUIDE };
@@ -7085,6 +7085,103 @@ const skiffAdminTool = defineTool({
7085
7085
  }
7086
7086
  });
7087
7087
  //#endregion
7088
+ //#region src/tools/autotrajectory-exp.ts
7089
+ /**
7090
+ * autotrajectory-exp.ts — 自主轨迹实验一站式管理工具(v1.26.12 实验提案,默认关)
7091
+ *
7092
+ * 定位:dsp **只提供工具与知识**,不向 CCC 自动安装任何东西(实验可能失败,不污染 CCC)——
7093
+ * 实验是 CCC 的自选动作:agent 调本工具(doc/全报告)即懂实验,init/random/check 辅助,
7094
+ * 实际执行(写配置/写偏见脚本/标记会话)由 CCC 自己决定、自己用现有工具完成。
7095
+ *
7096
+ * 实现:薄封装——exec 包内静态脚本(npm files 含 experiments/),脚本是单一真相源。
7097
+ * 环境注入 SERENITY_ROOT(当前 CCC 根)供脚本定位;bun 优先(可直跑 TS)。
7098
+ */
7099
+ /**
7100
+ * 定位包内实验脚本(npm files 分发 experiments/autotrajectory/)。
7101
+ * 布局差异:tsdown bundle 后 import.meta.url 指向 lib/index.js(lib → 包根 1 层);
7102
+ * vitest 源码直跑时指向 src/tools/x.ts(src/tools → 包根 2 层)——逐级上溯查找,
7103
+ * 两种布局都稳(找到 experiments/autotrajectory/scripts/autotrajectory-exp.ts 即止)。
7104
+ */
7105
+ function findExpScript(startDir) {
7106
+ let cur = startDir;
7107
+ while (true) {
7108
+ const cand = join(cur, "experiments", "autotrajectory", "scripts", "autotrajectory-exp.ts");
7109
+ if (existsSync(cand)) return cand;
7110
+ const parent = dirname(cur);
7111
+ if (parent === cur) return null;
7112
+ cur = parent;
7113
+ }
7114
+ }
7115
+ /** 包内实验脚本(上溯查找;找不到 → execute 报错提示包完整性) */
7116
+ const EXP_SCRIPT = findExpScript(dirname(fileURLToPath(import.meta.url)));
7117
+ const AUTO_TRAJECTORY_EXP_ACTIONS = [
7118
+ "all",
7119
+ "init",
7120
+ "random",
7121
+ "doc",
7122
+ "check",
7123
+ "status",
7124
+ "guide"
7125
+ ];
7126
+ function agentCwd$1(exec) {
7127
+ return exec.agent?.session?.header?.cwd ?? process.cwd();
7128
+ }
7129
+ function renderText(value) {
7130
+ return [{
7131
+ type: "text",
7132
+ text: typeof value === "string" ? value : JSON.stringify(value, null, 2)
7133
+ }];
7134
+ }
7135
+ const autoTrajectoryExpTool = defineTool({
7136
+ name: "autotrajectory-exp",
7137
+ description: "自主轨迹实验(Self-Sustaining Trajectory)一站式管理——实验提案 v1.26.12,默认关。无参/action=all:全报告(背景摘要 + 就绪检查 + 状态 + 下一步)——CCC agent 看一次即完整理解实验并知道怎么开始;init:初始化辅助(写配置 + 生成偏见提供者脚本模板);random:运行偏见提供者脚本输出当前偏见内容;doc:实验定义全文;check/status/guide:单项。实验是 CCC 的自选动作——dsp 只提供工具与知识,不自动安装任何东西。",
7138
+ parameters: { action: {
7139
+ type: "string",
7140
+ enum: [...AUTO_TRAJECTORY_EXP_ACTIONS],
7141
+ required: true,
7142
+ description: "Subcommand"
7143
+ } },
7144
+ output: {
7145
+ schema: { type: "json" },
7146
+ render: (_args, value) => renderText(value)
7147
+ },
7148
+ async execute(args, exec) {
7149
+ const root = findSerenityRoot(agentCwd$1(exec));
7150
+ const result = {};
7151
+ if (!EXP_SCRIPT) {
7152
+ result.error = "autotrajectory-exp 实验脚本未随安装分发(npm 包缺 experiments/autotrajectory/)——请检查包完整性";
7153
+ return result;
7154
+ }
7155
+ const script = EXP_SCRIPT;
7156
+ if (!existsSync(script)) {
7157
+ result.error = `autotrajectory-exp 脚本缺失(${script})——实验包未随安装分发,请检查 npm 包完整性`;
7158
+ return result;
7159
+ }
7160
+ const env = { ...process.env };
7161
+ if (root) env.SERENITY_ROOT = root;
7162
+ const r = spawnSync("bun", [script, args.action ?? "all"], {
7163
+ encoding: "utf-8",
7164
+ timeout: 6e5,
7165
+ env,
7166
+ stdio: [
7167
+ "ignore",
7168
+ "pipe",
7169
+ "pipe"
7170
+ ]
7171
+ });
7172
+ if (r.status === 0) {
7173
+ result.output = r.stdout?.trim() || "(empty)";
7174
+ return result;
7175
+ }
7176
+ if (r.error?.code === "ENOENT") {
7177
+ result.error = "autotrajectory-exp 需要 bun 运行时(bun not found in PATH)";
7178
+ return result;
7179
+ }
7180
+ result.error = r.stderr?.trim() || r.stdout?.trim() || `exit ${r.status ?? "?"}`;
7181
+ return result;
7182
+ }
7183
+ });
7184
+ //#endregion
7088
7185
  //#region src/seams/keeper.ts
7089
7186
  const SCORES = {
7090
7187
  write: 3,
@@ -7167,7 +7264,7 @@ function readContextPressure(ctx, session) {
7167
7264
  return null;
7168
7265
  }
7169
7266
  }
7170
- const PLUGIN_SOURCE$2 = {
7267
+ const PLUGIN_SOURCE$3 = {
7171
7268
  kind: "plugin",
7172
7269
  plugin: "dsh-serenity-hooks"
7173
7270
  };
@@ -7230,7 +7327,7 @@ function registerKeeper(ctx, opts = {}) {
7230
7327
  if (blocks.length === 0) return downstream;
7231
7328
  const reminderAll = createUserMessage({
7232
7329
  content: blocks,
7233
- source: PLUGIN_SOURCE$2
7330
+ source: PLUGIN_SOURCE$3
7234
7331
  });
7235
7332
  if (downstream.kind === "block") return {
7236
7333
  kind: "block",
@@ -8241,7 +8338,7 @@ function accIdentityText(root, configPaths = DEFAULT_SERENITY_CONFIG_PATHS, entr
8241
8338
  }
8242
8339
  return lines.join("\n");
8243
8340
  }
8244
- const PLUGIN_SOURCE$1 = {
8341
+ const PLUGIN_SOURCE$2 = {
8245
8342
  kind: "plugin",
8246
8343
  plugin: "dsh-serenity-hooks"
8247
8344
  };
@@ -8258,7 +8355,7 @@ function accMessage(root, configPaths, entrySkillMaxChars) {
8258
8355
  }];
8259
8356
  return createUserMessage({
8260
8357
  content,
8261
- source: PLUGIN_SOURCE$1
8358
+ source: PLUGIN_SOURCE$2
8262
8359
  });
8263
8360
  }
8264
8361
  /** 每 agent 是否已注入过(进程内存态) */
@@ -9787,7 +9884,7 @@ function buildRebuke(hits) {
9787
9884
  const rebukeStates = /* @__PURE__ */ new Map();
9788
9885
  //#endregion
9789
9886
  //#region src/output-guard-seam.ts
9790
- const PLUGIN_SOURCE = {
9887
+ const PLUGIN_SOURCE$1 = {
9791
9888
  kind: "plugin",
9792
9889
  plugin: "dsh-serenity-hooks"
9793
9890
  };
@@ -9843,7 +9940,7 @@ function registerOutputGuardHook(ctx) {
9843
9940
  type: "text",
9844
9941
  text: buildRebuke(hits)
9845
9942
  }],
9846
- source: PLUGIN_SOURCE
9943
+ source: PLUGIN_SOURCE$1
9847
9944
  }));
9848
9945
  } catch (error) {
9849
9946
  console.warn(`[serenity-hooks] output-guard steer failed: ${String(error?.message ?? error)}`);
@@ -12740,6 +12837,227 @@ qInput.focus()
12740
12837
  </html>`;
12741
12838
  }
12742
12839
  //#endregion
12840
+ //#region src/autotrajectory.ts
12841
+ const PLUGIN_SOURCE = {
12842
+ kind: "plugin",
12843
+ plugin: "dsh-serenity-hooks"
12844
+ };
12845
+ /** 自主轨迹会话目录后缀标志(用户拍板:后缀) */
12846
+ const AUTO_DIR_SUFFIX = "--auto";
12847
+ /** 调度 tick 周期(10min——验证形态"一个就够") */
12848
+ const TICK_MS = 6e5;
12849
+ /** SESSION.md 内「下一轮动机」段标记(自生偏见载体——轨迹预设自己的未来) */
12850
+ const MOTIVATION_MARKER = "下一轮动机";
12851
+ /** 缺省避开的高峰时段(北京时间 [start, end) 不唤起——用量峰谷省钱) */
12852
+ const DEFAULT_AVOID_HOURS = {
12853
+ start: 8,
12854
+ end: 18
12855
+ };
12856
+ function readAutoTrajectorySettings(root) {
12857
+ return loadSerenityConfig(root).autotrajectory ?? null;
12858
+ }
12859
+ /**
12860
+ * 北京时间(UTC+8)当前小时——不依赖服务器时区(服务器可能 UTC/本地任意)。
12861
+ */
12862
+ function beijingHour(nowMs) {
12863
+ return Math.floor((nowMs + 288e5) % 864e5 / 36e5);
12864
+ }
12865
+ /**
12866
+ * 唤起窗口判定:北京时间 [avoidStart, avoidEnd) 内不唤起(缺省 8~18)。
12867
+ * 单段避开(start<=end):窗口 = [0,start) ∪ [end,24);跨零点避开(start>end):窗口 = [end,start)。
12868
+ */
12869
+ function inAllowedWakeWindow(nowMs, avoid) {
12870
+ const start = avoid?.start ?? DEFAULT_AVOID_HOURS.start;
12871
+ const end = avoid?.end ?? DEFAULT_AVOID_HOURS.end;
12872
+ const h = beijingHour(nowMs);
12873
+ if (start <= end) return h < start || h >= end;
12874
+ return h >= end && h < start;
12875
+ }
12876
+ /** 标志位判定:SESSION.md 所在目录名以 --auto 结尾 → 自主轨迹形态 */
12877
+ function isAutoTrajectorySession(mdPath) {
12878
+ return basename(dirname(mdPath)).endsWith(AUTO_DIR_SUFFIX);
12879
+ }
12880
+ /**
12881
+ * 目标会话定位:**必须配置 cfg.session**(S###/目录名)——CCC 日常有多条 trajectory 在跑,
12882
+ * 绝不默认唤起(缺省最近活跃会误伤其他正在运行的轨迹;用户拍板:必须配置才生效)。
12883
+ * 未配置 session 或未命中 → null(不唤起)。
12884
+ */
12885
+ function resolveTargetMd(root, cfg) {
12886
+ if (!cfg?.session) return null;
12887
+ const found = findSession(sessionsRoot(root), cfg.session);
12888
+ if (!found) return null;
12889
+ const md = join(found.path, "SESSION.md");
12890
+ return existsSync(md) ? md : null;
12891
+ }
12892
+ /**
12893
+ * 唤起条件(纯逻辑,可测):enabled + 未在运行 + 目录标志 + mtime 超间隔 + 窗口允许。
12894
+ */
12895
+ function shouldWake(settings, mdPath, nowMs, running) {
12896
+ if (!settings?.enabled || running) return false;
12897
+ if (!mdPath || !isAutoTrajectorySession(mdPath)) return false;
12898
+ if (!inAllowedWakeWindow(nowMs, settings.avoidWakeHours)) return false;
12899
+ try {
12900
+ const mtime = statSync(mdPath).mtimeMs;
12901
+ const hours = Math.max(1, settings.intervalHours ?? 12);
12902
+ return nowMs - mtime >= hours * 36e5;
12903
+ } catch {
12904
+ return false;
12905
+ }
12906
+ }
12907
+ /** 自生动机读取:SESSION.md「下一轮动机」段内容(到下一个二级标题或文件尾;无 → null) */
12908
+ function readSelfGeneratedMotivation(mdPath) {
12909
+ try {
12910
+ const content = readFileSync(mdPath, "utf-8");
12911
+ const idx = content.indexOf(MOTIVATION_MARKER);
12912
+ if (idx < 0) return null;
12913
+ const rest = content.slice(idx + 5);
12914
+ const nextHeading = rest.search(/\n## /);
12915
+ return (nextHeading >= 0 ? rest.slice(0, nextHeading) : rest).trim() || null;
12916
+ } catch {
12917
+ return null;
12918
+ }
12919
+ }
12920
+ /**
12921
+ * 偏见内容:直接运行 CCC 根目录下偏见提供者脚本(biasProvider,缺省 autotrajectory-bias.ts)→ stdout。
12922
+ * 脚本缺失 → 返回 { text: null, error: 提示实现 }(唤起侧报错要求实现,不静默跳过)。
12923
+ * 路径逃逸校验(resolveInside);bun 优先,node 兜底;600s 超时。
12924
+ */
12925
+ async function fetchBiasContent(root, providerRel) {
12926
+ let scriptAbs;
12927
+ try {
12928
+ scriptAbs = resolveInside(root, providerRel);
12929
+ } catch {
12930
+ return {
12931
+ text: null,
12932
+ error: `biasProvider 路径逃逸(须在 CCC 根内): ${providerRel}`
12933
+ };
12934
+ }
12935
+ if (!existsSync(scriptAbs)) return {
12936
+ text: null,
12937
+ error: `请在 CCC 根目录实现偏见内容提供者脚本: ${providerRel}(stdout 输出偏见内容一行;acc_msm exec autotrajectory-exp init 可生成模板)`
12938
+ };
12939
+ const runs = [["bun", [scriptAbs]], [process.execPath, [scriptAbs]]];
12940
+ for (const [cmd, args] of runs) try {
12941
+ const r = spawnSync(cmd, args, {
12942
+ encoding: "utf-8",
12943
+ timeout: 6e5,
12944
+ stdio: [
12945
+ "ignore",
12946
+ "pipe",
12947
+ "pipe"
12948
+ ]
12949
+ });
12950
+ if (r.status === 0) return {
12951
+ text: (r.stdout ?? "").trim() || null,
12952
+ error: null
12953
+ };
12954
+ if (r.error?.code === "ENOENT") continue;
12955
+ return {
12956
+ text: null,
12957
+ error: `偏见内容提供者脚本执行失败(exit ${r.status ?? "?"}): ${r.stderr?.trim() || r.stdout?.trim() || ""}`
12958
+ };
12959
+ } catch {
12960
+ continue;
12961
+ }
12962
+ return {
12963
+ text: null,
12964
+ error: "偏见内容提供者脚本无法运行(bun 与 node 均不可用)"
12965
+ };
12966
+ }
12967
+ /** 唤起消息(三段式:身份锚定 / 先验偏见[自生动机+偏见内容] / 任务)——注入前台会话,用户可见 */
12968
+ function buildWakeMessage(opts) {
12969
+ const lines = [
12970
+ `[自主轨迹唤起] — 距上次轨迹活动已满 ${opts.intervalHours} 小时,自动继续。`,
12971
+ "",
12972
+ `身份锚定:继续 ${opts.sessionName} 的 trajectory(SESSION.md: ${opts.mdPath})。`,
12973
+ "先验偏见:"
12974
+ ];
12975
+ if (opts.motivation) lines.push(` · 自生动机:${opts.motivation}`);
12976
+ if (opts.biasContent) lines.push(` · 偏见内容:${opts.biasContent}`);
12977
+ if (!opts.motivation && !opts.biasContent) lines.push(" · (无——本轮纯自主探索)");
12978
+ lines.push("", "任务:执行一轮自主认知(探索/反事实检验),把产出写入 SESSION.md", "「自主探索日志」段,并预写「下一轮动机」段。完成后自然结束。");
12979
+ return lines.join("\n");
12980
+ }
12981
+ /**
12982
+ * 装配(index.ts apply 调用):仅当 CCC 配置 autotrajectory.enabled=true 时启动定时器;
12983
+ * 否则零资源占用。定时器 tick 检查唤起条件 → 注入活跃会话(agent.steer,前台可见)。
12984
+ */
12985
+ function registerAutoTrajectory(ctx) {
12986
+ const root = resolveAutoTrajectoryRoot(ctx);
12987
+ const settings = root ? readAutoTrajectorySettings(root) : null;
12988
+ if (!settings?.enabled) return;
12989
+ let running = false;
12990
+ const tick = () => {
12991
+ if (running) return;
12992
+ const mdPath = resolveTargetMd(root, settings);
12993
+ if (!shouldWake(settings, mdPath, Date.now(), running)) return;
12994
+ const agent = resolveTargetAgent(ctx, mdPath);
12995
+ if (!agent) {
12996
+ console.warn("[serenity-hooks] ✗ 自主轨迹唤起跳过:目标会话 agent 不可得(session use 激活后重试)");
12997
+ return;
12998
+ }
12999
+ running = true;
13000
+ (async () => {
13001
+ try {
13002
+ const provider = settings.biasProvider?.trim() || "autotrajectory-bias.ts";
13003
+ const biasRes = await fetchBiasContent(root, provider);
13004
+ if (biasRes.error) {
13005
+ console.error(`[serenity-hooks] ✗ 自主轨迹唤起中止(偏见内容缺失): ${biasRes.error}`);
13006
+ return;
13007
+ }
13008
+ const motivation = readSelfGeneratedMotivation(mdPath);
13009
+ const message = buildWakeMessage({
13010
+ sessionName: basename(dirname(mdPath)),
13011
+ mdPath,
13012
+ intervalHours: settings.intervalHours ?? 12,
13013
+ motivation,
13014
+ biasContent: biasRes.text
13015
+ });
13016
+ agent.steer(createUserMessage({
13017
+ content: [{
13018
+ type: "text",
13019
+ text: message
13020
+ }],
13021
+ source: PLUGIN_SOURCE
13022
+ }));
13023
+ console.log(`[serenity-hooks] ✓ 自主轨迹唤起(${basename(dirname(mdPath))},偏见提供者 ${provider})`);
13024
+ } catch (err) {
13025
+ console.warn(`[serenity-hooks] ✗ 自主轨迹唤起失败: ${String(err?.message ?? err)}`);
13026
+ } finally {
13027
+ running = false;
13028
+ }
13029
+ })();
13030
+ };
13031
+ setInterval(tick, TICK_MS).unref();
13032
+ tick();
13033
+ }
13034
+ /** 目标 agent:从 SESSION.md 反向定位 dsh 会话(标题 F3 命名 S###-日期 匹配);不可得 → null */
13035
+ function resolveTargetAgent(ctx, mdPath) {
13036
+ const idMatch = basename(dirname(mdPath)).match(/--S(\d{3,})--/);
13037
+ const sid = idMatch ? `S${idMatch[1]}` : null;
13038
+ try {
13039
+ const sessions = ctx.sessions;
13040
+ for (const s of sessions?.list?.() ?? []) if (sid && (s.title === sid || s.title?.startsWith(`${sid}-`))) {
13041
+ const agent = ctx.agents?.get?.(s.id ?? "");
13042
+ if (agent) return agent;
13043
+ }
13044
+ } catch {}
13045
+ return null;
13046
+ }
13047
+ /** 自主轨迹绑定的 CCC 根:进程 cwd 上溯 .serenity 优先,回退任一 live 会话 root */
13048
+ function resolveAutoTrajectoryRoot(ctx) {
13049
+ const fromCwd = findSerenityRoot(process.cwd());
13050
+ if (fromCwd) return fromCwd;
13051
+ try {
13052
+ const sessions = ctx.sessions;
13053
+ for (const s of sessions?.list?.() ?? []) {
13054
+ const r = findSerenityRoot(s?.header?.cwd ?? "");
13055
+ if (r) return r;
13056
+ }
13057
+ } catch {}
13058
+ return null;
13059
+ }
13060
+ //#endregion
12743
13061
  //#region src/index.ts
12744
13062
  const name = "dsh-serenity-hooks";
12745
13063
  /** 主动调用的服务;其余(agent 事件)随 harness 装配必然存在 */
@@ -12795,6 +13113,7 @@ function apply(ctx, config) {
12795
13113
  ctx.tools.register(createRebuildTool(ctx));
12796
13114
  ctx.tools.register(localstoreTool);
12797
13115
  ctx.tools.register(skiffAdminTool);
13116
+ ctx.tools.register(autoTrajectoryExpTool);
12798
13117
  }
12799
13118
  if (config.guards) registerGuards(ctx, { configPaths: config.serenityConfigPaths });
12800
13119
  if (config.keeper) registerKeeper(ctx, {
@@ -12820,6 +13139,7 @@ function apply(ctx, config) {
12820
13139
  registerBootstrap(ctx);
12821
13140
  registerSkiff(ctx);
12822
13141
  registerAcp(ctx);
13142
+ registerAutoTrajectory(ctx);
12823
13143
  }
12824
13144
  /**
12825
13145
  * F4 Skiff 调试服务装配:启停 = 人工(设置面板 Skiff 区块开关,settings 持久化)。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shgroup/dsh-serenity-hooks",
3
- "version": "1.26.11",
3
+ "version": "1.26.13",
4
4
  "description": "宁静号 ACC harness — Native Cordis 插件(DeepSeek Harness 运行时)。真实 DSH 工具注册(cc_fs/session/acc_msm 等 9 工具)+ 拦截缝机械约束(safe-mode/路径守卫/会话落盘)+ 系统提示词注入(ACC/CCE/Constraints/SKILL/Session 五块)。适配 DSH 公开版(deepseek-ai/deepseek-harness 0.1.0-rc)。",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -28,7 +28,9 @@
28
28
  "lib/types/**/*.d.ts",
29
29
  "cordis.patch.yml",
30
30
  "dsh.plugin.json",
31
- "README.md"
31
+ "README.md",
32
+ "experiments/autotrajectory/SKILL.md",
33
+ "experiments/autotrajectory/scripts/autotrajectory-exp.ts"
32
34
  ],
33
35
  "scripts": {
34
36
  "typecheck": "tsc --noEmit",