@aipper/aiws 0.0.28 → 0.0.30

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 (267) hide show
  1. package/README.md +18 -2
  2. package/bin/aiws.js +2 -2
  3. package/dist/aiws-package.d.ts +4 -0
  4. package/dist/aiws-package.js +11 -0
  5. package/dist/aiws-package.js.map +1 -0
  6. package/dist/aiws-paths.d.ts +48 -0
  7. package/dist/aiws-paths.js +129 -0
  8. package/dist/aiws-paths.js.map +1 -0
  9. package/dist/backup.d.ts +27 -0
  10. package/dist/backup.js +125 -0
  11. package/dist/backup.js.map +1 -0
  12. package/dist/cli.d.ts +1 -0
  13. package/dist/cli.js +773 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/codex-prompts.d.ts +17 -0
  16. package/dist/codex-prompts.js +49 -0
  17. package/dist/codex-prompts.js.map +1 -0
  18. package/dist/codex-skills.d.ts +17 -0
  19. package/dist/codex-skills.js +75 -0
  20. package/dist/codex-skills.js.map +1 -0
  21. package/dist/commands/change-advice.d.ts +25 -0
  22. package/dist/commands/change-advice.js +197 -0
  23. package/dist/commands/change-advice.js.map +1 -0
  24. package/dist/commands/change-evidence-command.d.ts +29 -0
  25. package/dist/commands/change-evidence-command.js +213 -0
  26. package/dist/commands/change-evidence-command.js.map +1 -0
  27. package/dist/commands/change-evidence-entry.d.ts +16 -0
  28. package/dist/commands/change-evidence-entry.js +35 -0
  29. package/dist/commands/change-evidence-entry.js.map +1 -0
  30. package/dist/commands/change-evidence.d.ts +108 -0
  31. package/dist/commands/change-evidence.js +341 -0
  32. package/dist/commands/change-evidence.js.map +1 -0
  33. package/dist/commands/change-finish.d.ts +71 -0
  34. package/dist/commands/change-finish.js +387 -0
  35. package/dist/commands/change-finish.js.map +1 -0
  36. package/dist/commands/change-git-status.d.ts +22 -0
  37. package/dist/commands/change-git-status.js +50 -0
  38. package/dist/commands/change-git-status.js.map +1 -0
  39. package/dist/commands/change-lifecycle-entry.d.ts +29 -0
  40. package/{src → dist}/commands/change-lifecycle-entry.js +21 -28
  41. package/dist/commands/change-lifecycle-entry.js.map +1 -0
  42. package/dist/commands/change-lifecycle.d.ts +56 -0
  43. package/dist/commands/change-lifecycle.js +211 -0
  44. package/dist/commands/change-lifecycle.js.map +1 -0
  45. package/dist/commands/change-metrics-command.d.ts +12 -0
  46. package/dist/commands/change-metrics-command.js +110 -0
  47. package/dist/commands/change-metrics-command.js.map +1 -0
  48. package/dist/commands/change-next-command.d.ts +18 -0
  49. package/dist/commands/change-next-command.js +138 -0
  50. package/dist/commands/change-next-command.js.map +1 -0
  51. package/dist/commands/change-review-gates.d.ts +107 -0
  52. package/dist/commands/change-review-gates.js +329 -0
  53. package/dist/commands/change-review-gates.js.map +1 -0
  54. package/dist/commands/change-scope-gate.d.ts +21 -0
  55. package/dist/commands/change-scope-gate.js +32 -0
  56. package/dist/commands/change-scope-gate.js.map +1 -0
  57. package/dist/commands/change-start.d.ts +30 -0
  58. package/dist/commands/change-start.js +91 -0
  59. package/dist/commands/change-start.js.map +1 -0
  60. package/dist/commands/change-state-command.d.ts +3 -0
  61. package/dist/commands/change-state-command.js +32 -0
  62. package/dist/commands/change-state-command.js.map +1 -0
  63. package/dist/commands/change-status-command.d.ts +13 -0
  64. package/dist/commands/change-status-command.js +126 -0
  65. package/dist/commands/change-status-command.js.map +1 -0
  66. package/dist/commands/change-status-context.d.ts +58 -0
  67. package/dist/commands/change-status-context.js +166 -0
  68. package/dist/commands/change-status-context.js.map +1 -0
  69. package/dist/commands/change-task-stats.d.ts +24 -0
  70. package/dist/commands/change-task-stats.js +66 -0
  71. package/dist/commands/change-task-stats.js.map +1 -0
  72. package/dist/commands/change-validate-entry.d.ts +17 -0
  73. package/dist/commands/change-validate-entry.js +44 -0
  74. package/dist/commands/change-validate-entry.js.map +1 -0
  75. package/dist/commands/change-validate.d.ts +32 -0
  76. package/dist/commands/change-validate.js +128 -0
  77. package/dist/commands/change-validate.js.map +1 -0
  78. package/dist/commands/change.d.ts +322 -0
  79. package/dist/commands/change.js +1731 -0
  80. package/dist/commands/change.js.map +1 -0
  81. package/dist/commands/codex-install-prompts.d.ts +4 -0
  82. package/dist/commands/codex-install-prompts.js +68 -0
  83. package/dist/commands/codex-install-prompts.js.map +1 -0
  84. package/dist/commands/codex-install-skills.d.ts +4 -0
  85. package/dist/commands/codex-install-skills.js +74 -0
  86. package/dist/commands/codex-install-skills.js.map +1 -0
  87. package/dist/commands/codex-status-prompts.d.ts +4 -0
  88. package/dist/commands/codex-status-prompts.js +44 -0
  89. package/dist/commands/codex-status-prompts.js.map +1 -0
  90. package/dist/commands/codex-status-skills.d.ts +4 -0
  91. package/dist/commands/codex-status-skills.js +54 -0
  92. package/dist/commands/codex-status-skills.js.map +1 -0
  93. package/dist/commands/codex-uninstall-prompts.d.ts +4 -0
  94. package/dist/commands/codex-uninstall-prompts.js +51 -0
  95. package/dist/commands/codex-uninstall-prompts.js.map +1 -0
  96. package/dist/commands/codex-uninstall-skills.d.ts +4 -0
  97. package/dist/commands/codex-uninstall-skills.js +59 -0
  98. package/dist/commands/codex-uninstall-skills.js.map +1 -0
  99. package/dist/commands/dashboard.d.ts +222 -0
  100. package/dist/commands/dashboard.js +193 -0
  101. package/dist/commands/dashboard.js.map +1 -0
  102. package/dist/commands/hooks-install.d.ts +4 -0
  103. package/dist/commands/hooks-install.js +90 -0
  104. package/dist/commands/hooks-install.js.map +1 -0
  105. package/dist/commands/hooks-status.d.ts +4 -0
  106. package/dist/commands/hooks-status.js +89 -0
  107. package/dist/commands/hooks-status.js.map +1 -0
  108. package/dist/commands/init.d.ts +4 -0
  109. package/dist/commands/init.js +100 -0
  110. package/dist/commands/init.js.map +1 -0
  111. package/dist/commands/opencode-auto.d.ts +11 -0
  112. package/dist/commands/opencode-auto.js +158 -0
  113. package/dist/commands/opencode-auto.js.map +1 -0
  114. package/dist/commands/opencode-status.d.ts +4 -0
  115. package/dist/commands/opencode-status.js +75 -0
  116. package/dist/commands/opencode-status.js.map +1 -0
  117. package/dist/commands/opencode-supervise.d.ts +24 -0
  118. package/dist/commands/opencode-supervise.js +188 -0
  119. package/dist/commands/opencode-supervise.js.map +1 -0
  120. package/dist/commands/rollback.d.ts +4 -0
  121. package/dist/commands/rollback.js +12 -0
  122. package/dist/commands/rollback.js.map +1 -0
  123. package/dist/commands/update.d.ts +4 -0
  124. package/dist/commands/update.js +212 -0
  125. package/dist/commands/update.js.map +1 -0
  126. package/dist/commands/validate.d.ts +4 -0
  127. package/dist/commands/validate.js +222 -0
  128. package/dist/commands/validate.js.map +1 -0
  129. package/dist/commands/ws-commit.d.ts +5 -0
  130. package/dist/commands/ws-commit.js +39 -0
  131. package/dist/commands/ws-commit.js.map +1 -0
  132. package/dist/commands/ws-deliver.d.ts +5 -0
  133. package/dist/commands/ws-deliver.js +59 -0
  134. package/dist/commands/ws-deliver.js.map +1 -0
  135. package/dist/commands/ws-finish.d.ts +5 -0
  136. package/dist/commands/ws-finish.js +142 -0
  137. package/dist/commands/ws-finish.js.map +1 -0
  138. package/dist/commands/ws-handoff.d.ts +5 -0
  139. package/dist/commands/ws-handoff.js +35 -0
  140. package/dist/commands/ws-handoff.js.map +1 -0
  141. package/dist/commands/ws-migrate.d.ts +5 -0
  142. package/dist/commands/ws-migrate.js +41 -0
  143. package/dist/commands/ws-migrate.js.map +1 -0
  144. package/dist/commands/ws-plan-verify.d.ts +5 -0
  145. package/dist/commands/ws-plan-verify.js +38 -0
  146. package/dist/commands/ws-plan-verify.js.map +1 -0
  147. package/dist/commands/ws-pull.d.ts +5 -0
  148. package/dist/commands/ws-pull.js +26 -0
  149. package/dist/commands/ws-pull.js.map +1 -0
  150. package/dist/commands/ws-push.d.ts +5 -0
  151. package/dist/commands/ws-push.js +68 -0
  152. package/dist/commands/ws-push.js.map +1 -0
  153. package/dist/commands/ws-submodule-setup.d.ts +5 -0
  154. package/dist/commands/ws-submodule-setup.js +55 -0
  155. package/dist/commands/ws-submodule-setup.js.map +1 -0
  156. package/dist/commands/ws-verify-before-complete.d.ts +5 -0
  157. package/dist/commands/ws-verify-before-complete.js +35 -0
  158. package/dist/commands/ws-verify-before-complete.js.map +1 -0
  159. package/dist/dashboard/app.d.ts +1 -0
  160. package/dist/dashboard/app.js +370 -0
  161. package/dist/dashboard/app.js.map +1 -0
  162. package/dist/delegation/cli.d.ts +6 -0
  163. package/dist/delegation/cli.js +14 -0
  164. package/dist/delegation/cli.js.map +1 -0
  165. package/dist/delegation/index.d.ts +35 -0
  166. package/dist/delegation/index.js +118 -0
  167. package/dist/delegation/index.js.map +1 -0
  168. package/dist/errors.d.ts +8 -0
  169. package/dist/errors.js +11 -0
  170. package/dist/errors.js.map +1 -0
  171. package/dist/exec.d.ts +9 -0
  172. package/dist/exec.js +22 -0
  173. package/dist/exec.js.map +1 -0
  174. package/dist/fs.d.ts +9 -0
  175. package/dist/fs.js +62 -0
  176. package/dist/fs.js.map +1 -0
  177. package/dist/governance.d.ts +10 -0
  178. package/dist/governance.js +135 -0
  179. package/dist/governance.js.map +1 -0
  180. package/dist/hash.d.ts +3 -0
  181. package/dist/hash.js +13 -0
  182. package/dist/hash.js.map +1 -0
  183. package/dist/hooks/deploy-claude.d.ts +13 -0
  184. package/dist/hooks/deploy-claude.js +67 -0
  185. package/dist/hooks/deploy-claude.js.map +1 -0
  186. package/dist/journal.d.ts +22 -0
  187. package/dist/journal.js +112 -0
  188. package/dist/journal.js.map +1 -0
  189. package/dist/json-schema-lite.d.ts +22 -0
  190. package/dist/json-schema-lite.js +148 -0
  191. package/dist/json-schema-lite.js.map +1 -0
  192. package/dist/managed-blocks.d.ts +24 -0
  193. package/dist/managed-blocks.js +84 -0
  194. package/dist/managed-blocks.js.map +1 -0
  195. package/dist/manifest.d.ts +24 -0
  196. package/dist/manifest.js +145 -0
  197. package/dist/manifest.js.map +1 -0
  198. package/dist/opencode-env.d.ts +62 -0
  199. package/dist/opencode-env.js +178 -0
  200. package/dist/opencode-env.js.map +1 -0
  201. package/dist/path-utils.d.ts +2 -0
  202. package/dist/path-utils.js +8 -0
  203. package/dist/path-utils.js.map +1 -0
  204. package/dist/spec.d.ts +17 -0
  205. package/dist/spec.js +174 -0
  206. package/dist/spec.js.map +1 -0
  207. package/dist/template.d.ts +20 -0
  208. package/dist/template.js +123 -0
  209. package/dist/template.js.map +1 -0
  210. package/dist/workspace.d.ts +4 -0
  211. package/dist/workspace.js +19 -0
  212. package/dist/workspace.js.map +1 -0
  213. package/package.json +11 -3
  214. package/src/aiws-package.js +0 -15
  215. package/src/backup.js +0 -149
  216. package/src/cli.js +0 -647
  217. package/src/codex-prompts.js +0 -74
  218. package/src/codex-skills.js +0 -111
  219. package/src/commands/change-advice.js +0 -200
  220. package/src/commands/change-evidence-command.js +0 -242
  221. package/src/commands/change-evidence-entry.js +0 -40
  222. package/src/commands/change-evidence.js +0 -340
  223. package/src/commands/change-finish.js +0 -484
  224. package/src/commands/change-git-status.js +0 -53
  225. package/src/commands/change-lifecycle.js +0 -236
  226. package/src/commands/change-metrics-command.js +0 -110
  227. package/src/commands/change-next-command.js +0 -129
  228. package/src/commands/change-review-gates.js +0 -315
  229. package/src/commands/change-scope-gate.js +0 -34
  230. package/src/commands/change-start.js +0 -120
  231. package/src/commands/change-state-command.js +0 -40
  232. package/src/commands/change-status-command.js +0 -134
  233. package/src/commands/change-status-context.js +0 -202
  234. package/src/commands/change-task-stats.js +0 -64
  235. package/src/commands/change-validate-entry.js +0 -45
  236. package/src/commands/change-validate.js +0 -127
  237. package/src/commands/change.js +0 -2087
  238. package/src/commands/codex-install-prompts.js +0 -68
  239. package/src/commands/codex-install-skills.js +0 -74
  240. package/src/commands/codex-status-prompts.js +0 -55
  241. package/src/commands/codex-status-skills.js +0 -63
  242. package/src/commands/codex-uninstall-prompts.js +0 -55
  243. package/src/commands/codex-uninstall-skills.js +0 -62
  244. package/src/commands/dashboard.js +0 -205
  245. package/src/commands/hooks-install.js +0 -92
  246. package/src/commands/hooks-status.js +0 -95
  247. package/src/commands/init.js +0 -93
  248. package/src/commands/opencode-status.js +0 -61
  249. package/src/commands/rollback.js +0 -13
  250. package/src/commands/update.js +0 -133
  251. package/src/commands/validate.js +0 -222
  252. package/src/dashboard/app.js +0 -371
  253. package/src/errors.js +0 -15
  254. package/src/exec.js +0 -34
  255. package/src/fs.js +0 -91
  256. package/src/governance.js +0 -159
  257. package/src/hash.js +0 -25
  258. package/src/json-schema-lite.js +0 -164
  259. package/src/managed-blocks.js +0 -131
  260. package/src/manifest.js +0 -153
  261. package/src/opencode-env.js +0 -76
  262. package/src/path-utils.js +0 -20
  263. package/src/spec.js +0 -195
  264. package/src/template.js +0 -187
  265. package/src/workspace.js +0 -23
  266. /package/{src → dist}/dashboard/index.html +0 -0
  267. /package/{src → dist}/dashboard/style.css +0 -0
