@shgroup/dsh-serenity-hooks 1.26.13 → 1.26.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-serenity-hooks",
3
- "version": "1.26.13",
3
+ "version": "1.26.15",
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": {
@@ -6,6 +6,7 @@
6
6
  * acc_msm exec autotrajectory-exp → 一站式全报告(背景 + 就绪 + 状态 + 下一步)
7
7
  * acc_msm exec autotrajectory-exp init → 初始化实验(写配置 + 生成偏见提供者脚本模板)
8
8
  * acc_msm exec autotrajectory-exp random → 运行偏见提供者脚本,输出当前偏见内容(验证)
9
+ * acc_msm exec autotrajectory-exp diag → 唤起条件链诊断(--ccc <path> 指定;无参递归扫描 /home/yh 两层)
9
10
  * acc_msm exec autotrajectory-exp doc → 实验定义说明全文(SKILL.md)
10
11
  * acc_msm exec autotrajectory-exp check → 仅就绪度检查
11
12
  * acc_msm exec autotrajectory-exp status → 仅当前状态
@@ -15,6 +16,9 @@
15
16
  * stdout 输出本轮唤起要注入的偏见内容(反事实方向/探索动机等)。tool 直接运行它;
16
17
  * 脚本缺失 → 报错要求实现(不再经 mech-registry 注册 MSM)。
17
18
  *
19
+ * 状态查看:WebUI 设置面板「自主轨迹」区块(GET /serenity/autotrajectory)+「立即唤起」按钮
20
+ * (POST /serenity/autotrajectory {action:'wake'},调试语义跳过窗口/间隔)——由插件提供,脚本不重复。
21
+ *
18
22
  * 零 DSH 依赖,任何 CCC 可运行。环境:SERENITY_ROOT(acc_msm exec 注入)或 cwd 上溯 .serenity。
19
23
  */
20
24
 
@@ -343,6 +347,121 @@ function all(root: string): string {
343
347
  return [BACKGROUND, ready, '', stat, '', next.join('\n'), '', guide()].join('\n')
344
348
  }
345
349
 
