@shgroup/dsh-serenity-hooks 1.32.0 → 1.34.1
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 +12 -11
- package/dsh.plugin.json +5 -5
- package/lib/acp-core.d.ts +2 -22
- package/lib/acp-http.d.ts +8 -0
- package/lib/api.d.ts +12 -4
- package/lib/autopilot-chain.d.ts +76 -0
- package/lib/autopilot-core-DCRkiWEe.js +229 -0
- package/lib/autopilot-core.d.ts +132 -0
- package/lib/autopilot-ops.d.ts +48 -0
- package/lib/autopilot-trajectory-D9Znxo75.js +782 -0
- package/lib/autopilot-trajectory.d.ts +79 -83
- package/lib/{ccc-DAsSHsub.js → ccc-NlLr_sxy.js} +18 -2
- package/lib/ccc-roots-Bd_SjEs7.js +152 -0
- package/lib/ccc-roots.d.ts +105 -0
- package/lib/ccc.d.ts +23 -6
- package/lib/client.js +30 -10
- package/lib/clock-runtime.d.ts +197 -0
- package/lib/config-ops.d.ts +9 -14
- package/lib/constants.d.ts +0 -2
- package/lib/container-status.d.ts +183 -0
- package/lib/diag-ops.d.ts +76 -0
- package/lib/face-host.d.ts +110 -0
- package/lib/fs-ops.d.ts +3 -2
- package/lib/gateway-auth.d.ts +2 -5
- package/lib/gateway.d.ts +0 -34
- package/lib/git-ops.d.ts +3 -2
- package/lib/handyman-ops.d.ts +3 -2
- package/lib/handyman-preset-inherit.d.ts +2 -1
- package/lib/host/access.d.ts +8 -7
- package/lib/host/contract.d.ts +17 -6
- package/lib/host/type-contract.d.ts +1 -2
- package/lib/im-bridge.d.ts +6 -5
- package/lib/index.d.ts +1 -1
- package/lib/index.js +11053 -8305
- package/lib/invariant.d.ts +5 -16
- package/lib/invariant.js +8 -4
- package/lib/json.d.ts +1 -1
- package/lib/kit-ops.d.ts +11 -31
- package/lib/localstore-ops.d.ts +3 -17
- package/lib/msm-ops.d.ts +34 -52
- package/lib/opencode-provider.d.ts +4 -5
- package/lib/output-guard-seam.d.ts +1 -4
- package/lib/output-guard.d.ts +12 -3
- package/lib/ports.d.ts +59 -0
- package/lib/rebuild.d.ts +5 -4
- package/lib/seams/bootstrap.d.ts +4 -3
- package/lib/seams/compact.d.ts +2 -1
- package/lib/seams/context.d.ts +2 -4
- package/lib/seams/env.d.ts +2 -1
- package/lib/seams/guards.d.ts +22 -34
- package/lib/seams/keeper.d.ts +4 -4
- package/lib/seams/system-prompt.d.ts +1 -5
- package/lib/session-cleanup.d.ts +3 -2
- package/lib/{settings-section-Bm-xG-NR.js → settings-section-DTYZjwUs.js} +70 -15
- package/lib/settings-section.d.ts +14 -35
- package/lib/skiff-core.d.ts +5 -10
- package/lib/skiff-debug.d.ts +15 -21
- package/lib/skiff-registry-FTjoWQTQ.js +25 -0
- package/lib/skiff-registry.d.ts +2 -1
- package/lib/{skiff-role-BYvNnwv1.js → skiff-role-CEHL5cek.js} +1 -1
- package/lib/skiff-role.d.ts +2 -2
- package/lib/skills/opencode-scan.d.ts +3 -2
- package/lib/skills-discovery.d.ts +15 -2
- package/lib/status.d.ts +2 -1
- package/lib/tools/acc-diag.d.ts +22 -0
- package/lib/tools/cce.d.ts +1 -2
- package/lib/tools/container-admin.d.ts +7 -3
- package/lib/tools/eap.d.ts +2 -3
- package/lib/tools/handyman.d.ts +0 -29
- package/lib/tools/msm.d.ts +0 -4
- package/lib/tools/neat.d.ts +1 -2
- package/lib/tools/praxis.d.ts +0 -1
- package/lib/tools/skiff-admin.d.ts +2 -2
- package/lib/tools/{session.d.ts → trajectory.d.ts} +25 -17
- package/lib/totp.d.ts +0 -4
- package/lib/trajectory-assistant.d.ts +2 -1
- package/lib/trajectory-bound-Cax1p9ut.js +190 -0
- package/lib/{session-bound.d.ts → trajectory-bound.d.ts} +5 -6
- package/lib/trajectory-ops-mrXK0H0I.js +410 -0
- package/lib/{session-ops.d.ts → trajectory-ops.d.ts} +27 -36
- package/lib/trajectory-skills.d.ts +71 -0
- package/lib/wake-registry-CYxIb484.js +257 -0
- package/lib/wake-registry.d.ts +3 -11
- package/lib/wake-scheduler.d.ts +23 -20
- package/lib/web-fetch-provider.d.ts +0 -21
- package/lib/{weixin-api-PjEhmjlZ.js → weixin-api-CtFYm53S.js} +3 -9
- package/lib/weixin-api.d.ts +6 -37
- package/lib/weixin-bridge.d.ts +5 -24
- package/lib/weixin-hook.d.ts +6 -12
- package/lib/weixin-output-guard.d.ts +2 -1
- package/lib/{weixin-route-wWk4AIwV.js → weixin-route-B2ajFypI.js} +4 -5
- package/lib/weixin-route.d.ts +0 -2
- package/lib/weixin-send-api.d.ts +15 -6
- package/package.json +3 -5
- package/experiments/autopilot-trajectory/SKILL.md +0 -115
- package/experiments/autopilot-trajectory/scripts/autopilot-trajectory.ts +0 -522
- package/lib/session-bound-NHozeLFc.js +0 -822
- package/lib/skiff-debug-K2k1JnGj.js +0 -2867
- package/lib/tools/autopilot-trajectory.d.ts +0 -25
- package/lib/{session-cleanup-CMT4mHWt.js → session-cleanup-B6IHZgww.js} +1 -1
|
@@ -1,522 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
/**
|
|
3
|
-
* autopilot-trajectory.ts — 自主轨迹实验管理 MSM(Mech,纯 TS 零 LLM 决策)——一站式
|
|
4
|
-
*
|
|
5
|
-
* 一个 tool 整合实验全部所需:
|
|
6
|
-
* acc_msm exec autopilot-trajectory → 一站式全报告(背景 + 就绪 + 状态 + 下一步)
|
|
7
|
-
* acc_msm exec autopilot-trajectory init → 初始化实验(写配置 + 生成偏见提供者脚本模板)
|
|
8
|
-
* acc_msm exec autopilot-trajectory random → 运行偏见提供者脚本,输出当前偏见内容(验证)
|
|
9
|
-
* acc_msm exec autopilot-trajectory diag → 唤起条件链诊断(--ccc <path> 指定;无参递归扫描 /home/yh 两层)
|
|
10
|
-
* acc_msm exec autopilot-trajectory doc → 实验定义说明全文(SKILL.md)
|
|
11
|
-
* acc_msm exec autopilot-trajectory check → 仅就绪度检查
|
|
12
|
-
* acc_msm exec autopilot-trajectory status → 仅当前状态
|
|
13
|
-
* acc_msm exec autopilot-trajectory guide → 仅步骤指引
|
|
14
|
-
*
|
|
15
|
-
* 概念(用户拍板命名):偏见内容提供者(bias provider)——CCC 根目录下一个脚本,
|
|
16
|
-
* stdout 输出本轮唤起要注入的偏见内容(反事实方向/探索动机等)。tool 直接运行它;
|
|
17
|
-
* 脚本缺失 → 报错要求实现(不再经 mech-registry 注册 MSM)。
|
|
18
|
-
*
|
|
19
|
-
* 状态查看:WebUI 设置面板「自主轨迹」区块(GET /serenity/autopilot-trajectory)+「立即唤起」按钮
|
|
20
|
-
* (POST /serenity/autopilot-trajectory {action:'wake'},调试语义跳过窗口/间隔)——由插件提供,脚本不重复。
|
|
21
|
-
*
|
|
22
|
-
* 零 DSH 依赖,任何 CCC 可运行。环境:SERENITY_ROOT(acc_msm exec 注入)或 cwd 上溯 .serenity。
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
import { existsSync, readFileSync, statSync, readdirSync, writeFileSync, mkdirSync } from 'node:fs'
|
|
26
|
-
import { join, resolve, basename, dirname } from 'node:path'
|
|
27
|
-
import { spawnSync } from 'node:child_process'
|
|
28
|
-
|
|
29
|
-
const DEFAULT_BIAS_PROVIDER = 'autopilot-bias.ts'
|
|
30
|
-
const AUTO_SUFFIX = '--auto'
|
|
31
|
-
const MOTIVATION_MARKER = '下一轮动机'
|
|
32
|
-
const CONFIG_PATHS = ['.opencode/serenity.json', '.dsh/serenity.json']
|
|
33
|
-
|
|
34
|
-
/** 偏见内容提供者脚本脚手架模板(init 生成;CCC 按自己的反馈信息来源改写) */
|
|
35
|
-
const BIAS_TEMPLATE = `#!/usr/bin/env bun
|
|
36
|
-
/**
|
|
37
|
-
* autopilot-bias.ts — 自主轨迹偏见内容提供者(CCC 实现)
|
|
38
|
-
*
|
|
39
|
-
* stdout 输出一行/一段文本 = 本轮唤起注入的偏见内容(反事实问题 / 探索方向 /
|
|
40
|
-
* 任何让轨迹偏离既有路径的输入)。偏见内容归 CCC——用本 CCC 自己的反馈信息来源
|
|
41
|
-
* 保证"足够随机"(历史会话 / 技能 / 文档 / 外部信息 / 真随机源……)。
|
|
42
|
-
*
|
|
43
|
-
* 本文件为脚手架——请按本 CCC 的信息来源改写。
|
|
44
|
-
*/
|
|
45
|
-
const sources = [
|
|
46
|
-
'AGENT_SESSIONS 中的历史会话',
|
|
47
|
-
'.opencode/skills 技能目录',
|
|
48
|
-
'docs/ 设计文档',
|
|
49
|
-
'…(CCC 自己的信息来源)',
|
|
50
|
-
]
|
|
51
|
-
const pick = sources[Math.floor(Math.random() * sources.length)]
|
|
52
|
-
console.log(\`反事实:如果「\${pick}」换个做法会怎样?\`)
|
|
53
|
-
`
|
|
54
|
-
|
|
55
|
-
/** 背景摘要(一站式的第一节——CCC agent 快速理解"为什么/验证什么") */
|
|
56
|
-
const BACKGROUND = [
|
|
57
|
-
'═══ 自主轨迹实验(Self-Sustaining Trajectory)═══',
|
|
58
|
-
'背景:Trajectory 是主体(Agent 可替换、Session 载体可重建)。瓶颈 = 人类 waiting——',
|
|
59
|
-
' 轨迹以"等待人类"为推进条件时,事件序列时间被人类响应间隔锚定,运转被拖慢。',
|
|
60
|
-
'猜想:无人等待的 trajectory——时钟自动唤起 + 先验偏见(自生动机 + 偏见内容)→ 运转加速。',
|
|
61
|
-
'验证:P4 可自动唤起并携带偏见 / P5 速度提升→更快产生满意效果;反证=熵增失控/自我确认/噪音化。',
|
|
62
|
-
'理论:specs §0.7 记录器→校准器(预测加工)。完整定义:doc(SKILL.md)。',
|
|
63
|
-
'',
|
|
64
|
-
].join('\n')
|
|
65
|
-
|
|
66
|
-
interface AutoConfig {
|
|
67
|
-
enabled?: boolean
|
|
68
|
-
intervalHours?: number
|
|
69
|
-
biasProvider?: string
|
|
70
|
-
/** 顶层提示词(v1.26.17):CCC 定义的稳定提示词,每次唤起最先注入(顶层约束/质量要求) */
|
|
71
|
-
topPrompt?: string
|
|
72
|
-
session?: string
|
|
73
|
-
avoidWakeHours?: { start?: number; end?: number }
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// ── 基础设施 ──
|
|
77
|
-
|
|
78
|
-
function findRoot(): string | null {
|
|
79
|
-
const fromEnv = process.env.SERENITY_ROOT
|
|
80
|
-
if (fromEnv && existsSync(join(fromEnv, '.serenity'))) return fromEnv
|
|
81
|
-
let cur = resolve(process.cwd())
|
|
82
|
-
while (true) {
|
|
83
|
-
if (existsSync(join(cur, '.serenity'))) return cur
|
|
84
|
-
const parent = dirname(cur)
|
|
85
|
-
if (parent === cur) return null
|
|
86
|
-
cur = parent
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function readUtf8(p: string): string {
|
|
91
|
-
return readFileSync(p, 'utf-8').replace(/^\uFEFF/, '')
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function loadConfig(root: string): AutoConfig | null {
|
|
95
|
-
for (const rel of CONFIG_PATHS) {
|
|
96
|
-
const p = join(root, rel)
|
|
97
|
-
if (!existsSync(p)) continue
|
|
98
|
-
try {
|
|
99
|
-
const cfg = JSON.parse(readUtf8(p)) as { autopilotTrajectory?: AutoConfig }
|
|
100
|
-
return cfg.autopilotTrajectory ?? null
|
|
101
|
-
} catch {
|
|
102
|
-
return null
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return null
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/** 偏见提供者脚本绝对路径(根内强制——逃逸拒绝) */
|
|
109
|
-
function biasProviderPath(root: string, providerRel: string): string {
|
|
110
|
-
const rootAbs = resolve(root)
|
|
111
|
-
const abs = resolve(root, providerRel)
|
|
112
|
-
if (abs !== rootAbs && !abs.startsWith(rootAbs + '/')) {
|
|
113
|
-
throw new Error(`biasProvider 路径逃逸(须在 CCC 根内): ${providerRel}`)
|
|
114
|
-
}
|
|
115
|
-
return abs
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/** 运行偏见提供者脚本(bun 优先,node 兜底),返回偏见内容或错误信息 */
|
|
119
|
-
function runBiasProvider(root: string, providerRel: string): { text: string | null; error: string | null } {
|
|
120
|
-
let scriptAbs: string
|
|
121
|
-
try {
|
|
122
|
-
scriptAbs = biasProviderPath(root, providerRel)
|
|
123
|
-
} catch (e) {
|
|
124
|
-
return { text: null, error: String((e as Error).message) }
|
|
125
|
-
}
|
|
126
|
-
if (!existsSync(scriptAbs)) {
|
|
127
|
-
return { text: null, error: `请在 CCC 根目录实现偏见内容提供者脚本: ${providerRel}(acc_msm exec autopilot-trajectory init 可生成模板)` }
|
|
128
|
-
}
|
|
129
|
-
for (const cmd of ['bun', process.execPath]) {
|
|
130
|
-
try {
|
|
131
|
-
const r = spawnSync(cmd, [scriptAbs], { encoding: 'utf-8', timeout: 600_000, stdio: ['ignore', 'pipe', 'pipe'] })
|
|
132
|
-
if (r.status === 0) {
|
|
133
|
-
const text = (r.stdout ?? '').trim()
|
|
134
|
-
return { text: text || null, error: null }
|
|
135
|
-
}
|
|
136
|
-
if ((r.error as NodeJS.ErrnoException | undefined)?.code === 'ENOENT') continue
|
|
137
|
-
return { text: null, error: `偏见内容提供者脚本执行失败(exit ${r.status ?? '?'}): ${r.stderr?.trim() || r.stdout?.trim() || ''}` }
|
|
138
|
-
} catch {
|
|
139
|
-
continue
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return { text: null, error: '偏见内容提供者脚本无法运行(bun 与 node 均不可用)' }
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/** 目标 SESSION.md:**session 必填**(S###/目录名匹配)——自动唤起不默认任何会话(CCC 日常多轨迹并行);未配置/未命中 → null */
|
|
146
|
-
function resolveTargetMd(root: string, cfg: AutoConfig): string | null {
|
|
147
|
-
if (!cfg?.session) return null
|
|
148
|
-
const sessionsDir = join(root, 'AGENT_SESSIONS')
|
|
149
|
-
if (!existsSync(sessionsDir)) return null
|
|
150
|
-
const dirs = readdirSync(sessionsDir, { withFileTypes: true })
|
|
151
|
-
.filter((d) => d.isDirectory())
|
|
152
|
-
.map((d) => join(sessionsDir, d.name))
|
|
153
|
-
for (const d of dirs) {
|
|
154
|
-
const md = join(d, 'SESSION.md')
|
|
155
|
-
if (existsSync(md) && basename(d).includes(cfg.session)) return md
|
|
156
|
-
}
|
|
157
|
-
return null
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function beijingHour(nowMs: number): number {
|
|
161
|
-
return Math.floor(((nowMs + 8 * 3600_000) % 86400_000) / 3600_000)
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function inAllowedWindow(nowMs: number, avoid?: { start?: number; end?: number }): boolean {
|
|
165
|
-
const start = avoid?.start ?? 8
|
|
166
|
-
const end = avoid?.end ?? 18
|
|
167
|
-
const h = beijingHour(nowMs)
|
|
168
|
-
if (start <= end) return h < start || h >= end
|
|
169
|
-
return h >= end && h < start
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// ── 子命令实现 ──
|
|
173
|
-
|
|
174
|
-
function doc(root: string): string {
|
|
175
|
-
const p = join(dirname(process.argv[1] ?? ''), '..', 'SKILL.md')
|
|
176
|
-
if (existsSync(p)) return readUtf8(p)
|
|
177
|
-
return `SKILL.md 未找到(${p})——实验定义见 serenity-acc-specs docs/self-sustaining-trajectory-hypothesis.md §7.1`
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function check(root: string): string {
|
|
181
|
-
const cfg = loadConfig(root)
|
|
182
|
-
const lines: string[] = [`[autopilot-trajectory] 实验就绪度检查(CCC: ${basename(root)})`, '']
|
|
183
|
-
const fail: string[] = []
|
|
184
|
-
|
|
185
|
-
if (!cfg) {
|
|
186
|
-
lines.push('✗ 未配置 autopilotTrajectory(.opencode/serenity.json 缺段)——acc_msm exec autopilot-trajectory init 一键初始化')
|
|
187
|
-
fail.push('config')
|
|
188
|
-
} else if (!cfg.enabled) {
|
|
189
|
-
lines.push('✗ autopilotTrajectory.enabled = false(未开启)')
|
|
190
|
-
fail.push('enabled')
|
|
191
|
-
} else {
|
|
192
|
-
lines.push(`✓ enabled = true`)
|
|
193
|
-
lines.push(` intervalHours = ${cfg.intervalHours ?? 12}`)
|
|
194
|
-
lines.push(` biasProvider = ${cfg.biasProvider?.trim() || DEFAULT_BIAS_PROVIDER}`)
|
|
195
|
-
if (cfg.topPrompt?.trim()) {
|
|
196
|
-
lines.push(`✓ topPrompt(轨迹焦点)已定义: ${cfg.topPrompt.trim().slice(0, 60)}${cfg.topPrompt.trim().length > 60 ? '…' : ''}(每次唤起最先注入,锚定防漂移)`)
|
|
197
|
-
} else {
|
|
198
|
-
lines.push(`⚠ topPrompt(轨迹焦点)未定义——建议 CCC 定义 autopilotTrajectory 时填写本轨迹核心焦点(实验观察:无焦点锚定,多轮唤起轨迹易漂移腐化)`)
|
|
199
|
-
}
|
|
200
|
-
if (cfg.session) lines.push(` session = ${cfg.session}`)
|
|
201
|
-
const avoid = cfg.avoidWakeHours
|
|
202
|
-
lines.push(` 唤起窗口避开北京 ${avoid?.start ?? 8}~${avoid?.end ?? 18} 点(用量峰谷省钱)`)
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const provider = cfg?.biasProvider?.trim() || DEFAULT_BIAS_PROVIDER
|
|
206
|
-
if (cfg?.enabled) {
|
|
207
|
-
const bias = runBiasProvider(root, provider)
|
|
208
|
-
if (bias.error) {
|
|
209
|
-
lines.push(`✗ 偏见内容提供者未就绪: ${bias.error}`)
|
|
210
|
-
fail.push('biasProvider')
|
|
211
|
-
} else {
|
|
212
|
-
lines.push(`✓ 偏见内容提供者可运行(输出示例: ${bias.text ?? '(空输出)'})`)
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
const md = resolveTargetMd(root, cfg ?? {})
|
|
217
|
-
if (!cfg?.session) {
|
|
218
|
-
lines.push('✗ 未配置 session(必填——自动唤起不默认任何会话,CCC 日常多轨迹并行)')
|
|
219
|
-
fail.push('session')
|
|
220
|
-
} else if (md) {
|
|
221
|
-
const flag = basename(dirname(md)).endsWith(AUTO_SUFFIX)
|
|
222
|
-
lines.push(`${flag ? '✓' : '✗'} 目标会话目录${flag ? '带' : '未带'} --auto 标志:${basename(dirname(md))}`)
|
|
223
|
-
if (!flag) {
|
|
224
|
-
lines.push(` → 目录名需以 --auto 结尾(AGENT_SESSIONS/<date>--<desc>--auto/)`)
|
|
225
|
-
fail.push('autoFlag')
|
|
226
|
-
}
|
|
227
|
-
const content = readUtf8(md)
|
|
228
|
-
if (content.includes(MOTIVATION_MARKER)) {
|
|
229
|
-
lines.push(`✓ SESSION.md 含「下一轮动机」段(自生偏见)`)
|
|
230
|
-
} else {
|
|
231
|
-
lines.push(`· SESSION.md 无「下一轮动机」段(可选——纯偏见内容亦可)`)
|
|
232
|
-
}
|
|
233
|
-
} else {
|
|
234
|
-
lines.push(`✗ 目标会话未命中:${cfg.session}(AGENT_SESSIONS 无匹配目录)`)
|
|
235
|
-
fail.push('session')
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
lines.push('')
|
|
239
|
-
lines.push(fail.length === 0 ? '✅ 实验就绪——等待时钟唤起(前台可见)' : `⚠️ 未就绪:${fail.join(', ')}`)
|
|
240
|
-
return lines.join('\n')
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
function status(root: string): string {
|
|
244
|
-
const cfg = loadConfig(root)
|
|
245
|
-
const now = Date.now()
|
|
246
|
-
const lines: string[] = [`[autopilot-trajectory] 实验状态(CCC: ${basename(root)},北京 ${beijingHour(now)} 点)`, '']
|
|
247
|
-
if (!cfg?.enabled) {
|
|
248
|
-
lines.push('autopilotTrajectory 未启用(enabled=false 或未配置)——零资源占用')
|
|
249
|
-
return lines.join('\n')
|
|
250
|
-
}
|
|
251
|
-
lines.push(`配置: intervalHours=${cfg.intervalHours ?? 12} | biasProvider=${cfg.biasProvider?.trim() || DEFAULT_BIAS_PROVIDER}${cfg.session ? ` | session=${cfg.session}` : ''}${cfg.topPrompt?.trim() ? ' | topPrompt ✓' : ''}`)
|
|
252
|
-
const md = resolveTargetMd(root, cfg)
|
|
253
|
-
if (!md) {
|
|
254
|
-
lines.push('目标会话:未找到')
|
|
255
|
-
return lines.join('\n')
|
|
256
|
-
}
|
|
257
|
-
const mtime = statSync(md).mtimeMs
|
|
258
|
-
const idleHours = (now - mtime) / 3600_000
|
|
259
|
-
const interval = Math.max(1, cfg.intervalHours ?? 12)
|
|
260
|
-
lines.push(`目标会话:${basename(dirname(md))}${basename(dirname(md)).endsWith(AUTO_SUFFIX) ? '(--auto ✓)' : '(无 --auto 标志)'}`)
|
|
261
|
-
lines.push(`上次轨迹活动:${idleHours.toFixed(1)} 小时前(阈值 ${interval}h)`)
|
|
262
|
-
lines.push(`唤起窗口:${inAllowedWindow(now, cfg.avoidWakeHours) ? '✅ 允许唤起' : '⏸ 高峰避开中(北京 8~18)'}`)
|
|
263
|
-
const wakeable = inAllowedWindow(now, cfg.avoidWakeHours) && idleHours >= interval
|
|
264
|
-
lines.push(`是否可唤起:${wakeable ? '✅ 是(等待下一个 10min tick)' : idleHours < interval ? `否——距上次活动不足 ${interval}h` : '否——高峰避开中'}`)
|
|
265
|
-
return lines.join('\n')
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function guide(): string {
|
|
269
|
-
return [
|
|
270
|
-
'[autopilot-trajectory] 实验步骤指引',
|
|
271
|
-
'',
|
|
272
|
-
'① 初始化(一键):acc_msm exec autopilot-trajectory init',
|
|
273
|
-
' ——写配置(.opencode/serenity.json autopilotTrajectory 段)+ 生成偏见提供者脚本模板(CCC 根 autopilot-bias.ts)',
|
|
274
|
-
'② **定义轨迹焦点(topPrompt)**:编辑配置中的 topPrompt——**CCC 自己填写**本轨迹的核心',
|
|
275
|
-
' 目标/纪律/质量要求(示例:"持续深化某领域认知,产出可重建的结论与决策记录")。',
|
|
276
|
-
' 它会在每次唤起时最先注入([轨迹焦点] 段),作为稳定焦点锚定 trajectory 防漂移——',
|
|
277
|
-
' **实验观察:无焦点锚定时多轮唤起轨迹腐化严重(焦点丢失)**。勿留空。',
|
|
278
|
-
'③ 实现偏见内容提供者:编辑 autopilot-bias.ts,stdout 输出偏见内容(反事实方向/探索动机,',
|
|
279
|
-
' 用本 CCC 自己的信息来源保证"足够随机");acc_msm exec autopilot-trajectory random 验证',
|
|
280
|
-
'④ 标记目标会话:目录名加 --auto 后缀 AGENT_SESSIONS/<date>--<desc>--auto/',
|
|
281
|
-
' (可选)该 SESSION.md 写「下一轮动机」段作自生偏见',
|
|
282
|
-
'⑤ 验证就绪:acc_msm exec autopilot-trajectory(一站式报告应为 ✅;topPrompt 未定义会 ⚠ 提示)',
|
|
283
|
-
'⑥ 观察:无人类活动满 intervalHours 且北京非高峰 → 前台会话自动出现 [自主轨迹唤起]',
|
|
284
|
-
' 产出落 SESSION.md「自主探索日志」+ 预写「下一轮动机」',
|
|
285
|
-
'',
|
|
286
|
-
'分工:焦点(topPrompt)= 稳定锚,每轮不变;偏见(biasProvider)= 随机探索方向,每轮不同——两者都由 CCC 定义。',
|
|
287
|
-
'完整定义见 SKILL.md(acc_msm exec autopilot-trajectory doc)',
|
|
288
|
-
].join('\n')
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/** 初始化:合并写配置(不覆盖其他段)+ 生成偏见提供者脚本模板(已存在则跳过) */
|
|
292
|
-
function init(root: string): string {
|
|
293
|
-
const out: string[] = ['[autopilot-trajectory] 初始化实验', '']
|
|
294
|
-
|
|
295
|
-
// ① 写配置
|
|
296
|
-
let cfgPath = join(root, CONFIG_PATHS[0]!)
|
|
297
|
-
if (!existsSync(cfgPath)) {
|
|
298
|
-
const alt = join(root, CONFIG_PATHS[1]!)
|
|
299
|
-
cfgPath = existsSync(alt) ? alt : cfgPath
|
|
300
|
-
}
|
|
301
|
-
mkdirSync(dirname(cfgPath), { recursive: true })
|
|
302
|
-
let merged: Record<string, unknown> = {}
|
|
303
|
-
if (existsSync(cfgPath)) {
|
|
304
|
-
try {
|
|
305
|
-
merged = JSON.parse(readUtf8(cfgPath)) as Record<string, unknown>
|
|
306
|
-
} catch {
|
|
307
|
-
/* 损坏则重建 */
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
const at = (merged.autopilotTrajectory as Record<string, unknown> | undefined) ?? {}
|
|
311
|
-
merged.autopilotTrajectory = {
|
|
312
|
-
enabled: true,
|
|
313
|
-
intervalHours: 12,
|
|
314
|
-
biasProvider: DEFAULT_BIAS_PROVIDER,
|
|
315
|
-
// 轨迹焦点(topPrompt):**CCC 自己定义**本轨迹的核心目标/纪律/质量要求——每次唤起最先
|
|
316
|
-
// 注入,作为稳定焦点锚定 trajectory,防止多轮自主唤起中焦点丢失(腐化)。请按本 CCC
|
|
317
|
-
// 的轨迹目标改写,不要留空(留空 = 唤起无焦点锚定,轨迹易漂移)。
|
|
318
|
-
topPrompt: '本轨迹的核心焦点:<CCC 填写——例如:持续深化某领域认知,产出可重建的结论与决策记录>',
|
|
319
|
-
...at,
|
|
320
|
-
}
|
|
321
|
-
writeFileSync(cfgPath, `${JSON.stringify(merged, null, 2)}\n`)
|
|
322
|
-
out.push(`✓ 配置写入: ${cfgPath}`)
|
|
323
|
-
out.push(` autopilotTrajectory = ${JSON.stringify(merged.autopilotTrajectory)}`)
|
|
324
|
-
out.push(` ⚠ 请编辑 topPrompt 为**本 CCC 的轨迹焦点**(现为占位——每次唤起最先注入,防轨迹漂移,勿留空)`)
|
|
325
|
-
|
|
326
|
-
// ② 生成偏见提供者脚本模板
|
|
327
|
-
const scriptAbs = biasProviderPath(root, DEFAULT_BIAS_PROVIDER)
|
|
328
|
-
if (existsSync(scriptAbs)) {
|
|
329
|
-
out.push(`· 偏见提供者脚本已存在(保留): ${DEFAULT_BIAS_PROVIDER}`)
|
|
330
|
-
} else {
|
|
331
|
-
writeFileSync(scriptAbs, BIAS_TEMPLATE)
|
|
332
|
-
out.push(`✓ 已生成偏见提供者脚本模板: ${DEFAULT_BIAS_PROVIDER}(编辑它,stdout 输出偏见内容)`)
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
out.push('', '下一步:② 编辑配置 topPrompt(轨迹焦点——CCC 自己填写本轨迹核心目标,勿留空)→ ③ 标记目标会话 --auto 后缀 → ⑤ acc_msm exec autopilot-trajectory 验证就绪')
|
|
336
|
-
return out.join('\n')
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
/** random:运行偏见提供者脚本,输出当前偏见内容(验证) */
|
|
340
|
-
function random(root: string): string {
|
|
341
|
-
const cfg = loadConfig(root)
|
|
342
|
-
const provider = cfg?.biasProvider?.trim() || DEFAULT_BIAS_PROVIDER
|
|
343
|
-
const bias = runBiasProvider(root, provider)
|
|
344
|
-
if (bias.error) return `[autopilot-trajectory] ✗ ${bias.error}`
|
|
345
|
-
return `[autopilot-trajectory] 当前偏见内容(${provider}):\n${bias.text ?? '(空输出)'}`
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/** 一站式全报告:背景 + 就绪检查 + 状态 + 下一步 + 指引(CCC agent 看一次即懂并知道下一步) */
|
|
349
|
-
function all(root: string): string {
|
|
350
|
-
const cfg = loadConfig(root)
|
|
351
|
-
const ready = check(root)
|
|
352
|
-
const stat = status(root)
|
|
353
|
-
const next: string[] = ['═══ 下一步 ═══']
|
|
354
|
-
if (!cfg) {
|
|
355
|
-
next.push('→ 本 CCC 尚未配置 autopilotTrajectory。开始实验:acc_msm exec autopilot-trajectory init 一键初始化。')
|
|
356
|
-
} else if (!cfg.enabled) {
|
|
357
|
-
next.push('→ autopilotTrajectory.enabled 为 false——置 true 开启实验(或 init 重新初始化)。')
|
|
358
|
-
} else if (ready.includes('✗')) {
|
|
359
|
-
next.push('→ 存在未就绪项(见上)。补齐后重跑本命令确认 ✅。')
|
|
360
|
-
} else {
|
|
361
|
-
next.push('→ 已就绪 ✅。保持会话空闲满 intervalHours 且北京非高峰 → 自动唤起(前台可见)。')
|
|
362
|
-
next.push('→ 之后可随时 acc_msm exec autopilot-trajectory status 查看距下次唤起的进度。')
|
|
363
|
-
}
|
|
364
|
-
return [BACKGROUND, ready, '', stat, '', next.join('\n'), '', guide()].join('\n')
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
/** 唤起条件链诊断(单 CCC)——逐条件当前值 + 阻断点 + 修复建议 */
|
|
368
|
-
function diagCcc(root: string): string {
|
|
369
|
-
const now = Date.now()
|
|
370
|
-
const lines: string[] = [`═══ 自主轨迹唤起诊断:${basename(root)}(${root})═══`]
|
|
371
|
-
const cfg = loadConfig(root)
|
|
372
|
-
const blocks: string[] = []
|
|
373
|
-
const suggest: string[] = []
|
|
374
|
-
|
|
375
|
-
// ① enabled(定时器是否启动)
|
|
376
|
-
if (!cfg) {
|
|
377
|
-
blocks.push('✗ autopilotTrajectory 未配置(定时器不启动)')
|
|
378
|
-
suggest.push('配置:.opencode/serenity.json 加 autopilotTrajectory 段(autopilot-trajectory init 可生成)')
|
|
379
|
-
} else if (!cfg.enabled) {
|
|
380
|
-
blocks.push('✗ enabled = false(定时器不启动)')
|
|
381
|
-
suggest.push('置 enabled: true')
|
|
382
|
-
} else {
|
|
383
|
-
blocks.push('✓ enabled = true')
|
|
384
|
-
}
|
|
385
|
-
if (cfg) {
|
|
386
|
-
blocks.push(` 配置: intervalHours=${cfg.intervalHours ?? 12} | biasProvider=${cfg.biasProvider?.trim() || DEFAULT_BIAS_PROVIDER}${cfg.session ? ` | session=${cfg.session}` : ' | session=未配置'}`)
|
|
387
|
-
const avoid = cfg.avoidWakeHours
|
|
388
|
-
blocks.push(` 窗口避开北京 ${avoid?.start ?? 8}~${avoid?.end ?? 18} 点`)
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// ② session(必填——不默认任何会话)
|
|
392
|
-
const md = resolveTargetMd(root, cfg ?? {})
|
|
393
|
-
if (!cfg?.session) {
|
|
394
|
-
blocks.push('✗ session 未配置(必填——自动唤起不默认任何会话)')
|
|
395
|
-
suggest.push('配置 session: "S###"(目标会话 S###/目录名)')
|
|
396
|
-
} else if (!md) {
|
|
397
|
-
blocks.push(`✗ session=${cfg.session} 未命中(AGENT_SESSIONS 无匹配目录)`)
|
|
398
|
-
suggest.push('确认目标会话存在(目录名含该关键字)')
|
|
399
|
-
} else {
|
|
400
|
-
blocks.push(`✓ session=${cfg.session} 命中(${basename(dirname(md))})`)
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
// ③ --auto 会话标志
|
|
404
|
-
if (md) {
|
|
405
|
-
const flag = basename(dirname(md)).endsWith(AUTO_SUFFIX)
|
|
406
|
-
if (flag) {
|
|
407
|
-
blocks.push('✓ 会话目录带 --auto 标志')
|
|
408
|
-
} else {
|
|
409
|
-
blocks.push(`✗ 会话目录无 --auto 标志(${basename(dirname(md))})`)
|
|
410
|
-
suggest.push('目录名加 --auto 后缀:AGENT_SESSIONS/<date>--<desc>--auto/')
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
// ④ mtime 间隔(无人类活动时长)
|
|
415
|
-
if (md) {
|
|
416
|
-
const mtime = statSync(md).mtimeMs
|
|
417
|
-
const idle = (now - mtime) / 3600_000
|
|
418
|
-
const interval = Math.max(1, cfg?.intervalHours ?? 12)
|
|
419
|
-
if (idle >= interval) blocks.push(`✓ 距上次轨迹活动 ${idle.toFixed(1)}h ≥ 阈值 ${interval}h`)
|
|
420
|
-
else blocks.push(`⏸ 距上次轨迹活动 ${idle.toFixed(1)}h < 阈值 ${interval}h(等待中——不满足不唤起)`)
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// ⑤ 北京时间唤起窗口
|
|
424
|
-
const h = beijingHour(now)
|
|
425
|
-
const inWin = inAllowedWindow(now, cfg?.avoidWakeHours)
|
|
426
|
-
blocks.push(`${inWin ? '✓' : '⏸'} 当前北京 ${h} 点——${inWin ? '在唤起窗口内' : '高峰避开中(缺省 8~18,用量峰谷省钱)'}`)
|
|
427
|
-
|
|
428
|
-
// ⑥ 偏见内容提供者脚本
|
|
429
|
-
if (cfg?.enabled) {
|
|
430
|
-
const provider = cfg.biasProvider?.trim() || DEFAULT_BIAS_PROVIDER
|
|
431
|
-
const bias = runBiasProvider(root, provider)
|
|
432
|
-
if (bias.error) {
|
|
433
|
-
blocks.push(`✗ 偏见脚本: ${bias.error}`)
|
|
434
|
-
suggest.push('实现偏见脚本(autopilot-trajectory init 生成模板后编辑)')
|
|
435
|
-
} else {
|
|
436
|
-
blocks.push(`✓ 偏见脚本可运行(输出: ${bias.text ?? '(空)'})`)
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
lines.push(...blocks.map((b) => ` ${b}`))
|
|
441
|
-
lines.push('')
|
|
442
|
-
const bad = blocks.filter((b) => b.startsWith('✗'))
|
|
443
|
-
if (bad.length === 0) {
|
|
444
|
-
lines.push('✅ 唤起条件全部满足——等待下一个 10min tick 自动唤起(前台可见)')
|
|
445
|
-
} else {
|
|
446
|
-
lines.push(`⚠️ 阻断点 ${bad.length} 项(全部满足才唤起):`)
|
|
447
|
-
for (const s of suggest) lines.push(` → ${s}`)
|
|
448
|
-
}
|
|
449
|
-
return lines.join('\n')
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
/** diag:--ccc <path> 指定目标 CCC;无参扫描常见 CCC 根(配置了 autopilotTrajectory 的优先) */
|
|
453
|
-
function diag(): string {
|
|
454
|
-
const argIdx = process.argv.indexOf('--ccc')
|
|
455
|
-
if (argIdx >= 0 && process.argv[argIdx + 1]) {
|
|
456
|
-
return diagCcc(resolve(process.argv[argIdx + 1]!))
|
|
457
|
-
}
|
|
458
|
-
const roots = new Set<string>()
|
|
459
|
-
const envRoot = process.env.SERENITY_ROOT
|
|
460
|
-
if (envRoot && existsSync(join(envRoot, '.serenity'))) roots.add(envRoot)
|
|
461
|
-
// 递归扫描 /home/yh 两层(覆盖 /home/yh/home/*、/home/yh/our-home/* 及任意实验 CCC 位置)
|
|
462
|
-
for (const base of ['/home/yh']) {
|
|
463
|
-
collectCccs(base, 0, roots, 2)
|
|
464
|
-
}
|
|
465
|
-
const list = [...roots]
|
|
466
|
-
if (list.length === 0) return '[autopilot-trajectory diag] 未发现 CCC(用 --ccc <path> 指定目标)'
|
|
467
|
-
const ordered = [...list.filter((r) => loadConfig(r)?.enabled), ...list.filter((r) => !loadConfig(r)?.enabled)]
|
|
468
|
-
return ordered.map(diagCcc).join('\n\n')
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
/** 递归收集 .serenity 标记目录(跳过隐藏目录;maxDepth 层内) */
|
|
472
|
-
function collectCccs(dir: string, depth: number, out: Set<string>, maxDepth: number): void {
|
|
473
|
-
if (depth > maxDepth || !existsSync(dir)) return
|
|
474
|
-
for (const d of readdirSync(dir, { withFileTypes: true })) {
|
|
475
|
-
if (!d.isDirectory() || d.name.startsWith('.')) continue
|
|
476
|
-
const r = join(dir, d.name)
|
|
477
|
-
if (existsSync(join(r, '.serenity'))) out.add(r)
|
|
478
|
-
collectCccs(r, depth + 1, out, maxDepth)
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
function main(): void {
|
|
483
|
-
const cmd = process.argv[2] ?? 'all'
|
|
484
|
-
const root = findRoot()
|
|
485
|
-
if (!root) {
|
|
486
|
-
console.error('[autopilot-trajectory] ✗ 未找到 CCC 根(无 .serenity;acc_msm exec 会自动注入 SERENITY_ROOT)')
|
|
487
|
-
process.exit(1)
|
|
488
|
-
}
|
|
489
|
-
switch (cmd) {
|
|
490
|
-
case 'all':
|
|
491
|
-
console.log(all(root))
|
|
492
|
-
break
|
|
493
|
-
case 'init':
|
|
494
|
-
console.log(init(root))
|
|
495
|
-
break
|
|
496
|
-
case 'random':
|
|
497
|
-
console.log(random(root))
|
|
498
|
-
break
|
|
499
|
-
case 'diag':
|
|
500
|
-
console.log(diag())
|
|
501
|
-
break
|
|
502
|
-
case 'doc':
|
|
503
|
-
console.log(doc(root))
|
|
504
|
-
break
|
|
505
|
-
case 'check':
|
|
506
|
-
console.log(check(root))
|
|
507
|
-
break
|
|
508
|
-
case 'status':
|
|
509
|
-
console.log(status(root))
|
|
510
|
-
break
|
|
511
|
-
case 'guide':
|
|
512
|
-
console.log(guide())
|
|
513
|
-
break
|
|
514
|
-
default:
|
|
515
|
-
console.error(`[autopilot-trajectory] 未知子命令: ${cmd}(可用: 无参一站式 / init / random / diag / doc / check / status / guide)`)
|
|
516
|
-
process.exit(2)
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
if (import.meta.main) {
|
|
521
|
-
main()
|
|
522
|
-
}
|