@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,54 @@
1
+ /**
2
+ * Codex Harness Profile (Scaffold)
3
+ *
4
+ * Paths and metadata are verified from vendor docs.
5
+ * Codex uses TOML config with `mcp_servers` key (nested tables).
6
+ * Agent definitions are TOML, not markdown.
7
+ * Skills use a different path ($HOME/.agents/skills/) than agents (~/.codex/agents/).
8
+ *
9
+ * NOT YET TESTED with UluOps agents. McpConfigStrategy throws
10
+ * until integration testing is complete.
11
+ *
12
+ * Will require `smol-toml` dependency when fully implemented.
13
+ */
14
+ import { homedir } from "node:os";
15
+ import { join } from "node:path";
16
+ import { HarnessNotTestedError } from "./types.js";
17
+ class CodexMcpConfig {
18
+ async read() {
19
+ throw new HarnessNotTestedError("Codex (agent format compatibility under review)");
20
+ }
21
+ merge() {
22
+ throw new HarnessNotTestedError("Codex (agent format compatibility under review)");
23
+ }
24
+ remove() {
25
+ throw new HarnessNotTestedError("Codex (agent format compatibility under review)");
26
+ }
27
+ async write() {
28
+ throw new HarnessNotTestedError("Codex (agent format compatibility under review)");
29
+ }
30
+ check() {
31
+ throw new HarnessNotTestedError("Codex (MCP config check not supported)");
32
+ }
33
+ }
34
+ const home = join(homedir(), ".codex");
35
+ export const codexProfile = {
36
+ name: "codex",
37
+ displayName: "Codex",
38
+ status: "experimental",
39
+ homeDir: home,
40
+ agentFormat: "toml",
41
+ factoryTarget: "codex",
42
+ agentExtension: ".toml",
43
+ paths: {
44
+ home,
45
+ globalMcpConfig: join(home, "config.toml"),
46
+ localMcpConfig: ".codex/config.toml",
47
+ agentsDir: join(home, "agents"),
48
+ commandsDir: join(homedir(), ".agents", "skills"),
49
+ settingsPath: null,
50
+ toolsDir: null,
51
+ },
52
+ mcpConfig: new CodexMcpConfig(),
53
+ hooks: null,
54
+ };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Gemini CLI Harness Profile
3
+ *
4
+ * Paths and metadata are verified from vendor docs.
5
+ * MCP config uses `mcpServers` key (same shape as Claude Code)
6
+ * but at a different file path (~/.gemini/settings.json).
7
+ *
8
+ * Gemini CLI requires `trust: true` in MCP server config to
9
+ * allow automatic tool execution without confirmation prompts.
10
+ */
11
+ import { type HarnessProfile } from "./types.js";
12
+ export declare const geminiCliProfile: HarnessProfile;
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Gemini CLI Harness Profile
3
+ *
4
+ * Paths and metadata are verified from vendor docs.
5
+ * MCP config uses `mcpServers` key (same shape as Claude Code)
6
+ * but at a different file path (~/.gemini/settings.json).
7
+ *
8
+ * Gemini CLI requires `trust: true` in MCP server config to
9
+ * allow automatic tool execution without confirmation prompts.
10
+ */
11
+ import { homedir } from "node:os";
12
+ import { join } from "node:path";
13
+ import { ULUOPS_SERVERS, } from "./types.js";
14
+ import { readConfig, mergeUluopsMcp, removeUluopsMcp, writeConfig, } from "../lib/config-merger.js";
15
+ import { readSettings, writeSettings, mergeUluopsHook, removeUluopsHook, hasUluopsHook, } from "../lib/settings-merger.js";
16
+ class GeminiMcpConfig {
17
+ async read(path) {
18
+ return readConfig(path);
19
+ }
20
+ merge(config, apiKey) {
21
+ // Gemini CLI requires trust: true for a smooth experience
22
+ return mergeUluopsMcp(config, apiKey, true);
23
+ }
24
+ remove(config) {
25
+ return removeUluopsMcp(config);
26
+ }
27
+ async write(path, config) {
28
+ await writeConfig(path, config);
29
+ }
30
+ check(config) {
31
+ const servers = config["mcpServers"];
32
+ if (!servers)
33
+ return false;
34
+ return ULUOPS_SERVERS.every((name) => name in servers);
35
+ }
36
+ }
37
+ class GeminiHooks {
38
+ static HOOK_TYPE = "AfterTool";
39
+ static MATCHER = "invoke_agent";
40
+ async install(settingsPath, hookCommand, dryRun) {
41
+ if (dryRun)
42
+ return true;
43
+ const settings = await readSettings(settingsPath);
44
+ const merged = mergeUluopsHook(settings, hookCommand, GeminiHooks.HOOK_TYPE, GeminiHooks.MATCHER);
45
+ await writeSettings(settingsPath, merged);
46
+ return true;
47
+ }
48
+ async remove(settingsPath, dryRun) {
49
+ if (dryRun)
50
+ return;
51
+ const settings = await readSettings(settingsPath);
52
+ const cleaned = removeUluopsHook(settings, GeminiHooks.HOOK_TYPE);
53
+ await writeSettings(settingsPath, cleaned);
54
+ }
55
+ async check(settingsPath) {
56
+ const settings = await readSettings(settingsPath);
57
+ return hasUluopsHook(settings, GeminiHooks.HOOK_TYPE);
58
+ }
59
+ }
60
+ const home = join(homedir(), ".gemini");
61
+ export const geminiCliProfile = {
62
+ name: "gemini-cli",
63
+ displayName: "Gemini CLI",
64
+ status: "stable",
65
+ homeDir: home,
66
+ agentFormat: "markdown",
67
+ factoryTarget: "gemini-cli",
68
+ agentExtension: ".md",
69
+ paths: {
70
+ home,
71
+ globalMcpConfig: join(home, "settings.json"),
72
+ localMcpConfig: ".gemini/settings.json",
73
+ agentsDir: join(home, "agents"),
74
+ commandsDir: join(home, "commands"),
75
+ settingsPath: join(home, "settings.json"),
76
+ toolsDir: join(home, "tools", "agent-metrics"),
77
+ },
78
+ mcpConfig: new GeminiMcpConfig(),
79
+ hooks: new GeminiHooks(),
80
+ };
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Harness Registry
3
+ *
4
+ * Central registry for harness profiles. Resolves names/aliases
5
+ * and detects installed harnesses.
6
+ */
7
+ import type { HarnessProfile } from "./types.js";
8
+ export type { HarnessProfile, HarnessPaths, McpConfigStrategy, HookStrategy, } from "./types.js";
9
+ export { ConfigParseError, HarnessNotTestedError, } from "./types.js";
10
+ export declare const ALL_PROFILES: readonly HarnessProfile[];
11
+ /** Resolve a harness name or alias to a canonical name. */
12
+ export declare function resolveHarnessName(input: string): string;
13
+ /** Get a harness profile by name or alias. Throws if not found. */
14
+ export declare function getProfile(name: string): HarnessProfile;
15
+ /**
16
+ * Detect which harnesses are installed by probing home directories.
17
+ *
18
+ * Excludes experimental profiles even when their home dir is present:
19
+ * auto-detection should never return a profile that will throw
20
+ * HarnessNotTestedError on use. Users can still opt in with
21
+ * `--harness <name>`, which goes through getProfile() and surfaces the
22
+ * explicit error message — the relational promise "in the detected
23
+ * list = safe to install" is preserved.
24
+ */
25
+ export declare function detectHarnesses(): HarnessProfile[];
26
+ /** List all available harness names (not aliases). */
27
+ export declare function listHarnesses(): string[];
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Harness Registry
3
+ *
4
+ * Central registry for harness profiles. Resolves names/aliases
5
+ * and detects installed harnesses.
6
+ */
7
+ import { existsSync } from "node:fs";
8
+ import { claudeCodeProfile } from "./claude-code.js";
9
+ import { opencodeProfile } from "./opencode.js";
10
+ import { geminiCliProfile } from "./gemini-cli.js";
11
+ import { codexProfile } from "./codex.js";
12
+ export { ConfigParseError, HarnessNotTestedError, } from "./types.js";
13
+ export const ALL_PROFILES = [
14
+ claudeCodeProfile,
15
+ opencodeProfile,
16
+ geminiCliProfile,
17
+ codexProfile,
18
+ ];
19
+ const aliases = new Map([
20
+ ["claude", "claude-code"],
21
+ ["oc", "opencode"],
22
+ ["gemini", "gemini-cli"],
23
+ ]);
24
+ /** Resolve a harness name or alias to a canonical name. */
25
+ export function resolveHarnessName(input) {
26
+ return aliases.get(input) ?? input;
27
+ }
28
+ /** Get a harness profile by name or alias. Throws if not found. */
29
+ export function getProfile(name) {
30
+ const resolved = resolveHarnessName(name);
31
+ const profile = ALL_PROFILES.find((p) => p.name === resolved);
32
+ if (!profile) {
33
+ const available = ALL_PROFILES.map((p) => p.name).join(", ");
34
+ throw new Error(`Unknown harness "${name}". Available: ${available}`);
35
+ }
36
+ return profile;
37
+ }
38
+ /**
39
+ * Detect which harnesses are installed by probing home directories.
40
+ *
41
+ * Excludes experimental profiles even when their home dir is present:
42
+ * auto-detection should never return a profile that will throw
43
+ * HarnessNotTestedError on use. Users can still opt in with
44
+ * `--harness <name>`, which goes through getProfile() and surfaces the
45
+ * explicit error message — the relational promise "in the detected
46
+ * list = safe to install" is preserved.
47
+ */
48
+ export function detectHarnesses() {
49
+ return ALL_PROFILES.filter((p) => p.status === "stable" && existsSync(p.paths.home));
50
+ }
51
+ /** List all available harness names (not aliases). */
52
+ export function listHarnesses() {
53
+ return ALL_PROFILES.map((p) => p.name);
54
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * OpenCode Harness Profile
3
+ *
4
+ * OpenCode uses JSON/JSONC config with a structurally different MCP shape:
5
+ * - `mcp` key (not `mcpServers`)
6
+ * - `type: "local"` required
7
+ * - `command` as flat array (not separate command/args)
8
+ * - `environment` (not `env`)
9
+ * - `enabled: true` and `timeout: 30000` recommended
10
+ *
11
+ * Verified working shape from ~/opencode.jsonc (2026-04-30).
12
+ */
13
+ import { type HarnessProfile } from "./types.js";
14
+ export declare const opencodeProfile: HarnessProfile;
@@ -0,0 +1,139 @@
1
+ /**
2
+ * OpenCode Harness Profile
3
+ *
4
+ * OpenCode uses JSON/JSONC config with a structurally different MCP shape:
5
+ * - `mcp` key (not `mcpServers`)
6
+ * - `type: "local"` required
7
+ * - `command` as flat array (not separate command/args)
8
+ * - `environment` (not `env`)
9
+ * - `enabled: true` and `timeout: 30000` recommended
10
+ *
11
+ * Verified working shape from ~/opencode.jsonc (2026-04-30).
12
+ */
13
+ import { readFile } from "node:fs/promises";
14
+ import { homedir } from "node:os";
15
+ import { join, isAbsolute } from "node:path";
16
+ import { parse as parseJsonc } from "jsonc-parser";
17
+ import { ULUOPS_SERVERS, ConfigParseError } from "./types.js";
18
+ import { atomicWrite } from "../lib/atomic-write.js";
19
+ class OpenCodeMcpConfig {
20
+ /** Maps requested path → actual resolved path (for .jsonc fallback). */
21
+ resolvedPaths = new Map();
22
+ async read(path) {
23
+ // Try the given path, then probe for .jsonc variant
24
+ let raw = null;
25
+ const candidates = [path, path.replace(/\.json$/, ".jsonc")];
26
+ for (const p of candidates) {
27
+ try {
28
+ raw = await readFile(p, "utf-8");
29
+ this.resolvedPaths.set(path, p);
30
+ break;
31
+ }
32
+ catch {
33
+ // Try next
34
+ }
35
+ }
36
+ if (raw === null) {
37
+ this.resolvedPaths.set(path, path);
38
+ return {};
39
+ }
40
+ try {
41
+ return parseJsonc(raw);
42
+ }
43
+ catch (err) {
44
+ throw new ConfigParseError(path, err);
45
+ }
46
+ }
47
+ merge(config, apiKey) {
48
+ const raw = config["mcp"];
49
+ const existing = (typeof raw === "object" && raw !== null ? raw : {});
50
+ const tracker = {
51
+ type: "local",
52
+ command: ["npx", "-y", "uluops-tracker-mcp-client"],
53
+ enabled: true,
54
+ timeout: 30000,
55
+ environment: {
56
+ ULUOPS_BASE_URL: "https://api.uluops.ai/api/v1",
57
+ ULUOPS_API_KEY: apiKey,
58
+ },
59
+ };
60
+ const registry = {
61
+ type: "local",
62
+ command: ["npx", "-y", "uluops-registry-mcp-client"],
63
+ enabled: true,
64
+ timeout: 30000,
65
+ environment: {
66
+ ULUOPS_REGISTRY_URL: "https://api.uluops.ai/api/v1/registry",
67
+ ULUOPS_API_KEY: apiKey,
68
+ },
69
+ };
70
+ return {
71
+ ...config,
72
+ mcp: {
73
+ ...existing,
74
+ "uluops-tracker": tracker,
75
+ "uluops-registry": registry,
76
+ },
77
+ };
78
+ }
79
+ remove(config) {
80
+ if (!config["mcp"] || typeof config["mcp"] !== "object")
81
+ return config;
82
+ const mcp = { ...config["mcp"] };
83
+ for (const name of ULUOPS_SERVERS) {
84
+ delete mcp[name];
85
+ }
86
+ const result = { ...config };
87
+ if (Object.keys(mcp).length === 0) {
88
+ delete result["mcp"];
89
+ }
90
+ else {
91
+ result["mcp"] = mcp;
92
+ }
93
+ return result;
94
+ }
95
+ async write(path, config) {
96
+ // Write back to the path that was actually read (may be .jsonc)
97
+ const target = this.resolvedPaths.get(path) ?? path;
98
+ await atomicWrite(target, JSON.stringify(config, null, 2) + "\n", {
99
+ mode: 0o600,
100
+ });
101
+ }
102
+ check(config) {
103
+ const mcp = config["mcp"];
104
+ if (!mcp)
105
+ return false;
106
+ return ULUOPS_SERVERS.every((name) => name in mcp);
107
+ }
108
+ }
109
+ const xdgConfig = (() => {
110
+ const env = process.env["XDG_CONFIG_HOME"];
111
+ if (env) {
112
+ if (!isAbsolute(env) || env.includes("..")) {
113
+ throw new Error(`XDG_CONFIG_HOME must be an absolute path without traversal: ${env}`);
114
+ }
115
+ return env;
116
+ }
117
+ return join(homedir(), ".config");
118
+ })();
119
+ const home = join(xdgConfig, "opencode");
120
+ export const opencodeProfile = {
121
+ name: "opencode",
122
+ displayName: "OpenCode",
123
+ status: "stable",
124
+ homeDir: home,
125
+ agentFormat: "markdown",
126
+ factoryTarget: "opencode",
127
+ agentExtension: ".md",
128
+ paths: {
129
+ home,
130
+ globalMcpConfig: join(home, "opencode.json"),
131
+ localMcpConfig: "opencode.json",
132
+ agentsDir: join(home, "agents"),
133
+ commandsDir: join(home, "commands"),
134
+ settingsPath: null,
135
+ toolsDir: null,
136
+ },
137
+ mcpConfig: new OpenCodeMcpConfig(),
138
+ hooks: null,
139
+ };
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Harness Type System
3
+ *
4
+ * Defines the abstraction layer for multi-harness support.
5
+ * Each harness (Claude Code, OpenCode, Codex, Gemini CLI) implements
6
+ * these interfaces to encapsulate its config format, paths, and capabilities.
7
+ */
8
+ /**
9
+ * Maturity status of a harness profile.
10
+ *
11
+ * - `"stable"` — implementation is tested end-to-end and safe to auto-detect.
12
+ * detectHarnesses() returns these.
13
+ * - `"experimental"` — scaffold only; throws HarnessNotTestedError on most
14
+ * operations. getProfile() still resolves these (so `--harness <name>`
15
+ * surfaces the explicit error), but detectHarnesses() filters them out so
16
+ * automatic install never picks an unusable profile.
17
+ */
18
+ export type HarnessStatus = "stable" | "experimental";
19
+ /** Static definition of a harness — no runtime state. */
20
+ export interface HarnessProfile {
21
+ /** Canonical name (e.g., 'claude-code', 'opencode', 'codex', 'gemini-cli') */
22
+ readonly name: string;
23
+ /** Display name for CLI output (e.g., 'Claude Code', 'OpenCode') */
24
+ readonly displayName: string;
25
+ /**
26
+ * Maturity status. Experimental profiles are excluded from auto-detection
27
+ * but still accept an explicit `--harness` flag so users can opt in to
28
+ * the not-yet-tested error surface.
29
+ */
30
+ readonly status: HarnessStatus;
31
+ /** Home directory for this harness */
32
+ readonly homeDir: string;
33
+ /** Agent definition format */
34
+ readonly agentFormat: "markdown" | "toml";
35
+ /** Target name for definition-factory rendering */
36
+ readonly factoryTarget: string;
37
+ /** File extension for agent definitions */
38
+ readonly agentExtension: ".md" | ".toml";
39
+ /** Paths for this harness */
40
+ readonly paths: HarnessPaths;
41
+ /** MCP config strategy for this harness's config format */
42
+ readonly mcpConfig: McpConfigStrategy;
43
+ /** Hook operations (null if harness doesn't support post-agent hooks) */
44
+ readonly hooks: HookStrategy | null;
45
+ }
46
+ export interface HarnessPaths {
47
+ /** Home dir (e.g., ~/.claude/) */
48
+ readonly home: string;
49
+ /** Global MCP config (e.g., ~/.claude.json, ~/.config/opencode/opencode.json) */
50
+ readonly globalMcpConfig: string;
51
+ /** Project-scoped MCP config filename (e.g., .mcp.json, opencode.json) — resolved relative to project root */
52
+ readonly localMcpConfig: string;
53
+ /** Global agent definitions dir */
54
+ readonly agentsDir: string;
55
+ /** Global commands/skills dir */
56
+ readonly commandsDir: string;
57
+ /** Settings file path, or null if harness has no settings file */
58
+ readonly settingsPath: string | null;
59
+ /** Tool installation dir, or null if harness has no tool installation */
60
+ readonly toolsDir: string | null;
61
+ }
62
+ /**
63
+ * Encapsulates format-specific MCP config read/merge/write.
64
+ * Claude Code/Gemini use JSON with `mcpServers` key.
65
+ * OpenCode uses JSON/JSONC with `mcp` key and different entry shape.
66
+ * Codex uses TOML with `mcp_servers` key.
67
+ */
68
+ export interface McpConfigStrategy {
69
+ /** Read existing config from disk. Returns parsed object. Returns {} if file missing. Throws ConfigParseError if malformed. */
70
+ read(path: string): Promise<Record<string, unknown>>;
71
+ /** Merge UluOps MCP servers into the parsed config. Format-aware. */
72
+ merge(config: Record<string, unknown>, apiKey: string): Record<string, unknown>;
73
+ /** Remove UluOps MCP servers from the parsed config. */
74
+ remove(config: Record<string, unknown>): Record<string, unknown>;
75
+ /** Write config back to disk in the harness's native format. Uses atomic write. */
76
+ write(path: string, config: Record<string, unknown>): Promise<void>;
77
+ /** Check if UluOps MCP servers are present in the parsed config. */
78
+ check(config: Record<string, unknown>): boolean;
79
+ }
80
+ /**
81
+ * Hook strategy for harnesses that support post-agent execution hooks.
82
+ * Currently only Claude Code supports this (SubagentStop event).
83
+ */
84
+ export interface HookStrategy {
85
+ /**
86
+ * Install the agent-metrics post-execution hook.
87
+ * @returns true if hook was installed or updated, false if already current (no-op).
88
+ * In dry-run mode, returns true (would install) without writing.
89
+ */
90
+ install(settingsPath: string, hookCommand: string, dryRun: boolean): Promise<boolean>;
91
+ /** Remove the hook. No-op if not installed. */
92
+ remove(settingsPath: string, dryRun: boolean): Promise<void>;
93
+ /** Check if hook is currently installed. */
94
+ check(settingsPath: string): Promise<boolean>;
95
+ }
96
+ /** MCP server names installed by UluOps setup. Shared across all harnesses. */
97
+ export declare const ULUOPS_SERVERS: readonly ["uluops-tracker", "uluops-registry"];
98
+ /** Thrown when a harness config file cannot be parsed. */
99
+ export declare class ConfigParseError extends Error {
100
+ readonly path: string;
101
+ constructor(path: string, cause: unknown);
102
+ }
103
+ /** Thrown when a harness is scaffolded but not yet tested/implemented. */
104
+ export declare class HarnessNotTestedError extends Error {
105
+ constructor(harnessName: string);
106
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Harness Type System
3
+ *
4
+ * Defines the abstraction layer for multi-harness support.
5
+ * Each harness (Claude Code, OpenCode, Codex, Gemini CLI) implements
6
+ * these interfaces to encapsulate its config format, paths, and capabilities.
7
+ */
8
+ /** MCP server names installed by UluOps setup. Shared across all harnesses. */
9
+ export const ULUOPS_SERVERS = ["uluops-tracker", "uluops-registry"];
10
+ /** Thrown when a harness config file cannot be parsed. */
11
+ export class ConfigParseError extends Error {
12
+ path;
13
+ constructor(path, cause) {
14
+ const msg = cause instanceof Error ? cause.message : String(cause);
15
+ super(`Failed to parse config at ${path}: ${msg}`);
16
+ this.path = path;
17
+ this.name = "ConfigParseError";
18
+ }
19
+ }
20
+ /** Thrown when a harness is scaffolded but not yet tested/implemented. */
21
+ export class HarnessNotTestedError extends Error {
22
+ constructor(harnessName) {
23
+ super(`${harnessName} harness is not yet tested. Use --harness claude-code or --harness opencode.`);
24
+ this.name = "HarnessNotTestedError";
25
+ }
26
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Agent Transform
3
+ *
4
+ * Transforms Claude Code agent markdown to other harness formats at install time.
5
+ * Single source of truth: assets/agents/ contains Claude Code format only.
6
+ * Each harness gets its frontmatter rewritten; the body is identical across all targets.
7
+ */
8
+ /**
9
+ * Transform a Claude Code agent markdown file to a target harness format.
10
+ * Returns the original content for claude-code; rewrites frontmatter for others.
11
+ */
12
+ export declare function transformAgent(markdown: string, harnessName: string): string;
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Agent Transform
3
+ *
4
+ * Transforms Claude Code agent markdown to other harness formats at install time.
5
+ * Single source of truth: assets/agents/ contains Claude Code format only.
6
+ * Each harness gets its frontmatter rewritten; the body is identical across all targets.
7
+ */
8
+ function parseAgentMarkdown(markdown) {
9
+ const first = markdown.indexOf("---");
10
+ if (first === -1)
11
+ return { frontmatter: {}, body: markdown };
12
+ const second = markdown.indexOf("---", first + 3);
13
+ if (second === -1)
14
+ return { frontmatter: {}, body: markdown };
15
+ const fmBlock = markdown.substring(first + 3, second).trim();
16
+ const body = markdown.substring(second + 3);
17
+ const frontmatter = {};
18
+ for (const line of fmBlock.split("\n")) {
19
+ const colonIdx = line.indexOf(":");
20
+ if (colonIdx === -1)
21
+ continue;
22
+ const key = line.substring(0, colonIdx).trim();
23
+ const value = line.substring(colonIdx + 1).trim();
24
+ if (key)
25
+ frontmatter[key] = value;
26
+ }
27
+ return { frontmatter, body };
28
+ }
29
+ // --- Tool mapping ---
30
+ const GEMINI_TOOL_MAP = {
31
+ Read: "read_file",
32
+ Grep: "grep_search",
33
+ Glob: "glob",
34
+ Bash: "run_shell_command",
35
+ };
36
+ const OPENCODE_PERMISSION_MAP = {
37
+ Read: { key: "read", level: "allow" },
38
+ Grep: { key: "grep", level: "allow" },
39
+ Glob: { key: "glob", level: "allow" },
40
+ Bash: { key: "bash", level: "ask" },
41
+ };
42
+ function parseToolsList(toolsStr) {
43
+ // Handle both "Read, Grep, Glob" and "[Read, Grep, Glob]" formats
44
+ return toolsStr
45
+ .replace(/^\[|\]$/g, "")
46
+ .split(",")
47
+ .map((t) => t.trim())
48
+ .filter(Boolean);
49
+ }
50
+ // --- Harness-specific frontmatter builders ---
51
+ function buildGeminiFrontmatter(fm) {
52
+ const lines = [];
53
+ lines.push(`name: ${fm["name"] ?? "unknown"}`);
54
+ const desc = fm["description"] ?? "";
55
+ // Quote description if it contains YAML-special chars
56
+ if (/[:#{}[\],&*?|>!%@`"']/.test(desc) || desc === "") {
57
+ lines.push(`description: "${desc.replace(/"/g, '\\"')}"`);
58
+ }
59
+ else {
60
+ lines.push(`description: ${desc}`);
61
+ }
62
+ lines.push("kind: local");
63
+ // Map tools
64
+ const tools = parseToolsList(fm["tools"] ?? "");
65
+ const geminiTools = tools
66
+ .map((t) => GEMINI_TOOL_MAP[t])
67
+ .filter(Boolean);
68
+ if (geminiTools.length > 0) {
69
+ lines.push("tools:");
70
+ for (const t of geminiTools) {
71
+ lines.push(` - ${t}`);
72
+ }
73
+ }
74
+ lines.push("model: gemini-3-preview");
75
+ lines.push("temperature: 0.2");
76
+ lines.push("max_turns: 30");
77
+ lines.push("timeout_mins: 10");
78
+ return lines.join("\n");
79
+ }
80
+ function buildOpenCodeFrontmatter(fm) {
81
+ const lines = [];
82
+ lines.push(`name: ${fm["name"] ?? "unknown"}`);
83
+ const desc = fm["description"] ?? "";
84
+ if (/[:#{}[\],&*?|>!%@`"']/.test(desc) || desc === "") {
85
+ lines.push(`description: "${desc.replace(/"/g, '\\"')}"`);
86
+ }
87
+ else {
88
+ lines.push(`description: ${desc}`);
89
+ }
90
+ lines.push("mode: subagent");
91
+ // Map tools to permissions
92
+ const tools = parseToolsList(fm["tools"] ?? "");
93
+ const permissions = {};
94
+ for (const t of tools) {
95
+ const mapping = OPENCODE_PERMISSION_MAP[t];
96
+ if (mapping)
97
+ permissions[mapping.key] = mapping.level;
98
+ }
99
+ if (Object.keys(permissions).length > 0) {
100
+ permissions["list"] = "allow";
101
+ lines.push("permission:");
102
+ for (const [key, level] of Object.entries(permissions)) {
103
+ lines.push(` ${key}: ${level}`);
104
+ }
105
+ }
106
+ lines.push("model: openai/gpt-5");
107
+ return lines.join("\n");
108
+ }
109
+ // --- Public API ---
110
+ /**
111
+ * Transform a Claude Code agent markdown file to a target harness format.
112
+ * Returns the original content for claude-code; rewrites frontmatter for others.
113
+ */
114
+ export function transformAgent(markdown, harnessName) {
115
+ if (harnessName === "claude-code")
116
+ return markdown;
117
+ const { frontmatter, body } = parseAgentMarkdown(markdown);
118
+ let newFrontmatter;
119
+ if (harnessName === "gemini-cli") {
120
+ newFrontmatter = buildGeminiFrontmatter(frontmatter);
121
+ }
122
+ else if (harnessName === "opencode") {
123
+ newFrontmatter = buildOpenCodeFrontmatter(frontmatter);
124
+ }
125
+ else {
126
+ return markdown; // Unknown harness — pass through unchanged
127
+ }
128
+ return `---\n${newFrontmatter}\n---${body}`;
129
+ }
@@ -0,0 +1,9 @@
1
+ export interface CommandEntry {
2
+ name: string;
3
+ description: string;
4
+ model: string;
5
+ }
6
+ /** Get all agent command entries from assets. */
7
+ export declare function getAgentCommands(): Promise<CommandEntry[]>;
8
+ /** Get all workflow command entries from assets. */
9
+ export declare function getWorkflowCommands(): Promise<CommandEntry[]>;