350
+ /** 唤起条件链诊断(单 CCC)——逐条件当前值 + 阻断点 + 修复建议 */
351
+ function diagCcc(root: string): string {
352
+ const now = Date.now()
353
+ const lines: string[] = [`═══ 自主轨迹唤起诊断:${basename(root)}(${root})═══`]
354
+ const cfg = loadConfig(root)
355
+ const blocks: string[] = []
356
+ const suggest: string[] = []
357
+
358
+ // ① enabled(定时器是否启动)
359
+ if (!cfg) {
360
+ blocks.push('✗ autotrajectory 未配置(定时器不启动)')
361
+ suggest.push('配置:.opencode/serenity.json 加 autotrajectory 段(autotrajectory-exp init 可生成)')
362
+ } else if (!cfg.enabled) {
363
+ blocks.push('✗ enabled = false(定时器不启动)')
364
+ suggest.push('置 enabled: true')
365
+ } else {
366
+ blocks.push('✓ enabled = true')
367
+ }
368
+ if (cfg) {
369
+ blocks.push(` 配置: intervalHours=${cfg.intervalHours ?? 12} | biasProvider=${cfg.biasProvider?.trim() || DEFAULT_BIAS_PROVIDER}${cfg.session ? ` | session=${cfg.session}` : ' | session=未配置'}`)
370
+ const avoid = cfg.avoidWakeHours
371
+ blocks.push(` 窗口避开北京 ${avoid?.start ?? 8}~${avoid?.end ?? 18} 点`)
372
+ }
373
+
374
+ // ② session(必填——不默认任何会话)
375
+ const md = resolveTargetMd(root, cfg ?? {})
376
+ if (!cfg?.session) {
377
+ blocks.push('✗ session 未配置(必填——自动唤起不默认任何会话)')
378
+ suggest.push('配置 session: "S###"(目标会话 S###/目录名)')
379
+ } else if (!md) {
380
+ blocks.push(`✗ session=${cfg.session} 未命中(AGENT_SESSIONS 无匹配目录)`)
381
+ suggest.push('确认目标会话存在(目录名含该关键字)')
382
+ } else {
383
+ blocks.push(`✓ session=${cfg.session} 命中(${basename(dirname(md))})`)
384
+ }
385
+
386
+ // ③ --auto 会话标志
387
+ if (md) {
388
+ const flag = basename(dirname(md)).endsWith(AUTO_SUFFIX)
389
+ if (flag) {
390
+ blocks.push('✓ 会话目录带 --auto 标志')
391
+ } else {
392
+ blocks.push(`✗ 会话目录无 --auto 标志(${basename(dirname(md))})`)
393
+ suggest.push('目录名加 --auto 后缀:AGENT_SESSIONS/<date>--<desc>--auto/')
394
+ }
395
+ }
396
+
397
+ // ④ mtime 间隔(无人类活动时长)
398
+ if (md) {
399
+ const mtime = statSync(md).mtimeMs
400
+ const idle = (now - mtime) / 3600_000
401
+ const interval = Math.max(1, cfg?.intervalHours ?? 12)
402
+ if (idle >= interval) blocks.push(`✓ 距上次轨迹活动 ${idle.toFixed(1)}h ≥ 阈值 ${interval}h`)
403
+ else blocks.push(`⏸ 距上次轨迹活动 ${idle.toFixed(1)}h < 阈值 ${interval}h(等待中——不满足不唤起)`)
404
+ }
405
+
406
+ // ⑤ 北京时间唤起窗口
407
+ const h = beijingHour(now)
408
+ const inWin = inAllowedWindow(now, cfg?.avoidWakeHours)
409
+ blocks.push(`${inWin ? '✓' : '⏸'} 当前北京 ${h} 点——${inWin ? '在唤起窗口内' : '高峰避开中(缺省 8~18,用量峰谷省钱)'}`)
410
+
411
+ // ⑥ 偏见内容提供者脚本
412
+ if (cfg?.enabled) {
413
+ const provider = cfg.biasProvider?.trim() || DEFAULT_BIAS_PROVIDER
414
+ const bias = runBiasProvider(root, provider)
415
+ if (bias.error) {
416
+ blocks.push(`✗ 偏见脚本: ${bias.error}`)
417
+ suggest.push('实现偏见脚本(autotrajectory-exp init 生成模板后编辑)')
418
+ } else {
419
+ blocks.push(`✓ 偏见脚本可运行(输出: ${bias.text ?? '(空)'})`)
420
+ }
421
+ }
422
+
423
+ lines.push(...blocks.map((b) => ` ${b}`))
424
+ lines.push('')
425
+ const bad = blocks.filter((b) => b.startsWith('✗'))
426
+ if (bad.length === 0) {
427
+ lines.push('✅ 唤起条件全部满足——等待下一个 10min tick 自动唤起(前台可见)')
428
+ } else {
429
+ lines.push(`⚠️ 阻断点 ${bad.length} 项(全部满足才唤起):`)
430
+ for (const s of suggest) lines.push(` → ${s}`)
431
+ }
432
+ return lines.join('\n')
433
+ }
434
+
435
+ /** diag:--ccc <path> 指定目标 CCC;无参扫描常见 CCC 根(配置了 autotrajectory 的优先) */
436
+ function diag(): string {
437
+ const argIdx = process.argv.indexOf('--ccc')
438
+ if (argIdx >= 0 && process.argv[argIdx + 1]) {
439
+ return diagCcc(resolve(process.argv[argIdx + 1]!))
440
+ }
441
+ const roots = new Set<string>()
442
+ const envRoot = process.env.SERENITY_ROOT
443
+ if (envRoot && existsSync(join(envRoot, '.serenity'))) roots.add(envRoot)
444
+ // 递归扫描 /home/yh 两层(覆盖 /home/yh/home/*、/home/yh/our-home/* 及任意实验 CCC 位置)
445
+ for (const base of ['/home/yh']) {
446
+ collectCccs(base, 0, roots, 2)
447
+ }
448
+ const list = [...roots]
449
+ if (list.length === 0) return '[autotrajectory-exp diag] 未发现 CCC(用 --ccc <path> 指定目标)'
450
+ const ordered = [...list.filter((r) => loadConfig(r)?.enabled), ...list.filter((r) => !loadConfig(r)?.enabled)]
451
+ return ordered.map(diagCcc).join('\n\n')
452
+ }
453
+
454
+ /** 递归收集 .serenity 标记目录(跳过隐藏目录;maxDepth 层内) */
455
+ function collectCccs(dir: string, depth: number, out: Set<string>, maxDepth: number): void {
456
+ if (depth > maxDepth || !existsSync(dir)) return
457
+ for (const d of readdirSync(dir, { withFileTypes: true })) {
458
+ if (!d.isDirectory() || d.name.startsWith('.')) continue
459
+ const r = join(dir, d.name)
460
+ if (existsSync(join(r, '.serenity'))) out.add(r)
461
+ collectCccs(r, depth + 1, out, maxDepth)
462
+ }
463
+ }
464
+
346
465
  function main(): void {
347
466
  const cmd = process.argv[2] ?? 'all'
348
467
  const root = findRoot()
@@ -360,6 +479,9 @@ function main(): void {
360
479
  case 'random':
361
480
  console.log(random(root))
362
481
  break
482
+ case 'diag':
483
+ console.log(diag())
484
+ break
363
485
  case 'doc':
364
486
  console.log(doc(root))
365
487
  break
@@ -373,7 +495,7 @@ function main(): void {
373
495
  console.log(guide())
374
496
  break
375
497
  default:
376
- console.error(`[autotrajectory-exp] 未知子命令: ${cmd}(可用: 无参一站式 / init / random / doc / check / status / guide)`)
498
+ console.error(`[autotrajectory-exp] 未知子命令: ${cmd}(可用: 无参一站式 / init / random / diag / doc / check / status / guide)`)
377
499
  process.exit(2)
378
500
  }
379
501
  }
package/lib/client.js CHANGED
@@ -4099,7 +4099,7 @@ Instruction-following style:
4099
4099
  }