@@ -1,202 +0,0 @@
1
- import path from "node:path";
2
-
3
- /**
4
- * @param {string} gitRoot
5
- * @param {string} changeId
6
- * @param {{
7
- * currentBranch: (gitRoot: string) => Promise<string>,
8
- * listGitWorktrees: (gitRoot: string) => Promise<Array<{ worktree: string, branch: string }>>,
9
- * pathExists: (path: string) => Promise<boolean>,
10
- * isGitRepository: (path: string) => Promise<boolean>,
11
- * inferChangeIdFromBranch: (branch: string) => string
12
- * }} deps
13
- */
14
- export async function resolveChangeStatusContext(gitRoot, changeId, deps) {
15
- const rootBranch = await deps.currentBranch(gitRoot);
16
- /** @type {Array<{ worktree: string, branch: string }>} */
17
- let worktrees = [];
18
- try {
19
- worktrees = await deps.listGitWorktrees(gitRoot);
20
- } catch {
21
- worktrees = [];
22
- }
23
-
24
- const changeRef = `refs/heads/change/${changeId}`;
25
- const changeWorktree = worktrees.find((worktree) => String(worktree.branch || "") === changeRef)?.worktree || "";
26
- const rootWorktree = path.resolve(gitRoot);
27
- let contextWorktree = rootWorktree;
28
- let source = "current_worktree";
29
- let warning = "";
30
- if (changeWorktree && path.resolve(changeWorktree) !== rootWorktree) {
31
- const candidate = path.resolve(changeWorktree);
32
- const candidateExists = await deps.pathExists(candidate);
33
- const candidateReady = candidateExists ? await deps.isGitRepository(candidate) : false;
34
- if (candidateReady) {
35
- contextWorktree = candidate;
36
- source = "change_worktree";
37
- } else {
38
- warning = `stale change worktree metadata: ${candidate} (run \`git worktree prune\`)`;
39
- }
40
- }
41
- const contextBranch = await deps.currentBranch(contextWorktree);
42
- const inferred = deps.inferChangeIdFromBranch(contextBranch);
43
-
44
- return {
45
- worktree: contextWorktree,
46
- branch: contextBranch,
47
- branchMatchesChange: inferred === changeId,
48
- source,
49
- warning,
50
- currentWorktree: rootWorktree,
51
- currentBranch: rootBranch,
52
- changeWorktree: changeWorktree ? path.resolve(changeWorktree) : "",
53
- };
54
- }
55
-
56
- /**
57
- * @param {string} changeDir
58
- * @param {{ pathExists: (path: string) => Promise<boolean>, readText: (path: string) => Promise<string> }} deps
59
- */
60
- export async function readChangeMetrics(changeDir, deps) {
61
- const metricsAbs = path.join(changeDir, "metrics.json");
62
- if (!(await deps.pathExists(metricsAbs))) return { state: "missing", abs: metricsAbs, events: [] };
63
- try {
64
- const parsed = JSON.parse(await deps.readText(metricsAbs));
65
- const events = Array.isArray(parsed?.events) ? parsed.events : [];
66
- return { state: "ok", abs: metricsAbs, events };
67
- } catch {
68
- return { state: "invalid", abs: metricsAbs, events: [] };
69
- }
70
- }
71
-
72
- const FINISH_DONE_COMPLETED_CLEANUPS = new Set([
73
- "removed",
74
- "pruned-missing",
75
- "skipped:no_separate_change_worktree",
76
- "skipped:current_worktree",
77
- ]);
78
-
79
- /**
80
- * @param {any} ev
81
- * @returns {{ state: string, reason: string, eventType: string } | null}
82
- */
83
- function classifyFinishLifecycleEvent(ev) {
84
- const type = String(ev?.type || "").trim();
85
- if (!type) return null;
86
- if (type === "finish_local") {
87
- return { state: "local", reason: "", eventType: type };
88
- }
89
- if (type === "finish_failed") {
90
- return { state: "failed", reason: String(ev?.payload?.error || ""), eventType: type };
91
- }
92
- if (type === "finish_cleanup_pending") {
93
- return {
94
- state: "cleanup_pending",
95
- reason: String(ev?.payload?.reason || ev?.payload?.cleanup || ""),
96
- eventType: type,
97
- };
98
- }
99
- if (type === "finish") {
100
- return { state: "done", reason: "", eventType: type };
101
- }
102
- if (type !== "finish_done") return null;
103
-
104
- const payload = ev?.payload && typeof ev.payload === "object" ? ev.payload : null;
105
- const hasPush = payload ? Object.prototype.hasOwnProperty.call(payload, "push") : false;
106
- const pushCompleted = hasPush ? payload?.push === true : null;
107
- const cleanup = String(payload?.cleanup || "").trim();
108
-
109
- if (pushCompleted === false || cleanup === "not_requested") {
110
- return { state: "local", reason: "", eventType: type };
111
- }
112
- if (!cleanup) {
113
- return { state: "done", reason: "", eventType: type };
114
- }
115
- if (FINISH_DONE_COMPLETED_CLEANUPS.has(cleanup)) {
116
- return { state: "done", reason: "", eventType: type };
117
- }
118
-
119
- return {
120
- state: "cleanup_pending",
121
- reason: cleanup.startsWith("skipped:") ? cleanup.slice("skipped:".length) : cleanup,
122
- eventType: type,
123
- };
124
- }
125
-
126
- /**
127
- * @param {{ state: string, events: any[] }} metrics
128
- */
129
- export function summarizeLifecycleSignals(metrics) {
130
- const events = Array.isArray(metrics?.events) ? metrics.events : [];
131
- /** @type {Record<string, number>} */
132
- const eventCounts = {};
133
- let finishState = "";
134
- let finishStateReason = "";
135
- let finishStateEventType = "";
136
- for (const ev of events) {
137
- const type = String(ev?.type || "").trim();
138
- if (!type) continue;
139
- eventCounts[type] = (eventCounts[type] || 0) + 1;
140
- const finishIsTerminal = finishState === "done";
141
- if (finishIsTerminal && type !== "finish_done" && type !== "finish") continue;
142
- const classified = classifyFinishLifecycleEvent(ev);
143
- if (!classified) continue;
144
- finishState = classified.state;
145
- finishStateReason = classified.reason;
146
- finishStateEventType = classified.eventType;
147
- }
148
-
149
- const latest = events.length > 0 ? events[events.length - 1] : null;
150
- const validateEvents = events.filter((ev) => ev?.type === "validate");
151
- const latestStrictValidate = [...validateEvents].reverse().find((ev) => ev?.payload?.strict === true) || null;
152
- const latestStrictScopeValidate =
153
- [...validateEvents].reverse().find((ev) => ev?.payload?.strict === true && ev?.payload?.check_scope === true) || null;
154
- const strictScopeValidateRuns = validateEvents.filter((ev) => ev?.payload?.strict === true && ev?.payload?.check_scope === true).length;
155
-
156
- return {
157
- metricsState: String(metrics?.state || "missing"),
158
- latestEventType: String(latest?.type || ""),
159
- eventCounts,
160
- evidenceRuns: eventCounts.evidence || 0,
161
- finishRuns: (eventCounts.finish || 0) + (eventCounts.finish_done || 0),
162
- finishCleanupPendingReason: finishState === "cleanup_pending" ? finishStateReason : "",
163
- finishState,
164
- finishStateReason,
165
- finishStateEventType,
166
- archiveRuns: eventCounts.archive || 0,
167
- strictValidatePass: latestStrictValidate ? latestStrictValidate?.payload?.ok === true : false,
168
- strictScopeValidateRuns,
169
- strictScopeValidatePass: latestStrictScopeValidate ? latestStrictScopeValidate?.payload?.ok === true : false,
170
- strictScopeValidateAt: String(latestStrictScopeValidate?.timestamp || ""),
171
- strictScopeValidateErrors: Number(latestStrictScopeValidate?.payload?.errors || 0),
172
- strictScopeValidateWarnings: Number(latestStrictScopeValidate?.payload?.warnings || 0),
173
- };
174
- }
175
-
176
- /**
177
- * @param {Record<string, string | null>} curTruth
178
- * @param {any} baseline
179
- * @returns {{ baselineLabel: string, baselineAt: string, driftFiles: string[] }}
180
- */
181
- export function truthDrift(curTruth, baseline) {
182
- /** @type {string[]} */
183
- const driftFiles = [];
184
-
185
- const createdTruth = baseline?.base_truth_files && typeof baseline.base_truth_files === "object" ? baseline.base_truth_files : {};
186
- const syncedTruth = baseline?.synced_truth_files && typeof baseline.synced_truth_files === "object" ? baseline.synced_truth_files : {};
187
- const effective = Object.keys(syncedTruth).length > 0 ? syncedTruth : createdTruth;
188
- const baselineLabel = Object.keys(syncedTruth).length > 0 ? "sync" : "creation";
189
- const baselineAt = Object.keys(syncedTruth).length > 0 ? String(baseline?.synced_at || "") : String(baseline?.created_at || "");
190
-
191
- for (const [rel, info] of Object.entries(effective || {})) {
192
- const baseSha = info && typeof info === "object" ? String(info.sha256 || "") : "";
193
- const curSha = curTruth[rel] ?? null;
194
- if (curSha == null) {
195
- driftFiles.push(rel);
196
- continue;
197
- }
198
- if (baseSha && curSha !== baseSha) driftFiles.push(rel);
199
- }
200
-
201
- return { baselineLabel, baselineAt, driftFiles };
202
- }
@@ -1,64 +0,0 @@
1
- /**
2
- * Parse checkbox tasks with AIWS-specific control markers.
3
- *
4
- * Supported markers:
5
- * - `[optional]`: unchecked optional tasks do not block archive/finish.
6
- * - `[n/a: ...]` / `[na: ...]` / `[not-applicable: ...]`: task is treated as closed.
7
- *
8
- * Returned `total/done/unchecked` are the effective gate counts. Optional open
9
- * tasks are reported separately via `optionalUnchecked`.
10
- *
11
- * @param {string} text
12
- */
13
- export function checkboxStats(text) {
14
- const lines = String(text || "").split(/\r?\n/);
15
- let total = 0;
16
- let done = 0;
17
- let unchecked = 0;
18
- let totalAll = 0;
19
- let doneAll = 0;
20
- let uncheckedAll = 0;
21
- let optionalTotal = 0;
22
- let optionalUnchecked = 0;
23
- let naCount = 0;
24
-
25
- for (const rawLine of lines) {
26
- const match = rawLine.match(/^\s*-\s+\[([ xX])\]\s+(.*)$/);
27
- if (!match) continue;
28
- totalAll += 1;
29
- const checked = String(match[1] || "").toLowerCase() === "x";
30
- const body = String(match[2] || "");
31
- const isOptional = /\[(?:optional|Optional)\]/.test(body);
32
- const isNa = /\[(?:n\/a|na|not-applicable)\s*:[^\]]+\]/i.test(body);
33
-
34
- if (checked) doneAll += 1;
35
- else uncheckedAll += 1;
36
-
37
- if (isOptional) {
38
- optionalTotal += 1;
39
- if (!checked && !isNa) optionalUnchecked += 1;
40
- continue;
41
- }
42
-
43
- total += 1;
44
- if (checked || isNa) {
45
- done += 1;
46
- if (isNa) naCount += 1;
47
- } else {
48
- unchecked += 1;
49
- }
50
- }
51
-
52
- return {
53
- total,
54
- done,
55
- unchecked,
56
- hasCheckboxes: totalAll > 0,
57
- totalAll,
58
- doneAll,
59
- uncheckedAll,
60
- optionalTotal,
61
- optionalUnchecked,
62
- naCount,
63
- };
64
- }
@@ -1,45 +0,0 @@
1
- /**
2
- * @param {{
3
- * gitRoot: string,
4
- * changeId: string,
5
- * options: { strict: boolean, allowTruthDrift: boolean, checkEvidence: boolean, checkScope: boolean }
6
- * }} input
7
- * @param {{
8
- * appendMetricsEvent: (gitRoot: string, changeId: string, type: string, payload: any) => Promise<void>,
9
- * validateChangeArtifacts: (gitRoot: string, changeId: string, options: any) => Promise<any>,
10
- * UserError: typeof import("../errors.js").UserError
11
- * }} deps
12
- */
13
- export async function runChangeValidateCommand(input, deps) {
14
- const { gitRoot, changeId, options } = input;
15
- const result = await deps.validateChangeArtifacts(gitRoot, changeId, {
16
- strict: options.strict === true,
17
- allowTruthDrift: options.allowTruthDrift === true,
18
- checkEvidence: options.checkEvidence === true,
19
- checkScope: options.checkScope === true,
20
- });
21
-
22
- await deps.appendMetricsEvent(gitRoot, changeId, "validate", {
23
- ok: result.ok === true,
24
- strict: options.strict === true,
25
- allow_truth_drift: options.allowTruthDrift === true,
26
- check_evidence: options.checkEvidence === true,
27
- check_scope: options.checkScope === true,
28
- errors: Array.isArray(result.errors) ? result.errors.length : 0,
29
- warnings: Array.isArray(result.warnings) ? result.warnings.length : 0,
30
- exit_code: result.exitCode,
31
- });
32
-
33
- if (result.raw) {
34
- return {
35
- output: result.ok ? `ok: change validated (${changeId})\n` : "",
36
- stderr: result.raw + "\n",
37
- errorToThrow: result.ok ? null : new deps.UserError(""),
38
- };
39
- }
40
- return {
41
- output: result.ok ? `ok: change validated (${changeId})\n` : "",
42
- stderr: "",
43
- errorToThrow: result.ok ? null : new deps.UserError(""),
44
- };
45
- }
@@ -1,127 +0,0 @@
1
- function parseChangeCheckerOutput(stdout, stderr) {
2
- const text = [String(stdout || ""), String(stderr || "")].filter(Boolean).join("\n");
3
- /** @type {string[]} */
4
- const errors = [];
5
- /** @type {string[]} */
6
- const warnings = [];
7
- for (const raw of text.split("\n")) {
8
- const line = raw.trim();
9
- if (!line) continue;
10
- if (line.startsWith("error: ")) errors.push(line.replace(/^error:\s*/, ""));
11
- else if (line.startsWith("warn: ")) warnings.push(line.replace(/^warn:\s*/, ""));
12
- }
13
- return { errors, warnings, raw: text.trim() };
14
- }
15
-
16
- function classifyCheckMessage(msg) {
17
- const s = String(msg || "");
18
- if (s.includes("truth file") || s.includes("truth drift") || s.includes("allow-truth-drift")) return "truth_drift";
19
- if (s.includes("WS:TODO") || s.includes("unrendered template placeholders")) return "placeholders";
20
- if (s.includes("missing:") || s.includes("empty:") || s.includes("Missing change dir")) return "missing_files";
21
- if (
22
- s.includes("Change_ID") ||
23
- s.includes("Req_ID") ||
24
- s.includes("Problem_ID") ||
25
- s.includes("Contract_Row") ||
26
- s.includes("Plan_File") ||
27
- s.includes("Evidence_Path")
28
- ) {
29
- return "bindings";
30
- }
31
- if (s.includes("scope check") || s.includes("out-of-scope")) return "scope_gate";
32
- if (
33
- s.includes("finish gate") ||
34
- s.includes("validate stamp") ||
35
- s.includes("verify-before-complete") ||
36
- s.includes("spec review") ||
37
- s.includes("quality review")
38
- ) {
39
- return "finish_gate";
40
- }
41
- if (
42
- s.includes("missing required sections") ||
43
- s.includes("has empty sections") ||
44
- s.includes("Plan section") ||
45
- s.includes("Verify section") ||
46
- s.includes("scope is too broad") ||
47
- s.includes("too abstract")
48
- ) {
49
- return "plan_quality";
50
- }
51
- return "other";
52
- }
53
-
54
- function groupCheckMessages(errors, warnings) {
55
- const groups = {
56
- truth_drift: { errors: [], warnings: [] },
57
- missing_files: { errors: [], warnings: [] },
58
- placeholders: { errors: [], warnings: [] },
59
- bindings: { errors: [], warnings: [] },
60
- scope_gate: { errors: [], warnings: [] },
61
- finish_gate: { errors: [], warnings: [] },
62
- plan_quality: { errors: [], warnings: [] },
63
- other: { errors: [], warnings: [] },
64
- };
65
-
66
- for (const message of errors || []) {
67
- const group = classifyCheckMessage(message);
68
- groups[group].errors.push(message);
69
- }
70
- for (const message of warnings || []) {
71
- const group = classifyCheckMessage(message);
72
- groups[group].warnings.push(message);
73
- }
74
- return groups;
75
- }
76
-
77
- /**
78
- * @param {string} gitRoot
79
- * @param {string} changeId
80
- * @param {{ strict: boolean, allowTruthDrift: boolean, checkEvidence?: boolean, checkScope?: boolean }} options
81
- * @param {{
82
- * assertValidChangeId: (changeId: string) => void,
83
- * collectFinishGateErrors: (changeId: string, reviewGates: any) => string[],
84
- * computeChangeStatus: (gitRoot: string, changeId: string) => Promise<any>,
85
- * ensureTruthFiles: (gitRoot: string) => Promise<void>,
86
- * resolveWsChangeChecker: (gitRoot: string) => Promise<{ args: string[] }>,
87
- * runPython: (cwd: string, args: string[]) => Promise<{ code: number, stdout: string, stderr: string }>
88
- * }} deps
89
- */
90
- export async function validateChangeArtifacts(gitRoot, changeId, options, deps) {
91
- deps.assertValidChangeId(changeId);
92
- await deps.ensureTruthFiles(gitRoot);
93
-
94
- const checker = await deps.resolveWsChangeChecker(gitRoot);
95
- const args = [...checker.args, "--workspace-root", gitRoot, "--change-id", changeId];
96
- if (options.strict) args.push("--strict");
97
- if (options.allowTruthDrift) args.push("--allow-truth-drift");
98
- if (options.checkEvidence) args.push("--check-evidence");
99
- if (options.checkScope) args.push("--check-scope");
100
-
101
- const res = await deps.runPython(gitRoot, ["-u", ...args]);
102
- const parsed = parseChangeCheckerOutput(res.stdout, res.stderr);
103
- const errors = [...parsed.errors];
104
- const warnings = [...parsed.warnings];
105
-
106
- if (options.checkEvidence === true) {
107
- const status = await deps.computeChangeStatus(gitRoot, changeId);
108
- errors.push(...deps.collectFinishGateErrors(changeId, status.reviewGates));
109
- }
110
-
111
- const rawLines = [];
112
- if (parsed.raw) rawLines.push(parsed.raw);
113
- for (const message of errors.slice(parsed.errors.length)) rawLines.push(`error: ${message}`);
114
- for (const message of warnings.slice(parsed.warnings.length)) rawLines.push(`warn: ${message}`);
115
- const exitCode = res.code === 0 && errors.length > 0 ? 1 : res.code;
116
- return {
117
- ok: exitCode === 0,
118
- changeId,
119
- strict: options.strict === true,
120
- allowTruthDrift: options.allowTruthDrift === true,
121
- exitCode,
122
- errors,
123
- warnings,
124
- groups: groupCheckMessages(errors, warnings),
125
- raw: rawLines.filter(Boolean).join("\n").trim(),
126
- };
127
- }