@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,95 +0,0 @@
1
- import path from "node:path";
2
- import fs from "node:fs/promises";
3
- import { resolveWorkspaceRoot } from "../workspace.js";
4
- import { runCommand } from "../exec.js";
5
- import { pathExists } from "../fs.js";
6
- import { UserError } from "../errors.js";
7
-
8
- /**
9
- * @param {string} absPath
10
- */
11
- async function resolveGitRoot(absPath) {
12
- let res;
13
- try {
14
- res = await runCommand("git", ["rev-parse", "--show-toplevel"], { cwd: absPath });
15
- } catch (e) {
16
- throw new UserError("git is required for hooks commands.", { details: e instanceof Error ? e.message : String(e) });
17
- }
18
- if (res.code !== 0) {
19
- throw new UserError("Not a git repository.", { details: res.stderr || res.stdout });
20
- }
21
- const root = String(res.stdout || "").trim();
22
- if (!root) throw new UserError("Failed to resolve git repository root.");
23
- return root;
24
- }
25
-
26
- /**
27
- * @param {string} gitRoot
28
- * @param {string} key
29
- */
30
- async function readGitConfig(gitRoot, key) {
31
- const res = await runCommand("git", ["config", "--get", key], { cwd: gitRoot });
32
- if (res.code !== 0) return "";
33
- return String(res.stdout || "").trim();
34
- }
35
-
36
- /**
37
- * @param {fs.Stats} st
38
- */
39
- function isExecutable(st) {
40
- return (st.mode & 0o111) !== 0;
41
- }
42
-
43
- /**
44
- * @param {{ targetPath: string }} options
45
- */
46
- export async function hooksStatusCommand(options) {
47
- const workspaceRoot = await resolveWorkspaceRoot(options.targetPath, { create: false });
48
- const gitRoot = await resolveGitRoot(workspaceRoot);
49
-
50
- const hooksPath = await readGitConfig(gitRoot, "core.hooksPath");
51
- const normalizedHooksPath = hooksPath.replace(/[\\/]+$/, "");
52
-
53
- const githooksDir = path.join(gitRoot, ".githooks");
54
- const commitMsg = path.join(githooksDir, "commit-msg");
55
- const preCommit = path.join(githooksDir, "pre-commit");
56
- const prePush = path.join(githooksDir, "pre-push");
57
-
58
- const githooksExists = await pathExists(githooksDir);
59
- const commitMsgExists = await pathExists(commitMsg);
60
- const preCommitExists = await pathExists(preCommit);
61
- const prePushExists = await pathExists(prePush);
62
-
63
- let commitMsgExec = false;
64
- let preCommitExec = false;
65
- let prePushExec = false;
66
- if (commitMsgExists) {
67
- const st = await fs.stat(commitMsg);
68
- commitMsgExec = isExecutable(st);
69
- }
70
- if (preCommitExists) {
71
- const st = await fs.stat(preCommit);
72
- preCommitExec = isExecutable(st);
73
- }
74
- if (prePushExists) {
75
- const st = await fs.stat(prePush);
76
- prePushExec = isExecutable(st);
77
- }
78
-
79
- console.log(`✓ aiws hooks status: ${gitRoot}`);
80
- console.log(`core.hooksPath: ${hooksPath ? hooksPath : "(default: .git/hooks)"}`);
81
- console.log(`.githooks/: ${githooksExists ? "ok" : "missing"}`);
82
- console.log(`.githooks/commit-msg: ${commitMsgExists ? (commitMsgExec ? "ok" : "not-executable") : "missing"}`);
83
- console.log(`.githooks/pre-commit: ${preCommitExists ? (preCommitExec ? "ok" : "not-executable") : "missing"}`);
84
- console.log(`.githooks/pre-push: ${prePushExists ? (prePushExec ? "ok" : "not-executable") : "missing"}`);
85
-
86
- const enabled = normalizedHooksPath === ".githooks";
87
- if (!enabled) {
88
- console.log("Next: aiws hooks install .");
89
- return;
90
- }
91
- if (!githooksExists || !commitMsgExists || !preCommitExists || !prePushExists || !commitMsgExec || !preCommitExec || !prePushExec) {
92
- console.log("Next: aiws hooks install .");
93
- return;
94
- }
95
- }
@@ -1,101 +0,0 @@
1
- import path from "node:path";
2
- import fs from "node:fs/promises";
3
- import { loadTemplate } from "../spec.js";
4
- import { expandManifestEntries, copyTemplateFileToWorkspace, applyManagedBlocksFromTemplate } from "../template.js";
5
- import { loadAiwsPackage } from "../aiws-package.js";
6
- import { writeWorkspaceManifest } from "../manifest.js";
7
- import { resolveWorkspaceRoot } from "../workspace.js";
8
- import { joinRel, normalizeRel } from "../path-utils.js";
9
- import { pathExists } from "../fs.js";
10
- import { BackupSession } from "../backup.js";
11
-
12
- /**
13
- * @param {{ targetPath: string, templateId: string }} options
14
- */
15
- export async function initCommand(options) {
16
- const workspaceRoot = await resolveWorkspaceRoot(options.targetPath, { create: true });
17
- const tpl = await loadTemplate(options.templateId);
18
- const aiws = await loadAiwsPackage();
19
-
20
- const defaults = tpl.manifest.defaults || {};
21
- const includeOptional = defaults.include_optional !== false;
22
- const tools = Array.isArray(defaults.tools) ? defaults.tools.map(String) : ["claude", "opencode", "codex"];
23
-
24
- const required = await expandManifestEntries(tpl.templateDir, tpl.manifest.required || []);
25
- const optional = includeOptional ? await expandManifestEntries(tpl.templateDir, tpl.manifest.optional || []) : [];
26
- const allFiles = Array.from(new Set([...required, ...optional]));
27
-
28
- const update = tpl.manifest.update || {};
29
- const replaceFiles = new Set((update.replace_file || []).map(normalizeRel));
30
- const managedBlocks = update.managed_blocks && typeof update.managed_blocks === "object" ? update.managed_blocks : {};
31
-
32
- // If we are overwriting existing files, take a backup for rollback.
33
- const backup = new BackupSession({ workspaceRoot, operation: "init" });
34
- await backup.recordFile(".aiws/manifest.json");
35
- for (const f of replaceFiles) {
36
- if (f && f !== ".aiws/manifest.json") await backup.recordFile(f);
37
- }
38
- for (const f of Object.keys(managedBlocks)) await backup.recordFile(f);
39
- await backup.finalize({ extra: { template_id: tpl.templateId } });
40
-
41
- // Ensure .aiws directory (manifest will be generated at the end)
42
- await fs.mkdir(path.join(workspaceRoot, ".aiws"), { recursive: true });
43
-
44
- for (const rel of allFiles) {
45
- const r = normalizeRel(rel);
46
- if (!r) continue;
47
- if (r === ".aiws/manifest.json") {
48
- // Always generated, never copied from template.
49
- continue;
50
- }
51
-
52
- if (replaceFiles.has(r)) {
53
- await copyTemplateFileToWorkspace({
54
- templateDir: tpl.templateDir,
55
- workspaceRoot,
56
- relPosix: r,
57
- chmod: r.startsWith(".githooks/") ? 0o755 : undefined,
58
- });
59
- continue;
60
- }
61
-
62
- if (Object.prototype.hasOwnProperty.call(managedBlocks, r)) {
63
- const blockIds = Array.isArray(managedBlocks[r]) ? managedBlocks[r].map(String) : [];
64
- await applyManagedBlocksFromTemplate({
65
- templateDir: tpl.templateDir,
66
- workspaceRoot,
67
- fileRel: r,
68
- blockIds,
69
- insertIfMissing: true,
70
- });
71
- continue;
72
- }
73
-
74
- // unmanaged: only create if missing
75
- const dest = joinRel(workspaceRoot, r);
76
- if (await pathExists(dest)) continue;
77
- await copyTemplateFileToWorkspace({ templateDir: tpl.templateDir, workspaceRoot, relPosix: r });
78
- }
79
-
80
- // Ensure replace_file-only entries (not listed in required/optional) are also copied
81
- for (const r of replaceFiles) {
82
- if (!r || r === ".aiws/manifest.json") continue;
83
- const dest = joinRel(workspaceRoot, r);
84
- if (await pathExists(dest)) continue;
85
- await copyTemplateFileToWorkspace({ templateDir: tpl.templateDir, workspaceRoot, relPosix: r });
86
- }
87
-
88
- const now = new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
89
- await writeWorkspaceManifest({
90
- workspaceRoot,
91
- templateId: tpl.templateId,
92
- specVersion: tpl.specVersion,
93
- aiwsVersion: aiws.version,
94
- installedAt: now,
95
- updatedAt: now,
96
- tools,
97
- templateManifest: tpl.manifest,
98
- });
99
-
100
- console.log(`✓ aiws init: ${workspaceRoot} (template=${tpl.templateId})`);
101
- }
@@ -1,167 +0,0 @@
1
- import path from "node:path";
2
- import { UserError } from "../errors.js";
3
- import { pathExists, readText } from "../fs.js";
4
- import { loadAiwsPackage } from "../aiws-package.js";
5
- import { loadTemplate } from "../spec.js";
6
- import { resolveWorkspaceRoot } from "../workspace.js";
7
- import { updateCommand } from "./update.js";
8
- import { detectOpenCodeEnvironment } from "../opencode-env.js";
9
- import { ensureOpenCodeWatchdog, tmuxInstalled } from "./opencode-supervise.js";
10
-
11
- const REQUIRED_TRUTH_FILES = ["AI_PROJECT.md", "REQUIREMENTS.md", "AI_WORKSPACE.md"];
12
- const REQUIRED_AUTONOMY_FILES = [
13
- ".opencode/oh-my-opencode.json.example",
14
- ".claude/settings.json.example",
15
- ".opencode/helpers/approval-whitelist-check.sh",
16
- ".opencode/helpers/approval-whitelist-run.sh",
17
- ".opencode/helpers/approval-whitelist-watchdog.sh",
18
- ".opencode/helpers/tmux-swarm-scan.sh",
19
- ".opencode/helpers/tmux-swarm-rescue.sh",
20
- ".opencode/skills/ws-autonomy/SKILL.md",
21
- ".opencode/commands/ws-autonomy.md",
22
- ".opencode/command/ws-autonomy.md",
23
- ".opencode/skills/ws-auto/SKILL.md",
24
- ".opencode/commands/ws-auto.md",
25
- ".opencode/command/ws-auto.md",
26
- ];
27
-
28
- async function collectMissingPaths(workspaceRoot, relPaths) {
29
- /** @type {string[]} */
30
- const missing = [];
31
- for (const rel of relPaths) {
32
- if (!(await pathExists(path.join(workspaceRoot, rel)))) {
33
- missing.push(rel);
34
- }
35
- }
36
- return missing;
37
- }
38
-
39
- async function readWorkspaceManifest(workspaceRoot) {
40
- const manifestPath = path.join(workspaceRoot, ".aiws", "manifest.json");
41
- if (!(await pathExists(manifestPath))) {
42
- throw new UserError("Missing .aiws/manifest.json. Run `aiws init .` first.");
43
- }
44
- return JSON.parse(await readText(manifestPath));
45
- }
46
-
47
- /**
48
- * @param {string} workspaceRoot
49
- */
50
- async function detectAutoBootstrapState(workspaceRoot) {
51
- const env = await detectOpenCodeEnvironment(workspaceRoot);
52
- const manifest = await readWorkspaceManifest(workspaceRoot);
53
- const templateId = String(manifest.template_id || "workspace");
54
- const tpl = await loadTemplate(templateId);
55
- const aiws = await loadAiwsPackage();
56
- const truthMissing = await collectMissingPaths(workspaceRoot, REQUIRED_TRUTH_FILES);
57
- const autonomyMissing = await collectMissingPaths(workspaceRoot, REQUIRED_AUTONOMY_FILES);
58
-
59
- /** @type {string[]} */
60
- const updateReasons = [];
61
- if (autonomyMissing.length > 0) {
62
- updateReasons.push(`autonomy_files_missing=${autonomyMissing.join(",")}`);
63
- }
64
- if (String(manifest.spec_version || "") !== String(tpl.specVersion || "")) {
65
- updateReasons.push(`spec_version=${String(manifest.spec_version || "(missing)")}->${String(tpl.specVersion || "(missing)")}`);
66
- }
67
- if (String(manifest.aiws_version || "") !== String(aiws.version || "")) {
68
- updateReasons.push(`aiws_version=${String(manifest.aiws_version || "(missing)")}->${String(aiws.version || "(missing)")}`);
69
- }
70
-
71
- return {
72
- env,
73
- manifest,
74
- truthMissing,
75
- autonomyMissing,
76
- updateRequired: updateReasons.length > 0,
77
- updateReasons,
78
- };
79
- }
80
-
81
- /**
82
- * @param {{
83
- * targetPath: string,
84
- * sessionName?: string,
85
- * windowName?: string,
86
- * once?: boolean,
87
- * pollMs?: string,
88
- * noUpdate?: boolean,
89
- * }} options
90
- */
91
- export async function opencodeAutoCommand(options) {
92
- const workspaceRoot = await resolveWorkspaceRoot(options.targetPath, { create: false });
93
- let state = await detectAutoBootstrapState(workspaceRoot);
94
- let updateApplied = false;
95
-
96
- console.log(`✓ aiws opencode auto: ${workspaceRoot}`);
97
- console.log(`found_truth: ${state.truthMissing.length === 0 ? REQUIRED_TRUTH_FILES.join(", ") : "(incomplete)"}`);
98
-
99
- if (state.truthMissing.length > 0) {
100
- console.log(`update: skipped (missing truth files: ${state.truthMissing.join(", ")})`);
101
- console.log(`mode: ${state.env.mode}`);
102
- console.log(`watchdog: skipped (missing truth files: ${state.truthMissing.join(", ")})`);
103
- console.log("next: 先补齐真值文件,再重新运行 `aiws opencode auto .` 或 `/ws-preflight`。");
104
- return;
105
- }
106
-
107
- if (state.updateRequired && options.noUpdate !== true) {
108
- console.log(`update: required (${state.updateReasons.join("; ")})`);
109
- await updateCommand({ targetPath: workspaceRoot });
110
- updateApplied = true;
111
- state = await detectAutoBootstrapState(workspaceRoot);
112
- } else if (state.updateRequired) {
113
- console.log(`update: required but skipped (--no-update)`);
114
- console.log(`update_reasons: ${state.updateReasons.join("; ")}`);
115
- } else {
116
- console.log("update: not needed");
117
- }
118
-
119
- console.log(`mode: ${state.env.mode}`);
120
- if (updateApplied) {
121
- console.log("update_applied: true");
122
- }
123
-
124
- if (state.env.configStatus === "invalid") {
125
- console.log(`watchdog: skipped (invalid config: ${state.env.rel.configPath})`);
126
- console.log(`next: 修复 ${state.env.rel.configPath} 的 JSON,然后重新运行 \`aiws opencode auto .\`.`);
127
- return;
128
- }
129
- if (!state.env.configExists) {
130
- console.log("watchdog: skipped (oMo config missing)");
131
- console.log(`next: 如需启用 autonomous bootstrap,可复制 ${state.env.rel.examplePath} -> ${state.env.rel.configPath},然后重新运行 \`aiws opencode auto .\`.`);
132
- return;
133
- }
134
- if (!state.env.watchdogSuperviseReady) {
135
- console.log("watchdog: skipped (approval/watchdog chain incomplete)");
136
- console.log("next: 先运行 `aiws opencode status .` 查看缺哪一项;如是托管文件缺失,可运行 `aiws update .`。");
137
- return;
138
- }
139
- if (!tmuxInstalled()) {
140
- console.log("watchdog: skipped (tmux missing)");
141
- console.log("next: 安装 tmux 后重新运行 `aiws opencode auto .`,或手工执行 approval-whitelist-watchdog helper。");
142
- return;
143
- }
144
-
145
- const ensureResult = ensureOpenCodeWatchdog({
146
- workspaceRoot,
147
- env: state.env,
148
- sessionName: options.sessionName,
149
- windowName: options.windowName,
150
- once: options.once === true,
151
- pollMs: options.pollMs ?? null,
152
- });
153
- console.log(`watchdog: ${ensureResult.state}`);
154
- console.log(`tmux session: ${ensureResult.sessionName}${ensureResult.currentSession ? " (current)" : ""}`);
155
- console.log(`watchdog window: ${ensureResult.windowName}`);
156
- console.log(`watchdog helper: ${ensureResult.helperRelPath}`);
157
- if (ensureResult.once) {
158
- console.log("watchdog_mode: once");
159
- } else {
160
- console.log(`watchdog_mode: loop${ensureResult.pollMs !== null ? ` (poll_ms=${ensureResult.pollMs})` : ""}`);
161
- }
162
- if (state.env.autonomyReady) {
163
- console.log("next: watchdog 已就绪,可继续 `/ws-auto` -> `/using-aiws` / `/ws-plan` / `/ws-autonomy`。");
164
- return;
165
- }
166
- console.log("next: watchdog 已启动,但 autonomy contract 尚未完整;建议先运行 `aiws opencode status .` 或 `/ws-autonomy` 查看缺口。");
167
- }
@@ -1,103 +0,0 @@
1
- import { resolveWorkspaceRoot } from "../workspace.js";
2
- import { detectOpenCodeEnvironment } from "../opencode-env.js";
3
-
4
- /**
5
- * @param {{ targetPath: string }} options
6
- */
7
- export async function opencodeStatusCommand(options) {
8
- const workspaceRoot = await resolveWorkspaceRoot(options.targetPath, { create: false });
9
- const env = await detectOpenCodeEnvironment(workspaceRoot);
10
-
11
- console.log(`✓ aiws opencode status: ${workspaceRoot}`);
12
- console.log(`.opencode/: ${env.opencodeDirExists ? "ok" : "missing"}`);
13
- console.log(`mode: ${env.mode}`);
14
- console.log(
15
- `oMo config: ${
16
- env.configStatus === "loaded"
17
- ? `${env.rel.configPath} (ok)`
18
- : env.configStatus === "invalid"
19
- ? `${env.rel.configPath} (invalid JSON: ${env.configError})`
20
- : "missing"
21
- }`,
22
- );
23
- console.log(`oMo example: ${env.exampleExists ? `${env.rel.examplePath} (present)` : "missing"}`);
24
- console.log(`recommended_agents_ready: ${env.recommendedAgentsReady}`);
25
- console.log(`enabled_agents: ${env.enabledAgents.length > 0 ? env.enabledAgents.join(", ") : "(none)"}`);
26
-
27
- const planner = env.agents["planner-sisyphus"];
28
- const librarian = env.agents.librarian;
29
- const explore = env.agents.explore;
30
- const oracle = env.agents.oracle;
31
- console.log(
32
- `aiws_roles: planner=${planner.enabled ? "planner-sisyphus" : "missing"}, explorer=${[
33
- explore.enabled ? "explore" : "",
34
- librarian.enabled ? "librarian" : "",
35
- ]
36
- .filter(Boolean)
37
- .join("+") || "missing"}, reviewer=${oracle.enabled ? "oracle" : "missing"}, integrator=current-agent`,
38
- );
39
-
40
- if (planner.present) {
41
- console.log(`planner-sisyphus.replace_plan: ${planner.replacePlan === null ? "(unset)" : String(planner.replacePlan)}`);
42
- console.log(`planner-sisyphus.prompt_append: ${planner.promptAppendConfigured ? "configured" : "missing"}`);
43
- }
44
- console.log(`background_tasks: ${env.backgroundTasksConfigured ? "configured" : "missing"}`);
45
- console.log(`auto_resume: ${env.autoResumeEnabled ? "true" : "false"}`);
46
- console.log(
47
- `approval_whitelist: ${
48
- env.approvalWhitelist.present
49
- ? env.approvalWhitelist.configured
50
- ? `configured (${env.approvalWhitelist.mode || "unset"})`
51
- : "incomplete"
52
- : "missing"
53
- }`,
54
- );
55
- console.log(`host_permission_mode: ${env.approvalWhitelist.hostPermissionMode || "missing"}`);
56
- console.log(
57
- `approval_helper: ${env.approvalWhitelistHelperExists ? `${env.rel.approvalWhitelistHelperPath} (present)` : "missing"}`,
58
- );
59
- console.log(
60
- `approval_runner: ${env.approvalWhitelistRunnerExists ? `${env.rel.approvalWhitelistRunnerPath} (present)` : "missing"}`,
61
- );
62
- console.log(
63
- `approval_watchdog: ${env.approvalWhitelistWatchdogExists ? `${env.rel.approvalWhitelistWatchdogPath} (present)` : "missing"}`,
64
- );
65
- console.log(`watchdog_supervisor: ${env.watchdogSuperviseReady ? "configured" : "incomplete"}`);
66
- console.log(
67
- `claude_hooks_example: ${env.claudeSettingsExampleExists ? `${env.rel.claudeSettingsExamplePath} (present)` : "missing"}`,
68
- );
69
- console.log(
70
- `tmux_helpers: scan=${env.tmuxScanHelperExists ? env.rel.tmuxScanHelperPath : "missing"}, rescue=${
71
- env.tmuxRescueHelperExists ? env.rel.tmuxRescueHelperPath : "missing"
72
- }`,
73
- );
74
- console.log(`autonomy_ready: ${env.autonomyReady}`);
75
-
76
- if (env.configStatus === "invalid") {
77
- console.log(`Next: 修复 ${env.rel.configPath} 的 JSON,然后重新运行 aiws opencode status .`);
78
- return;
79
- }
80
- if (!env.configExists && env.exampleExists) {
81
- console.log(`Next: 如需启用 oMo 优先模式,可复制 ${env.rel.examplePath} -> ${env.rel.configPath} 后按项目调整 agents;随后运行 \`aiws opencode auto .\` 或 \`/ws-auto\`.`);
82
- return;
83
- }
84
- if (env.mode === "oMo-enabled" && !env.recommendedAgentsReady) {
85
- console.log("Next: 补齐 planner-sisyphus / librarian / explore / oracle,或接受 fallback 到 standard-opencode。");
86
- return;
87
- }
88
- if (env.mode === "oMo-enabled" && !env.autonomyReady) {
89
- console.log(
90
- "Next: 如需 autonomous 模式,补齐 planner-sisyphus.prompt_append / backgroundTasks / experimental.auto_resume / approval whitelist,并确认 .claude/settings.json.example / approval helper / approval runner / approval watchdog / tmux helpers 存在。",
91
- );
92
- return;
93
- }
94
- if (env.mode === "oMo-enabled") {
95
- if (env.watchdogSuperviseReady) {
96
- console.log("Next: 如需一键做 bootstrap + watchdog ensure,运行 `aiws opencode auto .` 或 `/ws-auto`;若只想单独拉起 watchdog,再用 `aiws opencode supervise .`。");
97
- return;
98
- }
99
- console.log("Next: 运行 /ws-autonomy 或 /using-aiws,确认当前仓库的 completion/retry/rescue 合同。");
100
- return;
101
- }
102
- console.log("Next: 当前按 standard-opencode 运行;如需多 agent 优先委托,可启用 oh-my-opencode 项目配置。");
103
- }
@@ -1,200 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import path from "node:path";
3
- import { spawnSync } from "node:child_process";
4
- import { UserError } from "../errors.js";
5
- import { resolveWorkspaceRoot } from "../workspace.js";
6
- import { detectOpenCodeEnvironment } from "../opencode-env.js";
7
-
8
- function shellQuote(value) {
9
- return `'${String(value).replaceAll("'", `'\\''`)}'`;
10
- }
11
-
12
- function sanitizeName(value) {
13
- return String(value || "")
14
- .replaceAll(/[^A-Za-z0-9._-]+/g, "-")
15
- .replaceAll(/^-+|-+$/g, "") || "workspace";
16
- }
17
-
18
- function defaultSessionName(workspaceRoot) {
19
- const baseName = sanitizeName(path.basename(workspaceRoot));
20
- const hash = createHash("sha1").update(workspaceRoot).digest("hex").slice(0, 6);
21
- return `${baseName}-${hash}`;
22
- }
23
-
24
- function runTmux(args, options = {}) {
25
- const result = spawnSync("tmux", args, {
26
- encoding: "utf8",
27
- env: process.env,
28
- });
29
- if (options.allowFailure === true) {
30
- return result;
31
- }
32
- if (result.error) {
33
- throw new UserError(`Failed to run tmux ${args[0] ?? ""}`.trim(), {
34
- details: result.error instanceof Error ? result.error.message : String(result.error),
35
- });
36
- }
37
- if (result.status !== 0) {
38
- const stderr = (result.stderr || "").trim();
39
- throw new UserError(`tmux ${args[0] ?? ""} failed`, { details: stderr || `exit=${result.status}` });
40
- }
41
- return result;
42
- }
43
-
44
- export function tmuxInstalled() {
45
- const result = spawnSync("tmux", ["-V"], {
46
- encoding: "utf8",
47
- env: process.env,
48
- });
49
- return !result.error && result.status === 0;
50
- }
51
-
52
- function parsePositiveInt(value, optionName) {
53
- const parsed = Number.parseInt(String(value), 10);
54
- if (!Number.isFinite(parsed) || parsed <= 0) {
55
- throw new UserError(`Invalid ${optionName}: ${value}`, { details: `${optionName} must be a positive integer.` });
56
- }
57
- return parsed;
58
- }
59
-
60
- function buildWatchdogCommand(env, workspaceRoot, options) {
61
- const autonomyDir = path.join(workspaceRoot, ".agentdocs", "tmp", "opencode-autonomy");
62
- const args = [shellQuote(env.approvalWhitelistWatchdogPath), shellQuote(workspaceRoot)];
63
- if (options.once === true) {
64
- args.push("--once");
65
- }
66
- if (options.pollMs !== null) {
67
- args.push("--poll-ms", String(options.pollMs));
68
- }
69
- return `mkdir -p ${shellQuote(autonomyDir)} && export AIWS_OPENCODE_AUTONOMY_DIR=${shellQuote(autonomyDir)} && exec bash ${args.join(" ")}`;
70
- }
71
-
72
- function currentTmuxSessionName() {
73
- if (!process.env.TMUX) {
74
- return "";
75
- }
76
- const result = runTmux(["display-message", "-p", "#S"]);
77
- return (result.stdout || "").trim();
78
- }
79
-
80
- function sessionExists(sessionName) {
81
- const result = runTmux(["has-session", "-t", sessionName], { allowFailure: true });
82
- return result.status === 0;
83
- }
84
-
85
- function windowExists(sessionName, windowName) {
86
- const result = runTmux(["list-windows", "-t", sessionName, "-F", "#W"], { allowFailure: true });
87
- if (result.status !== 0) {
88
- return false;
89
- }
90
- return String(result.stdout || "")
91
- .split(/\r?\n/)
92
- .map((line) => line.trim())
93
- .filter(Boolean)
94
- .includes(windowName);
95
- }
96
-
97
- /**
98
- * @param {{
99
- * workspaceRoot: string,
100
- * env: Awaited<ReturnType<typeof detectOpenCodeEnvironment>>,
101
- * sessionName?: string,
102
- * windowName?: string,
103
- * once?: boolean,
104
- * pollMs?: string | null,
105
- * }} options
106
- */
107
- export function ensureOpenCodeWatchdog(options) {
108
- const workspaceRoot = options.workspaceRoot;
109
- const env = options.env;
110
- if (!tmuxInstalled()) {
111
- throw new UserError("tmux is required for watchdog supervision.", {
112
- details: "Install tmux first, or run the watchdog helper manually.",
113
- });
114
- }
115
- if (env.configStatus !== "loaded") {
116
- throw new UserError("oMo config is not ready for supervision.", {
117
- details: `Expected ${env.rel.configPath} to exist and be valid JSON before starting watchdog supervision.`,
118
- });
119
- }
120
- if (!env.approvalWhitelist.configured) {
121
- throw new UserError("approval whitelist policy is not ready.", {
122
- details: "Enable aiws.autonomy.approval_whitelist with assist-only + manual-only before starting watchdog supervision.",
123
- });
124
- }
125
- if (!env.approvalWhitelistHelperExists || !env.approvalWhitelistRunnerExists || !env.approvalWhitelistWatchdogExists) {
126
- throw new UserError("watchdog helper chain is incomplete.", {
127
- details: "Expected approval-whitelist-check.sh, approval-whitelist-run.sh, and approval-whitelist-watchdog.sh to exist under .opencode/helpers/.",
128
- });
129
- }
130
-
131
- const pollMs = options.pollMs ? parsePositiveInt(options.pollMs, "--poll-ms") : null;
132
- const currentSession = currentTmuxSessionName();
133
- const sessionName = options.sessionName || currentSession || defaultSessionName(workspaceRoot);
134
- const windowName = options.windowName || "watchdog";
135
- const command = buildWatchdogCommand(env, workspaceRoot, {
136
- once: options.once === true,
137
- pollMs,
138
- });
139
- const existed = sessionExists(sessionName);
140
-
141
- if (existed && windowExists(sessionName, windowName)) {
142
- return {
143
- sessionName,
144
- windowName,
145
- helperRelPath: env.rel.approvalWhitelistWatchdogPath,
146
- state: "already-running",
147
- currentSession: Boolean(currentSession && sessionName === currentSession),
148
- once: options.once === true,
149
- pollMs,
150
- };
151
- }
152
-
153
- if (existed) {
154
- runTmux(["new-window", "-d", "-t", sessionName, "-n", windowName, "-c", workspaceRoot, command]);
155
- } else {
156
- runTmux(["new-session", "-d", "-s", sessionName, "-n", windowName, "-c", workspaceRoot, command]);
157
- }
158
-
159
- return {
160
- sessionName,
161
- windowName,
162
- helperRelPath: env.rel.approvalWhitelistWatchdogPath,
163
- state: existed ? "created" : "started-with-new-session",
164
- currentSession: Boolean(currentSession && sessionName === currentSession),
165
- once: options.once === true,
166
- pollMs,
167
- };
168
- }
169
-
170
- /**
171
- * @param {{ targetPath: string, sessionName?: string, windowName?: string, once?: boolean, pollMs?: string }} options
172
- */
173
- export async function opencodeSuperviseCommand(options) {
174
- const workspaceRoot = await resolveWorkspaceRoot(options.targetPath, { create: false });
175
- const env = await detectOpenCodeEnvironment(workspaceRoot);
176
- const result = ensureOpenCodeWatchdog({
177
- workspaceRoot,
178
- env,
179
- sessionName: options.sessionName,
180
- windowName: options.windowName,
181
- once: options.once,
182
- pollMs: options.pollMs ?? null,
183
- });
184
-
185
- console.log(`✓ aiws opencode supervise: ${workspaceRoot}`);
186
- console.log(`tmux session: ${result.sessionName}${result.currentSession ? " (current)" : ""}`);
187
- if (result.state === "already-running") {
188
- console.log(`watchdog window: ${result.windowName} (already running)`);
189
- } else if (result.state === "created") {
190
- console.log(`watchdog window: ${result.windowName} (created)`);
191
- } else {
192
- console.log(`watchdog window: ${result.windowName} (started with new session)`);
193
- }
194
- console.log(`watchdog helper: ${result.helperRelPath}`);
195
- if (result.once) {
196
- console.log("mode: once");
197
- } else {
198
- console.log(`mode: loop${result.pollMs !== null ? ` (poll_ms=${result.pollMs})` : ""}`);
199
- }
200
- }
@@ -1,13 +0,0 @@
1
- import { resolveWorkspaceRoot } from "../workspace.js";
2
- import { resolveBackupRoot, rollbackFromBackup } from "../backup.js";
3
-
4
- /**
5
- * @param {{ targetPath: string, stamp: string }} options
6
- */
7
- export async function rollbackCommand(options) {
8
- const workspaceRoot = await resolveWorkspaceRoot(options.targetPath, { create: false });
9
- const backupRoot = await resolveBackupRoot(workspaceRoot, options.stamp);
10
- await rollbackFromBackup(workspaceRoot, backupRoot);
11
- console.log(`✓ aiws rollback: ${workspaceRoot} (${options.stamp})`);
12
- }
13
-