@aipper/aiws 0.0.29 → 0.0.31

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 (278) hide show
  1. package/bin/aiws.js +2 -2
  2. package/dist/aiws-package.d.ts +4 -0
  3. package/dist/aiws-package.js +11 -0
  4. package/dist/aiws-package.js.map +1 -0
  5. package/dist/aiws-paths.d.ts +48 -0
  6. package/dist/aiws-paths.js +129 -0
  7. package/dist/aiws-paths.js.map +1 -0
  8. package/dist/backup.d.ts +27 -0
  9. package/dist/backup.js +125 -0
  10. package/dist/backup.js.map +1 -0
  11. package/dist/cli.d.ts +1 -0
  12. package/dist/cli.js +773 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/codex-prompts.d.ts +17 -0
  15. package/dist/codex-prompts.js +49 -0
  16. package/dist/codex-prompts.js.map +1 -0
  17. package/dist/codex-skills.d.ts +17 -0
  18. package/dist/codex-skills.js +75 -0
  19. package/dist/codex-skills.js.map +1 -0
  20. package/dist/commands/change-advice.d.ts +25 -0
  21. package/dist/commands/change-advice.js +197 -0
  22. package/dist/commands/change-advice.js.map +1 -0
  23. package/dist/commands/change-evidence-command.d.ts +29 -0
  24. package/dist/commands/change-evidence-command.js +213 -0
  25. package/dist/commands/change-evidence-command.js.map +1 -0
  26. package/dist/commands/change-evidence-entry.d.ts +16 -0
  27. package/dist/commands/change-evidence-entry.js +35 -0
  28. package/dist/commands/change-evidence-entry.js.map +1 -0
  29. package/dist/commands/change-evidence.d.ts +108 -0
  30. package/dist/commands/change-evidence.js +341 -0
  31. package/dist/commands/change-evidence.js.map +1 -0
  32. package/dist/commands/change-finish.d.ts +71 -0
  33. package/dist/commands/change-finish.js +387 -0
  34. package/dist/commands/change-finish.js.map +1 -0
  35. package/dist/commands/change-git-status.d.ts +22 -0
  36. package/dist/commands/change-git-status.js +50 -0
  37. package/dist/commands/change-git-status.js.map +1 -0
  38. package/dist/commands/change-lifecycle-entry.d.ts +29 -0
  39. package/{src → dist}/commands/change-lifecycle-entry.js +21 -28
  40. package/dist/commands/change-lifecycle-entry.js.map +1 -0
  41. package/dist/commands/change-lifecycle.d.ts +56 -0
  42. package/dist/commands/change-lifecycle.js +211 -0
  43. package/dist/commands/change-lifecycle.js.map +1 -0
  44. package/dist/commands/change-metrics-command.d.ts +12 -0
  45. package/dist/commands/change-metrics-command.js +110 -0
  46. package/dist/commands/change-metrics-command.js.map +1 -0
  47. package/dist/commands/change-next-command.d.ts +18 -0
  48. package/dist/commands/change-next-command.js +138 -0
  49. package/dist/commands/change-next-command.js.map +1 -0
  50. package/dist/commands/change-review-gates.d.ts +107 -0
  51. package/dist/commands/change-review-gates.js +329 -0
  52. package/dist/commands/change-review-gates.js.map +1 -0
  53. package/dist/commands/change-scope-gate.d.ts +21 -0
  54. package/dist/commands/change-scope-gate.js +32 -0
  55. package/dist/commands/change-scope-gate.js.map +1 -0
  56. package/dist/commands/change-start.d.ts +30 -0
  57. package/dist/commands/change-start.js +91 -0
  58. package/dist/commands/change-start.js.map +1 -0
  59. package/dist/commands/change-state-command.d.ts +3 -0
  60. package/dist/commands/change-state-command.js +32 -0
  61. package/dist/commands/change-state-command.js.map +1 -0
  62. package/dist/commands/change-status-command.d.ts +13 -0
  63. package/dist/commands/change-status-command.js +126 -0
  64. package/dist/commands/change-status-command.js.map +1 -0
  65. package/dist/commands/change-status-context.d.ts +58 -0
  66. package/dist/commands/change-status-context.js +166 -0
  67. package/dist/commands/change-status-context.js.map +1 -0
  68. package/dist/commands/change-task-stats.d.ts +24 -0
  69. package/dist/commands/change-task-stats.js +66 -0
  70. package/dist/commands/change-task-stats.js.map +1 -0
  71. package/dist/commands/change-validate-entry.d.ts +17 -0
  72. package/dist/commands/change-validate-entry.js +44 -0
  73. package/dist/commands/change-validate-entry.js.map +1 -0
  74. package/dist/commands/change-validate.d.ts +32 -0
  75. package/dist/commands/change-validate.js +128 -0
  76. package/dist/commands/change-validate.js.map +1 -0
  77. package/dist/commands/change.d.ts +322 -0
  78. package/dist/commands/change.js +1731 -0
  79. package/dist/commands/change.js.map +1 -0
  80. package/dist/commands/codex-install-prompts.d.ts +4 -0
  81. package/dist/commands/codex-install-prompts.js +68 -0
  82. package/dist/commands/codex-install-prompts.js.map +1 -0
  83. package/dist/commands/codex-install-skills.d.ts +4 -0
  84. package/dist/commands/codex-install-skills.js +74 -0
  85. package/dist/commands/codex-install-skills.js.map +1 -0
  86. package/dist/commands/codex-status-prompts.d.ts +4 -0
  87. package/dist/commands/codex-status-prompts.js +44 -0
  88. package/dist/commands/codex-status-prompts.js.map +1 -0
  89. package/dist/commands/codex-status-skills.d.ts +4 -0
  90. package/dist/commands/codex-status-skills.js +54 -0
  91. package/dist/commands/codex-status-skills.js.map +1 -0
  92. package/dist/commands/codex-uninstall-prompts.d.ts +4 -0
  93. package/dist/commands/codex-uninstall-prompts.js +51 -0
  94. package/dist/commands/codex-uninstall-prompts.js.map +1 -0
  95. package/dist/commands/codex-uninstall-skills.d.ts +4 -0
  96. package/dist/commands/codex-uninstall-skills.js +59 -0
  97. package/dist/commands/codex-uninstall-skills.js.map +1 -0
  98. package/dist/commands/dashboard.d.ts +222 -0
  99. package/dist/commands/dashboard.js +193 -0
  100. package/dist/commands/dashboard.js.map +1 -0
  101. package/dist/commands/hooks-install.d.ts +4 -0
  102. package/dist/commands/hooks-install.js +90 -0
  103. package/dist/commands/hooks-install.js.map +1 -0
  104. package/dist/commands/hooks-status.d.ts +4 -0
  105. package/dist/commands/hooks-status.js +89 -0
  106. package/dist/commands/hooks-status.js.map +1 -0
  107. package/dist/commands/init.d.ts +4 -0
  108. package/dist/commands/init.js +100 -0
  109. package/dist/commands/init.js.map +1 -0
  110. package/dist/commands/opencode-auto.d.ts +11 -0
  111. package/dist/commands/opencode-auto.js +158 -0
  112. package/dist/commands/opencode-auto.js.map +1 -0
  113. package/dist/commands/opencode-status.d.ts +4 -0
  114. package/dist/commands/opencode-status.js +75 -0
  115. package/dist/commands/opencode-status.js.map +1 -0
  116. package/dist/commands/opencode-supervise.d.ts +24 -0
  117. package/dist/commands/opencode-supervise.js +188 -0
  118. package/dist/commands/opencode-supervise.js.map +1 -0
  119. package/dist/commands/rollback.d.ts +4 -0
  120. package/dist/commands/rollback.js +12 -0
  121. package/dist/commands/rollback.js.map +1 -0
  122. package/dist/commands/update.d.ts +4 -0
  123. package/dist/commands/update.js +212 -0
  124. package/dist/commands/update.js.map +1 -0
  125. package/dist/commands/validate.d.ts +4 -0
  126. package/dist/commands/validate.js +222 -0
  127. package/dist/commands/validate.js.map +1 -0
  128. package/dist/commands/ws-commit.d.ts +5 -0
  129. package/dist/commands/ws-commit.js +39 -0
  130. package/dist/commands/ws-commit.js.map +1 -0
  131. package/dist/commands/ws-deliver.d.ts +5 -0
  132. package/dist/commands/ws-deliver.js +59 -0
  133. package/dist/commands/ws-deliver.js.map +1 -0
  134. package/dist/commands/ws-finish.d.ts +5 -0
  135. package/dist/commands/ws-finish.js +142 -0
  136. package/dist/commands/ws-finish.js.map +1 -0
  137. package/dist/commands/ws-handoff.d.ts +5 -0
  138. package/dist/commands/ws-handoff.js +35 -0
  139. package/dist/commands/ws-handoff.js.map +1 -0
  140. package/dist/commands/ws-migrate.d.ts +5 -0
  141. package/dist/commands/ws-migrate.js +41 -0
  142. package/dist/commands/ws-migrate.js.map +1 -0
  143. package/dist/commands/ws-plan-verify.d.ts +5 -0
  144. package/dist/commands/ws-plan-verify.js +38 -0
  145. package/dist/commands/ws-plan-verify.js.map +1 -0
  146. package/dist/commands/ws-pull.d.ts +5 -0
  147. package/dist/commands/ws-pull.js +26 -0
  148. package/dist/commands/ws-pull.js.map +1 -0
  149. package/dist/commands/ws-push.d.ts +5 -0
  150. package/dist/commands/ws-push.js +68 -0
  151. package/dist/commands/ws-push.js.map +1 -0
  152. package/dist/commands/ws-submodule-setup.d.ts +5 -0
  153. package/dist/commands/ws-submodule-setup.js +55 -0
  154. package/dist/commands/ws-submodule-setup.js.map +1 -0
  155. package/dist/commands/ws-verify-before-complete.d.ts +5 -0
  156. package/dist/commands/ws-verify-before-complete.js +35 -0
  157. package/dist/commands/ws-verify-before-complete.js.map +1 -0
  158. package/dist/dashboard/app.d.ts +1 -0
  159. package/dist/dashboard/app.js +370 -0
  160. package/dist/dashboard/app.js.map +1 -0
  161. package/dist/delegation/cli.d.ts +6 -0
  162. package/dist/delegation/cli.js +14 -0
  163. package/dist/delegation/cli.js.map +1 -0
  164. package/dist/delegation/index.d.ts +35 -0
  165. package/dist/delegation/index.js +118 -0
  166. package/dist/delegation/index.js.map +1 -0
  167. package/dist/errors.d.ts +8 -0
  168. package/dist/errors.js +11 -0
  169. package/dist/errors.js.map +1 -0
  170. package/dist/exec.d.ts +9 -0
  171. package/dist/exec.js +22 -0
  172. package/dist/exec.js.map +1 -0
  173. package/dist/fs.d.ts +9 -0
  174. package/dist/fs.js +62 -0
  175. package/dist/fs.js.map +1 -0
  176. package/dist/governance.d.ts +10 -0
  177. package/dist/governance.js +135 -0
  178. package/dist/governance.js.map +1 -0
  179. package/dist/hash.d.ts +3 -0
  180. package/dist/hash.js +13 -0
  181. package/dist/hash.js.map +1 -0
  182. package/dist/hooks/deploy-claude.d.ts +13 -0
  183. package/dist/hooks/deploy-claude.js +67 -0
  184. package/dist/hooks/deploy-claude.js.map +1 -0
  185. package/dist/journal.d.ts +22 -0
  186. package/dist/journal.js +112 -0
  187. package/dist/journal.js.map +1 -0
  188. package/dist/json-schema-lite.d.ts +22 -0
  189. package/dist/json-schema-lite.js +148 -0
  190. package/dist/json-schema-lite.js.map +1 -0
  191. package/dist/managed-blocks.d.ts +24 -0
  192. package/dist/managed-blocks.js +84 -0
  193. package/dist/managed-blocks.js.map +1 -0
  194. package/dist/manifest.d.ts +24 -0
  195. package/dist/manifest.js +145 -0
  196. package/dist/manifest.js.map +1 -0
  197. package/dist/opencode-env.d.ts +62 -0
  198. package/dist/opencode-env.js +178 -0
  199. package/dist/opencode-env.js.map +1 -0
  200. package/dist/path-utils.d.ts +2 -0
  201. package/dist/path-utils.js +8 -0
  202. package/dist/path-utils.js.map +1 -0
  203. package/dist/spec.d.ts +17 -0
  204. package/dist/spec.js +174 -0
  205. package/dist/spec.js.map +1 -0
  206. package/dist/template.d.ts +20 -0
  207. package/dist/template.js +123 -0
  208. package/dist/template.js.map +1 -0
  209. package/dist/workspace.d.ts +4 -0
  210. package/dist/workspace.js +19 -0
  211. package/dist/workspace.js.map +1 -0
  212. package/package.json +11 -3
  213. package/src/aiws-package.js +0 -15
  214. package/src/backup.js +0 -149
  215. package/src/cli.js +0 -760
  216. package/src/codex-prompts.js +0 -74
  217. package/src/codex-skills.js +0 -111
  218. package/src/commands/change-advice.js +0 -181
  219. package/src/commands/change-evidence-command.js +0 -242
  220. package/src/commands/change-evidence-entry.js +0 -40
  221. package/src/commands/change-evidence.js +0 -340
  222. package/src/commands/change-finish.js +0 -413
  223. package/src/commands/change-git-status.js +0 -53
  224. package/src/commands/change-lifecycle.js +0 -236
  225. package/src/commands/change-metrics-command.js +0 -110
  226. package/src/commands/change-next-command.js +0 -133
  227. package/src/commands/change-review-gates.js +0 -331
  228. package/src/commands/change-scope-gate.js +0 -34
  229. package/src/commands/change-start.js +0 -85
  230. package/src/commands/change-state-command.js +0 -40
  231. package/src/commands/change-status-command.js +0 -125
  232. package/src/commands/change-status-context.js +0 -173
  233. package/src/commands/change-task-stats.js +0 -64
  234. package/src/commands/change-validate-entry.js +0 -45
  235. package/src/commands/change-validate.js +0 -127
  236. package/src/commands/change.js +0 -1829
  237. package/src/commands/codex-install-prompts.js +0 -68
  238. package/src/commands/codex-install-skills.js +0 -74
  239. package/src/commands/codex-status-prompts.js +0 -55
  240. package/src/commands/codex-status-skills.js +0 -63
  241. package/src/commands/codex-uninstall-prompts.js +0 -55
  242. package/src/commands/codex-uninstall-skills.js +0 -62
  243. package/src/commands/dashboard.js +0 -205
  244. package/src/commands/hooks-install.js +0 -92
  245. package/src/commands/hooks-status.js +0 -95
  246. package/src/commands/init.js +0 -101
  247. package/src/commands/opencode-auto.js +0 -167
  248. package/src/commands/opencode-status.js +0 -103
  249. package/src/commands/opencode-supervise.js +0 -200
  250. package/src/commands/rollback.js +0 -13
  251. package/src/commands/update.js +0 -145
  252. package/src/commands/validate.js +0 -228
  253. package/src/commands/ws-commit.js +0 -44
  254. package/src/commands/ws-deliver.js +0 -67
  255. package/src/commands/ws-finish.js +0 -83
  256. package/src/commands/ws-handoff.js +0 -40
  257. package/src/commands/ws-migrate.js +0 -41
  258. package/src/commands/ws-plan-verify.js +0 -44
  259. package/src/commands/ws-pull.js +0 -30
  260. package/src/commands/ws-push.js +0 -71
  261. package/src/commands/ws-submodule-setup.js +0 -65
  262. package/src/commands/ws-verify-before-complete.js +0 -39
  263. package/src/dashboard/app.js +0 -371
  264. package/src/errors.js +0 -15
  265. package/src/exec.js +0 -34
  266. package/src/fs.js +0 -91
  267. package/src/governance.js +0 -159
  268. package/src/hash.js +0 -25
  269. package/src/json-schema-lite.js +0 -164
  270. package/src/managed-blocks.js +0 -131
  271. package/src/manifest.js +0 -177
  272. package/src/opencode-env.js +0 -208
  273. package/src/path-utils.js +0 -20
  274. package/src/spec.js +0 -195
  275. package/src/template.js +0 -187
  276. package/src/workspace.js +0 -23
  277. /package/{src → dist}/dashboard/index.html +0 -0
  278. /package/{src → dist}/dashboard/style.css +0 -0
