@aipper/aiws 0.0.29 → 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 (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,74 +0,0 @@
1
- import os from "node:os";
2
- import path from "node:path";
3
- import { listFilesRecursive, readText } from "./fs.js";
4
- import { normalizeNewlines } from "./hash.js";
5
- import { extractTemplateBlock } from "./managed-blocks.js";
6
- import { UserError } from "./errors.js";
7
-
8
- /**
9
- * Resolve Codex global prompts directory:
10
- * - If `--dir` provided, use it directly.
11
- * - Else if `CODEX_HOME` is set, use `$CODEX_HOME/prompts`.
12
- * - Else use `~/.codex/prompts`.
13
- *
14
- * @param {string | undefined} dirOption
15
- */
16
- export function resolveCodexPromptsDir(dirOption) {
17
- if (dirOption) return path.resolve(dirOption);
18
- const envHome = String(process.env.CODEX_HOME || "").trim();
19
- if (envHome) return path.join(path.resolve(envHome), "prompts");
20
- return path.join(os.homedir(), ".codex", "prompts");
21
- }
22
-
23
- function timestamp() {
24
- const d = new Date();
25
- // 2026-01-28T12:34:56Z -> 20260128-123456Z
26
- return d.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z").replace("T", "-");
27
- }
28
-
29
- export function codexBackupStamp() {
30
- return timestamp();
31
- }
32
-
33
- /**
34
- * @param {string} promptsDir
35
- * @param {string} filename
36
- * @param {string=} stamp
37
- */
38
- export function codexBackupPathFor(promptsDir, filename, stamp) {
39
- return path.join(promptsDir, ".aiws", "backups", "codex-prompts", stamp || timestamp(), filename);
40
- }
41
-
42
- /**
43
- * List Codex prompt files in a template and extract their managed block inner text.
44
- *
45
- * @param {{ templateId: string, templateDir: string }} tpl
46
- * @returns {Promise<Array<{ rel: string, filename: string, name: string, blockId: string, srcAbs: string, templateText: string, innerText: string }>>}
47
- */
48
- export async function listTemplateCodexPrompts(tpl) {
49
- const relFiles = await listFilesRecursive(tpl.templateDir, ".codex/prompts");
50
- const promptFiles = relFiles
51
- .filter((rel) => rel.startsWith(".codex/prompts/"))
52
- .filter((rel) => rel.split("/").length === 3)
53
- .filter((rel) => rel.toLowerCase().endsWith(".md"));
54
-
55
- if (promptFiles.length === 0) {
56
- throw new UserError(`Template has no Codex prompt files: ${tpl.templateId}`, {
57
- details: `Missing under: ${path.join(tpl.templateDir, ".codex", "prompts")}`,
58
- exitCode: 1,
59
- });
60
- }
61
-
62
- /** @type {Array<{ rel: string, filename: string, name: string, blockId: string, srcAbs: string, templateText: string, innerText: string }>} */
63
- const out = [];
64
- for (const rel of promptFiles) {
65
- const filename = path.posix.basename(rel);
66
- const name = filename.replace(/\.md$/i, "");
67
- const blockId = `codex:${name}`;
68
- const srcAbs = path.join(tpl.templateDir, ...rel.split("/"));
69
- const templateText = normalizeNewlines(await readText(srcAbs));
70
- const { innerText } = extractTemplateBlock(templateText, blockId);
71
- out.push({ rel, filename, name, blockId, srcAbs, templateText, innerText });
72
- }
73
- return out;
74
- }
@@ -1,111 +0,0 @@
1
- import os from "node:os";
2
- import path from "node:path";
3
- import { listFilesRecursive, readText } from "./fs.js";
4
- import { normalizeNewlines } from "./hash.js";
5
- import { UserError } from "./errors.js";
6
-
7
- /**
8
- * Resolve Codex global skills directory:
9
- * - If `--dir` provided, use it directly.
10
- * - Else if `CODEX_HOME` is set, use `$CODEX_HOME/.agents/skills` as a compatibility/test override root.
11
- * - Else use `~/.agents/skills`.
12
- *
13
- * @param {string | undefined} dirOption
14
- */
15
- export function resolveCodexSkillsDir(dirOption) {
16
- if (dirOption) return path.resolve(dirOption);
17
- const envHome = String(process.env.CODEX_HOME || "").trim();
18
- if (envHome) return path.join(path.resolve(envHome), ".agents", "skills");
19
- return path.join(os.homedir(), ".agents", "skills");
20
- }
21
-
22
- function timestamp() {
23
- const d = new Date();
24
- // 2026-01-28T12:34:56Z -> 20260128-123456Z
25
- return d.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z").replace("T", "-");
26
- }
27
-
28
- export function codexSkillsBackupStamp() {
29
- return timestamp();
30
- }
31
-
32
- /**
33
- * @param {string} skillsDir
34
- * @param {string} skillName
35
- * @param {string=} stamp
36
- */
37
- export function codexSkillsBackupPathFor(skillsDir, skillName, stamp) {
38
- return path.join(skillsDir, ".aiws", "backups", "codex-skills", stamp || timestamp(), skillName, "SKILL.md");
39
- }
40
-
41
- /**
42
- * @param {string} text normalized
43
- * @returns {{ frontMatter: string, body: string }}
44
- */
45
- function splitYamlFrontMatter(text) {
46
- const t = normalizeNewlines(text);
47
- const lines = t.split("\n");
48
- if ((lines[0] ?? "") !== "---") {
49
- throw new UserError("Invalid SKILL.md: missing YAML front matter at top", { exitCode: 1 });
50
- }
51
- let end = -1;
52
- for (let i = 1; i < lines.length; i++) {
53
- if ((lines[i] ?? "") === "---") {
54
- end = i;
55
- break;
56
- }
57
- }
58
- if (end === -1) {
59
- throw new UserError("Invalid SKILL.md: YAML front matter not closed", { exitCode: 1 });
60
- }
61
-
62
- const frontMatter = `${lines.slice(0, end + 1).join("\n")}\n`;
63
- const body = lines.slice(end + 1).join("\n");
64
- return { frontMatter, body };
65
- }
66
-
67
- /**
68
- * List Codex repo skills in a template and prepare a managed-file wrapper for global installation.
69
- *
70
- * The wrapper adds an AIWS managed block after YAML front matter so updates can preserve user-added
71
- * text outside the managed block.
72
- *
73
- * @param {{ templateId: string, templateDir: string }} tpl
74
- * @returns {Promise<Array<{ rel: string, skillName: string, blockId: string, srcAbs: string, templateText: string, managedText: string, innerText: string }>>}
75
- */
76
- export async function listTemplateCodexSkills(tpl) {
77
- const relFiles = await listFilesRecursive(tpl.templateDir, ".agents/skills");
78
- const skillFiles = relFiles
79
- .filter((rel) => rel.startsWith(".agents/skills/"))
80
- .filter((rel) => rel.split("/").length === 4)
81
- .filter((rel) => rel.toLowerCase().endsWith("/skill.md"));
82
-
83
- if (skillFiles.length === 0) {
84
- throw new UserError(`Template has no Codex skills: ${tpl.templateId}`, {
85
- details: `Missing under: ${path.join(tpl.templateDir, ".agents", "skills")}`,
86
- exitCode: 1,
87
- });
88
- }
89
-
90
- /** @type {Array<{ rel: string, skillName: string, blockId: string, srcAbs: string, templateText: string, managedText: string, innerText: string }>} */
91
- const out = [];
92
- for (const rel of skillFiles) {
93
- const parts = rel.split("/");
94
- const skillName = parts[2] ?? "";
95
- if (!skillName) continue;
96
- const blockId = `codex-skill:${skillName}`;
97
- const srcAbs = path.join(tpl.templateDir, ...rel.split("/"));
98
- const templateText = normalizeNewlines(await readText(srcAbs));
99
- const { frontMatter, body } = splitYamlFrontMatter(templateText);
100
-
101
- const innerTextRaw = normalizeNewlines(body);
102
- const innerText = innerTextRaw.endsWith("\n") ? innerTextRaw : `${innerTextRaw}\n`;
103
-
104
- const begin = `<!-- AIWS_MANAGED_BEGIN:${blockId} -->`;
105
- const end = `<!-- AIWS_MANAGED_END:${blockId} -->`;
106
- const managedText = `${frontMatter}\n${begin}\n${innerText}${end}\n`;
107
-
108
- out.push({ rel, skillName, blockId, srcAbs, templateText, managedText, innerText });
109
- }
110
- return out;
111
- }
@@ -1,181 +0,0 @@
1
- /**
2
- * @param {string} gitRoot
3
- * @param {string} changeId
4
- * @param {{
5
- * computeChangeStatus: (gitRoot: string, changeId: string) => Promise<any>,
6
- * currentBranch: (gitRoot: string) => Promise<string>,
7
- * inferChangeIdFromBranch: (branch: string) => string,
8
- * changeDirAbs: (gitRoot: string, changeId: string) => string,
9
- * governanceGuidanceLines: (status: any) => Promise<string[]>,
10
- * scopeGateFailureAction: (changeId: string) => string,
11
- * scopeGatePendingRecommendation: (changeId: string) => string,
12
- * scopeGatePassedRecommendation: () => string
13
- * }} deps
14
- */
15
- export async function computeChangeNextAdvice(gitRoot, changeId, deps) {
16
- const status = await deps.computeChangeStatus(gitRoot, changeId);
17
- const branch = await deps.currentBranch(gitRoot);
18
- const inferred = deps.inferChangeIdFromBranch(branch);
19
- const advice = {
20
- changeId,
21
- branch: branch || "",
22
- inferredChangeId: inferred || "",
23
- phase: status.phase,
24
- governance: status.governance || null,
25
- scopeGate: status.scopeGate || null,
26
- blockersStrict: status.blockersStrict,
27
- evidence: status.evidence?.counts || null,
28
- collaboration: status.collaboration?.counts || null,
29
- actions: [],
30
- prohibitions: [],
31
- recommended: [],
32
- };
33
-
34
- if (!branch) {
35
- advice.actions.push("当前为 detached HEAD:建议切到 `change/<change-id>` 分支后再继续(或显式传入 `<change-id>`)");
36
- } else if (inferred && inferred !== changeId) {
37
- advice.actions.push(`当前分支为 \`${branch}\`(推断 change=${inferred}),但你在查看 change=${changeId}:建议先切换到 \`change/${changeId}\` 再执行开发/交付`);
38
- } else if (!inferred) {
39
- advice.actions.push(`当前分支为 \`${branch}\`(非 change 分支):建议 \`aiws change start ${changeId} --hooks --switch\` 或 \`git switch change/${changeId}\``);
40
- }
41
-
42
- if (status.metaState !== "ok") advice.actions.push(`补齐元信息并建立真值基线:\`aiws change sync ${changeId}\``);
43
- if (status.driftFiles.length > 0) {
44
- advice.actions.push("真值/合同已变化:先对齐 `AI_PROJECT.md` / `AI_WORKSPACE.md` / `REQUIREMENTS.md` 与 proposal/tasks");
45
- advice.actions.push(`确认后同步基线:\`aiws change sync ${changeId}\``);
46
- }
47
- if (status.terminatedReuse) {
48
- advice.actions.push(status.terminatedReuse.message);
49
- advice.prohibitions.push(`不要继续在 change/${changeId} 上开发或提交新改动`);
50
- advice.recommended.push(`优先续跑收尾:\`aiws change finish ${changeId} --push\``);
51
- advice.recommended.push(`仅在你明确只需要本地归档恢复时,才手工运行 \`aiws change archive ${changeId}\``);
52
- return advice;
53
- }
54
-
55
- const proposalPath = path.join(deps.changeDirAbs(gitRoot, changeId), "proposal.md");
56
- const tasksPath = path.join(deps.changeDirAbs(gitRoot, changeId), "tasks.md");
57
- if (status.blockersStrict.some((item) => item.includes("proposal.md") && item.includes("WS:TODO"))) {
58
- advice.actions.push(`完善 proposal:\`$EDITOR ${proposalPath}\``);
59
- }
60
- if (status.blockersStrict.some((item) => item.includes("tasks.md") && item.includes("WS:TODO"))) {
61
- advice.actions.push(`完善 tasks:\`$EDITOR ${tasksPath}\``);
62
- }
63
- if (status.blockersStrict.some((item) => item.includes("proposal.md missing attribution"))) {
64
- advice.actions.push("补齐归因:在 proposal.md 填写非空 `Req_ID` 或 `Problem_ID`(严格校验需要)");
65
- }
66
- if (status.blockersStrict.some((item) => item.includes("missing Contract_Row"))) {
67
- advice.actions.push("补齐绑定:在 proposal.md 填写非空 `Contract_Row`(严格校验需要)");
68
- }
69
- if (status.blockersStrict.some((item) => item.includes("Plan_File"))) {
70
- advice.actions.push("补齐绑定:修正 proposal.md 的 `Plan_File`(严格校验需要;必须存在且仅 1 个)");
71
- }
72
- if (status.blockersStrict.some((item) => item.includes("missing Evidence_Path"))) {
73
- advice.actions.push("补齐绑定:在 proposal.md 填写非空 `Evidence_Path`(严格校验需要;建议优先写 `changes/<id>/evidence/...`)");
74
- }
75
- if (status.scopeGate?.status === "failed") {
76
- advice.actions.push(deps.scopeGateFailureAction(changeId));
77
- }
78
- if (status.tasks.unchecked > 0) advice.actions.push(`完成未勾选任务(${status.tasks.unchecked} 项)`);
79
- if (status.blockersStrict.length === 0 && status.tasks.unchecked > 0) {
80
- advice.actions.push("质量门通过后继续开发:simple/local 单点修复优先 `$ws-dev-lite`;否则 `$ws-dev`");
81
- }
82
- if (
83
- status.blockersStrict.length === 0 &&
84
- status.tasks.unchecked === 0 &&
85
- Number(status?.reviewSignals?.effectiveCount || 0) > 0 &&
86
- Number(status?.reviewGates?.summary?.dualReviewMissingCount || 0) > 0
87
- ) {
88
- advice.actions.push("已有通用 review,但 dual review gate 未完成:继续补齐 `$ws-spec-review` / `$ws-quality-review`,不要把 `codex-review.md` 当成 finish gate");
89
- }
90
- if ((status.collaboration?.counts?.analysis || 0) > 0 && (status.collaboration?.counts?.review || 0) === 0) {
91
- advice.actions.push("已有委托分析但还没有 review 汇总结论:建议在 `changes/<id>/review/` 落盘结论后再交付");
92
- }
93
- if ((status.collaboration?.counts?.patches || 0) > 0) {
94
- advice.actions.push("存在委托 patch 草案:提交/交付前先人工审查 `changes/<id>/patches/`,不要直接无审查应用");
95
- }
96
-
97
- if (status.blockersStrict.length > 0 && advice.actions.length === 0) {
98
- advice.actions.push("先修复 Blockers (strict) 后复跑质量门,再进入编码:simple/local 单点修复优先 `$ws-dev-lite`;否则 `$ws-dev`");
99
- }
100
-
101
- if (status.blockersStrict.length === 0 && status.tasks.unchecked === 0) {
102
- for (const line of await deps.governanceGuidanceLines(status)) advice.recommended.push(line);
103
- if (advice.evidence && advice.evidence.persistent === 0) {
104
- advice.recommended.push("交付前建议生成持久证据并回填:`aiws change evidence <change-id>`");
105
- }
106
- if (status.scopeGate?.status === "not_run") {
107
- advice.recommended.push(deps.scopeGatePendingRecommendation(changeId));
108
- } else if (status.scopeGate?.status === "passed") {
109
- advice.recommended.push(deps.scopeGatePassedRecommendation());
110
- }
111
- if ((status.governance?.recommendedStage || "") === "ws-finish" || (status.governance?.currentStage || "") === "ws-commit") {
112
- advice.recommended.push("交付前门禁(推荐落盘):`aiws validate . --stamp`");
113
- }
114
- if ((status.collaboration?.counts?.review || 0) > 1) advice.recommended.push("存在多份 review:交付前建议在 handoff 或 review 汇总里收敛最终结论");
115
- } else if (advice.actions.length === 0) {
116
- advice.recommended.push("继续开发:simple/local 单点修复优先 `$ws-dev-lite`;否则 `$ws-dev`(小步实现 + 可复现验证)");
117
- if ((status.collaboration?.counts?.analysis || 0) > 0) advice.recommended.push("已有委托分析:进入实现前先收敛 `changes/<id>/analysis/` 结论");
118
- if ((status.collaboration?.counts?.patches || 0) > 0) advice.recommended.push("已有 patch 草案:应用前先人工审查 `changes/<id>/patches/`");
119
- }
120
-
121
- return advice;
122
- }
123
-
124
- /**
125
- * @param {{
126
- * changeId: string,
127
- * gitRoot: string,
128
- * now: string,
129
- * status: any,
130
- * advice: any,
131
- * planVerifyLine: string
132
- * }} input
133
- */
134
- export function renderChangeStateMarkdown(input) {
135
- /** @type {string[]} */
136
- const lines = [];
137
- lines.push(`# AIWS STATE: ${input.changeId}`);
138
- lines.push("");
139
- lines.push(`Generated: ${input.now}`);
140
- lines.push("");
141
- lines.push("## Context");
142
- lines.push(`- Worktree: \`${input.gitRoot}\``);
143
- lines.push(`- Branch: \`${input.advice.branch || "(detached)"}\``);
144
- lines.push("");
145
- lines.push("## Phase");
146
- lines.push(`- Phase: \`${input.status.phase}\``);
147
- lines.push(
148
- `- Tasks: ${input.status.tasks.done}/${input.status.tasks.total} (unchecked=${input.status.tasks.unchecked}, optional_open=${input.status.tasks.optionalUnchecked || 0}, n_a=${input.status.tasks.naCount || 0})`,
149
- );
150
- lines.push("");
151
- lines.push("## Bindings");
152
- if (input.status.reqId) lines.push(`- Req_ID: \`${input.status.reqId}\``);
153
- if (input.status.probId) lines.push(`- Problem_ID: \`${input.status.probId}\``);
154
- if (input.status.bindings?.contractRow) lines.push(`- Contract_Row: \`${input.status.bindings.contractRow}\``);
155
- if (input.status.bindings?.planFile) lines.push(`- Plan_File: \`${input.status.bindings.planFile}\``);
156
- lines.push("");
157
- lines.push("## Evidence");
158
- if (input.status.evidence?.counts) {
159
- const counts = input.status.evidence.counts;
160
- lines.push(
161
- `- Declared: \`${counts.total}\` (exists=\`${counts.exists}\`, missing=\`${counts.missing}\`, persistent=\`${counts.persistent}\`, tmp=\`${counts.tmp}\`)`,
162
- );
163
- } else {
164
- lines.push("- (unknown)");
165
- }
166
- lines.push("");
167
- lines.push("## Blockers (strict)");
168
- if (input.status.blockersStrict.length === 0) lines.push("- (none)");
169
- else for (const blocker of input.status.blockersStrict) lines.push(`- ${blocker}`);
170
- lines.push("");
171
- lines.push("## Next");
172
- lines.push(`- ${input.planVerifyLine}`);
173
- for (const action of input.advice.actions) lines.push(`- ${action}`);
174
- for (const recommendation of input.advice.recommended) lines.push(`- ${recommendation}`);
175
- if (input.advice.prohibitions.length > 0) {
176
- lines.push("");
177
- lines.push("## Do Not");
178
- for (const prohibition of input.advice.prohibitions) lines.push(`- ${prohibition}`);
179
- }
180
- return lines.join("\n") + "\n";
181
- }
@@ -1,242 +0,0 @@
1
- import path from "node:path";
2
- import fs from "node:fs/promises";
3
- import {
4
- buildDeliverySummary,
5
- collectCollaborationArtifacts,
6
- findLatestFileByMtime,
7
- formatDeclaredValues,
8
- mergeDeclaredValues,
9
- relFromRoot,
10
- upsertIdLine,
11
- upsertProposalEvidencePath,
12
- } from "./change-evidence.js";
13
- import { TMP_REVIEW_FALLBACKS, tmpReviewFallbackPath } from "./change-review-gates.js";
14
-
15
- /**
16
- * @param {{
17
- * gitRoot: string,
18
- * changeId: string,
19
- * changeDir: string,
20
- * proposalText: string,
21
- * options: { noValidate: boolean, allowFail: boolean }
22
- * }} input
23
- * @param {{
24
- * appendMetricsEvent: (gitRoot: string, changeId: string, type: string, payload: any) => Promise<void>,
25
- * computeChangeStatus: (gitRoot: string, changeId: string) => Promise<any>,
26
- * currentBranch: (gitRoot: string) => Promise<string>,
27
- * ensureDir: (path: string) => Promise<void>,
28
- * extractId: (label: string, text: string) => string,
29
- * nowIsoUtc: () => string,
30
- * nowStampUtc: () => string,
31
- * pathExists: (path: string) => Promise<boolean>,
32
- * planVerifyHint: (changeId: string) => string,
33
- * readText: (path: string) => Promise<string>,
34
- * splitDeclaredValues: (s: string) => string[],
35
- * validateChangeArtifacts: (gitRoot: string, changeId: string, options: any) => Promise<any>,
36
- * writeText: (path: string, content: string) => Promise<void>,
37
- * UserError: typeof import("../errors.js").UserError
38
- * }} deps
39
- */
40
- export async function runChangeEvidenceWorkflow(input, deps) {
41
- const { gitRoot, changeId, changeDir, proposalText, options } = input;
42
- const planDecl = deps.extractId("Plan_File", proposalText) || deps.extractId("Plan file", proposalText);
43
- const planFiles = deps.splitDeclaredValues(planDecl).map((item) => String(item || "").replace(/^\.\//, ""));
44
- const planRel = planFiles.length === 1 ? planFiles[0] : "";
45
- const planAbs = planRel ? path.join(gitRoot, planRel) : "";
46
- const planText = planAbs && (await deps.pathExists(planAbs)) ? await deps.readText(planAbs) : "";
47
-
48
- const now = deps.nowStampUtc();
49
- const evidenceDir = path.join(changeDir, "evidence");
50
- const reviewDir = path.join(changeDir, "review");
51
- const analysisDir = path.join(changeDir, "analysis");
52
- const patchesDir = path.join(changeDir, "patches");
53
- await deps.ensureDir(evidenceDir);
54
- await deps.ensureDir(reviewDir);
55
- await deps.ensureDir(analysisDir);
56
- await deps.ensureDir(patchesDir);
57
-
58
- /** @type {string[]} */
59
- const created = [];
60
- const branch = await deps.currentBranch(gitRoot);
61
- const status = await deps.computeChangeStatus(gitRoot, changeId);
62
-
63
- const statusPath = path.join(evidenceDir, `change-status-${now}.json`);
64
- await deps.writeText(
65
- statusPath,
66
- JSON.stringify(
67
- {
68
- generated_at: deps.nowIsoUtc(),
69
- ws_root: gitRoot,
70
- change_id: changeId,
71
- branch: branch || "",
72
- phase: status.phase,
73
- tasks: status.tasks,
74
- bindings: status.bindings,
75
- truth: {
76
- baseline: { label: status.baselineLabel, at: status.baselineAt },
77
- drift_files: status.driftFiles,
78
- },
79
- evidence: status.evidence?.counts || null,
80
- collaboration: status.collaboration?.counts || null,
81
- note: "aiws change evidence status snapshot; does not contain secrets.",
82
- },
83
- null,
84
- 2,
85
- ) + "\n",
86
- );
87
- created.push(relFromRoot(gitRoot, statusPath));
88
-
89
- /** @type {any | null} */
90
- let validateRes = null;
91
- let validateFailed = false;
92
- let validatePathForError = "";
93
- if (!options.noValidate) {
94
- validateRes = await deps.validateChangeArtifacts(gitRoot, changeId, { strict: true, allowTruthDrift: false });
95
- const validatePath = path.join(evidenceDir, `change-validate-strict-${now}.json`);
96
- await deps.writeText(validatePath, JSON.stringify(validateRes, null, 2) + "\n");
97
- created.push(relFromRoot(gitRoot, validatePath));
98
- validateFailed = validateRes.ok !== true;
99
- validatePathForError = validatePath;
100
- }
101
-
102
- const validateStampDir = path.join(gitRoot, ".agentdocs", "tmp", "aiws-validate");
103
- const latestValidateStamp = await findLatestFileByMtime(validateStampDir, (name) => name.endsWith(".json"));
104
- if (latestValidateStamp) {
105
- const dest = path.join(evidenceDir, `aiws-validate-stamp-${now}.json`);
106
- await fs.copyFile(latestValidateStamp, dest);
107
- created.push(relFromRoot(gitRoot, dest));
108
- }
109
-
110
- const syncStampDir = path.join(gitRoot, ".agentdocs", "tmp", "change-sync");
111
- const latestSyncStamp = await findLatestFileByMtime(syncStampDir, (name) => name.endsWith(`-${changeId}.json`));
112
- if (latestSyncStamp) {
113
- const dest = path.join(evidenceDir, `change-sync-stamp-${now}.json`);
114
- await fs.copyFile(latestSyncStamp, dest);
115
- created.push(relFromRoot(gitRoot, dest));
116
- }
117
-
118
- for (const { fileName, persistentKind } of TMP_REVIEW_FALLBACKS) {
119
- const src = tmpReviewFallbackPath(gitRoot, fileName);
120
- if (!(await deps.pathExists(src))) continue;
121
- const dest = persistentKind === "evidence" ? path.join(evidenceDir, fileName) : path.join(reviewDir, fileName);
122
- if (!(await deps.pathExists(dest))) {
123
- await fs.copyFile(src, dest);
124
- }
125
- const rel = relFromRoot(gitRoot, dest);
126
- if (!created.includes(rel)) created.push(rel);
127
- }
128
-
129
- if (await deps.pathExists(reviewDir)) {
130
- try {
131
- const reviewEntries = await fs.readdir(reviewDir, { withFileTypes: true });
132
- for (const entry of reviewEntries) {
133
- if (!entry.isFile()) continue;
134
- if (entry.name === "codex-review.md") continue;
135
- if (!entry.name.endsWith(".md")) continue;
136
- const rel = relFromRoot(gitRoot, path.join(reviewDir, entry.name));
137
- if (!created.includes(rel)) created.push(rel);
138
- }
139
- } catch {
140
- // ignore
141
- }
142
- }
143
-
144
- const collaboration = await collectCollaborationArtifacts(gitRoot, changeDir);
145
- const collaborationPath = path.join(evidenceDir, `collaboration-summary-${now}.json`);
146
- await deps.writeText(
147
- collaborationPath,
148
- JSON.stringify(
149
- {
150
- generated_at: deps.nowIsoUtc(),
151
- ws_root: gitRoot,
152
- change_id: changeId,
153
- counts: collaboration.counts,
154
- dirs: collaboration.dirs,
155
- note: "aiws collaboration summary; patch files are drafts and must be reviewed before apply.",
156
- },
157
- null,
158
- 2,
159
- ) + "\n",
160
- );
161
- created.push(relFromRoot(gitRoot, collaborationPath));
162
-
163
- const summaryAbs = path.join(evidenceDir, `delivery-summary-${now}.md`);
164
- await deps.writeText(
165
- summaryAbs,
166
- buildDeliverySummary({
167
- gitRoot,
168
- changeId,
169
- branch: branch || "",
170
- status,
171
- collaboration,
172
- created,
173
- validateRes,
174
- validateFailed,
175
- }),
176
- );
177
- created.push(relFromRoot(gitRoot, summaryAbs));
178
-
179
- const declaredEvidence = deps.extractId("Evidence_Path", proposalText) || deps.extractId("Evidence_Path(s)", proposalText);
180
- const existingProposalEvidence = deps.splitDeclaredValues(declaredEvidence).map((item) => String(item || "").replace(/^\.\//, ""));
181
- const mergedEvidence = mergeDeclaredValues(existingProposalEvidence, created);
182
- const mergedEvidenceText = formatDeclaredValues(mergedEvidence);
183
-
184
- const updatedProposal = upsertProposalEvidencePath(proposalText, mergedEvidenceText);
185
- if (updatedProposal.changed) {
186
- await deps.writeText(path.join(changeDir, "proposal.md"), updatedProposal.text);
187
- }
188
-
189
- let planUpdated = false;
190
- if (planAbs && planText) {
191
- const existingPlanEvidence = deps
192
- .splitDeclaredValues(deps.extractId("Evidence_Path", planText) || deps.extractId("Evidence_Path(s)", planText))
193
- .map((item) => String(item || "").replace(/^\.\//, ""));
194
- const mergedPlanEvidence = mergeDeclaredValues(existingPlanEvidence, mergedEvidence);
195
- const mergedPlanEvidenceText = formatDeclaredValues(mergedPlanEvidence);
196
- const updatedPlan = upsertIdLine(planText, ["Evidence_Path", "Evidence_Path(s)"], mergedPlanEvidenceText, { insertAfterLabels: ["Plan_File", "Contract_Row"] });
197
- if (updatedPlan.changed) {
198
- await deps.writeText(planAbs, updatedPlan.text);
199
- planUpdated = true;
200
- }
201
- }
202
-
203
- await deps.appendMetricsEvent(gitRoot, changeId, "evidence", {
204
- generated_at: deps.nowIsoUtc(),
205
- created: created.length,
206
- strict_validate: options.noValidate ? "skipped" : validateRes && validateRes.ok === true ? "ok" : "failed",
207
- allow_fail: options.allowFail === true,
208
- });
209
-
210
- /** @type {string[]} */
211
- const outputLines = [];
212
- outputLines.push(`✓ aiws change evidence: ${changeId}`);
213
- outputLines.push(`dir: ${path.relative(gitRoot, changeDir)}`);
214
- if (planRel) outputLines.push(`Plan_File: ${planRel}`);
215
- outputLines.push("created:");
216
- if (created.length > 0) {
217
- for (const item of created) outputLines.push(`- ${item}`);
218
- } else {
219
- outputLines.push("- (none)");
220
- }
221
- outputLines.push("updated:");
222
- outputLines.push(`- ${path.relative(gitRoot, path.join(changeDir, "proposal.md"))} (Evidence_Path)`);
223
- if (planRel && planText && planUpdated) outputLines.push(`- ${planRel} (Evidence_Path)`);
224
- else if (planRel && planText) outputLines.push(`- ${planRel} (Evidence_Path)`);
225
- outputLines.push("");
226
- outputLines.push("next:");
227
- outputLines.push(`- ${deps.planVerifyHint(changeId)}`);
228
- if (validateFailed) outputLines.push("- fix validation errors, then re-run evidence (or run with --allow-fail to proceed)");
229
- else outputLines.push(`- verify evidence gate: \`aiws change validate ${changeId} --strict --check-evidence\``);
230
-
231
- let errorToThrow = null;
232
- if (validateFailed && !options.allowFail) {
233
- const details = (validateRes && validateRes.raw ? String(validateRes.raw) : "").trim() || "Validation failed (see evidence JSON for details).";
234
- const hint = validatePathForError ? `\n\nevidence:\n- ${path.relative(gitRoot, validatePathForError)}` : "";
235
- errorToThrow = new deps.UserError("Failed to generate evidence due to strict validation errors.", { details: `${details}${hint}` });
236
- }
237
-
238
- return {
239
- output: outputLines.join("\n") + "\n",
240
- errorToThrow,
241
- };
242
- }
@@ -1,40 +0,0 @@
1
- import path from "node:path";
2
-
3
- /**
4
- * @param {{
5
- * gitRoot: string,
6
- * changeId: string,
7
- * options: { noValidate: boolean, allowFail: boolean }
8
- * }} input
9
- * @param {{
10
- * changeDirAbs: (gitRoot: string, changeId: string) => string,
11
- * fileState: (changeDir: string, rel: string) => Promise<any>,
12
- * pathExists: (path: string) => Promise<boolean>,
13
- * runChangeEvidenceWorkflow: (input: any, deps: any) => Promise<{ output: string, errorToThrow: any }>,
14
- * workflowDeps: Record<string, any>,
15
- * UserError: typeof import("../errors.js").UserError
16
- * }} deps
17
- */
18
- export async function runChangeEvidenceCommand(input, deps) {
19
- const { gitRoot, changeId, options } = input;
20
- const changeDir = deps.changeDirAbs(gitRoot, changeId);
21
- if (!(await deps.pathExists(changeDir))) {
22
- throw new deps.UserError(`Missing change dir: ${path.relative(gitRoot, changeDir)}`);
23
- }
24
-
25
- const proposal = await deps.fileState(changeDir, "proposal.md");
26
- if (proposal.state !== "ok") {
27
- throw new deps.UserError("proposal.md is required for evidence generation.", { details: path.relative(gitRoot, proposal.abs) });
28
- }
29
-
30
- return deps.runChangeEvidenceWorkflow(
31
- {
32
- gitRoot,
33
- changeId,
34
- changeDir,
35
- proposalText: proposal.text,
36
- options,
37
- },
38
- deps.workflowDeps,
39
- );
40
- }