@shgroup/opencode-serenity-plugin 0.2.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 (151) hide show
  1. package/README.md +199 -0
  2. package/bin/opencode-serenity-plugin.js +316 -0
  3. package/dist/activation.d.ts +40 -0
  4. package/dist/activation.d.ts.map +1 -0
  5. package/dist/activation.js +133 -0
  6. package/dist/activation.js.map +1 -0
  7. package/dist/bash-override.d.ts +10 -0
  8. package/dist/bash-override.d.ts.map +1 -0
  9. package/dist/bash-override.js +24 -0
  10. package/dist/bash-override.js.map +1 -0
  11. package/dist/bash-toggle.d.ts +17 -0
  12. package/dist/bash-toggle.d.ts.map +1 -0
  13. package/dist/bash-toggle.js +42 -0
  14. package/dist/bash-toggle.js.map +1 -0
  15. package/dist/config-schema.d.ts +300 -0
  16. package/dist/config-schema.d.ts.map +1 -0
  17. package/dist/config-schema.js +185 -0
  18. package/dist/config-schema.js.map +1 -0
  19. package/dist/errors.d.ts +90 -0
  20. package/dist/errors.d.ts.map +1 -0
  21. package/dist/errors.js +151 -0
  22. package/dist/errors.js.map +1 -0
  23. package/dist/fs/file-system-tool.d.ts +25 -0
  24. package/dist/fs/file-system-tool.d.ts.map +1 -0
  25. package/dist/fs/file-system-tool.js +318 -0
  26. package/dist/fs/file-system-tool.js.map +1 -0
  27. package/dist/fs/resolve-path.d.ts +53 -0
  28. package/dist/fs/resolve-path.d.ts.map +1 -0
  29. package/dist/fs/resolve-path.js +100 -0
  30. package/dist/fs/resolve-path.js.map +1 -0
  31. package/dist/hooks/compacting.d.ts +23 -0
  32. package/dist/hooks/compacting.d.ts.map +1 -0
  33. package/dist/hooks/compacting.js +90 -0
  34. package/dist/hooks/compacting.js.map +1 -0
  35. package/dist/hooks/permission-auto-reply.d.ts +91 -0
  36. package/dist/hooks/permission-auto-reply.d.ts.map +1 -0
  37. package/dist/hooks/permission-auto-reply.js +158 -0
  38. package/dist/hooks/permission-auto-reply.js.map +1 -0
  39. package/dist/hooks/permission-guards.d.ts +41 -0
  40. package/dist/hooks/permission-guards.d.ts.map +1 -0
  41. package/dist/hooks/permission-guards.js +153 -0
  42. package/dist/hooks/permission-guards.js.map +1 -0
  43. package/dist/hooks/shell-env.d.ts +20 -0
  44. package/dist/hooks/shell-env.d.ts.map +1 -0
  45. package/dist/hooks/shell-env.js +38 -0
  46. package/dist/hooks/shell-env.js.map +1 -0
  47. package/dist/hooks/util.d.ts +81 -0
  48. package/dist/hooks/util.d.ts.map +1 -0
  49. package/dist/hooks/util.js +172 -0
  50. package/dist/hooks/util.js.map +1 -0
  51. package/dist/index.d.ts +26 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +63 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/init/init-wizard.d.ts +39 -0
  56. package/dist/init/init-wizard.d.ts.map +1 -0
  57. package/dist/init/init-wizard.js +297 -0
  58. package/dist/init/init-wizard.js.map +1 -0
  59. package/dist/install.d.ts +117 -0
  60. package/dist/install.d.ts.map +1 -0
  61. package/dist/install.js +255 -0
  62. package/dist/install.js.map +1 -0
  63. package/dist/msm-schema.d.ts +76 -0
  64. package/dist/msm-schema.d.ts.map +1 -0
  65. package/dist/msm-schema.js +207 -0
  66. package/dist/msm-schema.js.map +1 -0
  67. package/dist/msm.d.ts +25 -0
  68. package/dist/msm.d.ts.map +1 -0
  69. package/dist/msm.js +317 -0
  70. package/dist/msm.js.map +1 -0
  71. package/dist/session/lib.d.ts +33 -0
  72. package/dist/session/lib.d.ts.map +1 -0
  73. package/dist/session/lib.js +475 -0
  74. package/dist/session/lib.js.map +1 -0
  75. package/dist/session/session-tool.d.ts +17 -0
  76. package/dist/session/session-tool.d.ts.map +1 -0
  77. package/dist/session/session-tool.js +109 -0
  78. package/dist/session/session-tool.js.map +1 -0
  79. package/dist/skills/install-skill.d.ts +36 -0
  80. package/dist/skills/install-skill.d.ts.map +1 -0
  81. package/dist/skills/install-skill.js +91 -0
  82. package/dist/skills/install-skill.js.map +1 -0
  83. package/dist/skills/template-loader.d.ts +79 -0
  84. package/dist/skills/template-loader.d.ts.map +1 -0
  85. package/dist/skills/template-loader.js +170 -0
  86. package/dist/skills/template-loader.js.map +1 -0
  87. package/dist/state.d.ts +35 -0
  88. package/dist/state.d.ts.map +1 -0
  89. package/dist/state.js +62 -0
  90. package/dist/state.js.map +1 -0
  91. package/dist/tui.d.ts +61 -0
  92. package/dist/tui.d.ts.map +1 -0
  93. package/dist/tui.js +279 -0
  94. package/dist/tui.js.map +1 -0
  95. package/dist/types/index.d.ts +30 -0
  96. package/dist/types/index.d.ts.map +1 -0
  97. package/dist/types/index.js +17 -0
  98. package/dist/types/index.js.map +1 -0
  99. package/dist/util/config-patch.d.ts +58 -0
  100. package/dist/util/config-patch.d.ts.map +1 -0
  101. package/dist/util/config-patch.js +117 -0
  102. package/dist/util/config-patch.js.map +1 -0
  103. package/dist/util/git.d.ts +29 -0
  104. package/dist/util/git.d.ts.map +1 -0
  105. package/dist/util/git.js +74 -0
  106. package/dist/util/git.js.map +1 -0
  107. package/dist/util/init-check.d.ts +22 -0
  108. package/dist/util/init-check.d.ts.map +1 -0
  109. package/dist/util/init-check.js +76 -0
  110. package/dist/util/init-check.js.map +1 -0
  111. package/dist/util/init.d.ts +54 -0
  112. package/dist/util/init.d.ts.map +1 -0
  113. package/dist/util/init.js +87 -0
  114. package/dist/util/init.js.map +1 -0
  115. package/dist/util/log.d.ts +25 -0
  116. package/dist/util/log.d.ts.map +1 -0
  117. package/dist/util/log.js +28 -0
  118. package/dist/util/log.js.map +1 -0
  119. package/dist/util/msm-call.d.ts +48 -0
  120. package/dist/util/msm-call.d.ts.map +1 -0
  121. package/dist/util/msm-call.js +86 -0
  122. package/dist/util/msm-call.js.map +1 -0
  123. package/dist/util/msm-exec-runtime.d.ts +123 -0
  124. package/dist/util/msm-exec-runtime.d.ts.map +1 -0
  125. package/dist/util/msm-exec-runtime.js +532 -0
  126. package/dist/util/msm-exec-runtime.js.map +1 -0
  127. package/dist/util/path.d.ts +10 -0
  128. package/dist/util/path.d.ts.map +1 -0
  129. package/dist/util/path.js +21 -0
  130. package/dist/util/path.js.map +1 -0
  131. package/dist/util/ready-state.d.ts +43 -0
  132. package/dist/util/ready-state.d.ts.map +1 -0
  133. package/dist/util/ready-state.js +104 -0
  134. package/dist/util/ready-state.js.map +1 -0
  135. package/dist/util/serenity-file.d.ts +30 -0
  136. package/dist/util/serenity-file.d.ts.map +1 -0
  137. package/dist/util/serenity-file.js +69 -0
  138. package/dist/util/serenity-file.js.map +1 -0
  139. package/dist/util/tui-install.d.ts +61 -0
  140. package/dist/util/tui-install.d.ts.map +1 -0
  141. package/dist/util/tui-install.js +94 -0
  142. package/dist/util/tui-install.js.map +1 -0
  143. package/docs/architecture-v0.md +294 -0
  144. package/docs/contract-v0.md +417 -0
  145. package/docs/plugin-self-contained-msm-v1.md +182 -0
  146. package/docs/refactor-direction-v1.11.md +78 -0
  147. package/docs/requirements-v0-scope.md +104 -0
  148. package/docs/requirements-v0-summary.md +108 -0
  149. package/docs/rr7-init-design.md +304 -0
  150. package/docs/v0.1-candidates.md +132 -0
  151. package/package.json +54 -0
