@shgroup/dsh-serenity-hooks 1.26.10 → 1.26.12

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.10",
3
+ "version": "1.26.12",
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
+ }