@uluops/setup 0.2.0 → 0.4.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 (107) hide show
  1. package/README.md +56 -53
  2. package/assets/agents/anxiety-reader-agent.md +464 -0
  3. package/assets/commands/agents/anxiety-reader.md +160 -0
  4. package/assets/commands/agents/api-contract.md +1 -0
  5. package/assets/commands/agents/architect.md +1 -0
  6. package/assets/commands/agents/aristotle-analyst.md +1 -0
  7. package/assets/commands/agents/aristotle-explorer.md +1 -0
  8. package/assets/commands/agents/aristotle-forecaster.md +1 -0
  9. package/assets/commands/agents/aristotle-validator.md +1 -0
  10. package/assets/commands/agents/assumption-excavator.md +1 -0
  11. package/assets/commands/agents/audit.md +1 -0
  12. package/assets/commands/agents/{validate.md → code-validate.md} +6 -5
  13. package/assets/commands/agents/docs-validate.md +1 -0
  14. package/assets/commands/agents/frontend.md +1 -0
  15. package/assets/commands/agents/mcp-validate.md +1 -0
  16. package/assets/commands/agents/optimize.md +1 -0
  17. package/assets/commands/agents/pattern-analyzer.md +1 -0
  18. package/assets/commands/agents/prompt-quality.md +1 -0
  19. package/assets/commands/agents/prompt-validate.md +1 -0
  20. package/assets/commands/agents/public-interface.md +1 -0
  21. package/assets/commands/agents/release.md +1 -0
  22. package/assets/commands/agents/security.md +1 -0
  23. package/assets/commands/agents/test-review.md +1 -0
  24. package/assets/commands/agents/type-safety.md +1 -0
  25. package/assets/commands/agents/workflow-synthesis.md +1 -0
  26. package/assets/commands/pipelines/aristotle.md +143 -0
  27. package/assets/commands/pipelines/ship.md +188 -0
  28. package/assets/commands/workflows/prompt-audit.md +37 -747
  29. package/dist/cli.js +251 -207
  30. package/dist/harnesses/claude-code.d.ts +8 -0
  31. package/dist/harnesses/claude-code.js +72 -0
  32. package/dist/harnesses/codex.d.ts +15 -0
  33. package/dist/harnesses/codex.js +53 -0
  34. package/dist/harnesses/gemini-cli.d.ts +16 -0
  35. package/dist/harnesses/gemini-cli.js +54 -0
  36. package/dist/harnesses/index.d.ts +18 -0
  37. package/dist/harnesses/index.js +45 -0
  38. package/dist/harnesses/opencode.d.ts +14 -0
  39. package/dist/harnesses/opencode.js +130 -0
  40. package/dist/harnesses/types.d.ts +87 -0
  41. package/dist/harnesses/types.js +24 -0
  42. package/dist/lib/agent-transform.d.ts +12 -0
  43. package/dist/lib/agent-transform.js +129 -0
  44. package/dist/lib/asset-catalog.d.ts +9 -0
  45. package/dist/lib/asset-catalog.js +56 -0
  46. package/dist/lib/atomic-write.d.ts +11 -0
  47. package/dist/lib/atomic-write.js +28 -0
  48. package/dist/lib/config-merger.d.ts +7 -1
  49. package/dist/lib/config-merger.js +34 -5
  50. package/dist/lib/display.d.ts +14 -0
  51. package/dist/lib/display.js +66 -0
  52. package/dist/lib/file-ops.d.ts +6 -0
  53. package/dist/lib/file-ops.js +22 -1
  54. package/dist/lib/hash.d.ts +1 -0
  55. package/dist/lib/hash.js +1 -0
  56. package/dist/lib/health.d.ts +2 -0
  57. package/dist/lib/health.js +10 -0
  58. package/dist/lib/manifest.d.ts +22 -5
  59. package/dist/lib/manifest.js +148 -13
  60. package/dist/lib/paths.d.ts +15 -3
  61. package/dist/lib/paths.js +71 -13
  62. package/dist/lib/settings-merger.d.ts +9 -1
  63. package/dist/lib/settings-merger.js +45 -17
  64. package/dist/steps/agents.d.ts +5 -1
  65. package/dist/steps/agents.js +59 -9
  66. package/dist/steps/auth.js +26 -10
  67. package/dist/steps/commands.d.ts +6 -1
  68. package/dist/steps/commands.js +87 -9
  69. package/dist/steps/detect.d.ts +3 -0
  70. package/dist/steps/detect.js +7 -0
  71. package/dist/steps/mcp.d.ts +6 -2
  72. package/dist/steps/mcp.js +46 -21
  73. package/dist/steps/metrics.d.ts +14 -10
  74. package/dist/steps/metrics.js +59 -89
  75. package/dist/steps/shell.d.ts +2 -0
  76. package/dist/steps/shell.js +16 -9
  77. package/dist/steps/signup.d.ts +6 -3
  78. package/dist/steps/signup.js +26 -14
  79. package/dist/steps/verify.d.ts +2 -2
  80. package/dist/steps/verify.js +84 -117
  81. package/package.json +32 -7
  82. package/assets/commands/workflows/aristotle.md +0 -543
  83. package/assets/commands/workflows/ship.md +0 -721
  84. package/dist/test/auth.test.d.ts +0 -1
  85. package/dist/test/auth.test.js +0 -43
  86. package/dist/test/config-io.test.d.ts +0 -1
  87. package/dist/test/config-io.test.js +0 -56
  88. package/dist/test/config-merger.test.d.ts +0 -1
  89. package/dist/test/config-merger.test.js +0 -94
  90. package/dist/test/detect.test.d.ts +0 -1
  91. package/dist/test/detect.test.js +0 -25
  92. package/dist/test/file-ops.test.d.ts +0 -1
  93. package/dist/test/file-ops.test.js +0 -100
  94. package/dist/test/hash.test.d.ts +0 -1
  95. package/dist/test/hash.test.js +0 -14
  96. package/dist/test/manifest.test.d.ts +0 -1
  97. package/dist/test/manifest.test.js +0 -78
  98. package/dist/test/paths.test.d.ts +0 -1
  99. package/dist/test/paths.test.js +0 -30
  100. package/dist/test/settings-merger.test.d.ts +0 -1
  101. package/dist/test/settings-merger.test.js +0 -167
  102. package/dist/test/shell-profile.test.d.ts +0 -1
  103. package/dist/test/shell-profile.test.js +0 -40
  104. package/dist/test/shell.test.d.ts +0 -1
  105. package/dist/test/shell.test.js +0 -71
  106. package/dist/test/signup.test.d.ts +0 -1
  107. package/dist/test/signup.test.js +0 -83
