@shgroup/dsh-serenity-hooks 1.32.0 → 1.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +11 -11
  2. package/dsh.plugin.json +5 -5
  3. package/experiments/autopilot-trajectory/SKILL.md +12 -12
  4. package/experiments/autopilot-trajectory/scripts/autopilot-trajectory.ts +69 -45
  5. package/lib/autopilot-script.d.ts +40 -0
  6. package/lib/autopilot-trajectory.d.ts +29 -0
  7. package/lib/{ccc-DAsSHsub.js → ccc-eu_IPF94.js} +17 -1
  8. package/lib/ccc.d.ts +20 -0
  9. package/lib/client.js +28 -8
  10. package/lib/diag-ops.d.ts +61 -0
  11. package/lib/index.d.ts +1 -1
  12. package/lib/index.js +3192 -3182
  13. package/lib/invariant.d.ts +5 -1
  14. package/lib/invariant.js +7 -3
  15. package/lib/json.d.ts +1 -1
  16. package/lib/msm-ops.d.ts +2 -2
  17. package/lib/output-guard-seam.d.ts +1 -1
  18. package/lib/rebuild.d.ts +4 -3
  19. package/lib/seams/guards.d.ts +27 -0
  20. package/lib/seams/keeper.d.ts +3 -3
  21. package/lib/{settings-section-Bm-xG-NR.js → settings-section-BuPGQv_H.js} +5 -6
  22. package/lib/settings-section.d.ts +15 -8
  23. package/lib/skiff-core.d.ts +1 -1
  24. package/lib/{skiff-debug-K2k1JnGj.js → skiff-debug-D83-Njy7.js} +7 -7
  25. package/lib/{skiff-role-BYvNnwv1.js → skiff-role-DAfPb6YQ.js} +1 -1
  26. package/lib/tools/acc-diag.d.ts +22 -0
  27. package/lib/tools/container-admin.d.ts +1 -1
  28. package/lib/tools/{session.d.ts → trajectory.d.ts} +32 -16
  29. package/lib/{session-bound-NHozeLFc.js → trajectory-bound-C8DUxi6_.js} +21 -276
  30. package/lib/{session-bound.d.ts → trajectory-bound.d.ts} +2 -2
  31. package/lib/{session-ops.d.ts → trajectory-ops.d.ts} +24 -28
  32. package/lib/wake-registry-D0Vj0WXb.js +270 -0
  33. package/lib/wake-scheduler.d.ts +41 -2
  34. package/lib/{weixin-route-wWk4AIwV.js → weixin-route-D1ND823E.js} +1 -1
  35. package/package.json +2 -2
  36. package/lib/tools/autopilot-trajectory.d.ts +0 -25
@@ -1,30 +1,27 @@
1
- import { a as findSerenityRoot } from "./ccc-DAsSHsub.js";
1
+ import { a as findSerenityRoot } from "./ccc-eu_IPF94.js";
2
2
  import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "node:fs";
3
3
  import { basename, dirname, join } from "node:path";
