@uluops/setup 0.4.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 (211) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -50
  3. package/assets/auto-tracker-save.mjs +142 -0
  4. package/assets/{agents → claude-code/agents}/api-contract-validator-agent.md +9 -228
  5. package/assets/{agents → claude-code/agents}/aristotle-analyst-agent.md +51 -4
  6. package/assets/{agents → claude-code/agents}/aristotle-explorer-agent.md +6 -2
  7. package/assets/{agents → claude-code/agents}/aristotle-forecaster-agent.md +15 -230
  8. package/assets/{agents → claude-code/agents}/aristotle-validator-agent.md +12 -252
  9. package/assets/{agents → claude-code/agents}/assumption-excavator-agent.md +21 -247
  10. package/assets/{agents → claude-code/agents}/code-auditor-agent.md +12 -255
  11. package/assets/{agents → claude-code/agents}/code-optimizer-agent.md +15 -236
  12. package/assets/{agents → claude-code/agents}/code-validator-agent.md +31 -300
  13. package/assets/claude-code/agents/docs-validator-agent.md +472 -0
  14. package/assets/{agents → claude-code/agents}/frontend-validator-agent.md +15 -258
  15. package/assets/{agents → claude-code/agents}/mcp-validator-agent.md +8 -252
  16. package/assets/{agents → claude-code/agents}/pre-implementation-architect-agent.md +8 -224
  17. package/assets/{agents → claude-code/agents}/prompt-engineer-agent.md +57 -290
  18. package/assets/{agents → claude-code/agents}/prompt-pattern-analyzer-agent.md +10 -225
  19. package/assets/{agents → claude-code/agents}/prompt-quality-validator-agent.md +11 -249
  20. package/assets/{agents → claude-code/agents}/public-interface-validator-agent.md +15 -268
  21. package/assets/claude-code/agents/release-readiness-agent.md +495 -0
  22. package/assets/{agents → claude-code/agents}/security-analyst-agent.md +236 -480
  23. package/assets/{agents → claude-code/agents}/test-architect-agent.md +16 -259
  24. package/assets/{agents → claude-code/agents}/type-safety-validator-agent.md +23 -266
  25. package/assets/{agents → claude-code/agents}/workflow-synthesis-agent.md +23 -226
  26. package/assets/{commands → claude-code/commands}/agents/anxiety-reader.md +12 -15
  27. package/assets/{commands → claude-code/commands}/agents/api-contract.md +156 -136
  28. package/assets/{commands → claude-code/commands}/agents/architect.md +156 -136
  29. package/assets/claude-code/commands/agents/aristotle-analyst.md +157 -0
  30. package/assets/claude-code/commands/agents/aristotle-explorer.md +157 -0
  31. package/assets/claude-code/commands/agents/aristotle-forecaster.md +157 -0
  32. package/assets/claude-code/commands/agents/aristotle-validator.md +157 -0
  33. package/assets/{commands → claude-code/commands}/agents/assumption-excavator.md +49 -7
  34. package/assets/{commands → claude-code/commands}/agents/audit.md +156 -137
  35. package/assets/{commands → claude-code/commands}/agents/docs-validate.md +156 -134
  36. package/assets/{commands → claude-code/commands}/agents/frontend.md +156 -136
  37. package/assets/{commands → claude-code/commands}/agents/mcp-validate.md +156 -137
  38. package/assets/{commands → claude-code/commands}/agents/optimize.md +156 -134
  39. package/assets/{commands → claude-code/commands}/agents/pattern-analyzer.md +150 -127
  40. package/assets/{commands → claude-code/commands}/agents/prompt-quality.md +155 -135
  41. package/assets/claude-code/commands/agents/prompt-validate.md +155 -0
  42. package/assets/{commands → claude-code/commands}/agents/public-interface.md +156 -135
  43. package/assets/{commands → claude-code/commands}/agents/release.md +156 -136
  44. package/assets/{commands → claude-code/commands}/agents/security.md +156 -138
  45. package/assets/{commands → claude-code/commands}/agents/test-review.md +156 -137
  46. package/assets/{commands → claude-code/commands}/agents/type-safety.md +156 -136
  47. package/assets/{commands/agents/code-validate.md → claude-code/commands/agents/validate.md} +156 -135
  48. package/assets/claude-code/commands/agents/workflow-synthesis.md +157 -0
  49. package/assets/{commands → claude-code/commands}/pipelines/aristotle.md +8 -8
  50. package/assets/{commands → claude-code/commands}/pipelines/ship.md +8 -8
  51. package/assets/claude-code/commands/workflows/post-implementation.md +60 -0
  52. package/assets/claude-code/commands/workflows/pre-implementation.md +46 -0
  53. package/assets/{commands → claude-code/commands}/workflows/prompt-audit.md +2 -2
  54. package/assets/codex/agents/anxiety-reader-agent.toml +462 -0
  55. package/assets/codex/agents/api-contract-validator-agent.toml +738 -0
  56. package/assets/codex/agents/aristotle-analyst-agent.toml +750 -0
  57. package/assets/codex/agents/aristotle-explorer-agent.toml +155 -0
  58. package/assets/codex/agents/aristotle-forecaster-agent.toml +449 -0
  59. package/assets/codex/agents/aristotle-validator-agent.toml +424 -0
  60. package/assets/codex/agents/assumption-excavator-agent.toml +1126 -0
  61. package/assets/codex/agents/code-auditor-agent.toml +815 -0
  62. package/assets/codex/agents/code-optimizer-agent.toml +652 -0
  63. package/assets/codex/agents/code-validator-agent.toml +573 -0
  64. package/assets/codex/agents/docs-validator-agent.toml +468 -0
  65. package/assets/codex/agents/frontend-validator-agent.toml +598 -0
  66. package/assets/codex/agents/mcp-validator-agent.toml +580 -0
  67. package/assets/codex/agents/pre-implementation-architect-agent.toml +817 -0
  68. package/assets/codex/agents/prompt-engineer-agent.toml +922 -0
  69. package/assets/codex/agents/prompt-pattern-analyzer-agent.toml +689 -0
  70. package/assets/codex/agents/prompt-quality-validator-agent.toml +777 -0
  71. package/assets/codex/agents/public-interface-validator-agent.toml +695 -0
  72. package/assets/codex/agents/release-readiness-agent.toml +491 -0
  73. package/assets/codex/agents/security-analyst-agent.toml +847 -0
  74. package/assets/codex/agents/test-architect-agent.toml +615 -0
  75. package/assets/codex/agents/type-safety-validator-agent.toml +686 -0
  76. package/assets/codex/agents/workflow-synthesis-agent.toml +631 -0
  77. package/assets/gemini-cli/agents/anxiety-reader-agent.md +470 -0
  78. package/assets/gemini-cli/agents/api-contract-validator-agent.md +747 -0
  79. package/assets/gemini-cli/agents/aristotle-analyst-agent.md +758 -0
  80. package/assets/gemini-cli/agents/aristotle-explorer-agent.md +163 -0
  81. package/assets/gemini-cli/agents/aristotle-forecaster-agent.md +457 -0
  82. package/assets/gemini-cli/agents/aristotle-validator-agent.md +432 -0
  83. package/assets/gemini-cli/agents/assumption-excavator-agent.md +1134 -0
  84. package/assets/gemini-cli/agents/code-auditor-agent.md +827 -0
  85. package/assets/gemini-cli/agents/code-optimizer-agent.md +661 -0
  86. package/assets/gemini-cli/agents/code-validator-agent.md +582 -0
  87. package/assets/gemini-cli/agents/docs-validator-agent.md +477 -0
  88. package/assets/gemini-cli/agents/frontend-validator-agent.md +610 -0
  89. package/assets/gemini-cli/agents/mcp-validator-agent.md +589 -0
  90. package/assets/gemini-cli/agents/pre-implementation-architect-agent.md +826 -0
  91. package/assets/gemini-cli/agents/prompt-engineer-agent.md +931 -0
  92. package/assets/gemini-cli/agents/prompt-pattern-analyzer-agent.md +698 -0
  93. package/assets/gemini-cli/agents/prompt-quality-validator-agent.md +786 -0
  94. package/assets/gemini-cli/agents/public-interface-validator-agent.md +707 -0
  95. package/assets/gemini-cli/agents/release-readiness-agent.md +500 -0
  96. package/assets/gemini-cli/agents/security-analyst-agent.md +859 -0
  97. package/assets/gemini-cli/agents/test-architect-agent.md +624 -0
  98. package/assets/gemini-cli/agents/type-safety-validator-agent.md +695 -0
  99. package/assets/gemini-cli/agents/workflow-synthesis-agent.md +639 -0
  100. package/assets/gemini-cli/commands/agents/anxiety-reader.toml +155 -0
  101. package/assets/gemini-cli/commands/agents/api-contract.toml +154 -0
  102. package/assets/gemini-cli/commands/agents/architect.toml +154 -0
  103. package/assets/gemini-cli/commands/agents/aristotle-analyst.toml +155 -0
  104. package/assets/gemini-cli/commands/agents/aristotle-explorer.toml +155 -0
  105. package/assets/gemini-cli/commands/agents/aristotle-forecaster.toml +155 -0
  106. package/assets/gemini-cli/commands/agents/aristotle-validator.toml +155 -0
  107. package/assets/gemini-cli/commands/agents/assumption-excavator.toml +155 -0
  108. package/assets/gemini-cli/commands/agents/audit.toml +154 -0
  109. package/assets/gemini-cli/commands/agents/docs-validate.toml +154 -0
  110. package/assets/gemini-cli/commands/agents/frontend.toml +154 -0
  111. package/assets/gemini-cli/commands/agents/mcp-validate.toml +154 -0
  112. package/assets/gemini-cli/commands/agents/optimize.toml +154 -0
  113. package/assets/gemini-cli/commands/agents/pattern-analyzer.toml +148 -0
  114. package/assets/gemini-cli/commands/agents/prompt-quality.toml +153 -0
  115. package/assets/gemini-cli/commands/agents/prompt-validate.toml +153 -0
  116. package/assets/gemini-cli/commands/agents/public-interface.toml +154 -0
  117. package/assets/gemini-cli/commands/agents/release.toml +154 -0
  118. package/assets/gemini-cli/commands/agents/security.toml +154 -0
  119. package/assets/gemini-cli/commands/agents/test-review.toml +154 -0
  120. package/assets/gemini-cli/commands/agents/type-safety.toml +154 -0
  121. package/assets/gemini-cli/commands/agents/validate.toml +154 -0
  122. package/assets/gemini-cli/commands/agents/workflow-synthesis.toml +155 -0
  123. package/assets/gemini-cli/commands/pipelines/aristotle.toml +139 -0
  124. package/assets/gemini-cli/commands/pipelines/ship.toml +184 -0
  125. package/assets/gemini-cli/commands/workflows/post-implementation.toml +56 -0
  126. package/assets/gemini-cli/commands/workflows/pre-implementation.toml +42 -0
  127. package/assets/gemini-cli/commands/workflows/prompt-audit.toml +40 -0
  128. package/assets/opencode/agents/anxiety-reader-agent.md +472 -0
  129. package/assets/opencode/agents/api-contract-validator-agent.md +749 -0
  130. package/assets/opencode/agents/aristotle-analyst-agent.md +760 -0
  131. package/assets/opencode/agents/aristotle-explorer-agent.md +164 -0
  132. package/assets/opencode/agents/aristotle-forecaster-agent.md +459 -0
  133. package/assets/opencode/agents/aristotle-validator-agent.md +434 -0
  134. package/assets/opencode/agents/assumption-excavator-agent.md +1136 -0
  135. package/assets/opencode/agents/code-auditor-agent.md +826 -0
  136. package/assets/opencode/agents/code-optimizer-agent.md +663 -0
  137. package/assets/opencode/agents/code-validator-agent.md +584 -0
  138. package/assets/opencode/agents/docs-validator-agent.md +479 -0
  139. package/assets/opencode/agents/frontend-validator-agent.md +609 -0
  140. package/assets/opencode/agents/mcp-validator-agent.md +591 -0
  141. package/assets/opencode/agents/pre-implementation-architect-agent.md +828 -0
  142. package/assets/opencode/agents/prompt-engineer-agent.md +933 -0
  143. package/assets/opencode/agents/prompt-pattern-analyzer-agent.md +700 -0
  144. package/assets/opencode/agents/prompt-quality-validator-agent.md +788 -0
  145. package/assets/opencode/agents/public-interface-validator-agent.md +706 -0
  146. package/assets/opencode/agents/release-readiness-agent.md +502 -0
  147. package/assets/opencode/agents/security-analyst-agent.md +858 -0
  148. package/assets/opencode/agents/test-architect-agent.md +626 -0
  149. package/assets/opencode/agents/type-safety-validator-agent.md +697 -0
  150. package/assets/opencode/agents/workflow-synthesis-agent.md +641 -0
  151. package/dist/cli.js +12 -414
  152. package/dist/commands/helpers.d.ts +73 -0
  153. package/dist/commands/helpers.js +274 -0
  154. package/dist/commands/setup.d.ts +13 -0
  155. package/dist/commands/setup.js +93 -0
  156. package/dist/commands/uninstall.d.ts +3 -0
  157. package/dist/commands/uninstall.js +126 -0
  158. package/dist/commands/verify.d.ts +1 -0
  159. package/dist/commands/verify.js +28 -0
  160. package/dist/harnesses/claude-code.d.ts +1 -1
  161. package/dist/harnesses/claude-code.js +3 -1
  162. package/dist/harnesses/codex.js +6 -5
  163. package/dist/harnesses/gemini-cli.d.ts +4 -8
  164. package/dist/harnesses/gemini-cli.js +47 -21
  165. package/dist/harnesses/index.d.ts +10 -1
  166. package/dist/harnesses/index.js +11 -2
  167. package/dist/harnesses/opencode.d.ts +1 -1
  168. package/dist/harnesses/opencode.js +15 -6
  169. package/dist/harnesses/types.d.ts +19 -0
  170. package/dist/harnesses/types.js +2 -0
  171. package/dist/lib/asset-catalog.js +2 -2
  172. package/dist/lib/config-merger.d.ts +2 -1
  173. package/dist/lib/config-merger.js +12 -4
  174. package/dist/lib/file-ops.d.ts +5 -0
  175. package/dist/lib/file-ops.js +18 -3
  176. package/dist/lib/hash.d.ts +1 -1
  177. package/dist/lib/hash.js +2 -2
  178. package/dist/lib/manifest.d.ts +30 -1
  179. package/dist/lib/manifest.js +5 -7
  180. package/dist/lib/paths.d.ts +16 -1
  181. package/dist/lib/paths.js +31 -3
  182. package/dist/lib/settings-merger.d.ts +24 -9
  183. package/dist/lib/settings-merger.js +57 -22
  184. package/dist/lib/version.d.ts +2 -0
  185. package/dist/lib/version.js +10 -0
  186. package/dist/steps/agents.d.ts +1 -2
  187. package/dist/steps/agents.js +7 -18
  188. package/dist/steps/cli.d.ts +53 -0
  189. package/dist/steps/cli.js +90 -0
  190. package/dist/steps/commands.d.ts +1 -1
  191. package/dist/steps/commands.js +20 -71
  192. package/dist/steps/detect.js +4 -0
  193. package/dist/steps/mcp.js +7 -15
  194. package/dist/steps/metrics.d.ts +12 -0
  195. package/dist/steps/metrics.js +52 -22
  196. package/dist/steps/shell.js +11 -1
  197. package/dist/steps/signup.d.ts +2 -2
  198. package/dist/steps/signup.js +9 -12
  199. package/dist/steps/verify.js +47 -8
  200. package/package.json +12 -11
  201. package/assets/agents/docs-validator-agent.md +0 -490
  202. package/assets/agents/release-readiness-agent.md +0 -482
  203. package/assets/commands/agents/aristotle-analyst.md +0 -116
  204. package/assets/commands/agents/aristotle-explorer.md +0 -93
  205. package/assets/commands/agents/aristotle-forecaster.md +0 -115
  206. package/assets/commands/agents/aristotle-validator.md +0 -115
  207. package/assets/commands/agents/prompt-validate.md +0 -136
  208. package/assets/commands/agents/workflow-synthesis.md +0 -102
  209. package/assets/commands/workflows/post-implementation.md +0 -577
  210. package/assets/commands/workflows/pre-implementation.md +0 -670
  211. /package/assets/{agents → claude-code/agents}/anxiety-reader-agent.md +0 -0