@@ -1,149 +1,126 @@
1
1
  import { readdir, access } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
  import { loadManifest } from "../lib/manifest.js";
4
- import { readConfig } from "../lib/config-merger.js";
5
- import { readSettings, hasUluopsHook } from "../lib/settings-merger.js";
6
- import { getMetricsToolDir, getSettingsPath } from "./metrics.js";
7
- export async function verify() {
8
- const checks = [];
4
+ import { getHealthTimeout } from "../lib/health.js";
5
+ import { getProfile } from "../harnesses/index.js";
6
+ /** Verify a single harness entry, appending results to checks. Returns false if any check fails. */
7
+ async function verifyHarness(harnessName, hm, checks) {
9
8
  let allOk = true;
10
- // 1. Manifest
11
- const manifest = await loadManifest();
12
- if (!manifest) {
13
- checks.push({
14
- label: "Manifest found",
15
- passed: false,
16
- detail: "No manifest — run npx @uluops/setup first",
17
- });
18
- return { ok: false, checks };
19
- }
20
- checks.push({
21
- label: `Manifest found (v${manifest.version}, installed ${manifest.installedAt.split("T")[0]})`,
22
- passed: true,
23
- });
24
- // 2. MCP config
25
- const config = await readConfig(manifest.mcpConfigPath);
26
- const hasTracker = !!config.mcpServers?.["uluops-tracker"];
27
- const hasRegistry = !!config.mcpServers?.["uluops-registry"];
28
- if (hasTracker && hasRegistry) {
29
- checks.push({
30
- label: `MCP config present in ${manifest.mcpConfigPath} (2 servers)`,
31
- passed: true,
32
- });
9
+ let profile;
10
+ try {
11
+ profile = getProfile(harnessName);
33
12
  }
34
- else {
35
- checks.push({
36
- label: "MCP config",
37
- passed: false,
38
- detail: `Missing: ${[!hasTracker && "tracker", !hasRegistry && "registry"].filter(Boolean).join(", ")}`,
39
- });
40
- allOk = false;
13
+ catch {
14
+ checks.push({ label: `Harness: ${harnessName}`, passed: false, detail: "Unknown harness in manifest" });
15
+ return false;
41
16
  }
42
- // 3. Agent files
43
- const agentsDir = join(manifest.defsPath, "agents");
17
+ // MCP config
44
18
  try {
45
- const agentFiles = await readdir(agentsDir);
46
- const found = manifest.agents.filter((a) => agentFiles.includes(a)).length;
47
- if (found === manifest.agents.length) {
48
- checks.push({
49
- label: `${found}/${manifest.agents.length} agents in ${agentsDir}`,
50
- passed: true,
51
- });
19
+ const config = await profile.mcpConfig.read(hm.mcpConfigPath);
20
+ if (profile.mcpConfig.check(config)) {
21
+ checks.push({ label: `[${profile.displayName}] MCP config present in ${hm.mcpConfigPath} (2 servers)`, passed: true });
52
22
  }
53
23
  else {
54
- checks.push({
55
- label: `${found}/${manifest.agents.length} agents in ${agentsDir}`,
56
- passed: false,
57
- detail: `Missing ${manifest.agents.length - found} agent(s)`,
58
- });
24
+ checks.push({ label: `[${profile.displayName}] MCP config`, passed: false, detail: "UluOps servers not found in config" });
59
25
  allOk = false;
60
26
  }
61
27
  }
62
28
  catch {
29
+ checks.push({ label: `[${profile.displayName}] MCP config`, passed: false, detail: `Cannot read ${hm.mcpConfigPath}` });
30
+ allOk = false;
31
+ }
32
+ // Agent files
33
+ const agentsDir = join(hm.defsPath, "agents");
34
+ try {
35
+ const agentFiles = await readdir(agentsDir);
36
+ const found = hm.agents.filter((a) => agentFiles.includes(a)).length;
63
37
  checks.push({
64
- label: "Agent files",
65
- passed: false,
66
- detail: `Directory not found: ${agentsDir}`,
38
+ label: `[${profile.displayName}] ${found}/${hm.agents.length} agents in ${agentsDir}`,
39
+ passed: found === hm.agents.length,
40
+ detail: found < hm.agents.length ? `Missing ${hm.agents.length - found} agent(s)` : undefined,
67
41
  });
42
+ if (found < hm.agents.length)
43
+ allOk = false;
44
+ }
45
+ catch {
46
+ checks.push({ label: `[${profile.displayName}] Agent files`, passed: false, detail: `Directory not found: ${agentsDir}` });
68
47
  allOk = false;
69
48
  }
70
- // 4. Command files
71
- const commandsDir = join(manifest.defsPath, "commands");
72
- try {
49
+ // Command files
50
+ if (hm.commands.length > 0) {
51
+ const commandsDir = join(hm.defsPath, "commands");
73
52
  let found = 0;
74
- for (const cmd of manifest.commands) {
53
+ for (const cmd of hm.commands) {
75
54
  try {
76
55
  await access(join(commandsDir, cmd));
77
56
  found++;
78
57
  }
79
- catch {
80
- // Missing
81
- }
82
- }
83
- if (found === manifest.commands.length) {
84
- checks.push({
85
- label: `${found}/${manifest.commands.length} commands in ${commandsDir}`,
86
- passed: true,
87
- });
58
+ catch { /* Missing */ }
88
59
  }
89
- else {
90
- checks.push({
91
- label: `${found}/${manifest.commands.length} commands in ${commandsDir}`,
92
- passed: false,
93
- detail: `Missing ${manifest.commands.length - found} command(s)`,
94
- });
95
- allOk = false;
96
- }
97
- }
98
- catch {
99
60
  checks.push({
100
- label: "Command files",
101
- passed: false,
102
- detail: `Directory not found: ${commandsDir}`,
61
+ label: `[${profile.displayName}] ${found}/${hm.commands.length} commands`,
62
+ passed: found === hm.commands.length,
63
+ detail: found < hm.commands.length ? `Missing ${hm.commands.length - found} command(s)` : undefined,
103
64
  });
104
- allOk = false;
65
+ if (found < hm.commands.length)
66
+ allOk = false;
105
67
  }
106
- // 5. Agent metrics hook
107
- if (manifest.metricsHookInstalled) {
108
- const settings = await readSettings(getSettingsPath());
109
- const hookPresent = hasUluopsHook(settings);
110
- const toolDir = getMetricsToolDir();
68
+ // Hooks
69
+ if (hm.hooksInstalled && profile.hooks && profile.paths.settingsPath) {
70
+ const hookPresent = await profile.hooks.check(profile.paths.settingsPath);
111
71
  let hookFilePresent = false;
112
- try {
113
- await access(join(toolDir, "dist", "hook.js"));
114
- hookFilePresent = true;
115
- }
116
- catch {
117
- // Missing
72
+ if (profile.paths.toolsDir) {
73
+ try {
74
+ await access(join(profile.paths.toolsDir, "dist", "hook.js"));
75
+ hookFilePresent = true;
76
+ }
77
+ catch { /* Missing */ }
118
78
  }
119
79
  if (hookPresent && hookFilePresent) {
120
- checks.push({
121
- label: "Agent metrics hook configured and tool files present",
122
- passed: true,
123
- });
80
+ checks.push({ label: `[${profile.displayName}] Agent metrics hook configured`, passed: true });
124
81
  }
125
82
  else {
126
83
  const missing = [
127
- !hookPresent && "hook not in settings.json",
128
- !hookFilePresent && "hook.js not found",
129
- ]
130
- .filter(Boolean)
131
- .join(", ");
132
- checks.push({
133
- label: "Agent metrics",
134
- passed: false,
135
- detail: missing,
136
- });
84
+ ...(!hookPresent ? ["hook not in settings"] : []),
85
+ ...(!hookFilePresent ? ["hook.js not found"] : []),
86
+ ].join(", ");
87
+ checks.push({ label: `[${profile.displayName}] Agent metrics`, passed: false, detail: missing });
137
88
  allOk = false;
138
89
  }
139
90
  }
140
- // 6. API connectivity
141
- const apiKey = extractApiKey(config);
91
+ return allOk;
92
+ }
93
+ /** Run all verification checks against the current installation and return structured results. */
94
+ export async function verify() {
95
+ const checks = [];
96
+ let allOk = true;
97
+ // 1. Manifest
98
+ const manifest = await loadManifest();
99
+ if (!manifest) {
100
+ checks.push({
101
+ label: "Manifest found",
102
+ passed: false,
103
+ detail: "No manifest — run npx @uluops/setup first",
104
+ });
105
+ return { ok: false, checks };
106
+ }
107
+ checks.push({
108
+ label: `Manifest found (v${manifest.version}, installed ${manifest.installedAt.split("T")[0]})`,
109
+ passed: true,
110
+ });
111
+ // 2. Per-harness checks
112
+ for (const [harnessName, hm] of Object.entries(manifest.harnesses)) {
113
+ const ok = await verifyHarness(harnessName, hm, checks);
114
+ if (!ok)
115
+ allOk = false;
116
+ }
117
+ // 3. API connectivity (harness-agnostic)
118
+ const apiKey = process.env["ULUOPS_API_KEY"];
142
119
  if (apiKey) {
143
120
  try {
144
121
  const res = await fetch("https://api.uluops.ai/api/v1/registry/users/me", {
145
122
  headers: { Authorization: `Bearer ${apiKey}` },
146
- signal: AbortSignal.timeout(5000),
123
+ signal: AbortSignal.timeout(getHealthTimeout()),
147
124
  });
148
125
  if (res.ok) {
149
126
  const data = (await res.json());
@@ -172,13 +149,3 @@ export async function verify() {
172
149
  }
173
150
  return { ok: allOk, checks };
174
151
  }
175
- function extractApiKey(config) {
176
- const raw = config.mcpServers;
177
- if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
178
- return process.env["ULUOPS_API_KEY"];
179
- }
180
- const servers = raw;
181
- return (servers["uluops-registry"]?.env?.["ULUOPS_API_KEY"] ??
182
- servers["uluops-tracker"]?.env?.["ULUOPS_TRACKER_API_KEY"] ??
183
- process.env["ULUOPS_API_KEY"]);
184
- }
package/package.json CHANGED
@@ -1,22 +1,46 @@
1
1
  {
2
2
  "name": "@uluops/setup",
3
- "version": "0.2.0",
4
- "description": "Zero-friction installer for UluOps + Claude Code",
3
+ "version": "0.4.0",
4
+ "description": "Zero-friction installer for UluOps agentic harnesses",
5
+ "license": "SEE LICENSE IN LICENSE",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/Uluops/-uluops-setup.git"
9
+ },
10
+ "homepage": "https://uluops.ai",
11
+ "keywords": [
12
+ "uluops",
13
+ "mcp",
14
+ "agents",
15
+ "claude",
16
+ "opencode",
17
+ "agentic",
18
+ "harness",
19
+ "setup",
20
+ "installer"
21
+ ],
5
22
  "type": "module",
6
23
  "bin": {
7
24
  "uluops-setup": "./dist/cli.js"
8
25
  },
26
+ "exports": {
27
+ "./cli": "./dist/cli.js"
28
+ },
9
29
  "files": [
10
- "dist",
30
+ "dist/cli.js",
31
+ "dist/cli.d.ts",
32
+ "dist/lib/**",
33
+ "dist/steps/**",
34
+ "dist/harnesses/**",
11
35
  "assets"
12
36
  ],
13
37
  "engines": {
14
- "node": ">=18.0.0"
38
+ "node": ">=20.0.0"
15
39
  },
16
40
  "scripts": {
17
- "build": "tsc",
41
+ "build": "tsc -p tsconfig.build.json",
18
42
  "dev": "tsx src/cli.ts",
19
- "typecheck": "tsc --noEmit",
43
+ "typecheck": "tsc -p tsconfig.build.json --noEmit && tsc -p tsconfig.test.json --noEmit",
20
44
  "test": "vitest run",
21
45
  "test:watch": "vitest watch",
22
46
  "prepublishOnly": "npm run build"
@@ -25,7 +49,8 @@
25
49
  "@inquirer/prompts": "^7.0.0",
26
50
  "@uluops/agent-metrics": "^0.2.0",
27
51
  "chalk": "^5.0.0",
28
- "commander": "^12.0.0"
52
+ "commander": "^12.0.0",
53
+ "jsonc-parser": "^3.3.1"
29
54
  },
30
55
  "devDependencies": {
31
56
  "@types/node": "^22.0.0",