4
- //#region src/session-ops.ts
4
+ //#region src/trajectory-ops.ts
5
5
  /**
6
- * session-ops.ts — session 工具纯操作层(零 DSH 依赖,可独立单测)
6
+ * trajectory-ops.ts — 轨迹工具纯操作层(零 DSH 依赖,可独立单测)
7
7
  *
8
- * 行为对齐 osp(opencode-serenity-plugin/src/session/lib.ts)——osp 是 ACC 工具 spec:
9
- * - create:--desc / --issue 二选一(互斥、缺省报错);issue 模式目录 YYYY-MM-DD--<issue>
10
- * (无 S###,sessionId=issue);desc 模式 YYYY-MM-DD--S###--<desc>;goal 写入目标段;dry-run 预览
11
- * - close:需 name + confirm=true;标记 [x] 已完成+已关闭 + 进度记录"关闭"
12
- * - archive:name 缺省 → 批量归档(completed + ≥7 天 → 移动 _archived/);单会话需 completed + grace
13
- * - list/show/health/qa/summary:文本输出格式与 osp 一致
14
- * 保留 dsp S134 活跃会话机制(内存 Map + events 恢复,不落盘)——osp 同为内存 active-state。
8
+ * 行为对齐 osp(opencode-serenity-plugin/src/session/lib.ts)——osp 是 ACC 工具 spec。
9
+ *
10
+ * v1.33 收敛(S142 §32):本文件只服务 `container_trajectory` 的 6 个动作
11
+ * (list / show / create / use / rebuild / wake-later)。旧 `logbook` 面里
12
+ * **close / archive / health / qa 四个动作已删**(用户裁决「功能上废弃,实际上没用」),
13
+ * 其函数(closeSession / archiveSessions / healthCheck / qaCheck)**同批删除**——
14
+ * 保留下来的只有:create(--desc / --issue 二选一、dry-run 预览)、
15
+ * list(含 summarize 仪表盘)、show、use(激活 + 绑定)、以及供 list 用的 summarize。
16
+ * 「完成」不再由 close 写入,而是从 SESSION.md 的 `[x]` 推导;归档走 `container_fs mv`。
15
17
  */