4100
4100
  //#endregion
4101
4101
  //#region \0sp-css:/home/yh/home/home-serenity/AI_LAB/dsh-serenity-plugin/hooks/dsh-serenity-hooks/src/client/SettingsSection
4102
- const css = "/* SettingsSection — dsh 原生设置面板 serenity-hooks 简单配置页\n v1.21.1 看齐 dsh 自身:官方 settings 设计语言——\n section > title + intro + group(groupTitle) + rowCard 行卡;\n 全部 --dsw-alias-* token(与 ui-settings-models 同词汇表)。 */\n\n/* 页面容器(官方 .section:flex column gap 12) */\n.ss-section {\n display: flex;\n flex-direction: column;\n gap: 14px;\n max-width: 720px;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 页面标题(官方 .title:16px/24 500) */\n.ss-title {\n margin: 0;\n font-size: 16px;\n line-height: 24px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 页面说明(官方 .intro:14px/22 tertiary) */\n.ss-intro {\n margin: 0;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 分组(多级标题:分组标题 + 行卡列表) */\n.ss-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* 分组标题(二级:12px/18 500 secondary——官方 fieldLabel 风格) */\n.ss-groupTitle {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* 行卡列表(官方 .rows:无 marker,gap 8) */\n.ss-rows {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* 行卡(官方 .rowCard:border-l2 r12 padding 12/14) */\n.ss-rowCard {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n padding: 12px 14px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n}\n\n/* 行卡文本(标题 + 说明 左列) */\n.ss-rowText {\n display: flex;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n flex: 1;\n}\n\n/* 行卡标题(官方 .rowName:14px/22 500) */\n.ss-rowName {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 行卡说明(12px/18 tertiary) */\n.ss-rowDesc {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 行卡控件(右置) */\n.ss-rowControl {\n flex: none;\n display: flex;\n align-items: center;\n}\n\n/* 开关(官方 token 的自绘 toggle:track 22px,thumb 16px) */\n.ss-switch {\n position: relative;\n flex: none;\n width: 40px;\n height: 22px;\n cursor: pointer;\n}\n\n.ss-switch input {\n position: absolute;\n opacity: 0;\n width: 100%;\n height: 100%;\n margin: 0;\n cursor: pointer;\n}\n\n.ss-switchTrack {\n position: absolute;\n inset: 0;\n border-radius: 11px;\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.3));\n transition: background var(--ds-transition-duration-fast, 0.15s) var(--ds-ease-in-out, ease);\n}\n\n.ss-switchTrack::after {\n content: '';\n position: absolute;\n top: 3px;\n left: 3px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--dsw-alias-label-primary, #eee);\n transition: transform var(--ds-transition-duration-fast, 0.15s) var(--ds-ease-in-out, ease);\n}\n\n.ss-switch input:checked + .ss-switchTrack {\n background: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n.ss-switch input:checked + .ss-switchTrack::after {\n transform: translateX(18px);\n}\n\n.ss-switch input:disabled + .ss-switchTrack {\n opacity: 0.4;\n cursor: default;\n}\n\n/* 阈值行(滑块 + 值) */\n.ss-threshold {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.ss-threshold input[type='range'] {\n width: 160px;\n}\n\n/* Skiff 调试端口输入(number;关闭时跟随 disabled 半透明) */\n.ss-portInput {\n width: 96px;\n padding: 6px 8px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-fill-l1, rgba(128, 128, 128, 0.08));\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n\n.ss-portInput:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n.ss-value {\n min-width: 40px;\n font-variant-numeric: tabular-nums;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n text-align: right;\n}\n\n/* 底部帮助行 */\n.ss-hint {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 降级提示 */\n.ss-degrade {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-warn-label);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n";
4102
+ const css = "/* SettingsSection — dsh 原生设置面板 serenity-hooks 简单配置页\n v1.21.1 看齐 dsh 自身:官方 settings 设计语言——\n section > title + intro + group(groupTitle) + rowCard 行卡;\n 全部 --dsw-alias-* token(与 ui-settings-models 同词汇表)。 */\n\n/* 页面容器(官方 .section:flex column gap 12) */\n.ss-section {\n display: flex;\n flex-direction: column;\n gap: 14px;\n max-width: 720px;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 页面标题(官方 .title:16px/24 500) */\n.ss-title {\n margin: 0;\n font-size: 16px;\n line-height: 24px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 页面说明(官方 .intro:14px/22 tertiary) */\n.ss-intro {\n margin: 0;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 分组(多级标题:分组标题 + 行卡列表) */\n.ss-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* 分组标题(二级:12px/18 500 secondary——官方 fieldLabel 风格) */\n.ss-groupTitle {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* 行卡列表(官方 .rows:无 marker,gap 8) */\n.ss-rows {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* 行卡(官方 .rowCard:border-l2 r12 padding 12/14) */\n.ss-rowCard {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n padding: 12px 14px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n}\n\n/* 行卡文本(标题 + 说明 左列) */\n.ss-rowText {\n display: flex;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n flex: 1;\n}\n\n/* 行卡标题(官方 .rowName:14px/22 500) */\n.ss-rowName {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 行卡说明(12px/18 tertiary) */\n.ss-rowDesc {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 行卡控件(右置) */\n.ss-rowControl {\n flex: none;\n display: flex;\n align-items: center;\n}\n\n/* 开关(官方 token 的自绘 toggle:track 22px,thumb 16px) */\n.ss-switch {\n position: relative;\n flex: none;\n width: 40px;\n height: 22px;\n cursor: pointer;\n}\n\n.ss-switch input {\n position: absolute;\n opacity: 0;\n width: 100%;\n height: 100%;\n margin: 0;\n cursor: pointer;\n}\n\n.ss-switchTrack {\n position: absolute;\n inset: 0;\n border-radius: 11px;\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.3));\n transition: background var(--ds-transition-duration-fast, 0.15s) var(--ds-ease-in-out, ease);\n}\n\n.ss-switchTrack::after {\n content: '';\n position: absolute;\n top: 3px;\n left: 3px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--dsw-alias-label-primary, #eee);\n transition: transform var(--ds-transition-duration-fast, 0.15s) var(--ds-ease-in-out, ease);\n}\n\n.ss-switch input:checked + .ss-switchTrack {\n background: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n.ss-switch input:checked + .ss-switchTrack::after {\n transform: translateX(18px);\n}\n\n.ss-switch input:disabled + .ss-switchTrack {\n opacity: 0.4;\n cursor: default;\n}\n\n/* 阈值行(滑块 + 值) */\n.ss-threshold {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.ss-threshold input[type='range'] {\n width: 160px;\n}\n\n/* Skiff 调试端口输入(number;关闭时跟随 disabled 半透明) */\n.ss-portInput {\n width: 96px;\n padding: 6px 8px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-fill-l1, rgba(128, 128, 128, 0.08));\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n\n.ss-portInput:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n.ss-value {\n min-width: 40px;\n font-variant-numeric: tabular-nums;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n text-align: right;\n}\n\n/* 自主轨迹「立即唤起」按钮(v1.26.14 调试语义;官方 button 语言:primary 弱化) */\n.ss-wakeBtn {\n flex: none;\n padding: 5px 12px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.12));\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n cursor: pointer;\n transition: opacity var(--ds-transition-duration-fast, 0.15s) ease;\n}\n\n.ss-wakeBtn:hover:not(:disabled) {\n border-color: var(--dsw-alias-state-success-primary, #22c55e);\n color: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n.ss-wakeBtn:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n/* 底部帮助行 */\n.ss-hint {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 降级提示 */\n.ss-degrade {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-warn-label);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n";
4103
4103
  if (typeof document !== "undefined" && document.querySelector("style[data-sp-css=\"SettingsSection\"]") === null) {
4104
4104
  const tag = document.createElement("style");
4105
4105
  tag.setAttribute("data-sp-css", "SettingsSection");
@@ -4339,10 +4339,126 @@ Instruction-following style:
4339
4339
  className: "ss-groupTitle",
4340
4340
  children: "彩蛋模式"
4341
4341
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PersonaEditor, {})]
4342
+ }),
4343
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4344
+ className: "ss-group",
4345
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
4346
+ className: "ss-groupTitle",
4347
+ children: "自主轨迹"
4348
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutoTrajectoryStatusBlock, {})]
4342
4349
  })
