@uluops/setup 0.2.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +109 -89
  3. package/assets/auto-tracker-save.mjs +142 -0
  4. package/assets/claude-code/agents/anxiety-reader-agent.md +464 -0
  5. package/assets/{agents → claude-code/agents}/api-contract-validator-agent.md +9 -228
  6. package/assets/{agents → claude-code/agents}/aristotle-analyst-agent.md +51 -4
  7. package/assets/{agents → claude-code/agents}/aristotle-explorer-agent.md +6 -2
  8. package/assets/{agents → claude-code/agents}/aristotle-forecaster-agent.md +15 -230
  9. package/assets/{agents → claude-code/agents}/aristotle-validator-agent.md +12 -252
  10. package/assets/{agents → claude-code/agents}/assumption-excavator-agent.md +21 -247
  11. package/assets/{agents → claude-code/agents}/code-auditor-agent.md +12 -255
  12. package/assets/{agents → claude-code/agents}/code-optimizer-agent.md +15 -236
  13. package/assets/{agents → claude-code/agents}/code-validator-agent.md +31 -300
  14. package/assets/claude-code/agents/docs-validator-agent.md +472 -0
  15. package/assets/{agents → claude-code/agents}/frontend-validator-agent.md +15 -258
  16. package/assets/{agents → claude-code/agents}/mcp-validator-agent.md +8 -252
  17. package/assets/{agents → claude-code/agents}/pre-implementation-architect-agent.md +8 -224
  18. package/assets/{agents → claude-code/agents}/prompt-engineer-agent.md +57 -290
  19. package/assets/{agents → claude-code/agents}/prompt-pattern-analyzer-agent.md +10 -225
  20. package/assets/{agents → claude-code/agents}/prompt-quality-validator-agent.md +11 -249
  21. package/assets/{agents → claude-code/agents}/public-interface-validator-agent.md +15 -268
  22. package/assets/claude-code/agents/release-readiness-agent.md +495 -0
  23. package/assets/{agents → claude-code/agents}/security-analyst-agent.md +236 -480
  24. package/assets/{agents → claude-code/agents}/test-architect-agent.md +16 -259
  25. package/assets/{agents → claude-code/agents}/type-safety-validator-agent.md +23 -266
  26. package/assets/{agents → claude-code/agents}/workflow-synthesis-agent.md +23 -226
  27. package/assets/claude-code/commands/agents/anxiety-reader.md +157 -0
  28. package/assets/{commands → claude-code/commands}/agents/api-contract.md +156 -135
  29. package/assets/{commands → claude-code/commands}/agents/architect.md +156 -135
  30. package/assets/claude-code/commands/agents/aristotle-analyst.md +157 -0
  31. package/assets/claude-code/commands/agents/aristotle-explorer.md +157 -0
  32. package/assets/claude-code/commands/agents/aristotle-forecaster.md +157 -0
  33. package/assets/claude-code/commands/agents/aristotle-validator.md +157 -0
  34. package/assets/{commands → claude-code/commands}/agents/assumption-excavator.md +49 -6
  35. package/assets/{commands → claude-code/commands}/agents/audit.md +156 -136
  36. package/assets/{commands → claude-code/commands}/agents/docs-validate.md +156 -133
  37. package/assets/{commands → claude-code/commands}/agents/frontend.md +156 -135
  38. package/assets/{commands → claude-code/commands}/agents/mcp-validate.md +156 -136
  39. package/assets/{commands → claude-code/commands}/agents/optimize.md +156 -133
  40. package/assets/{commands → claude-code/commands}/agents/pattern-analyzer.md +150 -126
  41. package/assets/{commands → claude-code/commands}/agents/prompt-quality.md +155 -134
  42. package/assets/claude-code/commands/agents/prompt-validate.md +155 -0
  43. package/assets/{commands → claude-code/commands}/agents/public-interface.md +156 -134
  44. package/assets/{commands → claude-code/commands}/agents/release.md +156 -135
  45. package/assets/{commands → claude-code/commands}/agents/security.md +156 -137
  46. package/assets/{commands → claude-code/commands}/agents/test-review.md +156 -136
  47. package/assets/{commands → claude-code/commands}/agents/type-safety.md +156 -135
  48. package/assets/{commands → claude-code/commands}/agents/validate.md +156 -134
  49. package/assets/claude-code/commands/agents/workflow-synthesis.md +157 -0
  50. package/assets/claude-code/commands/pipelines/aristotle.md +143 -0
  51. package/assets/claude-code/commands/pipelines/ship.md +188 -0
  52. package/assets/claude-code/commands/workflows/post-implementation.md +60 -0
  53. package/assets/claude-code/commands/workflows/pre-implementation.md +46 -0
  54. package/assets/claude-code/commands/workflows/prompt-audit.md +44 -0
  55. package/assets/codex/agents/anxiety-reader-agent.toml +462 -0
  56. package/assets/codex/agents/api-contract-validator-agent.toml +738 -0
  57. package/assets/codex/agents/aristotle-analyst-agent.toml +750 -0
  58. package/assets/codex/agents/aristotle-explorer-agent.toml +155 -0
  59. package/assets/codex/agents/aristotle-forecaster-agent.toml +449 -0
  60. package/assets/codex/agents/aristotle-validator-agent.toml +424 -0
  61. package/assets/codex/agents/assumption-excavator-agent.toml +1126 -0
  62. package/assets/codex/agents/code-auditor-agent.toml +815 -0
  63. package/assets/codex/agents/code-optimizer-agent.toml +652 -0
  64. package/assets/codex/agents/code-validator-agent.toml +573 -0
  65. package/assets/codex/agents/docs-validator-agent.toml +468 -0
  66. package/assets/codex/agents/frontend-validator-agent.toml +598 -0
  67. package/assets/codex/agents/mcp-validator-agent.toml +580 -0
  68. package/assets/codex/agents/pre-implementation-architect-agent.toml +817 -0
  69. package/assets/codex/agents/prompt-engineer-agent.toml +922 -0
  70. package/assets/codex/agents/prompt-pattern-analyzer-agent.toml +689 -0
  71. package/assets/codex/agents/prompt-quality-validator-agent.toml +777 -0
  72. package/assets/codex/agents/public-interface-validator-agent.toml +695 -0
  73. package/assets/codex/agents/release-readiness-agent.toml +491 -0
  74. package/assets/codex/agents/security-analyst-agent.toml +847 -0
  75. package/assets/codex/agents/test-architect-agent.toml +615 -0
  76. package/assets/codex/agents/type-safety-validator-agent.toml +686 -0
  77. package/assets/codex/agents/workflow-synthesis-agent.toml +631 -0
  78. package/assets/gemini-cli/agents/anxiety-reader-agent.md +470 -0
  79. package/assets/gemini-cli/agents/api-contract-validator-agent.md +747 -0
  80. package/assets/gemini-cli/agents/aristotle-analyst-agent.md +758 -0
  81. package/assets/gemini-cli/agents/aristotle-explorer-agent.md +163 -0
  82. package/assets/gemini-cli/agents/aristotle-forecaster-agent.md +457 -0
  83. package/assets/gemini-cli/agents/aristotle-validator-agent.md +432 -0
  84. package/assets/gemini-cli/agents/assumption-excavator-agent.md +1134 -0
  85. package/assets/gemini-cli/agents/code-auditor-agent.md +827 -0
  86. package/assets/gemini-cli/agents/code-optimizer-agent.md +661 -0
  87. package/assets/gemini-cli/agents/code-validator-agent.md +582 -0
  88. package/assets/gemini-cli/agents/docs-validator-agent.md +477 -0
  89. package/assets/gemini-cli/agents/frontend-validator-agent.md +610 -0
  90. package/assets/gemini-cli/agents/mcp-validator-agent.md +589 -0
  91. package/assets/gemini-cli/agents/pre-implementation-architect-agent.md +826 -0
  92. package/assets/gemini-cli/agents/prompt-engineer-agent.md +931 -0
  93. package/assets/gemini-cli/agents/prompt-pattern-analyzer-agent.md +698 -0
  94. package/assets/gemini-cli/agents/prompt-quality-validator-agent.md +786 -0
  95. package/assets/gemini-cli/agents/public-interface-validator-agent.md +707 -0
  96. package/assets/gemini-cli/agents/release-readiness-agent.md +500 -0
  97. package/assets/gemini-cli/agents/security-analyst-agent.md +859 -0
  98. package/assets/gemini-cli/agents/test-architect-agent.md +624 -0
  99. package/assets/gemini-cli/agents/type-safety-validator-agent.md +695 -0
  100. package/assets/gemini-cli/agents/workflow-synthesis-agent.md +639 -0
  101. package/assets/gemini-cli/commands/agents/anxiety-reader.toml +155 -0
  102. package/assets/gemini-cli/commands/agents/api-contract.toml +154 -0
  103. package/assets/gemini-cli/commands/agents/architect.toml +154 -0
  104. package/assets/gemini-cli/commands/agents/aristotle-analyst.toml +155 -0
  105. package/assets/gemini-cli/commands/agents/aristotle-explorer.toml +155 -0
  106. package/assets/gemini-cli/commands/agents/aristotle-forecaster.toml +155 -0
  107. package/assets/gemini-cli/commands/agents/aristotle-validator.toml +155 -0
  108. package/assets/gemini-cli/commands/agents/assumption-excavator.toml +155 -0
  109. package/assets/gemini-cli/commands/agents/audit.toml +154 -0
  110. package/assets/gemini-cli/commands/agents/docs-validate.toml +154 -0
  111. package/assets/gemini-cli/commands/agents/frontend.toml +154 -0
  112. package/assets/gemini-cli/commands/agents/mcp-validate.toml +154 -0
  113. package/assets/gemini-cli/commands/agents/optimize.toml +154 -0
  114. package/assets/gemini-cli/commands/agents/pattern-analyzer.toml +148 -0
  115. package/assets/gemini-cli/commands/agents/prompt-quality.toml +153 -0
  116. package/assets/gemini-cli/commands/agents/prompt-validate.toml +153 -0
  117. package/assets/gemini-cli/commands/agents/public-interface.toml +154 -0
  118. package/assets/gemini-cli/commands/agents/release.toml +154 -0
  119. package/assets/gemini-cli/commands/agents/security.toml +154 -0
  120. package/assets/gemini-cli/commands/agents/test-review.toml +154 -0
  121. package/assets/gemini-cli/commands/agents/type-safety.toml +154 -0
  122. package/assets/gemini-cli/commands/agents/validate.toml +154 -0
  123. package/assets/gemini-cli/commands/agents/workflow-synthesis.toml +155 -0
  124. package/assets/gemini-cli/commands/pipelines/aristotle.toml +139 -0
  125. package/assets/gemini-cli/commands/pipelines/ship.toml +184 -0
  126. package/assets/gemini-cli/commands/workflows/post-implementation.toml +56 -0
  127. package/assets/gemini-cli/commands/workflows/pre-implementation.toml +42 -0
  128. package/assets/gemini-cli/commands/workflows/prompt-audit.toml +40 -0
  129. package/assets/opencode/agents/anxiety-reader-agent.md +472 -0
  130. package/assets/opencode/agents/api-contract-validator-agent.md +749 -0
  131. package/assets/opencode/agents/aristotle-analyst-agent.md +760 -0
  132. package/assets/opencode/agents/aristotle-explorer-agent.md +164 -0
  133. package/assets/opencode/agents/aristotle-forecaster-agent.md +459 -0
  134. package/assets/opencode/agents/aristotle-validator-agent.md +434 -0
  135. package/assets/opencode/agents/assumption-excavator-agent.md +1136 -0
  136. package/assets/opencode/agents/code-auditor-agent.md +826 -0
  137. package/assets/opencode/agents/code-optimizer-agent.md +663 -0
  138. package/assets/opencode/agents/code-validator-agent.md +584 -0
  139. package/assets/opencode/agents/docs-validator-agent.md +479 -0
  140. package/assets/opencode/agents/frontend-validator-agent.md +609 -0
  141. package/assets/opencode/agents/mcp-validator-agent.md +591 -0
  142. package/assets/opencode/agents/pre-implementation-architect-agent.md +828 -0
  143. package/assets/opencode/agents/prompt-engineer-agent.md +933 -0
  144. package/assets/opencode/agents/prompt-pattern-analyzer-agent.md +700 -0
  145. package/assets/opencode/agents/prompt-quality-validator-agent.md +788 -0
  146. package/assets/opencode/agents/public-interface-validator-agent.md +706 -0
  147. package/assets/opencode/agents/release-readiness-agent.md +502 -0
  148. package/assets/opencode/agents/security-analyst-agent.md +858 -0
  149. package/assets/opencode/agents/test-architect-agent.md +626 -0
  150. package/assets/opencode/agents/type-safety-validator-agent.md +697 -0
  151. package/assets/opencode/agents/workflow-synthesis-agent.md +641 -0
  152. package/dist/cli.js +22 -380
  153. package/dist/commands/helpers.d.ts +73 -0
  154. package/dist/commands/helpers.js +274 -0
  155. package/dist/commands/setup.d.ts +13 -0
  156. package/dist/commands/setup.js +93 -0
  157. package/dist/commands/uninstall.d.ts +3 -0
  158. package/dist/commands/uninstall.js +126 -0
  159. package/dist/commands/verify.d.ts +1 -0
  160. package/dist/commands/verify.js +28 -0
  161. package/dist/harnesses/claude-code.d.ts +8 -0
  162. package/dist/harnesses/claude-code.js +74 -0
  163. package/dist/harnesses/codex.d.ts +15 -0
  164. package/dist/harnesses/codex.js +54 -0
  165. package/dist/harnesses/gemini-cli.d.ts +12 -0
  166. package/dist/harnesses/gemini-cli.js +80 -0
  167. package/dist/harnesses/index.d.ts +27 -0
  168. package/dist/harnesses/index.js +54 -0
  169. package/dist/harnesses/opencode.d.ts +14 -0
  170. package/dist/harnesses/opencode.js +139 -0
  171. package/dist/harnesses/types.d.ts +106 -0
  172. package/dist/harnesses/types.js +26 -0
  173. package/dist/lib/agent-transform.d.ts +12 -0
  174. package/dist/lib/agent-transform.js +129 -0
  175. package/dist/lib/asset-catalog.d.ts +9 -0
  176. package/dist/lib/asset-catalog.js +56 -0
  177. package/dist/lib/atomic-write.d.ts +11 -0
  178. package/dist/lib/atomic-write.js +28 -0
  179. package/dist/lib/config-merger.d.ts +9 -2
  180. package/dist/lib/config-merger.js +44 -7
  181. package/dist/lib/display.d.ts +14 -0
  182. package/dist/lib/display.js +66 -0
  183. package/dist/lib/file-ops.d.ts +11 -0
  184. package/dist/lib/file-ops.js +40 -4
  185. package/dist/lib/hash.d.ts +1 -0
  186. package/dist/lib/hash.js +2 -1
  187. package/dist/lib/health.d.ts +2 -0
  188. package/dist/lib/health.js +10 -0
  189. package/dist/lib/manifest.d.ts +51 -5
  190. package/dist/lib/manifest.js +146 -13
  191. package/dist/lib/paths.d.ts +30 -3
  192. package/dist/lib/paths.js +98 -12
  193. package/dist/lib/settings-merger.d.ts +31 -8
  194. package/dist/lib/settings-merger.js +87 -24
  195. package/dist/lib/version.d.ts +2 -0
  196. package/dist/lib/version.js +10 -0
  197. package/dist/steps/agents.d.ts +4 -1
  198. package/dist/steps/agents.js +48 -9
  199. package/dist/steps/auth.js +26 -10
  200. package/dist/steps/cli.d.ts +53 -0
  201. package/dist/steps/cli.js +90 -0
  202. package/dist/steps/commands.d.ts +6 -1
  203. package/dist/steps/commands.js +36 -9
  204. package/dist/steps/detect.d.ts +3 -0
  205. package/dist/steps/detect.js +11 -0
  206. package/dist/steps/mcp.d.ts +6 -2
  207. package/dist/steps/mcp.js +39 -22
  208. package/dist/steps/metrics.d.ts +26 -10
  209. package/dist/steps/metrics.js +108 -108
  210. package/dist/steps/shell.d.ts +2 -0
  211. package/dist/steps/shell.js +26 -9
  212. package/dist/steps/signup.d.ts +7 -4
  213. package/dist/steps/signup.js +29 -20
  214. package/dist/steps/verify.d.ts +2 -2
  215. package/dist/steps/verify.js +118 -112
  216. package/package.json +40 -14
  217. package/assets/agents/docs-validator-agent.md +0 -490
  218. package/assets/agents/release-readiness-agent.md +0 -482
  219. package/assets/commands/agents/aristotle-analyst.md +0 -115
  220. package/assets/commands/agents/aristotle-explorer.md +0 -92
  221. package/assets/commands/agents/aristotle-forecaster.md +0 -114
  222. package/assets/commands/agents/aristotle-validator.md +0 -114
  223. package/assets/commands/agents/prompt-validate.md +0 -135
  224. package/assets/commands/agents/workflow-synthesis.md +0 -101
  225. package/assets/commands/workflows/aristotle.md +0 -543
  226. package/assets/commands/workflows/post-implementation.md +0 -577
  227. package/assets/commands/workflows/pre-implementation.md +0 -670
  228. package/assets/commands/workflows/prompt-audit.md +0 -754
  229. package/assets/commands/workflows/ship.md +0 -721
  230. package/dist/test/auth.test.d.ts +0 -1
  231. package/dist/test/auth.test.js +0 -43
  232. package/dist/test/config-io.test.d.ts +0 -1
  233. package/dist/test/config-io.test.js +0 -56
  234. package/dist/test/config-merger.test.d.ts +0 -1
  235. package/dist/test/config-merger.test.js +0 -94
  236. package/dist/test/detect.test.d.ts +0 -1
  237. package/dist/test/detect.test.js +0 -25
  238. package/dist/test/file-ops.test.d.ts +0 -1
  239. package/dist/test/file-ops.test.js +0 -100
  240. package/dist/test/hash.test.d.ts +0 -1
  241. package/dist/test/hash.test.js +0 -14
  242. package/dist/test/manifest.test.d.ts +0 -1
  243. package/dist/test/manifest.test.js +0 -78
  244. package/dist/test/paths.test.d.ts +0 -1
  245. package/dist/test/paths.test.js +0 -30
  246. package/dist/test/settings-merger.test.d.ts +0 -1
  247. package/dist/test/settings-merger.test.js +0 -167
  248. package/dist/test/shell-profile.test.d.ts +0 -1
  249. package/dist/test/shell-profile.test.js +0 -40
  250. package/dist/test/shell.test.d.ts +0 -1
  251. package/dist/test/shell.test.js +0 -71
  252. package/dist/test/signup.test.d.ts +0 -1
  253. package/dist/test/signup.test.js +0 -83