16
- const SESSION_ACTIONS = [
18
+ const TRAJECTORY_ACTIONS = [
17
19
  "list",
18
20
  "show",
19
21
  "create",
20
22
  "use",
21
- "close",
22
- "health",
23
- "qa",
24
- "archive",
25
- "summary",
26
- "hook-develop-guide",
27
- "rebuild"
23
+ "rebuild",
24
+ "wake-later"
28
25
  ];
29
26
  /**
30
27
  * 读取 Session 事件序列(v1.28.1 适配 0.1.2-rc.1 补齐):rc.1 起官方 Session 类
@@ -45,11 +42,7 @@ function sessionEvents(session) {
45
42
  return s.events ?? [];
46
43
  }
47
44
  const SESSION_MD = "SESSION.md";
48
- const ARCHIVE_DIR_NAME = "_archived";
49
45
  const HEALTH_STALE_DAYS = 7;
50
- const HEALTH_STALLED_PCT = 30;
51
- const HEALTH_STALLED_DAYS = 3;
52
- const HEALTH_GHOST_DAYS = 2;
53
46
  const DAY = 864e5;
54
47
  function sessionsRoot(root) {
55
48
  return join(root, "AGENT_SESSIONS");
@@ -60,18 +53,12 @@ function parseSessionMd(filePath) {
60
53
  const content = readFileSync(filePath, "utf-8");
61
54
  return {
62
55
  hasSessionMd: true,
63
- completed: /\[\s*x\s*\]/i.test(content),
64
- completedCount: (content.match(/\[\s*x\s*\]/gi) ?? []).length,
65
- pendingCount: (content.match(/\[\s*[ \t]\s*\]/g) ?? []).length,
66
- unresolvedCount: (content.match(/(未解决|open|question|TODO)/gi) ?? []).length
56
+ completed: /\[\s*x\s*\]/i.test(content)
67
57
  };
68
58
  } catch {
69
59
  return {
70
60
  hasSessionMd: false,
71
- completed: false,
72
- completedCount: 0,
73
- pendingCount: 0,
74
- unresolvedCount: 0
61
+ completed: false
75
62
  };
76
63
  }
77
64
  }
@@ -83,10 +70,7 @@ function readSessionEntry(dirPath) {
83
70
  const mdPath = join(dirPath, SESSION_MD);
84
71
  const status = existsSync(mdPath) ? parseSessionMd(mdPath) : {
85
72
  hasSessionMd: false,
86
- completed: false,
87
- completedCount: 0,
88
- pendingCount: 0,
89
- unresolvedCount: 0
73
+ completed: false
90
74
  };
91
75
  return {
92
76
  dirName,
@@ -298,26 +282,6 @@ function useSession(root, key, scope = DEFAULT_SESSION_SCOPE) {
298
282
  };
299
283
  }
300
284
  /**
301
- * close 子命令(对齐 osp closeSession):需 name + confirm=true;
302
- * 标记 SESSION.md 为 [x] 已完成 + [x] 已关闭 + 进度记录"关闭";清除该会话的活跃状态。
303
- */
304
- function closeSession(root, key, confirm, scope = DEFAULT_SESSION_SCOPE) {
305
- if (!confirm) return "⚠ Close requires explicit confirmation.\n Re-run with --confirm to confirm closing this session.";
306
- const session = findSession(sessionsRoot(root), key);
307
- if (!session) throw new Error(`Session not found: "${key}". Use "list" to see available sessions.`);
308
- if (session.status.completed) return `Session "${session.dirName}" is already completed.`;
309
- const mdPath = join(session.path, SESSION_MD);
310
- if (!existsSync(mdPath)) throw new Error(`Session "${session.dirName}" has no SESSION.md — nothing to close.`);
311
- let content = readFileSync(mdPath, "utf-8");
312
- content = content.replace(/\r\n/g, "\n");
313
- content = content.replace(/## 状态\n\n?- \[ \] 进行中/, "## 状态\n- [x] 已完成\n- [x] 已关闭");
314
- const now = (/* @__PURE__ */ new Date()).toISOString().slice(0, 16).replace("T", " ");
315
- if (!content.includes("-- 关闭")) content = content.replace(/(## 进度记录\n)/, `$1- ${now} — 关闭\n`);
316
- writeFileSync(mdPath, content, "utf-8");
317
- clearActiveSessionInfo(scope);
318
- return `Session "${session.dirName}" closed and marked as completed.`;
319
- }
320
- /**
321
285
  * 从会话历史(events)解析会话身份(进程重启恢复;只扫**当前会话**自己的历史——无跨会话串台)。
322
286
  *
323
287
  * v1.24.11 稳固化(S142 用户需求:重建后新会话必须准确知道从哪个 SESSION 恢复):
@@ -415,76 +379,7 @@ function resolveSessionByTitle(title, sessionsDir) {
415
379
  if (fuzzy.length === 1) return join(fuzzy[0].path, SESSION_MD);
416
380
  return null;
417
381
  }
418
- /** health 子命令(对齐 osp healthCheck:stale/stalled/ghost/drift 四类检查,文本输出) */
419
- function healthCheck(root) {
420
- const sessions = readAllSessions(sessionsRoot(root));
421
- if (sessions.length === 0) return "No sessions found — nothing to check.";
422
- const now = Date.now();
423
- const issues = [];
424
- for (const s of sessions) {
425
- const ageDays = (now - s.mtime.getTime()) / DAY;
426
- const st = s.status;
427
- if (ageDays > HEALTH_STALE_DAYS && !st.completed) issues.push({
428
- dirName: s.dirName,
429
- issue: `No activity for ${Math.floor(ageDays)}d`,
430
- severity: "stale"
431
- });
432
- const totalTasks = st.completedCount + st.pendingCount;
433
- if (totalTasks > 0) {
434
- const pct = Math.round(st.completedCount / totalTasks * 100);
435
- if (pct < HEALTH_STALLED_PCT && ageDays > HEALTH_STALLED_DAYS && !st.completed) issues.push({
436
- dirName: s.dirName,
437
- issue: `Only ${pct}% done after ${Math.floor(ageDays)}d`,
438
- severity: "stalled"
439
- });
440
- }
441
- if (!st.hasSessionMd && ageDays > HEALTH_GHOST_DAYS) issues.push({
442
- dirName: s.dirName,
443
- issue: "No SESSION.md (ghost directory)",
444
- severity: "ghost"
445
- });
446
- if (st.unresolvedCount > 3 && !st.completed) issues.push({
447
- dirName: s.dirName,
448
- issue: `${st.unresolvedCount} unresolved items`,
449
- severity: "drift"
450
- });
451
- }
452
- if (issues.length === 0) return "All sessions healthy — no issues found.";
453
- const lines = issues.map((i) => `[${i.severity.toUpperCase()}] ${i.dirName}: ${i.issue}`);
454
- return `${issues.length} issue(s) found:\n` + lines.join("\n");
455
- }
456
- /** archive 子命令(对齐 osp archiveSessions:移动 _archived/;name 缺省批量) */
457
- function archiveSessions(root, opts) {
458
- const { name, dryRun } = opts;
459
- const sessionsDir = sessionsRoot(root);
460
- const now = Date.now();
461
- const archiveDir = join(sessionsDir, ARCHIVE_DIR_NAME);
462
- if (name) {
463
- const session = findSession(sessionsDir, name);
464
- if (!session) throw new Error(`Session not found: "${name}"`);
465
- if (!session.status.completed) return `Session "${session.dirName}" is not completed — skipping.`;
466
- const ageDays = (now - session.mtime.getTime()) / DAY;
467
- if (ageDays < 7) return `Session "${session.dirName}" completed ${Math.floor(ageDays)}d ago — needs ${7 - Math.floor(ageDays)} more days before archiving.`;
468
- if (dryRun) return `[dry-run] Would archive: ${session.dirName} → ${ARCHIVE_DIR_NAME}/`;
469
- if (!existsSync(archiveDir)) mkdirSync(archiveDir, { recursive: true });
470
- renameSync(session.path, join(archiveDir, session.dirName));
471
- return `Archived: ${session.dirName} → _archived/`;
472
- }
473
- const toArchive = readAllSessions(sessionsDir).filter((s) => {
474
- if (!s.status.completed) return false;
475
- return (now - s.mtime.getTime()) / DAY >= 7;
476
- });
477
- if (toArchive.length === 0) return "No sessions eligible for archiving.";
478
- if (dryRun) return `[dry-run] Would archive ${toArchive.length} session(s):\n` + toArchive.map((s) => ` ${s.dirName}`).join("\n");
479
- if (!existsSync(archiveDir)) mkdirSync(archiveDir, { recursive: true });
480
- let count = 0;
481
- for (const s of toArchive) {
482
- renameSync(s.path, join(archiveDir, s.dirName));
483
- count++;
484
- }
485
- return `Archived ${count} session(s) → _archived/`;
486
- }
487
- /** summary 子命令(对齐 osp sessionSummary 文本仪表盘) */
382
+ /** summary 仪表盘(供 `list` 动作拼接;v1.33 起独立 `summary` 动作已撤,并入 list) */
488
383
  function summarize(root) {
489
384
  const sessions = readAllSessions(sessionsRoot(root));
490
385
  if (sessions.length === 0) return "AGENT_SESSIONS/ is empty.";
@@ -509,157 +404,7 @@ function summarize(root) {
509
404
  return ` ${s.status.completed ? "✓" : "○"} ${s.dirName} (${age}d ago)`;
510
405
  })
511
406
  ];
512
- if (stale > 0) lines.push("", "⚠ Warning: Stale sessions found — run \"session health\" for details.");
513
- return lines.join("\n");
514
- }
515
- /** 事实核对:SESSION.md 声明 vs 实际情况(结构/一致性/新鲜度/决策质量/产出物) */
516
- function qaCheck(root, key) {
517
- const session = findSession(sessionsRoot(root), key);
518
- if (!session) throw new Error(`Session not found: "${key}". Use "list" to see available sessions.`);
519
- const mdPath = join(session.path, SESSION_MD);
520
- if (!existsSync(mdPath)) return `[ERROR] Session "${session.dirName}" has no SESSION.md — nothing to verify.`;
521
- const content = readFileSync(mdPath, "utf-8");
522
- const issues = [];
523
- for (const section of [
524
- {
525
- heading: "目标",
526
- label: "目标 (goal)"
527
- },
528
- {
529
- heading: "状态",
530
- label: "状态 (status)"
531
- },
532
- {
533
- heading: "关键决策",
534
- label: "关键决策 (key decisions)"
535
- },
536
- {
537
- heading: "进度记录",
538
- label: "进度记录 (progress)"
539
- },
540
- {
541
- heading: "产出物",
542
- label: "产出物 (outputs)"
543
- },
544
- {
545
- heading: "未解决的问题",
546
- label: "未解决的问题 (unresolved)"
547
- }
548
- ]) {
549
- const headingRegex = new RegExp(`^##\\s*${section.heading}[\\s\\S]*?(?=^##|(?![\\s\\S]))`, "m");
550
- const match = content.match(headingRegex);
551
- if (!match) {
552
- issues.push({
553
- severity: "warning",
554
- category: "structure",
555
- message: `Missing section: ${section.label}`
556
- });
557
- continue;
558
- }
559
- const headingLineRegex = new RegExp(`^##\\s*${section.heading}\\s*$`, "m");
560
- const body = match[0].replace(headingLineRegex, "").trim();
561
- if (!body || /^[-*]\s*$/.test(body)) issues.push({
562
- severity: "warning",
563
- category: "structure",
564
- message: `Section "${section.label}" is empty (only placeholder)`
565
- });
566
- }
567
- const completedTasks = (content.match(/\[\s*x\s*\]/gi) ?? []).length;
568
- const pendingTasks = (content.match(/\[\s*[ \t]\s*\]/gi) ?? []).length;
569
- const statusSection = content.match(/^##\s*状态[\s\S]*?(?=^##|(?![^]))/im);
570
- const statusBody = statusSection ? statusSection[0].replace(/^##\s*状态.*$/m, "").trim() : "";
571
- const hasCompletionMark = statusBody ? /#+\s*(?:完成|done|completed|closed)\b/i.test(statusBody) || /(?:全部完成|已全部完成|所有.*任务.*完成|任务.*全部完成|已完成.*所有)/i.test(statusBody) : false;
572
- const unresolvedSection = content.match(/^##\s*未解决的问题[\s\S]*?(?=^##|(?![^]))/im);
573
- const unresolvedBody = unresolvedSection ? unresolvedSection[0].replace(/^##\s*未解决的问题.*$/m, "").trim() : "";
574
- const unresolvedCount = unresolvedBody ? (unresolvedBody.match(/(?:未解决|open|question|TODO)/gi) ?? []).length : 0;
575
- if (hasCompletionMark && pendingTasks > 0) issues.push({
576
- severity: "error",
577
- category: "consistency",
578
- message: `Session marked as completed but has ${pendingTasks} pending task(s)`
579
- });
580
- if (hasCompletionMark && unresolvedCount > 0) issues.push({
581
- severity: "warning",
582
- category: "consistency",
583
- message: `Session marked as completed but has ${unresolvedCount} unresolved item(s)`
584
- });
585
- if (completedTasks > 0 && pendingTasks === 0 && !hasCompletionMark) issues.push({
586
- severity: "info",
587
- category: "consistency",
588
- message: `All ${completedTasks} task(s) completed but session not marked complete`
589
- });
590
- const progressSection = content.match(/##\s*进度记录[\s\S]*?(?=^##|\z)/m);
591
- if (progressSection) {
592
- const dateMatches = progressSection[0].match(/\b(\d{4}-\d{2}-\d{2})\b/g);
593
- if (dateMatches && dateMatches.length > 0) {
594
- const lastDateStr = dateMatches[dateMatches.length - 1];
595
- const lastDate = new Date(lastDateStr);
596
- const daysSince = Math.floor((Date.now() - lastDate.getTime()) / DAY);
597
- if (daysSince > HEALTH_STALE_DAYS && pendingTasks > 0) issues.push({
598
- severity: "warning",
599
- category: "stale",
600
- message: `No progress entry for ${daysSince} days (last: ${lastDateStr}), session still has ${pendingTasks} pending task(s)`
601
- });
602
- }
603
- }
604
- const decisionSection = content.match(/##\s*关键决策[\s\S]*?(?=^##|\z)/m);
605
- if (decisionSection) {
606
- const decisionLines = decisionSection[0].split("\n").filter((l) => /^\|\s*\d+\s*\|/.test(l));
607
- if (decisionLines.length > 0) {
608
- const emptyDecisions = decisionLines.filter((l) => {
609
- const cells = l.split("|").map((c) => c.trim());
610
- return cells.length >= 4 && (!cells[2] || !cells[3] || cells[2] === "-" || cells[3] === "-");
611
- });
612
- if (emptyDecisions.length > 0) issues.push({
613
- severity: "info",
614
- category: "quality",
615
- message: `${emptyDecisions.length} decision(s) have empty reason — consider filling gaps`
616
- });
617
- } else if (!hasCompletionMark) issues.push({
618
- severity: "info",
619
- category: "quality",
620
- message: "No decisions recorded yet — add key decisions as the session progresses"
621
- });
622
- }
623
- const outputSection = content.match(/##\s*产出物[\s\S]*?(?=^##|\z)/m);
624
- if (outputSection) {
625
- const outputLines = outputSection[0].split("\n").filter((l) => /^\s*[-*]\s/.test(l));
626
- const fileRefs = [];
627
- for (const line of outputLines) {
628
- const refs = line.match(/`[^`]+`/g) ?? [];
629
- fileRefs.push(...refs.map((r) => r.replace(/`/g, "")));
630
- const inlineRefs = line.match(/\b[\w./-]+\.[a-zA-Z]{1,5}\b/g) ?? [];
631
- fileRefs.push(...inlineRefs.filter((r) => r.includes("/") || r.includes(".")));
632
- }
633
- if (fileRefs.length > 0) {
634
- const missing = fileRefs.filter((ref) => !existsSync(join(root, ref)));
635
- if (missing.length > 0 && completedTasks > 0) issues.push({
636
- severity: "warning",
637
- category: "outputs",
638
- message: `${missing.length} referenced file(s) not found: ${missing.slice(0, 3).join(", ")}${missing.length > 3 ? `... (+${missing.length - 3} more)` : ""}`
639
- });
640
- }
641
- }
642
- const errorCount = issues.filter((i) => i.severity === "error").length;
643
- const warningCount = issues.filter((i) => i.severity === "warning").length;
644
- const infoCount = issues.filter((i) => i.severity === "info").length;
645
- const verified = errorCount === 0 && warningCount === 0;
646
- const lines = [
647
- `QA Report: ${session.dirName}`,
648
- `────────────────${"─".repeat(session.dirName.length)}`,
649
- `Summary: ${issues.length} issue(s) found (${errorCount} error, ${warningCount} warning, ${infoCount} info)`,
650
- `Status: ${verified ? "✓ Verified" : "⚠ Issues found"}`
651
- ];
652
- if (issues.length > 0) {
653
- lines.push("");
654
- for (const issue of issues) {
655
- const tag = issue.severity === "error" ? "ERR" : issue.severity === "warning" ? "WRN" : "INF";
656
- lines.push(` [${tag}:${issue.category}] ${issue.message}`);
657
- }
658
- }
659
- lines.push("", "Recommendations:");
660
- if (errorCount > 0) lines.push(" • Fix errors before closing the session (status vs content mismatch)");
661
- if (warningCount > 0) lines.push(" • Review warnings — they may indicate incomplete or outdated information");
662
- if (verified) lines.push(" • Session looks clean — no issues detected");
407
+ if (stale > 0) lines.push("", "⚠ Warning: stale trajectories present (no activity > 7d) — see the list above for detail.");
663
408
  return lines.join("\n");
664
409
  }
665
410
  /** 绑定文件相对 CCC 根的路径 */
@@ -819,4 +564,4 @@ function appendBound(session, action, rec) {
819
564
  }
820
565
  }
821
566
  //#endregion
822
- export { showSession as C, setActiveSessionInfo as S, useSession as T, qaCheck as _, DEFAULT_SESSION_SCOPE as a, sessionEvents as b, clearActiveSessionInfo as c, extractSessionMdPathFromText as d, findSession as f, parseSessionContextFromEvents as g, listSessions as h, resolveSessionTrajectoryLabel as i, closeSession as l, healthCheck as m, listBoundSessionIds as n, SESSION_ACTIONS as o, getActiveSessionInfo as p, readLastBound as r, archiveSessions as s, appendBound as t, createSession as u, readActiveSessionMd as v, summarize as w, sessionsRoot as x, resolveSessionByTitle as y };
567
+ export { sessionsRoot as _, DEFAULT_SESSION_SCOPE as a, summarize as b, createSession as c, getActiveSessionInfo as d, listSessions as f, sessionEvents as g, resolveSessionByTitle as h, resolveSessionTrajectoryLabel as i, extractSessionMdPathFromText as l, readActiveSessionMd as m, listBoundSessionIds as n, TRAJECTORY_ACTIONS as o, parseSessionContextFromEvents as p, readLastBound as r, clearActiveSessionInfo as s, appendBound as t, findSession as u, setActiveSessionInfo as v, useSession as x, showSession as y };
@@ -1,8 +1,8 @@
1
1
  /**
2
- * session-bound.ts — SESSION 绑定持久化(CCC 内 `AGENT_SESSIONS/.bindings.json`)
2
+ * trajectory-bound.ts — SESSION 绑定持久化(CCC 内 `AGENT_SESSIONS/.bindings.json`)
3
3
  *
4
4
  * 目标(S142 用户拍板,方案 v1.0):让「dsh 会话(载体)↔ SESSION(宁静号轨迹)」
5
- * 的绑定坚固——LLM 不能因智力因素(幻觉/理解偏差)在过程中或 logbook rebuild 后
5
+ * 的绑定坚固——LLM 不能因智力因素(幻觉/理解偏差)在过程中或 container_trajectory rebuild 后
6
6
  * 自行更换 SESSION。
7
7
  *
8
8
  * 存储形态(v1.30.6 起,S142 review F-01):绑定**不再写入 dsh 会话日志**。
@@ -1,17 +1,29 @@
1
1
  /**
2
- * session-ops.ts — session 工具纯操作层(零 DSH 依赖,可独立单测)
2
+ * trajectory-ops.ts — 轨迹工具纯操作层(零 DSH 依赖,可独立单测)
3
3
  *
4
- * 行为对齐 osp(opencode-serenity-plugin/src/session/lib.ts)——osp 是 ACC 工具 spec:
5
- * - create:--desc / --issue 二选一(互斥、缺省报错);issue 模式目录 YYYY-MM-DD--<issue>
6
- * (无 S###,sessionId=issue);desc 模式 YYYY-MM-DD--S###--<desc>;goal 写入目标段;dry-run 预览
7
- * - close:需 name + confirm=true;标记 [x] 已完成+已关闭 + 进度记录"关闭"
8
- * - archive:name 缺省 → 批量归档(completed + ≥7 天 → 移动 _archived/);单会话需 completed + grace
9
- * - list/show/health/qa/summary:文本输出格式与 osp 一致
10
- * 保留 dsp S134 活跃会话机制(内存 Map + events 恢复,不落盘)——osp 同为内存 active-state。
4
+ * 行为对齐 osp(opencode-serenity-plugin/src/session/lib.ts)——osp 是 ACC 工具 spec。
5
+ *
6
+ * v1.33 收敛(S142 §32):本文件只服务 `container_trajectory` 的 6 个动作
7
+ * (list / show / create / use / rebuild / wake-later)。旧 `logbook` 面里
8
+ * **close / archive / health / qa 四个动作已删**(用户裁决「功能上废弃,实际上没用」),
9
+ * 其函数(closeSession / archiveSessions / healthCheck / qaCheck)**同批删除**——
10
+ * 保留下来的只有:create(--desc / --issue 二选一、dry-run 预览)、
11
+ * list(含 summarize 仪表盘)、show、use(激活 + 绑定)、以及供 list 用的 summarize。
12
+ * 「完成」不再由 close 写入,而是从 SESSION.md 的 `[x]` 推导;归档走 `container_fs mv`。
11
13
  */
12
14
  import type { JsonValue } from './json.js';
13
- export type SessionAction = 'list' | 'show' | 'create' | 'use' | 'close' | 'health' | 'qa' | 'archive' | 'summary' | 'hook-develop-guide' | 'rebuild';
14
- export declare const SESSION_ACTIONS: readonly SessionAction[];
15
+ /**
16
+ * `container_trajectory` 工具的动作集合(v1.33,S142 §32 用户裁决后的收敛结果)。
17
+ *
18
+ * 为什么只有 6 个(R↓):旧面是 `logbook`(11)+ `trajectory`(12)两个工具,用户裁决
19
+ * 「都合并成 trajectory,废除 logbook 这个词」并逐条删并 ——
20
+ * summary 并进 list|health/qa 淘汰(判据=旧模板,EAP 已取代;仅"空壳/长期无活动"并入 use)|
21
+ * close/archive 删(completed 由 SESSION.md 的 `[x]` 推导;归档走 container_fs mv)|
22
+ * hook-develop-guide 并进 container_admin msm guide|autopilot 面归 container_admin 的 autopilot 域|
23
+ * wake-add/list/rm 收敛为 wake-later。
24
+ */
25
+ export type TrajectoryAction = 'list' | 'show' | 'create' | 'use' | 'rebuild' | 'wake-later';
26
+ export declare const TRAJECTORY_ACTIONS: readonly TrajectoryAction[];
15
27
  /**
16
28
  * 读取 Session 事件序列(v1.28.1 适配 0.1.2-rc.1 补齐):rc.1 起官方 Session 类
17
29
  * 移除 `.events` 属性 → `snapshotEvents()` 方法(dsh-session/src/session.ts:
@@ -26,10 +38,8 @@ export declare function sessionEvents<T = unknown>(session: unknown): readonly T
26
38
  export declare function sessionsRoot(root: string): string;
27
39
  interface SessionStatus {
28
40
  hasSessionMd: boolean;
41
+ /** 「完成」的判据 = SESSION.md 里出现 `[x]`(v1.33 起不再由 close 动作写入) */
29
42
  completed: boolean;
30
- completedCount: number;
31
- pendingCount: number;
32
- unresolvedCount: number;
33
43
  }
34
44
  export interface SessionEntry {
35
45
  dirName: string;
@@ -98,11 +108,6 @@ export declare function useSession(root: string, key: string, scope?: string): {
98
108
  mdPath: string;
99
109
  context: string;
100
110
  };
101
- /**
102
- * close 子命令(对齐 osp closeSession):需 name + confirm=true;
103
- * 标记 SESSION.md 为 [x] 已完成 + [x] 已关闭 + 进度记录"关闭";清除该会话的活跃状态。
104
- */
105
- export declare function closeSession(root: string, key: string, confirm: boolean, scope?: string): string;
106
111
  /**
107
112
  * 从会话历史(events)解析会话身份(进程重启恢复;只扫**当前会话**自己的历史——无跨会话串台)。
108
113
  *
@@ -136,16 +141,7 @@ export declare function resolveSessionByTitle(title: string, sessionsDir: string
136
141
  * 只作最后手段(内存/events/锚点全缺时),保证重建锚点至少指向一个真实存在的轨迹。
137
142
  */
138
143
  export declare function findLatestActiveSessionMd(root: string): string | null;
139
- /** health 子命令(对齐 osp healthCheck:stale/stalled/ghost/drift 四类检查,文本输出) */
140
- export declare function healthCheck(root: string): string;
141
- /** archive 子命令(对齐 osp archiveSessions:移动 _archived/;name 缺省批量) */
142
- export declare function archiveSessions(root: string, opts: {
143
- name?: string;
144
- dryRun: boolean;
145
- }): string;
146
- /** summary 子命令(对齐 osp sessionSummary 文本仪表盘) */
144
+ /** summary 仪表盘(供 `list` 动作拼接;v1.33 起独立 `summary` 动作已撤,并入 list) */
147
145
  export declare function summarize(root: string): string;
148
- /** 事实核对:SESSION.md 声明 vs 实际情况(结构/一致性/新鲜度/决策质量/产出物) */
149
- export declare function qaCheck(root: string, key: string): string;
150
146
  export type SessionInfo = SessionEntry;
151
147
  export type { JsonValue };