@@ -0,0 +1,475 @@
1
+ /**
2
+ * session/lib.ts — 会话管理核心逻辑
3
+ *
4
+ * 供 session-tool.ts 消费,实现会话 CRUD + 健康检查 + 归档。
5
+ */
6
+ import { readdirSync, readFileSync, writeFileSync, existsSync, mkdirSync, renameSync, statSync, } from 'node:fs';
7
+ import { join, basename } from 'node:path';
8
+ import { SessionError } from '../errors.js';
9
+ // ── 常量 ──
10
+ const SESSION_MD = 'SESSION.md';
11
+ const HEALTH_STALE_DAYS = 7;
12
+ const HEALTH_STALLED_PCT = 30;
13
+ const HEALTH_STALLED_DAYS = 3;
14
+ const HEALTH_GHOST_DAYS = 2;
15
+ // ── 工具函数 ──
16
+ /** 解析 SESSION.md 文件,提取状态元数据 */
17
+ function parseSessionMd(filePath) {
18
+ try {
19
+ const content = readFileSync(filePath, 'utf8');
20
+ const hasSessionMd = true;
21
+ const completed = /\[\s*x\s*\]/.test(content);
22
+ const completedCount = (content.match(/\[\s*x\s*\]/g) ?? []).length;
23
+ const pendingCount = (content.match(/\[\s*[ \t]\s*\]/g) ?? []).length;
24
+ const unresolvedCount = (content.match(/(未解决|open|question|TODO)/gi) ?? []).length;
25
+ return { hasSessionMd, completed, completedCount, pendingCount, unresolvedCount };
26
+ }
27
+ catch {
28
+ return { hasSessionMd: false, completed: false, completedCount: 0, pendingCount: 0, unresolvedCount: 0 };
29
+ }
30
+ }
31
+ /** 读取单个会话条目 */
32
+ function readSessionEntry(dirPath) {
33
+ try {
34
+ const stat = statSync(dirPath);
35
+ if (!stat.isDirectory())
36
+ return null;
37
+ const dirName = basename(dirPath);
38
+ const sessionMdPath = join(dirPath, SESSION_MD);
39
+ const status = existsSync(sessionMdPath)
40
+ ? parseSessionMd(sessionMdPath)
41
+ : { hasSessionMd: false, completed: false, completedCount: 0, pendingCount: 0, unresolvedCount: 0 };
42
+ return { dirName, path: dirPath, mtime: stat.mtime, status };
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ }
48
+ /** 读取 AGENT_SESSIONS 中所有会话 */
49
+ function readAllSessions(sessionsDir) {
50
+ try {
51
+ return readdirSync(sessionsDir, { withFileTypes: true })
52
+ .filter((e) => e.isDirectory())
53
+ .map((e) => readSessionEntry(join(sessionsDir, e.name)))
54
+ .filter((s) => s !== null)
55
+ .sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
56
+ }
57
+ catch {
58
+ return [];
59
+ }
60
+ }
61
+ /** 根据 ID(S###)或目录名查找会话 */
62
+ function findSession(sessionsDir, name) {
63
+ const all = readAllSessions(sessionsDir);
64
+ // 精确匹配目录名
65
+ const byName = all.find((s) => s.dirName === name);
66
+ if (byName)
67
+ return byName;
68
+ // 按 ID 匹配(S###)— 提取目录名中的 S### 段
69
+ const idPattern = /--S(\d{3,})--/;
70
+ // 去掉输入中的 S 前缀(从 "S031" 提取 "031",允许 "S31" → "031")
71
+ const searchId = name.replace(/^S/, '').padStart(3, '0');
72
+ const byId = all.find((s) => {
73
+ const match = s.dirName.match(idPattern);
74
+ return match && match[1] === searchId;
75
+ });
76
+ if (byId)
77
+ return byId;
78
+ return null;
79
+ }
80
+ // ── 核心 API ──
81
+ /** list 子命令 */
82
+ export function listSessions(sessionsDir) {
83
+ const sessions = readAllSessions(sessionsDir);
84
+ if (sessions.length === 0) {
85
+ return '(no sessions in AGENT_SESSIONS/)';
86
+ }
87
+ const lines = sessions.map((s) => {
88
+ const age = Math.floor((Date.now() - s.mtime.getTime()) / 86400000);
89
+ const status = s.status.completed ? '✓' : '○';
90
+ const sessionId = s.dirName;
91
+ return `${status} ${sessionId} (${age}d ago)`;
92
+ });
93
+ return `AGENT_SESSIONS/ (${sessions.length} sessions)\n` + lines.join('\n');
94
+ }
95
+ /** show 子命令 */
96
+ export function showSession(sessionsDir, name) {
97
+ const session = findSession(sessionsDir, name);
98
+ if (!session) {
99
+ throw new SessionError(`Session not found: "${name}". Use "list" to see available sessions.`);
100
+ }
101
+ const mdPath = join(session.path, SESSION_MD);
102
+ if (!existsSync(mdPath)) {
103
+ return `Session ${session.dirName} (no SESSION.md — directory exists but is empty)`;
104
+ }
105
+ const content = readFileSync(mdPath, 'utf8');
106
+ return `# ${session.dirName}\n\n${content}`;
107
+ }
108
+ export function createSession(opts) {
109
+ const { sessionsDir, desc, type, goal, dryRun } = opts;
110
+ // Validate desc format
111
+ if (!/^[a-z][a-z0-9-]{0,49}$/.test(desc)) {
112
+ throw new SessionError(`Invalid description "${desc}": must be kebab-case (lowercase a-z, 0-9, dashes; max 50 chars, no leading digit or dash)`);
113
+ }
114
+ // 生成日期前缀
115
+ const now = new Date();
116
+ const datePrefix = now.toISOString().slice(0, 10); // YYYY-MM-DD
117
+ if (type === 'project') {
118
+ if (dryRun) {
119
+ return `[dry-run] Would create project session: "${desc}" (no directory, record in _project-links.md)`;
120
+ }
121
+ // project 模式: 不创建目录,在 _project-links.md 追加记录
122
+ const linksPath = join(sessionsDir, '_project-links.md');
123
+ const linkEntry = `- [${datePrefix}] ${desc}${goal ? ` — ${goal}` : ''}`;
124
+ if (existsSync(linksPath)) {
125
+ const existing = readFileSync(linksPath, 'utf8');
126
+ if (existing.includes(linkEntry)) {
127
+ return `Project link already exists: "${desc}"`;
128
+ }
129
+ }
130
+ writeFileSync(linksPath, (existsSync(linksPath) ? readFileSync(linksPath, 'utf8') + '\n' : '') + linkEntry + '\n', 'utf8');
131
+ return `Project session "${desc}" registered in _project-links.md`;
132
+ }
133
+ // item 模式: 创建目录 + SESSION.md
134
+ // 分配 S### ID — 从现有最大值 + 1
135
+ const sessions = readAllSessions(sessionsDir);
136
+ const idPattern = /--S(\d{3,})--/;
137
+ let maxId = 0;
138
+ for (const s of sessions) {
139
+ const match = s.dirName.match(idPattern);
140
+ if (match) {
141
+ const idStr = match[1];
142
+ if (idStr) {
143
+ const num = parseInt(idStr, 10);
144
+ if (num > maxId)
145
+ maxId = num;
146
+ }
147
+ }
148
+ }
149
+ const nextId = String(maxId + 1).padStart(3, '0');
150
+ const dirName = `${datePrefix}--S${nextId}--${desc}`;
151
+ const sessionPath = join(sessionsDir, dirName);
152
+ if (!dryRun && existsSync(sessionPath)) {
153
+ throw new SessionError(`Session directory already exists: "${dirName}"`);
154
+ }
155
+ if (dryRun) {
156
+ return `[dry-run] Would create: ${dirName}/\n type=item\n goal=${goal ?? '(none)'}`;
157
+ }
158
+ // 创建目录
159
+ mkdirSync(sessionPath, { recursive: true });
160
+ // 写 SESSION.md
161
+ const sessionMd = `# SESSION: ${desc}\n- ID: S${nextId}\n\n## 目标\n${goal ?? '(待补充)'}\n\n## 状态\n- [ ] 进行中\n\n## 关键决策\n| # | 决策 | 理由 |\n|---|------|------|\n| 1 | | |\n\n## 进度记录\n- ${now.toISOString().slice(0, 16).replace('T', ' ')} — 创建\n\n## 产出物\n- \n\n## 未解决的问题\n- \n`;
162
+ writeFileSync(join(sessionPath, SESSION_MD), sessionMd, 'utf8');
163
+ return `Created: ${dirName}/ (S${nextId})`;
164
+ }
165
+ /** health 子命令 */
166
+ export function healthCheck(sessionsDir) {
167
+ const sessions = readAllSessions(sessionsDir);
168
+ if (sessions.length === 0) {
169
+ return 'No sessions found — nothing to check.';
170
+ }
171
+ const now = Date.now();
172
+ const DAY_MS = 86400000;
173
+ const issues = [];
174
+ for (const s of sessions) {
175
+ const ageDays = (now - s.mtime.getTime()) / DAY_MS;
176
+ const st = s.status;
177
+ // STALE: > 7天无活动
178
+ if (ageDays > HEALTH_STALE_DAYS && !st.completed) {
179
+ issues.push({ dirName: s.dirName, issue: `No activity for ${Math.floor(ageDays)}d`, severity: 'stale' });
180
+ }
181
+ // STALLED: 完成度 < 30% 且创建超过 3 天
182
+ const totalTasks = st.completedCount + st.pendingCount;
183
+ if (totalTasks > 0) {
184
+ const pct = Math.round((st.completedCount / totalTasks) * 100);
185
+ if (pct < HEALTH_STALLED_PCT && ageDays > HEALTH_STALLED_DAYS && !st.completed) {
186
+ issues.push({ dirName: s.dirName, issue: `Only ${pct}% done after ${Math.floor(ageDays)}d`, severity: 'stalled' });
187
+ }
188
+ }
189
+ // GHOST: SESSION.md 不存在的空壳目录
190
+ if (!st.hasSessionMd && ageDays > HEALTH_GHOST_DAYS) {
191
+ issues.push({ dirName: s.dirName, issue: 'No SESSION.md (ghost directory)', severity: 'ghost' });
192
+ }
193
+ // DRIFT: 未解决问题过多
194
+ if (st.unresolvedCount > 3 && !st.completed) {
195
+ issues.push({ dirName: s.dirName, issue: `${st.unresolvedCount} unresolved items`, severity: 'drift' });
196
+ }
197
+ }
198
+ if (issues.length === 0) {
199
+ return 'All sessions healthy — no issues found.';
200
+ }
201
+ const lines = issues.map((i) => `[${i.severity.toUpperCase()}] ${i.dirName}: ${i.issue}`);
202
+ return `${issues.length} issue(s) found:\n` + lines.join('\n');
203
+ }
204
+ export function archiveSessions(opts) {
205
+ const { sessionsDir, name, dryRun } = opts;
206
+ const now = Date.now();
207
+ const DAY_MS = 86400000;
208
+ const ARCHIVE_DIR = join(sessionsDir, '_archived');
209
+ if (name) {
210
+ // 归档单个指定会话
211
+ const session = findSession(sessionsDir, name);
212
+ if (!session) {
213
+ throw new SessionError(`Session not found: "${name}"`);
214
+ }
215
+ // 检查是否可归档(完成 + 超过 grace period)
216
+ if (!session.status.completed) {
217
+ return `Session "${session.dirName}" is not completed — skipping.`;
218
+ }
219
+ const ageDays = (now - session.mtime.getTime()) / DAY_MS;
220
+ if (ageDays < 7) {
221
+ return `Session "${session.dirName}" completed ${Math.floor(ageDays)}d ago — needs ${7 - Math.floor(ageDays)} more days before archiving.`;
222
+ }
223
+ if (dryRun) {
224
+ return `[dry-run] Would archive: ${session.dirName} → ${ARCHIVE_DIR}/`;
225
+ }
226
+ if (!existsSync(ARCHIVE_DIR)) {
227
+ mkdirSync(ARCHIVE_DIR, { recursive: true });
228
+ }
229
+ renameSync(session.path, join(ARCHIVE_DIR, session.dirName));
230
+ return `Archived: ${session.dirName} → _archived/`;
231
+ }
232
+ // 批量归档所有符合条件的主控板
233
+ const sessions = readAllSessions(sessionsDir);
234
+ const toArchive = sessions.filter((s) => {
235
+ if (!s.status.completed)
236
+ return false;
237
+ const ageDays = (now - s.mtime.getTime()) / DAY_MS;
238
+ return ageDays >= 7;
239
+ });
240
+ if (toArchive.length === 0) {
241
+ return 'No sessions eligible for archiving.';
242
+ }
243
+ if (dryRun) {
244
+ return `[dry-run] Would archive ${toArchive.length} session(s):\n` +
245
+ toArchive.map((s) => ` ${s.dirName}`).join('\n');
246
+ }
247
+ if (!existsSync(ARCHIVE_DIR)) {
248
+ mkdirSync(ARCHIVE_DIR, { recursive: true });
249
+ }
250
+ let count = 0;
251
+ for (const s of toArchive) {
252
+ renameSync(s.path, join(ARCHIVE_DIR, s.dirName));
253
+ count++;
254
+ }
255
+ return `Archived ${count} session(s) → _archived/`;
256
+ }
257
+ /** summary 子命令 */
258
+ export function sessionSummary(sessionsDir) {
259
+ const sessions = readAllSessions(sessionsDir);
260
+ if (sessions.length === 0) {
261
+ return 'AGENT_SESSIONS/ is empty.';
262
+ }
263
+ const now = Date.now();
264
+ const DAY_MS = 86400000;
265
+ const completed = sessions.filter((s) => s.status.completed).length;
266
+ const active = sessions.filter((s) => !s.status.completed).length;
267
+ const stale = sessions.filter((s) => !s.status.completed && (now - s.mtime.getTime()) / DAY_MS > HEALTH_STALE_DAYS).length;
268
+ const ghost = sessions.filter((s) => !s.status.hasSessionMd).length;
269
+ const recent = sessions.slice(0, 5);
270
+ const lines = [
271
+ `AGENT_SESSIONS Summary`,
272
+ `────────────────────────`,
273
+ `Total: ${sessions.length}`,
274
+ `Active: ${active}`,
275
+ `Completed: ${completed}`,
276
+ `Stale: ${stale}`,
277
+ `Ghost: ${ghost}`,
278
+ ``,
279
+ `Recent activity (top 5):`,
280
+ ...recent.map((s) => {
281
+ const age = Math.floor((now - s.mtime.getTime()) / DAY_MS);
282
+ return ` ${s.status.completed ? '✓' : '○'} ${s.dirName} (${age}d ago)`;
283
+ }),
284
+ ];
285
+ if (stale > 0) {
286
+ lines.push('', '⚠ Warning: Stale sessions found — run "session-tool health" for details.');
287
+ }
288
+ return lines.join('\n');
289
+ }
290
+ /** 事实核对:检查 SESSION.md 声明与实际情况的一致性 */
291
+ export function qaSession(sessionsDir, name) {
292
+ const session = findSession(sessionsDir, name);
293
+ if (!session) {
294
+ throw new SessionError(`Session not found: "${name}". Use "list" to see available sessions.`);
295
+ }
296
+ const mdPath = join(session.path, SESSION_MD);
297
+ if (!existsSync(mdPath)) {
298
+ return `[ERROR] Session "${session.dirName}" has no SESSION.md — nothing to verify.`;
299
+ }
300
+ const content = readFileSync(mdPath, 'utf8');
301
+ const issues = [];
302
+ // ── 1. 结构性检查:必选章节是否存在 ──
303
+ const requiredSections = [
304
+ { heading: '目标', label: '目标 (goal)' },
305
+ { heading: '状态', label: '状态 (status)' },
306
+ { heading: '关键决策', label: '关键决策 (key decisions)' },
307
+ { heading: '进度记录', label: '进度记录 (progress)' },
308
+ { heading: '产出物', label: '产出物 (outputs)' },
309
+ { heading: '未解决的问题', label: '未解决的问题 (unresolved)' },
310
+ ];
311
+ for (const section of requiredSections) {
312
+ // (?![\s\S]) = JS 惯用 "end of string" 断言([\s\S] 匹配任意字符含换行)
313
+ const headingRegex = new RegExp(`^##\\s*${section.heading}[\\s\\S]*?(?=^##|(?![\\s\\S]))`, 'm');
314
+ const match = content.match(headingRegex);
315
+ if (!match) {
316
+ issues.push({
317
+ severity: 'warning',
318
+ category: 'structure',
319
+ message: `Missing section: ${section.label}`,
320
+ });
321
+ continue;
322
+ }
323
+ // 检查章节是否只有空占位符(用 new RegExp 支持变量 heading)
324
+ const headingLineRegex = new RegExp(`^##\\s*${section.heading}\\s*$`, 'm');
325
+ const body = match[0].replace(headingLineRegex, '').trim();
326
+ if (!body || /^[-*]\s*$/.test(body)) {
327
+ issues.push({
328
+ severity: 'warning',
329
+ category: 'structure',
330
+ message: `Section "${section.label}" is empty (only placeholder)`,
331
+ });
332
+ }
333
+ }
334
+ // ── 2. 完成度矛盾检查 ──
335
+ const completedTasks = (content.match(/\[\s*x\s*\]/gi) ?? []).length;
336
+ const pendingTasks = (content.match(/\[\s*[ \t]\s*\]/gi) ?? []).length;
337
+ // 从"状态"段提取 completion mark(避免 goal/progress 中的"完成"误触发)
338
+ const statusSection = content.match(/^##\s*状态[\s\S]*?(?=^##|(?![^]))/mi);
339
+ const statusBody = statusSection
340
+ ? statusSection[0].replace(/^##\s*状态.*$/m, '').trim()
341
+ : '';
342
+ const hasCompletionMark = statusBody
343
+ ? /#+\s*(?:完成|done|completed|closed)\b/i.test(statusBody)
344
+ || /(?:全部完成|已全部完成|所有.*任务.*完成|任务.*全部完成|已完成.*所有)/i.test(statusBody)
345
+ : false;
346
+ // 从"未解决的问题"章节正文提取 unresolved 计数,避免 section 标题中的"未解决"误报
347
+ const unresolvedSection = content.match(/^##\s*未解决的问题[\s\S]*?(?=^##|(?![^]))/mi);
348
+ const unresolvedBody = unresolvedSection
349
+ ? unresolvedSection[0].replace(/^##\s*未解决的问题.*$/m, '').trim()
350
+ : '';
351
+ const unresolvedCount = unresolvedBody
352
+ ? (unresolvedBody.match(/(?:未解决|open|question|TODO)/gi) ?? []).length
353
+ : 0;
354
+ if (hasCompletionMark && pendingTasks > 0) {
355
+ issues.push({
356
+ severity: 'error',
357
+ category: 'consistency',
358
+ message: `Session marked as completed but has ${pendingTasks} pending task(s)`,
359
+ });
360
+ }
361
+ if (hasCompletionMark && unresolvedCount > 0) {
362
+ issues.push({
363
+ severity: 'warning',
364
+ category: 'consistency',
365
+ message: `Session marked as completed but has ${unresolvedCount} unresolved item(s)`,
366
+ });
367
+ }
368
+ if (completedTasks > 0 && pendingTasks === 0 && !hasCompletionMark) {
369
+ issues.push({
370
+ severity: 'info',
371
+ category: 'consistency',
372
+ message: `All ${completedTasks} task(s) completed but session not marked complete`,
373
+ });
374
+ }
375
+ // ── 3. 进度新鲜度检查 ──
376
+ const progressSection = content.match(/##\s*进度记录[\s\S]*?(?=^##|\z)/m);
377
+ if (progressSection) {
378
+ const dateMatches = progressSection[0].match(/\b(\d{4}-\d{2}-\d{2})\b/g);
379
+ if (dateMatches && dateMatches.length > 0) {
380
+ const lastDateStr = dateMatches[dateMatches.length - 1];
381
+ if (lastDateStr) {
382
+ const lastDate = new Date(lastDateStr);
383
+ const now = new Date();
384
+ const daysSince = Math.floor((now.getTime() - lastDate.getTime()) / 86400000);
385
+ if (daysSince > HEALTH_STALE_DAYS && pendingTasks > 0) {
386
+ issues.push({
387
+ severity: 'warning',
388
+ category: 'stale',
389
+ message: `No progress entry for ${daysSince} days (last: ${lastDateStr}), session still has ${pendingTasks} pending task(s)`,
390
+ });
391
+ }
392
+ }
393
+ }
394
+ }
395
+ // ── 4. 决策质量检查 ──
396
+ const decisionSection = content.match(/##\s*关键决策[\s\S]*?(?=^##|\z)/m);
397
+ if (decisionSection) {
398
+ const decisionLines = decisionSection[0].split('\n').filter((l) => /^\|\s*\d+\s*\|/.test(l));
399
+ if (decisionLines.length > 0) {
400
+ const emptyDecisions = decisionLines.filter((l) => {
401
+ const cells = l.split('|').map((c) => c.trim());
402
+ // | 1 | 决策 | 理由 | — 如果决策或理由列为空
403
+ return cells.length >= 4 && (!cells[2] || !cells[3] || cells[2] === '-' || cells[3] === '-');
404
+ });
405
+ if (emptyDecisions.length > 0) {
406
+ issues.push({
407
+ severity: 'info',
408
+ category: 'quality',
409
+ message: `${emptyDecisions.length} decision(s) have empty reason — consider filling gaps`,
410
+ });
411
+ }
412
+ }
413
+ else if (!hasCompletionMark) {
414
+ issues.push({
415
+ severity: 'info',
416
+ category: 'quality',
417
+ message: 'No decisions recorded yet — add key decisions as the session progresses',
418
+ });
419
+ }
420
+ }
421
+ // ── 5. 产出物文件存在性检查 ──
422
+ const outputSection = content.match(/##\s*产出物[\s\S]*?(?=^##|\z)/m);
423
+ if (outputSection) {
424
+ const outputLines = outputSection[0].split('\n').filter((l) => /^\s*[-*]\s/.test(l));
425
+ const fileRefs = [];
426
+ for (const line of outputLines) {
427
+ // 提取看起来像文件路径的引用(含 / 或 . 或 ` 包裹)
428
+ const refs = line.match(/`[^`]+`/g) ?? [];
429
+ fileRefs.push(...refs.map((r) => r.replace(/`/g, '')));
430
+ // 也匹配行内路径模式
431
+ const inlineRefs = line.match(/\b[\w./-]+\.[a-zA-Z]{1,5}\b/g) ?? [];
432
+ fileRefs.push(...inlineRefs.filter((r) => r.includes('/') || r.includes('.')));
433
+ }
434
+ if (fileRefs.length > 0) {
435
+ const missing = fileRefs.filter((ref) => !existsSync(join(session.path, ref)));
436
+ if (missing.length > 0 && completedTasks > 0) {
437
+ issues.push({
438
+ severity: 'warning',
439
+ category: 'outputs',
440
+ message: `${missing.length} referenced file(s) not found: ${missing.slice(0, 3).join(', ')}${missing.length > 3 ? `... (+${missing.length - 3} more)` : ''}`,
441
+ });
442
+ }
443
+ }
444
+ }
445
+ // ── 报告生成 ──
446
+ const errorCount = issues.filter((i) => i.severity === 'error').length;
447
+ const warningCount = issues.filter((i) => i.severity === 'warning').length;
448
+ const infoCount = issues.filter((i) => i.severity === 'info').length;
449
+ const verified = errorCount === 0 && warningCount === 0;
450
+ const lines = [
451
+ `QA Report: ${session.dirName}`,
452
+ `────────────────${'─'.repeat(session.dirName.length)}`,
453
+ `Summary: ${issues.length} issue(s) found (${errorCount} error, ${warningCount} warning, ${infoCount} info)`,
454
+ `Status: ${verified ? '✓ Verified' : '⚠ Issues found'}`,
455
+ ];
456
+ if (issues.length > 0) {
457
+ lines.push('');
458
+ for (const issue of issues) {
459
+ const tag = issue.severity === 'error' ? 'ERR' : issue.severity === 'warning' ? 'WRN' : 'INF';
460
+ lines.push(` [${tag}:${issue.category}] ${issue.message}`);
461
+ }
462
+ }
463
+ lines.push('', 'Recommendations:');
464
+ if (errorCount > 0) {
465
+ lines.push(' • Fix errors before closing the session (status vs content mismatch)');
466
+ }
467
+ if (warningCount > 0) {
468
+ lines.push(' • Review warnings — they may indicate incomplete or outdated information');
469
+ }
470
+ if (verified) {
471
+ lines.push(' • Session looks clean — no issues detected');
472
+ }
473
+ return lines.join('\n');
474
+ }
475
+ //# sourceMappingURL=lib.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lib.js","sourceRoot":"","sources":["../../src/session/lib.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * session-tool.ts — 通用会话管理工具(v0.1 D5)
3
+ *
4
+ * Plugin 自注册的会话生命周期管理工具,不依赖任何实例特定的脚本。
5
+ * 路径基于 file-system root(.serenity 向上遍历)动态解析。
6
+ *
7
+ * 子命令:
8
+ * list — 列出 AGENT_SESSIONS/ 中的会话
9
+ * show — 查看指定会话详情
10
+ * create — 创建会话(item / project 双模式)
11
+ * health — 健康检查(stale/stalled/drift/ghost)
12
+ * archive — 归档已关闭的超期会话
13
+ * summary — 全局仪表盘
14
+ */
15
+ import { type ToolDefinition } from '@opencode-ai/plugin';
16
+ export declare const sessionTool: ToolDefinition;
17
+ //# sourceMappingURL=session-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-tool.d.ts","sourceRoot":"","sources":["../../src/session/session-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAQ,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAchE,eAAO,MAAM,WAAW,EAAE,cAoGxB,CAAC"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * session-tool.ts — 通用会话管理工具(v0.1 D5)
3
+ *
4
+ * Plugin 自注册的会话生命周期管理工具,不依赖任何实例特定的脚本。
5
+ * 路径基于 file-system root(.serenity 向上遍历)动态解析。
6
+ *
7
+ * 子命令:
8
+ * list — 列出 AGENT_SESSIONS/ 中的会话
9
+ * show — 查看指定会话详情
10
+ * create — 创建会话(item / project 双模式)
11
+ * health — 健康检查(stale/stalled/drift/ghost)
12
+ * archive — 归档已关闭的超期会话
13
+ * summary — 全局仪表盘
14
+ */
15
+ import { tool } from '@opencode-ai/plugin';
16
+ import { z } from 'zod';
17
+ import { findSerenityRoot, resolveRootPath } from '../fs/resolve-path.js';
18
+ import { SessionError } from '../errors.js';
19
+ import { listSessions, showSession, healthCheck, createSession, archiveSessions, sessionSummary, qaSession, } from './lib.js';
20
+ export const sessionTool = tool({
21
+ description: 'Session lifecycle management for serenity instances. ' +
22
+ 'Manages AGENT_SESSIONS/ directory: list, show, create, health, archive, summary. ' +
23
+ 'All paths are resolved relative to the serenity instance root.',
24
+ args: {
25
+ subcommand: z
26
+ .enum(['list', 'show', 'create', 'health', 'qa', 'archive', 'summary'])
27
+ .describe('Operation to perform:\n' +
28
+ ' list — List all sessions with status summary\n' +
29
+ ' show — View session details (accepts S### or directory name)\n' +
30
+ ' create — Create a new session (--type=item|project --desc <desc>)\n' +
31
+ ' health — Health check: stale/stalled/drift/ghost\n' +
32
+ ' qa — Fact-check a session: verify SESSION.md claims against reality\n' +
33
+ ' archive — Archive completed sessions past their grace period\n' +
34
+ ' summary — Dashboard: stats + recent activity + warnings'),
35
+ name: z
36
+ .string()
37
+ .optional()
38
+ .describe('Session identifier for show/archive subcommands (e.g. "S001" or directory name)'),
39
+ desc: z
40
+ .string()
41
+ .optional()
42
+ .describe('Short description for create subcommand (kebab-case, max 5 words)'),
43
+ type: z
44
+ .enum(['item', 'project'])
45
+ .optional()
46
+ .default('item')
47
+ .describe('Session type for create: item (single task) or project (long-running)'),
48
+ goal: z
49
+ .string()
50
+ .optional()
51
+ .describe('Optional one-sentence goal for the session'),
52
+ 'dry-run': z
53
+ .boolean()
54
+ .optional()
55
+ .default(false)
56
+ .describe('Preview changes without actually modifying files'),
57
+ },
58
+ execute: async (input, ctx) => {
59
+ const cwd = ctx.directory;
60
+ const root = findSerenityRoot(cwd);
61
+ const sessionsDir = resolveRootPath(root, 'AGENT_SESSIONS');
62
+ const sub = input.subcommand;
63
+ if (sub === 'list') {
64
+ return listSessions(sessionsDir);
65
+ }
66
+ if (sub === 'show') {
67
+ if (!input.name) {
68
+ throw new SessionError('session-tool show: requires --name (S### or directory name)');
69
+ }
70
+ return showSession(sessionsDir, input.name);
71
+ }
72
+ if (sub === 'create') {
73
+ if (!input.desc) {
74
+ throw new SessionError('session-tool create: requires --desc (short description)');
75
+ }
76
+ // create 是 Semi-Mech 操作,由 LLM 完成命名/分类等认知决策
77
+ // 此工具提供目录创建 + SESSION.md 骨架写入
78
+ return createSession({
79
+ sessionsDir,
80
+ root,
81
+ desc: input.desc,
82
+ type: input.type ?? 'item',
83
+ goal: input.goal,
84
+ dryRun: input['dry-run'] ?? false,
85
+ });
86
+ }
87
+ if (sub === 'health') {
88
+ return healthCheck(sessionsDir);
89
+ }
90
+ if (sub === 'archive') {
91
+ return archiveSessions({
92
+ sessionsDir,
93
+ name: input.name,
94
+ dryRun: input['dry-run'] ?? false,
95
+ });
96
+ }
97
+ if (sub === 'summary') {
98
+ return sessionSummary(sessionsDir);
99
+ }
100
+ if (sub === 'qa') {
101
+ if (!input.name) {
102
+ throw new SessionError('session-tool qa: requires --name (S### or directory name)');
103
+ }
104
+ return qaSession(sessionsDir, input.name);
105
+ }
106
+ throw new SessionError(`session-tool: unknown subcommand "${sub}"`);
107
+ },
108
+ });
109
+ //# sourceMappingURL=session-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-tool.js","sourceRoot":"","sources":["../../src/session/session-tool.ts"],"names":[],"mappings":"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"}