@@ -1,331 +0,0 @@
1
- import path from "node:path";
2
- import fs from "node:fs/promises";
3
- import { pathExists } from "../fs.js";
4
- import { loadWorkflowReviewGates } from "../spec.js";
5
-
6
- export const TMP_REVIEW_FALLBACKS = [
7
- { fileName: "codex-review.md", persistentKind: "review" },
8
- { fileName: "spec-review.md", persistentKind: "review" },
9
- { fileName: "quality-review.md", persistentKind: "review" },
10
- { fileName: "verify-before-complete.md", persistentKind: "evidence" },
11
- ];
12
-
13
- /**
14
- * @param {string} input
15
- */
16
- function normalizeSlashes(input) {
17
- return String(input || "").replaceAll("\\", "/");
18
- }
19
-
20
- /**
21
- * @param {string} gitRoot
22
- * @param {string} absPath
23
- */
24
- function relFromRoot(gitRoot, absPath) {
25
- return normalizeSlashes(path.relative(gitRoot, absPath));
26
- }
27
-
28
- /**
29
- * @param {string} gitRoot
30
- * @param {string} fileName
31
- */
32
- export function tmpReviewFallbackPath(gitRoot, fileName) {
33
- return path.join(gitRoot, ".agentdocs", "tmp", "review", fileName);
34
- }
35
-
36
- /**
37
- * @param {string} gitRoot
38
- * @param {string} changeId
39
- * @param {string} fileName
40
- */
41
- function persistentReviewPath(gitRoot, changeId, fileName) {
42
- return path.join(gitRoot, "changes", changeId, "review", fileName);
43
- }
44
-
45
- /**
46
- * @param {string} gitRoot
47
- * @param {string} changeId
48
- * @param {string} fileName
49
- */
50
- function persistentEvidencePath(gitRoot, changeId, fileName) {
51
- return path.join(gitRoot, "changes", changeId, "evidence", fileName);
52
- }
53
-
54
- /**
55
- * @param {string} gitRoot
56
- * @param {string} changeId
57
- */
58
- async function hasGenericReviewSignal(gitRoot, changeId) {
59
- const persistentCodexReview = persistentReviewPath(gitRoot, changeId, "codex-review.md");
60
- if (await pathExists(persistentCodexReview)) return true;
61
- const tmpCodexReview = tmpReviewFallbackPath(gitRoot, "codex-review.md");
62
- return await pathExists(tmpCodexReview);
63
- }
64
-
65
- /**
66
- * @param {string} gitRoot
67
- * @param {string} changeId
68
- * @param {string} gateId
69
- */
70
- function reviewGateArtifactPaths(gitRoot, changeId, gateId) {
71
- switch (gateId) {
72
- case "spec_review":
73
- return {
74
- primaryAbs: persistentReviewPath(gitRoot, changeId, "spec-review.md"),
75
- fallbackAbs: tmpReviewFallbackPath(gitRoot, "spec-review.md"),
76
- };
77
- case "quality_review":
78
- return {
79
- primaryAbs: persistentReviewPath(gitRoot, changeId, "quality-review.md"),
80
- fallbackAbs: tmpReviewFallbackPath(gitRoot, "quality-review.md"),
81
- };
82
- case "verify_before_complete":
83
- return {
84
- primaryAbs: persistentEvidencePath(gitRoot, changeId, "verify-before-complete.md"),
85
- fallbackAbs: tmpReviewFallbackPath(gitRoot, "verify-before-complete.md"),
86
- };
87
- default:
88
- return null;
89
- }
90
- }
91
-
92
- /**
93
- * @param {string} absDir
94
- * @param {(fileName: string) => boolean} predicate
95
- */
96
- async function findLatestFileByMtime(absDir, predicate) {
97
- /** @type {Array<{ abs: string, mtimeMs: number }>} */
98
- const matches = [];
99
- if (!(await pathExists(absDir))) return "";
100
- try {
101
- const entries = await fs.readdir(absDir, { withFileTypes: true });
102
- for (const entry of entries) {
103
- if (!entry.isFile()) continue;
104
- if (!predicate(entry.name)) continue;
105
- const abs = path.join(absDir, entry.name);
106
- const st = await fs.stat(abs);
107
- matches.push({ abs, mtimeMs: st.mtimeMs });
108
- }
109
- } catch {
110
- return "";
111
- }
112
- matches.sort((a, b) => b.mtimeMs - a.mtimeMs);
113
- return matches[0]?.abs || "";
114
- }
115
-
116
- /**
117
- * @param {string} gitRoot
118
- */
119
- async function listActiveChangeIds(gitRoot) {
120
- const changesRoot = path.join(gitRoot, "changes");
121
- try {
122
- const entries = await fs.readdir(changesRoot, { withFileTypes: true });
123
- return entries
124
- .filter((entry) => entry.isDirectory())
125
- .map((entry) => entry.name)
126
- .filter((name) => name && !name.startsWith(".") && name !== "archive" && name !== "templates")
127
- .sort();
128
- } catch {
129
- return [];
130
- }
131
- }
132
-
133
- /**
134
- * @param {string} gitRoot
135
- * @param {string} changeId
136
- * @param {{ branchMatchesChange?: boolean }} [context]
137
- */
138
- async function canAttributeTmpReviewFallback(gitRoot, changeId, context) {
139
- if (context?.branchMatchesChange === true) return true;
140
- const activeChangeIds = await listActiveChangeIds(gitRoot);
141
- return activeChangeIds.length === 1 && activeChangeIds[0] === changeId;
142
- }
143
-
144
- /**
145
- * @param {string} gitRoot
146
- * @param {string} changeId
147
- * @param {{ branchMatchesChange?: boolean }} [context]
148
- * @param {{ counts?: { review?: number } }} [collaboration]
149
- */
150
- export async function collectReviewSignals(gitRoot, changeId, context, collaboration) {
151
- const persistentCount = Number(collaboration?.counts?.review || 0);
152
- const tmpFallbackPaths = [];
153
- const canAttributeTmpFallback = await canAttributeTmpReviewFallback(gitRoot, changeId, context);
154
-
155
- for (const { fileName, persistentKind } of TMP_REVIEW_FALLBACKS) {
156
- if (persistentKind !== "review") continue;
157
- const tmpReviewPath = tmpReviewFallbackPath(gitRoot, fileName);
158
- if (!(await pathExists(tmpReviewPath))) continue;
159
- const persistentPath = persistentReviewPath(gitRoot, changeId, fileName);
160
- if (await pathExists(persistentPath)) continue;
161
- if (!canAttributeTmpFallback) continue;
162
- tmpFallbackPaths.push(relFromRoot(gitRoot, tmpReviewPath));
163
- }
164
-
165
- const tmpFallbackExists = tmpFallbackPaths.length > 0;
166
- const effectiveCount = persistentCount + tmpFallbackPaths.length;
167
- let source = "none";
168
- if (persistentCount > 0 && tmpFallbackExists) source = "persistent+tmp_fallback";
169
- else if (persistentCount > 0) source = "persistent";
170
- else if (tmpFallbackExists) source = "tmp_fallback";
171
-
172
- return {
173
- persistentCount,
174
- tmpFallbackExists,
175
- tmpFallbackCount: tmpFallbackPaths.length,
176
- tmpFallbackPath: tmpFallbackPaths[0] || "",
177
- tmpFallbackPaths,
178
- effectiveCount,
179
- source,
180
- };
181
- }
182
-
183
- /**
184
- * @param {string} gitRoot
185
- * @param {string} changeId
186
- * @param {{ branchMatchesChange?: boolean }} [context]
187
- */
188
- export async function collectReviewGates(gitRoot, changeId, context) {
189
- const spec = await loadWorkflowReviewGates();
190
- const canAttributeTmpFallback = await canAttributeTmpReviewFallback(gitRoot, changeId, context);
191
- const genericReviewSignal = canAttributeTmpFallback ? await hasGenericReviewSignal(gitRoot, changeId) : await pathExists(persistentReviewPath(gitRoot, changeId, "codex-review.md"));
192
-
193
- /** @type {Array<any>} */
194
- const gates = [];
195
- for (const gate of spec.gates) {
196
- const paths = reviewGateArtifactPaths(gitRoot, changeId, gate.id);
197
- if (!paths) continue;
198
- const primaryExists = await pathExists(paths.primaryAbs);
199
- const fallbackExists = await pathExists(paths.fallbackAbs);
200
- const primaryPath = relFromRoot(gitRoot, paths.primaryAbs);
201
- const fallbackPath = relFromRoot(gitRoot, paths.fallbackAbs);
202
-
203
- let ready = false;
204
- let status = "missing";
205
- let foundPath = "";
206
- if (primaryExists) {
207
- ready = true;
208
- status = "persistent";
209
- foundPath = primaryPath;
210
- } else if (fallbackExists && canAttributeTmpFallback) {
211
- ready = true;
212
- status = "tmp_fallback";
213
- foundPath = fallbackPath;
214
- } else if (fallbackExists) {
215
- ready = false;
216
- status = "tmp_unattributed";
217
- foundPath = fallbackPath;
218
- }
219
-
220
- gates.push({
221
- id: gate.id,
222
- name: gate.name,
223
- stage: gate.stage,
224
- focus: gate.focus,
225
- next: gate.next,
226
- ready,
227
- status,
228
- primaryPath,
229
- fallbackPath,
230
- foundPath,
231
- });
232
- }
233
-
234
- const specReview = gates.find((gate) => gate.id === "spec_review") || null;
235
- const qualityReview = gates.find((gate) => gate.id === "quality_review") || null;
236
- const verifyBeforeComplete = gates.find((gate) => gate.id === "verify_before_complete") || null;
237
- const validateStampDir = path.join(gitRoot, ".agentdocs", "tmp", "aiws-validate");
238
- const latestValidateStamp = await findLatestFileByMtime(validateStampDir, (name) => name.endsWith(".json"));
239
- const validateStamp = {
240
- id: "validate_stamp",
241
- name: "validate-stamp",
242
- ready: Boolean(latestValidateStamp),
243
- status: latestValidateStamp ? "latest" : "missing",
244
- dir: relFromRoot(gitRoot, validateStampDir),
245
- foundPath: latestValidateStamp ? relFromRoot(gitRoot, latestValidateStamp) : "",
246
- };
247
-
248
- const dualReviewMissingIds = [specReview, qualityReview].filter((gate) => !(gate && gate.ready)).map((gate) => gate?.id || "");
249
- const finishGateMissingIds = [];
250
- if (!specReview?.ready) finishGateMissingIds.push("spec_review");
251
- if (!qualityReview?.ready) finishGateMissingIds.push("quality_review");
252
- if (!validateStamp.ready) finishGateMissingIds.push("validate_stamp");
253
- if (!verifyBeforeComplete?.ready) finishGateMissingIds.push("verify_before_complete");
254
- const genericReviewOnly = genericReviewSignal && dualReviewMissingIds.length === 2;
255
- const dualReviewPending = dualReviewMissingIds.length > 0;
256
-
257
- return {
258
- source: spec.source,
259
- specVersion: spec.specVersion,
260
- version: spec.version,
261
- gates,
262
- specReview,
263
- qualityReview,
264
- verifyBeforeComplete,
265
- validateStamp,
266
- summary: {
267
- gateCount: gates.length,
268
- gateReadyCount: gates.filter((gate) => gate.ready).length,
269
- genericReviewOnly,
270
- dualReviewPending,
271
- dualReviewReady: dualReviewMissingIds.length === 0,
272
- dualReviewMissingIds,
273
- dualReviewMissingCount: dualReviewMissingIds.length,
274
- finishGateReady: finishGateMissingIds.length === 0,
275
- finishGateMissingIds,
276
- finishGateMissingCount: finishGateMissingIds.length,
277
- },
278
- };
279
- }
280
-
281
- /**
282
- * @param {string} changeId
283
- * @param {any} reviewGates
284
- */
285
- export function collectFinishGateErrors(changeId, reviewGates) {
286
- const summary = reviewGates?.summary && typeof reviewGates.summary === "object" ? reviewGates.summary : {};
287
- const missingIds = Array.isArray(summary.finishGateMissingIds) ? summary.finishGateMissingIds : [];
288
- if (missingIds.length === 0) return [];
289
-
290
- /** @type {string[]} */
291
- const errors = [];
292
- for (const missingId of missingIds) {
293
- if (missingId === "spec_review") {
294
- const gate = reviewGates?.specReview || {};
295
- if (gate.status === "tmp_unattributed") {
296
- errors.push(`finish gate has unattributed tmp spec review (persist it to changes/${changeId}/review/spec-review.md or rerun in the owning change context)`);
297
- } else {
298
- errors.push(`finish gate missing spec review (run \`$ws-spec-review\` or write changes/${changeId}/review/spec-review.md)`);
299
- }
300
- continue;
301
- }
302
- if (missingId === "quality_review") {
303
- const gate = reviewGates?.qualityReview || {};
304
- if (gate.status === "tmp_unattributed") {
305
- errors.push(`finish gate has unattributed tmp quality review (persist it to changes/${changeId}/review/quality-review.md or rerun in the owning change context)`);
306
- } else {
307
- errors.push(`finish gate missing quality review (run \`$ws-quality-review\` or write changes/${changeId}/review/quality-review.md)`);
308
- }
309
- continue;
310
- }
311
- if (missingId === "validate_stamp") {
312
- errors.push("finish gate missing validate stamp (run `aiws validate . --stamp`)");
313
- continue;
314
- }
315
- if (missingId === "verify_before_complete") {
316
- const gate = reviewGates?.verifyBeforeComplete || {};
317
- if (gate.status === "tmp_unattributed") {
318
- errors.push(
319
- `finish gate has unattributed tmp verify-before-complete evidence (persist it to changes/${changeId}/evidence/verify-before-complete.md or rerun in the owning change context)`,
320
- );
321
- } else {
322
- errors.push(
323
- `finish gate missing verify-before-complete evidence (run \`$ws-verify-before-complete\` or write changes/${changeId}/evidence/verify-before-complete.md)`,
324
- );
325
- }
326
- continue;
327
- }
328
- errors.push(`finish gate missing required artifact: ${missingId}`);
329
- }
330
- return errors;
331
- }
@@ -1,34 +0,0 @@
1
- /**
2
- * @param {any} lifecycle
3
- */
4
- export function computeScopeGate(lifecycle) {
5
- const runs = Number(lifecycle?.strictScopeValidateRuns || 0);
6
- const pass = lifecycle?.strictScopeValidatePass === true;
7
- return {
8
- checked: runs > 0,
9
- ready: runs > 0 && pass,
10
- status: runs === 0 ? "not_run" : pass ? "passed" : "failed",
11
- source: runs > 0 ? "metrics.validate.check_scope" : "",
12
- lastRunAt: String(lifecycle?.strictScopeValidateAt || ""),
13
- errors: Number(lifecycle?.strictScopeValidateErrors || 0),
14
- warnings: Number(lifecycle?.strictScopeValidateWarnings || 0),
15
- };
16
- }
17
-
18
- /**
19
- * @param {string} changeId
20
- */
21
- export function scopeGateFailureAction(changeId) {
22
- return `scope gate 未通过:更新 plan 的 \`## Scope\` / \`### In Scope\` 或收敛改动后复跑 \`aiws change validate ${changeId} --strict --check-scope\``;
23
- }
24
-
25
- /**
26
- * @param {string} changeId
27
- */
28
- export function scopeGatePendingRecommendation(changeId) {
29
- return `范围门禁:\`aiws change validate ${changeId} --strict --check-scope\``;
30
- }
31
-
32
- export function scopeGatePassedRecommendation() {
33
- return "范围门禁:最近一次 `--check-scope` 已通过";
34
- }
@@ -1,85 +0,0 @@
1
- import path from "node:path";
2
-
3
- /**
4
- * @param {string} changeDir
5
- * @param {string} baseBranch
6
- * @param {string} changeBranch
7
- * @param {{
8
- * nowIsoUtc: () => string,
9
- * pathExists: (path: string) => Promise<boolean>,
10
- * readText: (path: string) => Promise<string>,
11
- * writeText: (path: string, content: string) => Promise<void>
12
- * }} deps
13
- */
14
- export async function maybeRecordBaseBranch(changeDir, baseBranch, changeBranch, deps) {
15
- const base = String(baseBranch || "").trim();
16
- if (!base) return;
17
- if (base === String(changeBranch || "").trim()) return;
18
- const metaPath = path.join(changeDir, ".ws-change.json");
19
- if (!(await deps.pathExists(metaPath))) return;
20
- /** @type {any} */
21
- let meta = null;
22
- try {
23
- meta = JSON.parse(await deps.readText(metaPath));
24
- } catch {
25
- meta = null;
26
- }
27
- if (!meta || typeof meta !== "object") return;
28
- const current = String(meta.base_branch || "").trim();
29
- if (current) return;
30
- meta.base_branch = base;
31
- meta.base_branch_set_at = deps.nowIsoUtc();
32
- await deps.writeText(metaPath, JSON.stringify(meta, null, 2) + "\n");
33
- }
34
-
35
- /**
36
- * @param {string} gitRoot
37
- * @param {{ branch: string, hasBranch: boolean, hasGitmodules: boolean }} options
38
- * @param {{
39
- * runCommand: typeof import("../exec.js").runCommand,
40
- * UserError: typeof import("../errors.js").UserError
41
- * }} deps
42
- */
43
- export async function switchOrCreateStartBranch(gitRoot, options, deps) {
44
- if (options.hasBranch) {
45
- if (options.hasGitmodules) {
46
- console.error("warn: .gitmodules detected; switching only the superproject branch (submodules stay on their current/pin branches).");
47
- }
48
- let sw = await deps.runCommand("git", ["switch", options.branch], { cwd: gitRoot });
49
- if (sw.code === 0) return;
50
-
51
- let co = await deps.runCommand("git", ["checkout", options.branch], { cwd: gitRoot });
52
- if (co.code !== 0) throw new deps.UserError("Failed to switch branch.", { details: co.stderr || co.stdout });
53
- return;
54
- }
55
-
56
- if (options.hasGitmodules) {
57
- console.error("warn: .gitmodules detected; creating and switching only the superproject branch (submodules stay on their current/pin branches).");
58
- }
59
- let sw = await deps.runCommand("git", ["switch", "-c", options.branch], { cwd: gitRoot });
60
- if (sw.code === 0) return;
61
-
62
- let co = await deps.runCommand("git", ["checkout", "-b", options.branch], { cwd: gitRoot });
63
- if (co.code !== 0) throw new deps.UserError("Failed to create branch.", { details: co.stderr || co.stdout });
64
- }
65
-
66
- /**
67
- * @param {string} gitRoot
68
- * @param {{ branch: string, hasBranch: boolean, headReady: boolean }} options
69
- * @param {{
70
- * runCommand: typeof import("../exec.js").runCommand,
71
- * UserError: typeof import("../errors.js").UserError
72
- * }} deps
73
- */
74
- export async function prepareNoSwitchBranch(gitRoot, options, deps) {
75
- if (options.hasBranch) return true;
76
- if (!options.headReady) {
77
- console.error(`warn: repo has no commits; cannot create branch "${options.branch}" without switching (skipped)`);
78
- return false;
79
- }
80
- const branchResult = await deps.runCommand("git", ["branch", options.branch], { cwd: gitRoot });
81
- if (branchResult.code !== 0) {
82
- throw new deps.UserError("Failed to create branch.", { details: branchResult.stderr || branchResult.stdout });
83
- }
84
- return true;
85
- }
@@ -1,40 +0,0 @@
1
- import path from "node:path";
2
-
3
- /**
4
- * @param {{
5
- * gitRoot: string,
6
- * changeId: string,
7
- * options: { write: boolean }
8
- * }} input
9
- * @param {{
10
- * appendMetricsEvent: (gitRoot: string, changeId: string, type: string, payload: any) => Promise<void>,
11
- * changeDirAbs: (gitRoot: string, changeId: string) => string,
12
- * computeChangeNextAdvice: (gitRoot: string, changeId: string) => Promise<any>,
13
- * computeChangeStatus: (gitRoot: string, changeId: string) => Promise<any>,
14
- * nowIsoUtc: () => string,
15
- * planVerifyHint: (changeId: string) => string,
16
- * renderChangeStateMarkdown: (input: any) => string,
17
- * writeText: (path: string, content: string) => Promise<void>
18
- * }} deps
19
- */
20
- export async function runChangeStateCommand(input, deps) {
21
- const { gitRoot, changeId, options } = input;
22
- const status = await deps.computeChangeStatus(gitRoot, changeId);
23
- const advice = await deps.computeChangeNextAdvice(gitRoot, changeId);
24
-
25
- const output = deps.renderChangeStateMarkdown({
26
- changeId,
27
- gitRoot,
28
- now: deps.nowIsoUtc(),
29
- status,
30
- advice,
31
- planVerifyLine: deps.planVerifyHint(changeId),
32
- });
33
- const dest = path.join(deps.changeDirAbs(gitRoot, changeId), "STATE.md");
34
- if (options.write === true) {
35
- await deps.writeText(dest, output);
36
- await deps.appendMetricsEvent(gitRoot, changeId, "state_written", { path: path.relative(gitRoot, dest) });
37
- return { output: `ok: state written: ${path.relative(gitRoot, dest)}\n` };
38
- }
39
- return { output };
40
- }
@@ -1,125 +0,0 @@
1
- /**
2
- * @param {{
3
- * gitRoot: string,
4
- * branch: string,
5
- * status: any
6
- * }} input
7
- * @param {{
8
- * effectiveReviewCount: (status: any) => number,
9
- * governanceGuidanceLines: (status: any) => Promise<string[]>,
10
- * planVerifyHint: (changeId: string) => string
11
- * }} deps
12
- */
13
- export async function renderChangeStatusOutput(input, deps) {
14
- const { gitRoot, branch, status } = input;
15
- /** @type {string[]} */
16
- const lines = [];
17
-
18
- lines.push(`✓ aiws change status: ${status.changeId}`);
19
- lines.push(`dir: ${status.dir}`);
20
- lines.push(`phase: ${status.phase}`);
21
- lines.push(`branch: ${branch || "(detached HEAD)"}`);
22
- lines.push(`meta: ${status.metaState}`);
23
- if (status.reqId) lines.push(`Req_ID: ${status.reqId}`);
24
- if (status.probId) lines.push(`Problem_ID: ${status.probId}`);
25
- lines.push(
26
- `tasks: ${status.tasks.done}/${status.tasks.total} (unchecked=${status.tasks.unchecked}, optional_open=${status.tasks.optionalUnchecked || 0}, n_a=${status.tasks.naCount || 0})`,
27
- );
28
- if (status.reviewSignals) {
29
- lines.push(`review_signal: effective=${status.reviewSignals.effectiveCount} source=${status.reviewSignals.source}`);
30
- }
31
- if (status.reviewGates?.summary) {
32
- const summary = status.reviewGates.summary;
33
- const missing = summary.finishGateMissingIds.length > 0 ? summary.finishGateMissingIds.join(", ") : "(none)";
34
- lines.push(
35
- `review_gates: generic_only=${summary.genericReviewOnly} dual_pending=${summary.dualReviewPending} dual_ready=${summary.dualReviewReady} finish_ready=${summary.finishGateReady} missing=${missing}`,
36
- );
37
- for (const gate of status.reviewGates.gates || []) {
38
- lines.push(`review_gate:${gate.id} ready=${gate.ready} status=${gate.status}${gate.foundPath ? ` path=${gate.foundPath}` : ""}`);
39
- }
40
- if (status.reviewGates.validateStamp) {
41
- const validateStamp = status.reviewGates.validateStamp;
42
- lines.push(
43
- `review_gate:${validateStamp.id} ready=${validateStamp.ready} status=${validateStamp.status}${validateStamp.foundPath ? ` path=${validateStamp.foundPath}` : ""}`,
44
- );
45
- }
46
- }
47
- if (status.scopeGate) {
48
- lines.push(
49
- `scope_gate: status=${status.scopeGate.status} ready=${status.scopeGate.ready} checked=${status.scopeGate.checked} errors=${status.scopeGate.errors} warnings=${status.scopeGate.warnings}${status.scopeGate.lastRunAt ? ` at=${status.scopeGate.lastRunAt}` : ""}`,
50
- );
51
- }
52
- if (status.git) {
53
- lines.push(
54
- `git: clean=${status.git.clean} staged=${status.git.staged} unstaged=${status.git.unstaged} untracked=${status.git.untracked} conflicted=${status.git.conflicted}`,
55
- );
56
- }
57
- if (status.governance) {
58
- lines.push(`governance: current=${status.governance.currentStage} next=${status.governance.recommendedStage}`);
59
- if (status.governance.rationale) lines.push(`governance_reason: ${status.governance.rationale}`);
60
- if (status.governance.ruleId) lines.push(`governance_rule: ${status.governance.ruleId}`);
61
- if (status.governance.source) lines.push(`governance_source: ${status.governance.source}`);
62
- }
63
- lines.push(`baseline: ${status.baselineLabel}${status.baselineAt ? ` (at=${status.baselineAt})` : ""}`);
64
- lines.push(`drift: ${status.driftFiles.length > 0 ? status.driftFiles.join(", ") : "(none)"}`);
65
- if (status.evidence?.counts) {
66
- const counts = status.evidence.counts;
67
- lines.push(`evidence: declared=${counts.total} (exists=${counts.exists}, missing=${counts.missing}, persistent=${counts.persistent}, tmp=${counts.tmp})`);
68
- }
69
- if (status.collaboration?.counts) {
70
- const counts = status.collaboration.counts;
71
- lines.push(`collaboration: analysis=${counts.analysis}, patches=${counts.patches}, review=${counts.review}, evidence_dir=${counts.evidence}`);
72
- }
73
-
74
- lines.push("");
75
- lines.push("Blockers (strict):");
76
- if (status.blockersStrict.length === 0) lines.push("- (none)");
77
- else for (const blocker of status.blockersStrict) lines.push(`- ${blocker}`);
78
-
79
- lines.push("");
80
- lines.push("Blockers (archive):");
81
- if (status.blockersArchive.length === 0) lines.push("- (none)");
82
- else for (const blocker of status.blockersArchive) lines.push(`- ${blocker}`);
83
-
84
- lines.push("");
85
- lines.push("Next (recommended):");
86
- if (status.terminatedReuse) {
87
- lines.push(`- ${status.terminatedReuse.message}`);
88
- lines.push(`- rerun \`aiws change finish ${status.changeId} --push\` to resume the unfinished finish/archive flow`);
89
- lines.push(`- do not continue development or commit on \`change/${status.changeId}\``);
90
- return lines.join("\n") + "\n";
91
- }
92
- lines.push(`- ${deps.planVerifyHint(status.changeId)}`);
93
- if (status.blockersStrict.length > 0) {
94
- lines.push("- 先修复 Blockers (strict) 后复跑质量门,再进入编码:simple/local 单点修复优先 `$ws-dev-lite`;否则 `$ws-dev`");
95
- return lines.join("\n") + "\n";
96
- }
97
-
98
- if (status.tasks.unchecked > 0) {
99
- lines.push("- 继续开发:simple/local 单点修复优先 `$ws-dev-lite`;否则 `$ws-dev`(小步实现 + 可复现验证)");
100
- if ((status.collaboration?.counts?.analysis || 0) > 0) lines.push("- 已有委托分析:在编码前先收敛 `changes/<id>/analysis/` 中的结论");
101
- if ((status.collaboration?.counts?.patches || 0) > 0) lines.push("- 已有 patch 草案:应用前先人工审查 `changes/<id>/patches/`");
102
- lines.push("- 提交/交付前强制门禁:`aiws validate .`(可选落盘:`aiws validate . --stamp`)");
103
- lines.push(`- (可选)状态快照:\`aiws change state ${status.changeId} --write\``);
104
- return lines.join("\n") + "\n";
105
- }
106
-
107
- if (status.evidence?.counts && status.evidence.counts.persistent === 0) {
108
- lines.push("- 交付前建议生成持久证据:`changes/<id>/evidence/...`(并把路径回填到 proposal.md 的 Evidence_Path)");
109
- }
110
- if (status.evidence?.missing && status.evidence.missing.length > 0) {
111
- const show = status.evidence.missing.slice(0, 5);
112
- lines.push(`- 交付前建议补齐缺失证据文件(missing=${status.evidence.missing.length}):${show.join(", ")}${status.evidence.missing.length > show.length ? ", ..." : ""}`);
113
- }
114
- if ((status.collaboration?.counts?.patches || 0) > 0) {
115
- lines.push("- 存在委托 patch 草案:交付前确认其已被人工审查,并在 review/handoff 中记录结论");
116
- }
117
- if ((status.collaboration?.counts?.analysis || 0) > 0 && deps.effectiveReviewCount(status) === 0) {
118
- lines.push("- 存在委托分析但尚无 review 汇总:建议先在 `changes/<id>/review/` 形成结论后再交付");
119
- }
120
- lines.push(`- (可选)状态快照:\`aiws change state ${status.changeId} --write\``);
121
- for (const line of await deps.governanceGuidanceLines(status)) lines.push(`- ${line}`);
122
- if (status.governance?.rationale) lines.push(`- 阶段判定:${status.governance.rationale}`);
123
- if (status.governance?.warning) lines.push(`- 注意:${status.governance.warning}`);
124
- return lines.join("\n") + "\n";
125
- }