4343
4350
  ]
4344
4351
  });
4345
4352
  }
4353
+ /** 「自主轨迹」只读状态区块(v1.26.14):展示当前工作区 CCC 的实验状态;实验配置改走 CCC 配置文件 */
4354
+ function AutoTrajectoryStatusBlock() {
4355
+ const [status, setStatus] = (0, react.useState)(null);
4356
+ const [unavailable, setUnavailable] = (0, react.useState)(false);
4357
+ const [waking, setWaking] = (0, react.useState)(false);
4358
+ const [wakeResult, setWakeResult] = (0, react.useState)(null);
4359
+ const refresh = (0, react.useCallback)(async () => {
4360
+ try {
4361
+ const res = await fetch("/serenity/autotrajectory", { headers: { accept: "application/json" } });
4362
+ if (!res.ok) return;
4363
+ const body = await res.json();
4364
+ if (body.status) {
4365
+ setStatus(body.status);
4366
+ setUnavailable(false);
4367
+ } else {
4368
+ setStatus(null);
4369
+ setUnavailable(true);
4370
+ }
4371
+ } catch {}
4372
+ }, []);
4373
+ (0, react.useEffect)(() => {
4374
+ refresh();
4375
+ return () => {};
4376
+ }, [refresh]);
4377
+ const wakeNow = async () => {
4378
+ if (waking) return;
4379
+ setWaking(true);
4380
+ setWakeResult(null);
4381
+ try {
4382
+ const res = await fetch("/serenity/autotrajectory", {
4383
+ method: "POST",
4384
+ headers: {
4385
+ "content-type": "application/json",
4386
+ "x-serenity-ui": "1"
4387
+ },
4388
+ body: JSON.stringify({ action: "wake" })
4389
+ });
4390
+ const body = await res.json();
4391
+ setWakeResult(body.detail ?? body.error ?? `HTTP ${res.status}`);
4392
+ refresh();
4393
+ } catch (err) {
4394
+ setWakeResult(err instanceof Error ? err.message : String(err));
4395
+ } finally {
4396
+ setWaking(false);
4397
+ }
4398
+ };
4399
+ if (unavailable) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
4400
+ className: "ss-rows",
4401
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
4402
+ title: "未激活",
4403
+ desc: "当前工作区不在 CCC 内(无 .serenity)——先在工作区打开一个 CCC 会话",
4404
+ control: null
4405
+ }) })
4406
+ });
4407
+ if (!status) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
4408
+ className: "ss-rows",
4409
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
4410
+ title: "加载中…",
4411
+ desc: "读取自主轨迹实验状态",
4412
+ control: null
4413
+ }) })
4414
+ });
4415
+ const target = status.target;
4416
+ const stateText = !status.configured ? "未配置(实验未开始)" : !status.enabled ? "已配置,未启用(enabled=false,零资源占用)" : "已启用 — 时钟唤起等待中";
4417
+ const targetText = target ? `${target.dirName}${target.autoFlag ? "(--auto ✓)" : "(无 --auto 标志)"} · 空闲 ${target.idleHours.toFixed(1)}h / 阈值 ${status.intervalHours}h` : status.session ? `会话 ${status.session} 未命中(AGENT_SESSIONS 无匹配)` : "未配置目标会话(不唤起)";
4418
+ const wakeReady = status.enabled && !!target && target.autoFlag;
4419
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
4420
+ className: "ss-rows",
4421
+ children: [
4422
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
4423
+ title: "实验状态",
4424
+ desc: stateText,
4425
+ control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4426
+ className: "ss-value",
4427
+ children: status.enabled ? "● 运行中" : status.configured ? "○ 待启" : "—"
4428
+ })
4429
+ }) }),
4430
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
4431
+ title: "目标会话",
4432
+ desc: targetText,
4433
+ control: target?.wakeable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4434
+ className: "ss-value",
4435
+ children: "可唤起"
4436
+ }) : null
4437
+ }) }),
4438
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
4439
+ title: "唤起窗口",
4440
+ desc: `当前北京 ${status.beijingHour} 点 — ${status.windowAllowed ? "允许唤起" : `高峰避开中(${status.avoidWakeHours.start}~${status.avoidWakeHours.end})`}`,
4441
+ control: null
4442
+ }) }),
4443
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
4444
+ title: "偏见提供者",
4445
+ desc: status.biasProvider,
4446
+ control: null
4447
+ }) }),
4448
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
4449
+ title: "立即唤起",
4450
+ desc: wakeResult ?? "调试:手动触发一次唤起(跳过窗口/间隔,仍校验配置与偏见脚本)",
4451
+ control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4452
+ type: "button",
4453
+ className: "ss-wakeBtn",
4454
+ disabled: !wakeReady || waking,
4455
+ onClick: () => void wakeNow(),
4456
+ children: waking ? "唤起中…" : "立即唤起"
4457
+ })
4458
+ }) })
4459
+ ]
4460
+ });
4461
+ }
4346
4462
  //#endregion
4347
4463
  //#region src/client/index.ts
4348
4464
  const inject = [