@@ -0,0 +1,90 @@
1
+ import { spawnSync } from "node:child_process";
2
+ export const CLI_PACKAGE = "@uluops/cli";
3
+ export const CLI_BIN = "ulu";
4
+ /** Default executor — shells out to `ulu` and `npm`. */
5
+ export const defaultExecutor = {
6
+ detect: () => {
7
+ const r = spawnSync(CLI_BIN, ["--version"], {
8
+ encoding: "utf-8",
9
+ stdio: ["ignore", "pipe", "ignore"],
10
+ });
11
+ if (r.status !== 0 || !r.stdout)
12
+ return null;
13
+ return r.stdout.trim() || null;
14
+ },
15
+ install: () => {
16
+ const r = spawnSync("npm", ["install", "-g", CLI_PACKAGE], {
17
+ encoding: "utf-8",
18
+ stdio: ["ignore", "pipe", "pipe"],
19
+ });
20
+ if (r.status === 0)
21
+ return { ok: true };
22
+ const stderr = (r.stderr ?? "").toString().trim();
23
+ const stdout = (r.stdout ?? "").toString().trim();
24
+ return { ok: false, error: stderr || stdout || `exit ${r.status}` };
25
+ },
26
+ uninstall: () => {
27
+ const r = spawnSync("npm", ["uninstall", "-g", CLI_PACKAGE], {
28
+ encoding: "utf-8",
29
+ stdio: ["ignore", "pipe", "pipe"],
30
+ });
31
+ if (r.status === 0)
32
+ return { ok: true };
33
+ const stderr = (r.stderr ?? "").toString().trim();
34
+ const stdout = (r.stdout ?? "").toString().trim();
35
+ return { ok: false, error: stderr || stdout || `exit ${r.status}` };
36
+ },
37
+ };
38
+ /**
39
+ * Install `@uluops/cli` globally if not already present.
40
+ *
41
+ * Designed to never abort the parent setup flow:
42
+ * - If `ulu` is already on PATH, returns `{ installed: true, alreadyPresent: true }` without touching npm.
43
+ * - If `npm install -g` fails (permissions, network, nvm prefix surprise), returns
44
+ * `{ installed: false, error }` so the caller can warn-and-continue.
45
+ * - In dryRun mode, no executor calls happen.
46
+ */
47
+ export async function installCli(opts) {
48
+ const executor = opts.executor ?? defaultExecutor;
49
+ const existing = executor.detect();
50
+ if (existing !== null) {
51
+ return { installed: true, version: existing, alreadyPresent: true };
52
+ }
53
+ if (opts.dryRun) {
54
+ return { installed: false, version: null, alreadyPresent: false };
55
+ }
56
+ const res = executor.install();
57
+ if (!res.ok) {
58
+ return {
59
+ installed: false,
60
+ version: null,
61
+ alreadyPresent: false,
62
+ error: res.error,
63
+ };
64
+ }
65
+ const after = executor.detect();
66
+ return {
67
+ installed: after !== null,
68
+ version: after,
69
+ alreadyPresent: false,
70
+ };
71
+ }
72
+ /**
73
+ * Uninstall `@uluops/cli` globally. Best-effort: if the package isn't there,
74
+ * npm exits non-zero on some platforms — we treat that as success.
75
+ */
76
+ export async function uninstallCli(opts) {
77
+ const executor = opts.executor ?? defaultExecutor;
78
+ if (opts.dryRun)
79
+ return { removed: true };
80
+ const before = executor.detect();
81
+ if (before === null)
82
+ return { removed: true };
83
+ const res = executor.uninstall();
84
+ if (res.ok)
85
+ return { removed: true };
86
+ const after = executor.detect();
87
+ if (after === null)
88
+ return { removed: true };
89
+ return { removed: false, error: res.error };
90
+ }
@@ -1,9 +1,14 @@
1
+ import type { HarnessProfile } from "../harnesses/index.js";
1
2
  export interface CommandsResult {
2
3
  agentCommands: number;
3
4
  workflowCommands: number;
5
+ pipelineCommands: number;
4
6
  skipped: number;
5
7
  removed: number;
6
8
  files: string[];
9
+ skippedReason?: string;
7
10
  }