package/dist/cli.js CHANGED
@@ -1,418 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from "commander";
3
3
  import chalk from "chalk";
4
- import { readFile, readdir } from "node:fs/promises";
5
- import { join, dirname } from "node:path";
6
- import { fileURLToPath } from "node:url";
7
- import { detect } from "./steps/detect.js";
8
- import { resolveApiKey } from "./steps/auth.js";
9
- import { signup } from "./steps/signup.js";
10
- import { installMcp, uninstallMcp } from "./steps/mcp.js";
11
- import { installAgents, uninstallAgents } from "./steps/agents.js";
12
- import { installCommands, uninstallCommands } from "./steps/commands.js";
13
- import { writeShellExport, removeShellExport } from "./steps/shell.js";
14
- import { verify } from "./steps/verify.js";
15
- import { installMetrics, uninstallMetrics } from "./steps/metrics.js";
16
- import { probeHookSupport } from "./lib/settings-merger.js";
17
- import { loadManifest, saveManifest, deleteManifest, validateManifest, } from "./lib/manifest.js";
18
- import { ASSETS_DIR, findProjectRoot } from "./lib/paths.js";
19
- import { getHealthTimeout } from "./lib/health.js";
20
- import { ok, warn, fail, info, printSetupSummary, printAgentList } from "./lib/display.js";
21
- import { getProfile, resolveHarnessName, listHarnesses, HarnessNotTestedError, } from "./harnesses/index.js";
22
- const __dirname = dirname(fileURLToPath(import.meta.url));
23
- async function getVersion() {
24
- const pkgPath = join(__dirname, "..", "package.json");
25
- const pkg = JSON.parse(await readFile(pkgPath, "utf-8"));
26
- return pkg.version;
27
- }
28
- async function runSetup(opts) {
29
- const version = await getVersion();
30
- const profile = getProfile(opts.harness);
31
- console.log();
32
- console.log(` ${chalk.dim("⟨u⟩")} ${chalk.cyan.bold("ulu")}${chalk.bold("·ops")}`);
33
- console.log(` ${chalk.dim("operating intelligence as infrastructure")}`);
34
- console.log();
35
- console.log(` Setup v${version} — ${chalk.bold(profile.displayName)}`);
36
- console.log();
37
- if (opts.dryRun) {
38
- info(chalk.dim("(dry run — no changes will be made)\n"));
39
- }
40
- const { env, apiKey } = await initContext(opts);
41
- console.log();
42
- // Load existing manifest for update detection
43
- const existingManifest = await loadManifest();
44
- const existingHarness = existingManifest?.harnesses[profile.name];
45
- if (existingManifest && existingManifest.version !== version) {
46
- info(`Updating ${chalk.dim(existingManifest.version)} → ${chalk.green(version)}`);
47
- console.log();
48
- }
49
- else if (existingHarness) {
50
- info(chalk.dim(`Already at v${version} — checking for changes`));
51
- console.log();
52
- }
53
- // Check for conflicts on first install for this harness
54
- if (!existingHarness && !opts.yes && !opts.dryRun) {
55
- await checkConflicts(profile, opts.localDefs);
56
- }
57
- const mcpResult = await configureMcpStep(profile, apiKey, opts);
58
- const agentsResult = await installAgentsDefs(profile, opts, existingHarness?.agents);
59
- const commandsResult = await installCommandsDefs(profile, opts, existingHarness?.commands);
60
- const metricsResult = await configureMetricsStep(profile, opts);
61
- await runHealthCheck(opts);
62
- const shellModified = await configureShell(env, apiKey, opts);
63
- // Save manifest
64
- if (!opts.dryRun) {
65
- const now = new Date().toISOString();
66
- const harnessEntry = {
67
- installedAt: now,
68
- setupVersion: version,
69
- mcpScope: opts.scope,
70
- mcpConfigPath: mcpResult.configPath,
71
- defsScope: opts.localDefs ? "local" : "global",
72
- defsPath: opts.localDefs
73
- ? join(await findProjectRoot(), "uluops")
74
- : profile.paths.home,
75
- agents: agentsResult.files,
76
- commands: commandsResult.files,
77
- hooksInstalled: metricsResult.hookConfigured,
78
- };
79
- const manifest = existingManifest ?? {
80
- version,
81
- installedAt: now,
82
- shellModified: false,
83
- harnesses: {},
84
- };
85
- manifest.version = version;
86
- manifest.installedAt = now;
87
- manifest.shellModified = shellModified || manifest.shellModified;
88
- manifest.harnesses[profile.name] = harnessEntry;
89
- await saveManifest(manifest);
90
- }
91
- await printSetupSummary({
92
- profile,
93
- agentCount: agentsResult.files.length,
94
- commandCount: commandsResult.files.length,
95
- apiKey,
96
- });
97
- }
98
- // --- extracted helpers ---
99
- /** Resolve API key via flag, env, file, signup, or interactive prompt. Returns env detection + key. */
100
- async function initContext(opts) {
101
- const env = await detect();
102
- let apiKey;
103
- try {
104
- if (opts.signup) {
105
- info("Create your UluOps account\n");
106
- const auth = await signup();
107
- apiKey = auth.apiKey;
108
- ok(`Account created (${auth.email})`);
109
- ok(`API key generated`);
110
- }
111
- else {
112
- const auth = await resolveApiKey({
113
- apiKeyFlag: opts.apiKey,
114
- skipValidation: opts.skipValidation,
115
- interactive: !opts.yes && !opts.apiKey && !process.env["ULUOPS_API_KEY"],
116
- });
117
- apiKey = auth.apiKey;
118
- if (auth.email)
119
- ok(`Key validated (${auth.email})`);
120
- else if (opts.skipValidation)
121
- ok("Key accepted (validation skipped)");
122
- else
123
- ok("Key validated");
124
- }
125
- }
126
- catch (err) {
127
- fail(err instanceof Error ? err.message : String(err));
128
- process.exit(1);
129
- }
130
- return { env, apiKey };
131
- }
132
- /** Write MCP server entries to harness config and report warnings. */
133
- async function configureMcpStep(profile, apiKey, opts) {
134
- const res = await installMcp(profile, apiKey, opts.scope, opts.dryRun);
135
- ok(`MCP config → ${res.configPath} (2 servers)`);
136
- for (const w of res.packageWarnings)
137
- warn(w);
138
- return res;
139
- }
140
- /** Copy agent definitions from assets to harness directory. */
141
- async function installAgentsDefs(profile, opts, prev) {
142
- const res = await installAgents(profile, opts.localDefs, opts.dryRun, prev);
143
- const parts = [];
144
- if (res.copied > 0)
145
- parts.push(`${res.copied} copied`);
146
- if (res.skipped > 0)
147
- parts.push(`${res.skipped} unchanged`);
148
- if (res.removed > 0)
149
- parts.push(`${res.removed} removed`);
150
- const dest = opts.localDefs
151
- ? "./uluops/agents/"
152
- : `${profile.paths.agentsDir.replace(process.env["HOME"] ?? "", "~")}/`;
153
- ok(`${res.files.length} agents → ${dest}${parts.length ? ` (${parts.join(", ")})` : ""}`);
154
- return res;
155
- }
156
- /** Copy slash-command definitions from assets (Claude Code only). */
157
- async function installCommandsDefs(profile, opts, prev) {
158
- const res = await installCommands(profile, opts.localDefs, opts.dryRun, prev);
159
- if (res.skippedReason === "not-supported") {
160
- info(chalk.dim(`Commands not yet supported for ${profile.displayName} (coming soon)`));
161
- return res;
162
- }
163
- const total = res.agentCommands + res.workflowCommands + res.pipelineCommands;
164
- const parts = [];
165
- if (total > 0)
166
- parts.push(`${total} copied`);
167
- if (res.skipped > 0)
168
- parts.push(`${res.skipped} unchanged`);
169
- if (res.removed > 0)
170
- parts.push(`${res.removed} removed`);
171
- const dest = opts.localDefs
172
- ? "./uluops/commands/"
173
- : `${profile.paths.commandsDir.replace(process.env["HOME"] ?? "", "~")}/`;
174
- ok(`${res.files.length} commands → ${dest}${parts.length ? ` (${parts.join(", ")})` : ""}`);
175
- return res;
176
- }
177
- /** Install agent-metrics hook and tool files (Claude Code only). */
178
- async function configureMetricsStep(profile, opts) {
179
- if (!profile.hooks) {
180
- info(chalk.dim(`Metrics hooks not supported for ${profile.displayName}`));
181
- return { toolFilesCopied: 0, hookConfigured: false };
182
- }
183
- const probe = probeHookSupport();
184
- if (probe.warning)
185
- warn(probe.warning);
186
- const res = await installMetrics(profile, opts.dryRun);
187
- if (res.hookConfigured) {
188
- const parts = [];
189
- if (res.toolFilesCopied > 0)
190
- parts.push(`${res.toolFilesCopied} files`);
191
- parts.push("hook configured");
192
- const toolPath = profile.paths.toolsDir?.replace(process.env["HOME"] ?? "", "~");
193
- ok(`Agent metrics → ${toolPath}/ (${parts.join(", ")})`);
194
- }
195
- else {
196
- warn("Agent metrics hook not configured (tool files not found)");
197
- }
198
- return res;
199
- }
200
- /** Ping tracker and registry health endpoints. */
201
- async function runHealthCheck(opts) {
202
- if (!opts.skipValidation && !opts.dryRun) {
203
- try {
204
- const [trackerOk, registryOk] = await Promise.all([
205
- checkEndpoint("https://api.uluops.ai/api/v1/health"),
206
- checkEndpoint("https://api.uluops.ai/api/v1/registry/health"),
207
- ]);
208
- if (trackerOk && registryOk)
209
- ok("Health check passed — both APIs reachable");
210
- else
211
- warn("Some APIs unreachable (MCP tools may have limited functionality)");
212
- }
213
- catch {
214
- warn("Health check skipped (network issue)");
215
- }
216
- }
217
- }
218
- /** Optionally write ULUOPS_API_KEY export to shell profile. */
219
- async function configureShell(env, apiKey, opts) {
220
- let modified = false;
221
- if (opts.shell && env.shellProfile) {
222
- if (!opts.yes && !opts.dryRun) {
223
- const confirmed = await confirmShellWrite(env.shellProfile);
224
- if (!confirmed) {
225
- warn("Skipped writing API key to shell profile");
226
- return false;
227
- }
228
- }
229
- await writeShellExport(env.shellProfile, apiKey, opts.dryRun);
230
- ok(`ULUOPS_API_KEY added to ${env.shellProfile}`);
231
- warn("API key stored in plaintext in shell profile. Consider rotating if shared machine.");
232
- modified = true;
233
- }
234
- else if (opts.shell) {
235
- warn("--shell requested but no supported shell detected ($SHELL). Skipping.");
236
- }
237
- return modified;
238
- }
239
- /** Interactive y/N confirmation before writing API key to shell profile. */
240
- async function confirmShellWrite(profilePath) {
241
- const readline = await import("node:readline/promises");
242
- const rl = readline.createInterface({
243
- input: process.stdin,
244
- output: process.stdout,
245
- });
246
- const answer = await rl.question(`Write ULUOPS_API_KEY to ${profilePath}? (y/N) `);
247
- rl.close();
248
- return answer.trim().toLowerCase() === "y";
249
- }
250
- async function runUninstall(opts) {
251
- const version = await getVersion();
252
- console.log();
253
- console.log(` ${chalk.dim("⟨u⟩")} ${chalk.cyan.bold("ulu")}${chalk.bold("·ops")} ${chalk.red("Uninstall")} v${version}`);
254
- console.log();
255
- if (opts.dryRun) {
256
- info(chalk.dim("(dry run — no changes will be made)\n"));
257
- }
258
- const manifest = await loadManifest();
259
- if (!manifest) {
260
- warn("No manifest found — nothing to uninstall.");
261
- return;
262
- }
263
- const validation = await validateManifest(manifest);
264
- if (!validation.valid) {
265
- fail("Manifest references paths that no longer exist:");
266
- for (const err of validation.errors)
267
- info(` ${err}`);
268
- console.log();
269
- info("Uninstall may be incomplete. Proceeding with what's available.");
270
- console.log();
271
- }
272
- if (validation.warnings.length > 0) {
273
- for (const w of validation.warnings)
274
- warn(w);
275
- console.log();
276
- }
277
- for (const [harnessName, hm] of Object.entries(manifest.harnesses)) {
278
- let profile;
279
- try {
280
- profile = getProfile(harnessName);
281
- }
282
- catch {
283
- warn(`Unknown harness "${harnessName}" in manifest — skipping`);
284
- continue;
285
- }
286
- info(chalk.bold(profile.displayName));
287
- if (!opts.dryRun) {
288
- const agentCount = await uninstallAgents(hm.agents, hm.defsPath);
289
- ok(`Removed ${agentCount} agent(s)`);
290
- }
291
- else {
292
- ok(`Would remove ${hm.agents.length} agent(s)`);
293
- }
294
- if (hm.commands.length > 0) {
295
- if (!opts.dryRun) {
296
- const cmdCount = await uninstallCommands(hm.commands, hm.defsPath);
297
- ok(`Removed ${cmdCount} command(s)`);
298
- }
299
- else {
300
- ok(`Would remove ${hm.commands.length} command(s)`);
301
- }
302
- }
303
- if (!opts.dryRun) {
304
- try {
305
- await uninstallMcp(profile, hm.mcpConfigPath);
306
- ok(`Removed MCP servers from ${hm.mcpConfigPath}`);
307
- }
308
- catch {
309
- warn(`Could not remove MCP servers from ${hm.mcpConfigPath}`);
310
- }
311
- }
312
- else {
313
- ok(`Would remove MCP servers from ${hm.mcpConfigPath}`);
314
- }
315
- if (hm.hooksInstalled) {
316
- if (!opts.dryRun) {
317
- await uninstallMetrics(profile, false);
318
- ok("Removed agent-metrics hook and tool files");
319
- }
320
- else {
321
- ok("Would remove agent-metrics hook and tool files");
322
- }
323
- }
324
- console.log();
325
- }
326
- // Remove shell export
327
- if (manifest.shellModified) {
328
- const { getShellProfile } = await import("./lib/paths.js");
329
- const shellProfile = getShellProfile();
330
- if (shellProfile && !opts.dryRun) {
331
- await removeShellExport(shellProfile.path);
332
- ok(`Removed export from ${shellProfile.path}`);
333
- }
334
- else if (shellProfile) {
335
- ok(`Would remove export from ${shellProfile.path}`);
336
- }
337
- }
338
- if (!opts.dryRun) {
339
- await deleteManifest();
340
- ok("Manifest deleted");
341
- }
342
- console.log();
343
- info("UluOps has been removed. Restart your harness to complete.");
344
- console.log();
345
- }
346
- async function runVerify() {
347
- const version = await getVersion();
348
- console.log();
349
- console.log(` ${chalk.dim("⟨u⟩")} ${chalk.cyan.bold("ulu")}${chalk.bold("·ops")} Installation Check v${version}`);
350
- console.log();
351
- const result = await verify();
352
- for (const check of result.checks) {
353
- if (check.passed) {
354
- ok(check.label);
355
- }
356
- else {
357
- fail(`${check.label}${check.detail ? ` — ${check.detail}` : ""}`);
358
- }
359
- }
360
- console.log();
361
- if (result.ok) {
362
- info(chalk.green("All checks passed."));
363
- }
364
- else {
365
- info(chalk.red("Some checks failed. Run npx @uluops/setup to fix."));
366
- }
367
- console.log();
368
- process.exit(result.ok ? 0 : 1);
369
- }
370
- /** Warn if existing agent files will be overwritten and prompt for confirmation. */
371
- async function checkConflicts(profile, localDefs) {
372
- const destDir = localDefs
373
- ? join(await findProjectRoot(), "uluops", "agents")
374
- : profile.paths.agentsDir;
375
- const srcDir = join(ASSETS_DIR, "agents", profile.name);
376
- let existingFiles;
377
- let assetFiles;
378
- try {
379
- existingFiles = await readdir(destDir);
380
- assetFiles = await readdir(srcDir);
381
- }
382
- catch {
383
- return;
384
- }
385
- const conflicts = assetFiles.filter((f) => existingFiles.includes(f));
386
- if (conflicts.length === 0)
387
- return;
388
- warn(`Found ${conflicts.length} existing agents that match UluOps definitions:`);
389
- for (const f of conflicts.slice(0, 5)) {
390
- info(` ${f}`);
391
- }
392
- if (conflicts.length > 5) {
393
- info(` ... and ${conflicts.length - 5} more`);
394
- }
395
- console.log();
396
- info("These will be overwritten.");
397
- console.log();
398
- const { confirm } = await import("@inquirer/prompts");
399
- const proceed = await confirm({ message: "Continue?", default: true });
400
- if (!proceed) {
401
- process.exit(0);
402
- }
403
- }
404
- /** Fetch a URL and return true if the response is OK, false on any failure. */
405
- async function checkEndpoint(url) {
406
- try {
407
- const res = await fetch(url, {
408
- signal: AbortSignal.timeout(getHealthTimeout()),
409
- });
410
- return res.ok;
411
- }
412
- catch {
413
- return false;
414
- }
415
- }
4
+ import { info, printAgentList } from "./lib/display.js";
5
+ import { getVersion } from "./lib/version.js";
6
+ import { resolveHarnessName, listHarnesses, HarnessNotTestedError, } from "./harnesses/index.js";
7
+ import { runSetup } from "./commands/setup.js";
8
+ import { runUninstall } from "./commands/uninstall.js";
9
+ import { runVerify } from "./commands/verify.js";
416
10
  async function main() {
417
11
  const version = await getVersion();
418
12
  const program = new Command()
@@ -422,9 +16,11 @@ async function main() {
422
16
  .option("--api-key <key>", "API key (skip prompt)")
423
17
  .option("--signup", "Create a new account (email + password, no browser)")
424
18
  .option("--harness <name>", `Target harness: ${listHarnesses().join(", ")} (aliases: claude, oc, gemini)`, "claude-code")
425
- .option("--scope <mode>", 'MCP config scope: "global" or "local"', "global")
426
- .option("--local-defs", "Save agents/commands locally instead of harness global dir", false)
19
+ .option("--scope <mode>", 'MCP connectivity scope: "global" (~/.claude.json) or "local" (.mcp.json)', "global")
20
+ .option("--local-defs", "Save agents/commands locally (./uluops/) for project isolation", false)
427
21
  .option("--shell", "Write API key export to shell profile", false)
22
+ .option("--with-cli", "Install @uluops/cli globally without prompting")
23
+ .option("--no-cli", "Skip @uluops/cli install without prompting (takes precedence over --with-cli)")
428
24
  .option("--skip-validation", "Accept API key without verifying", false)
429
25
  .option("--list", "Show available agents and workflows without installing")
430
26
  .option("--verify", "Check existing installation health")
@@ -463,6 +59,8 @@ async function main() {
463
59
  scope,
464
60
  localDefs: opts.localDefs,
465
61
  shell: opts.shell,
62
+ withCli: opts.withCli,
63
+ cli: opts.cli,
466
64
  skipValidation: opts.skipValidation,
467
65
  dryRun: opts.dryRun,
468
66
  yes: opts.yes,
@@ -0,0 +1,73 @@
1
+ import { detect } from "../steps/detect.js";
2
+ import type { McpResult } from "../steps/mcp.js";
3
+ import type { AgentsResult } from "../steps/agents.js";
4
+ import type { CommandsResult } from "../steps/commands.js";
5
+ import type { MetricsResult } from "../steps/metrics.js";
6
+ import type { CliExecutor, CliInstallResult } from "../steps/cli.js";
7
+ import type { HarnessProfile } from "../harnesses/index.js";
8
+ /** Resolve API key via flag, env, file, signup, or interactive prompt. Returns env detection + key. */
9
+ export declare function initContext(opts: {
10
+ apiKey?: string;
11
+ signup: boolean;
12
+ skipValidation: boolean;
13
+ yes: boolean;
14
+ }): Promise<{
15
+ env: Awaited<ReturnType<typeof detect>>;
16
+ apiKey: string;
17
+ }>;
18
+ /** Write MCP server entries to harness config and report warnings. */
19
+ export declare function configureMcpStep(profile: HarnessProfile, apiKey: string, opts: {
20
+ scope: "global" | "local";
21
+ dryRun: boolean;
22
+ }): Promise<McpResult>;
23
+ /** Copy agent definitions from assets to harness directory. */
24
+ export declare function installAgentsDefs(profile: HarnessProfile, opts: {
25
+ localDefs: boolean;
26
+ dryRun: boolean;
27
+ }, prev?: string[]): Promise<AgentsResult>;
28
+ /** Copy slash-command definitions from assets (Claude Code only). */
29
+ export declare function installCommandsDefs(profile: HarnessProfile, opts: {
30
+ localDefs: boolean;
31
+ dryRun: boolean;
32
+ }, prev?: string[]): Promise<CommandsResult>;
33
+ /** Install agent-metrics hook and tool files (Claude Code only). */
34
+ export declare function configureMetricsStep(profile: HarnessProfile, opts: {
35
+ dryRun: boolean;
36
+ }): Promise<MetricsResult>;
37
+ /**
38
+ * Decide whether to install `@uluops/cli` globally and do it (or not).
39
+ *
40
+ * Decision matrix:
41
+ * - `--no-cli` (opts.cli === false) → skip, no prompt
42
+ * - `--with-cli` (opts.withCli === true) → install, no prompt
43
+ * - Neither flag + non-interactive (--yes / --api-key / no TTY) → skip
44
+ * - Neither flag + interactive → prompt (default Y)
45
+ *
46
+ * Returns null when the step did not run (skipped). Returns a `CliInstallResult`
47
+ * when an install attempt was made, with details for the manifest.
48
+ */
49
+ export declare function configureCliStep(opts: {
50
+ withCli?: boolean;
51
+ cli?: boolean;
52
+ yes: boolean;
53
+ apiKey?: string;
54
+ dryRun: boolean;
55
+ executor?: CliExecutor;
56
+ }): Promise<CliInstallResult | null>;
57
+ /** Ping tracker and registry health endpoints. */
58
+ export declare function runHealthCheck(opts: {
59
+ skipValidation: boolean;
60
+ dryRun: boolean;
61
+ }): Promise<void>;
62
+ /** Optionally write ULUOPS_API_KEY export to shell profile. */
63
+ export declare function configureShell(env: {
64
+ shellProfile: string | null;
65
+ }, apiKey: string, opts: {
66
+ shell: boolean;
67
+ yes: boolean;
68
+ dryRun: boolean;
69
+ }): Promise<boolean>;
70
+ /** Interactive y/N confirmation before writing API key to shell profile. */
71
+ export declare function confirmShellWrite(profilePath: string): Promise<boolean>;
72
+ /** Warn if existing agent files will be overwritten and prompt for confirmation. */
73
+ export declare function checkConflicts(profile: HarnessProfile, localDefs: boolean): Promise<void>;