8
- export declare function installCommands(localDefs: boolean, dryRun: boolean, existingManifestCommands?: string[]): Promise<CommandsResult>;
11
+ /** Install pre-rendered command files from harness-specific assets. */
12
+ export declare function installCommands(profile: HarnessProfile, localDefs: boolean, dryRun: boolean, existingManifestCommands?: string[]): Promise<CommandsResult>;
13
+ /** Remove previously installed command files by relative path. Returns count of successfully removed files. */
9
14
  export declare function uninstallCommands(files: string[], defsPath: string): Promise<number>;
@@ -1,13 +1,37 @@
1
1
  import { readdir, mkdir, unlink } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
- import { ASSETS_DIR, getCommandsDir } from "../lib/paths.js";
4
- import { copyIfChanged } from "../lib/file-ops.js";
5
- const SUBDIRS = ["agents", "workflows"];
6
- export async function installCommands(localDefs, dryRun, existingManifestCommands) {
7
- const srcBase = join(ASSETS_DIR, "commands");
8
- const destBase = getCommandsDir(localDefs);
3
+ import { ASSETS_DIR, findProjectRoot } from "../lib/paths.js";
4
+ import { copyIfChanged, unlinkFiles } from "../lib/file-ops.js";
5
+ const SUBDIRS = ["agents", "workflows", "pipelines"];
6
+ /** Install pre-rendered command files from harness-specific assets. */
7
+ export async function installCommands(profile, localDefs, dryRun, existingManifestCommands) {
8
+ const srcBase = join(ASSETS_DIR, profile.name, "commands");
9
+ const destBase = localDefs
10
+ ? join(await findProjectRoot(), "uluops", "commands")
11
+ : profile.paths.commandsDir;
12
+ // If no commands directory exists for this harness, skip gracefully
13
+ let hasSrcDir;
14
+ try {
15
+ await readdir(srcBase);
16
+ hasSrcDir = true;
17
+ }
18
+ catch {
19
+ hasSrcDir = false;
20
+ }
21
+ if (!hasSrcDir) {
22
+ return {
23
+ agentCommands: 0,
24
+ workflowCommands: 0,
25
+ pipelineCommands: 0,
26
+ skipped: 0,
27
+ removed: 0,
28
+ files: [],
29
+ skippedReason: "not-supported",
30
+ };
31
+ }
9
32
  let agentCommands = 0;
10
33
  let workflowCommands = 0;
34
+ let pipelineCommands = 0;
11
35
  let skipped = 0;
12
36
  const allFiles = [];
13
37
  for (const subdir of SUBDIRS) {
@@ -18,7 +42,7 @@ export async function installCommands(localDefs, dryRun, existingManifestCommand
18
42
  }
19
43
  let files;
20
44
  try {
21
- files = (await readdir(srcDir)).filter((f) => f.endsWith(".md"));
45
+ files = (await readdir(srcDir)).filter((f) => f.endsWith(".md") || f.endsWith(".toml"));
22
46
  }
23
47
  catch {
24
48
  continue;
@@ -29,8 +53,10 @@ export async function installCommands(localDefs, dryRun, existingManifestCommand
29
53
  if (result === "copied") {
30
54
  if (subdir === "agents")
31
55
  agentCommands++;
32
- else
56
+ else if (subdir === "workflows")
33
57
  workflowCommands++;
58
+ else
59
+ pipelineCommands++;
34
60
  }
35
61
  else {
36
62
  skipped++;
@@ -58,12 +84,13 @@ export async function installCommands(localDefs, dryRun, existingManifestCommand
58
84
  return {
59
85
  agentCommands,
60
86
  workflowCommands,
87
+ pipelineCommands,
61
88
  skipped,
62
89
  removed,
63
90
  files: allFiles,
64
91
  };
65
92
  }
93
+ /** Remove previously installed command files by relative path. Returns count of successfully removed files. */
66
94
  export async function uninstallCommands(files, defsPath) {
67
- const { unlinkFiles } = await import("../lib/file-ops.js");
68
95
  return unlinkFiles(join(defsPath, "commands"), files);
69
96
  }
@@ -1,3 +1,4 @@
1
+ import type { HarnessProfile } from "../harnesses/index.js";
1
2
  export interface Environment {
2
3
  os: "linux" | "darwin" | "win32";
3
4
  isWsl: boolean;
@@ -5,5 +6,7 @@ export interface Environment {
5
6
  shellProfile: string | null;
6
7
  nodeVersion: string;
7
8
  claudeHomeExists: boolean;
9
+ detectedHarnesses: HarnessProfile[];
8
10
  }
11
+ /** Detect the current environment: OS, shell, Node version, harnesses, and Claude home status. */
9
12
  export declare function detect(): Promise<Environment>;
@@ -1,16 +1,25 @@
1
1
  import { platform, release } from "node:os";
2
2
  import { access } from "node:fs/promises";
3
3
  import { getClaudeHome, getShellProfile } from "../lib/paths.js";
4
+ import { detectHarnesses } from "../harnesses/index.js";
4
5
  const SUPPORTED_PLATFORMS = new Set(["linux", "darwin", "win32"]);
6
+ /** Detect the current environment: OS, shell, Node version, harnesses, and Claude home status. */
5
7
  export async function detect() {
6
8
  const p = platform();
7
9
  if (!SUPPORTED_PLATFORMS.has(p)) {
8
10
  throw new Error(`Unsupported platform: ${p}. Expected linux, darwin, or win32.`);
9
11
  }
10
12
  const os = p;
13
+ if (os === "win32") {
14
+ throw new Error("Windows (native) is not supported. Please use WSL2 (Ubuntu) and run setup inside WSL.");
15
+ }
11
16
  const isWsl = os === "linux" && release().toLowerCase().includes("microsoft");
12
17
  const profile = getShellProfile();
13
18
  const nodeVersion = process.version;
19
+ const majorVersion = parseInt(nodeVersion.slice(1).split(".")[0] ?? "0", 10);
20
+ if (majorVersion < 20) {
21
+ throw new Error(`Unsupported Node.js version: ${nodeVersion}. @uluops/setup requires Node.js 20 or higher.`);
22
+ }
14
23
  let claudeHomeExists = false;
15
24
  try {
16
25
  await access(getClaudeHome());
@@ -19,6 +28,7 @@ export async function detect() {
19
28
  catch {
20
29
  // Does not exist
21
30
  }
31
+ const detectedHarnesses = detectHarnesses();
22
32
  return {
23
33
  os,
24
34
  isWsl,
@@ -26,5 +36,6 @@ export async function detect() {
26
36
  shellProfile: profile?.path ?? null,
27
37
  nodeVersion,
28
38
  claudeHomeExists,
39
+ detectedHarnesses,
29
40
  };
30
41
  }
@@ -1,6 +1,10 @@
1
+ import type { HarnessProfile } from "../harnesses/index.js";
1
2
  export interface McpResult {
2
3
  configPath: string;
3
4
  scope: "global" | "local";
5
+ packageWarnings: string[];
4
6
  }
5
- export declare function installMcp(apiKey: string, scope: "global" | "local", dryRun: boolean): Promise<McpResult>;
6
- export declare function uninstallMcp(configPath: string): Promise<void>;
7
+ /** Write UluOps MCP server entries into a harness's config file. */
8
+ export declare function installMcp(profile: HarnessProfile, apiKey: string, scope: "global" | "local", dryRun: boolean): Promise<McpResult>;
9
+ /** Remove UluOps MCP server entries from the harness config. */
10
+ export declare function uninstallMcp(profile: HarnessProfile, configPath: string): Promise<void>;
package/dist/steps/mcp.js CHANGED
@@ -1,40 +1,57 @@
1
- import { readFile, writeFile, access } from "node:fs/promises";
1
+ import { readFile, access } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
- import { readConfig, mergeUluopsMcp, removeUluopsMcp, writeConfig, } from "../lib/config-merger.js";
4
- import { getClaudeJsonPath, getLocalMcpPath } from "../lib/paths.js";
5
- export async function installMcp(apiKey, scope, dryRun) {
6
- const configPath = scope === "global" ? getClaudeJsonPath() : getLocalMcpPath();
7
- const config = await readConfig(configPath);
8
- const merged = mergeUluopsMcp(config, apiKey);
3
+ import { checkMcpPackageAvailability } from "../lib/config-merger.js";
4
+ import { findProjectRoot, getBackupDir } from "../lib/paths.js";
5
+ import { atomicWrite } from "../lib/atomic-write.js";
6
+ import { backupFile } from "../lib/file-ops.js";
7
+ /** Write UluOps MCP server entries into a harness's config file. */
8
+ export async function installMcp(profile, apiKey, scope, dryRun) {
9
+ const configPath = scope === "global"
10
+ ? profile.paths.globalMcpConfig
11
+ : join(await findProjectRoot(), profile.paths.localMcpConfig);
12
+ const config = await profile.mcpConfig.read(configPath);
13
+ const merged = profile.mcpConfig.merge(config, apiKey);
14
+ const packageWarnings = [];
15
+ const { missing } = await checkMcpPackageAvailability();
16
+ if (missing.length > 0) {
17
+ packageWarnings.push(`npm packages not found in registry: ${missing.join(", ")}. MCP servers may fail to start.`);
18
+ }
9
19
  if (!dryRun) {
10
- await writeConfig(configPath, merged);
20
+ // Backup before first write
21
+ await backupConfig(profile.name, configPath);
22
+ await profile.mcpConfig.write(configPath, merged);
11
23
  }
12
- // If local scope in a git repo, add .mcp.json to .gitignore
13
24
  if (scope === "local" && !dryRun) {
14
- await addToGitignore();
25
+ await addToGitignore(profile.paths.localMcpConfig);
15
26
  }
16
- return { configPath, scope };
27
+ return { configPath, scope, packageWarnings };
28
+ }
29
+ /** Remove UluOps MCP server entries from the harness config. */
30
+ export async function uninstallMcp(profile, configPath) {
31
+ await backupConfig(profile.name, configPath);
32
+ const config = await profile.mcpConfig.read(configPath);
33
+ const cleaned = profile.mcpConfig.remove(config);
34
+ await profile.mcpConfig.write(configPath, cleaned);
17
35
  }
18
- export async function uninstallMcp(configPath) {
19
- const config = await readConfig(configPath);
20
- const cleaned = removeUluopsMcp(config);
21
- await writeConfig(configPath, cleaned);
36
+ async function backupConfig(harnessName, configPath) {
37
+ await backupFile(configPath, getBackupDir(harnessName));
22
38
  }
23
- async function addToGitignore() {
24
- const gitignorePath = join(process.cwd(), ".gitignore");
39
+ async function addToGitignore(localConfigFilename) {
40
+ const root = await findProjectRoot();
41
+ const gitignorePath = join(root, ".gitignore");
25
42
  try {
26
- await access(join(process.cwd(), ".git"));
43
+ await access(join(root, ".git"));
27
44
  }
28
45
  catch {
29
- return; // Not a git repo
46
+ return;
30
47
  }
31
48
  try {
32
49
  const content = await readFile(gitignorePath, "utf-8");
33
- if (content.includes(".mcp.json"))
50
+ if (content.includes(localConfigFilename))
34
51
  return;
35
- await writeFile(gitignorePath, content.trimEnd() + "\n.mcp.json\n");
52
+ await atomicWrite(gitignorePath, content.trimEnd() + `\n${localConfigFilename}\n`);
36
53
  }
37
54
  catch {
38
- await writeFile(gitignorePath, ".mcp.json\n");
55
+ await atomicWrite(gitignorePath, `${localConfigFilename}\n`);
39
56
  }
40
57
  }
@@ -1,22 +1,38 @@
1
1
  /**
2
2
  * Metrics Step
3
3
  *
4
- * Installs agent-metrics tool files to ~/.claude/tools/agent-metrics/
5
- * and configures the SubagentStop hook in settings.json for auto-capture.
4
+ * Installs agent-metrics tool files and configures post-agent hooks.
5
+ * Only active for harnesses that support hooks (currently Claude Code only).
6
6
  */
7
- /** Where agent-metrics dist files are installed */
8
- export declare function getMetricsToolDir(): string;
9
- /** Path to Claude Code's settings.json */
10
- export declare function getSettingsPath(): string;
7
+ import type { HarnessProfile } from "../harnesses/index.js";
8
+ /**
9
+ * The hook command that runs on SubagentStop.
10
+ * @internal Exported for testing only — not part of the public API.
11
+ */
12
+ export declare function getHookCommand(profile: HarnessProfile): string;
11
13
  export interface MetricsResult {
12
14
  toolFilesCopied: number;
13
15
  hookConfigured: boolean;
16
+ /**
17
+ * Version of @uluops/agent-metrics whose dist was installed into the
18
+ * harness tree. Null when the metrics step was skipped or the source
19
+ * package.json could not be read.
20
+ */
21
+ hooksInstalledVersion: string | null;
22
+ skippedReason?: string;
14
23
  }
15
24
  /**
16
- * Install agent-metrics: copy tool files and configure SubagentStop hook.
25
+ * Read the installed agent-metrics version from the harness tree.
26
+ * Returns null when the file is missing or unparseable.
27
+ * Exported so verify.ts can detect drift between installed and source.
28
+ */
29
+ export declare function readInstalledMetricsVersion(toolDir: string): Promise<string | null>;
30
+ /**
31
+ * Install agent-metrics: copy tool files and configure hook.
32
+ * Skips entirely if the harness doesn't support hooks.
17
33
  */
18
- export declare function installMetrics(dryRun: boolean): Promise<MetricsResult>;
34
+ export declare function installMetrics(profile: HarnessProfile, dryRun: boolean): Promise<MetricsResult>;
19
35
  /**
20
- * Uninstall agent-metrics: remove hook from settings and optionally remove tool files.
36
+ * Uninstall agent-metrics: remove hook and tool files.
21
37
  */
22
- export declare function uninstallMetrics(dryRun: boolean): Promise<void>;
38
+ export declare function uninstallMetrics(profile: HarnessProfile, dryRun: boolean): Promise<void>;