@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.
- package/LICENSE +21 -0
- package/README.md +67 -50
- package/assets/auto-tracker-save.mjs +142 -0
- package/assets/{agents → claude-code/agents}/api-contract-validator-agent.md +9 -228
- package/assets/{agents → claude-code/agents}/aristotle-analyst-agent.md +51 -4
- package/assets/{agents → claude-code/agents}/aristotle-explorer-agent.md +6 -2
- package/assets/{agents → claude-code/agents}/aristotle-forecaster-agent.md +15 -230
- package/assets/{agents → claude-code/agents}/aristotle-validator-agent.md +12 -252
- package/assets/{agents → claude-code/agents}/assumption-excavator-agent.md +21 -247
- package/assets/{agents → claude-code/agents}/code-auditor-agent.md +12 -255
- package/assets/{agents → claude-code/agents}/code-optimizer-agent.md +15 -236
- package/assets/{agents → claude-code/agents}/code-validator-agent.md +31 -300
- package/assets/claude-code/agents/docs-validator-agent.md +472 -0
- package/assets/{agents → claude-code/agents}/frontend-validator-agent.md +15 -258
- package/assets/{agents → claude-code/agents}/mcp-validator-agent.md +8 -252
- package/assets/{agents → claude-code/agents}/pre-implementation-architect-agent.md +8 -224
- package/assets/{agents → claude-code/agents}/prompt-engineer-agent.md +57 -290
- package/assets/{agents → claude-code/agents}/prompt-pattern-analyzer-agent.md +10 -225
- package/assets/{agents → claude-code/agents}/prompt-quality-validator-agent.md +11 -249
- package/assets/{agents → claude-code/agents}/public-interface-validator-agent.md +15 -268
- package/assets/claude-code/agents/release-readiness-agent.md +495 -0
- package/assets/{agents → claude-code/agents}/security-analyst-agent.md +236 -480
- package/assets/{agents → claude-code/agents}/test-architect-agent.md +16 -259
- package/assets/{agents → claude-code/agents}/type-safety-validator-agent.md +23 -266
- package/assets/{agents → claude-code/agents}/workflow-synthesis-agent.md +23 -226
- package/assets/{commands → claude-code/commands}/agents/anxiety-reader.md +12 -15
- package/assets/{commands → claude-code/commands}/agents/api-contract.md +156 -136
- package/assets/{commands → claude-code/commands}/agents/architect.md +156 -136
- package/assets/claude-code/commands/agents/aristotle-analyst.md +157 -0
- package/assets/claude-code/commands/agents/aristotle-explorer.md +157 -0
- package/assets/claude-code/commands/agents/aristotle-forecaster.md +157 -0
- package/assets/claude-code/commands/agents/aristotle-validator.md +157 -0
- package/assets/{commands → claude-code/commands}/agents/assumption-excavator.md +49 -7
- package/assets/{commands → claude-code/commands}/agents/audit.md +156 -137
- package/assets/{commands → claude-code/commands}/agents/docs-validate.md +156 -134
- package/assets/{commands → claude-code/commands}/agents/frontend.md +156 -136
- package/assets/{commands → claude-code/commands}/agents/mcp-validate.md +156 -137
- package/assets/{commands → claude-code/commands}/agents/optimize.md +156 -134
- package/assets/{commands → claude-code/commands}/agents/pattern-analyzer.md +150 -127
- package/assets/{commands → claude-code/commands}/agents/prompt-quality.md +155 -135
- package/assets/claude-code/commands/agents/prompt-validate.md +155 -0
- package/assets/{commands → claude-code/commands}/agents/public-interface.md +156 -135
- package/assets/{commands → claude-code/commands}/agents/release.md +156 -136
- package/assets/{commands → claude-code/commands}/agents/security.md +156 -138
- package/assets/{commands → claude-code/commands}/agents/test-review.md +156 -137
- package/assets/{commands → claude-code/commands}/agents/type-safety.md +156 -136
- package/assets/{commands/agents/code-validate.md → claude-code/commands/agents/validate.md} +156 -135
- package/assets/claude-code/commands/agents/workflow-synthesis.md +157 -0
- package/assets/{commands → claude-code/commands}/pipelines/aristotle.md +8 -8
- package/assets/{commands → claude-code/commands}/pipelines/ship.md +8 -8
- package/assets/claude-code/commands/workflows/post-implementation.md +60 -0
- package/assets/claude-code/commands/workflows/pre-implementation.md +46 -0
- package/assets/{commands → claude-code/commands}/workflows/prompt-audit.md +2 -2
- package/assets/codex/agents/anxiety-reader-agent.toml +462 -0
- package/assets/codex/agents/api-contract-validator-agent.toml +738 -0
- package/assets/codex/agents/aristotle-analyst-agent.toml +750 -0
- package/assets/codex/agents/aristotle-explorer-agent.toml +155 -0
- package/assets/codex/agents/aristotle-forecaster-agent.toml +449 -0
- package/assets/codex/agents/aristotle-validator-agent.toml +424 -0
- package/assets/codex/agents/assumption-excavator-agent.toml +1126 -0
- package/assets/codex/agents/code-auditor-agent.toml +815 -0
- package/assets/codex/agents/code-optimizer-agent.toml +652 -0
- package/assets/codex/agents/code-validator-agent.toml +573 -0
- package/assets/codex/agents/docs-validator-agent.toml +468 -0
- package/assets/codex/agents/frontend-validator-agent.toml +598 -0
- package/assets/codex/agents/mcp-validator-agent.toml +580 -0
- package/assets/codex/agents/pre-implementation-architect-agent.toml +817 -0
- package/assets/codex/agents/prompt-engineer-agent.toml +922 -0
- package/assets/codex/agents/prompt-pattern-analyzer-agent.toml +689 -0
- package/assets/codex/agents/prompt-quality-validator-agent.toml +777 -0
- package/assets/codex/agents/public-interface-validator-agent.toml +695 -0
- package/assets/codex/agents/release-readiness-agent.toml +491 -0
- package/assets/codex/agents/security-analyst-agent.toml +847 -0
- package/assets/codex/agents/test-architect-agent.toml +615 -0
- package/assets/codex/agents/type-safety-validator-agent.toml +686 -0
- package/assets/codex/agents/workflow-synthesis-agent.toml +631 -0
- package/assets/gemini-cli/agents/anxiety-reader-agent.md +470 -0
- package/assets/gemini-cli/agents/api-contract-validator-agent.md +747 -0
- package/assets/gemini-cli/agents/aristotle-analyst-agent.md +758 -0
- package/assets/gemini-cli/agents/aristotle-explorer-agent.md +163 -0
- package/assets/gemini-cli/agents/aristotle-forecaster-agent.md +457 -0
- package/assets/gemini-cli/agents/aristotle-validator-agent.md +432 -0
- package/assets/gemini-cli/agents/assumption-excavator-agent.md +1134 -0
- package/assets/gemini-cli/agents/code-auditor-agent.md +827 -0
- package/assets/gemini-cli/agents/code-optimizer-agent.md +661 -0
- package/assets/gemini-cli/agents/code-validator-agent.md +582 -0
- package/assets/gemini-cli/agents/docs-validator-agent.md +477 -0
- package/assets/gemini-cli/agents/frontend-validator-agent.md +610 -0
- package/assets/gemini-cli/agents/mcp-validator-agent.md +589 -0
- package/assets/gemini-cli/agents/pre-implementation-architect-agent.md +826 -0
- package/assets/gemini-cli/agents/prompt-engineer-agent.md +931 -0
- package/assets/gemini-cli/agents/prompt-pattern-analyzer-agent.md +698 -0
- package/assets/gemini-cli/agents/prompt-quality-validator-agent.md +786 -0
- package/assets/gemini-cli/agents/public-interface-validator-agent.md +707 -0
- package/assets/gemini-cli/agents/release-readiness-agent.md +500 -0
- package/assets/gemini-cli/agents/security-analyst-agent.md +859 -0
- package/assets/gemini-cli/agents/test-architect-agent.md +624 -0
- package/assets/gemini-cli/agents/type-safety-validator-agent.md +695 -0
- package/assets/gemini-cli/agents/workflow-synthesis-agent.md +639 -0
- package/assets/gemini-cli/commands/agents/anxiety-reader.toml +155 -0
- package/assets/gemini-cli/commands/agents/api-contract.toml +154 -0
- package/assets/gemini-cli/commands/agents/architect.toml +154 -0
- package/assets/gemini-cli/commands/agents/aristotle-analyst.toml +155 -0
- package/assets/gemini-cli/commands/agents/aristotle-explorer.toml +155 -0
- package/assets/gemini-cli/commands/agents/aristotle-forecaster.toml +155 -0
- package/assets/gemini-cli/commands/agents/aristotle-validator.toml +155 -0
- package/assets/gemini-cli/commands/agents/assumption-excavator.toml +155 -0
- package/assets/gemini-cli/commands/agents/audit.toml +154 -0
- package/assets/gemini-cli/commands/agents/docs-validate.toml +154 -0
- package/assets/gemini-cli/commands/agents/frontend.toml +154 -0
- package/assets/gemini-cli/commands/agents/mcp-validate.toml +154 -0
- package/assets/gemini-cli/commands/agents/optimize.toml +154 -0
- package/assets/gemini-cli/commands/agents/pattern-analyzer.toml +148 -0
- package/assets/gemini-cli/commands/agents/prompt-quality.toml +153 -0
- package/assets/gemini-cli/commands/agents/prompt-validate.toml +153 -0
- package/assets/gemini-cli/commands/agents/public-interface.toml +154 -0
- package/assets/gemini-cli/commands/agents/release.toml +154 -0
- package/assets/gemini-cli/commands/agents/security.toml +154 -0
- package/assets/gemini-cli/commands/agents/test-review.toml +154 -0
- package/assets/gemini-cli/commands/agents/type-safety.toml +154 -0
- package/assets/gemini-cli/commands/agents/validate.toml +154 -0
- package/assets/gemini-cli/commands/agents/workflow-synthesis.toml +155 -0
- package/assets/gemini-cli/commands/pipelines/aristotle.toml +139 -0
- package/assets/gemini-cli/commands/pipelines/ship.toml +184 -0
- package/assets/gemini-cli/commands/workflows/post-implementation.toml +56 -0
- package/assets/gemini-cli/commands/workflows/pre-implementation.toml +42 -0
- package/assets/gemini-cli/commands/workflows/prompt-audit.toml +40 -0
- package/assets/opencode/agents/anxiety-reader-agent.md +472 -0
- package/assets/opencode/agents/api-contract-validator-agent.md +749 -0
- package/assets/opencode/agents/aristotle-analyst-agent.md +760 -0
- package/assets/opencode/agents/aristotle-explorer-agent.md +164 -0
- package/assets/opencode/agents/aristotle-forecaster-agent.md +459 -0
- package/assets/opencode/agents/aristotle-validator-agent.md +434 -0
- package/assets/opencode/agents/assumption-excavator-agent.md +1136 -0
- package/assets/opencode/agents/code-auditor-agent.md +826 -0
- package/assets/opencode/agents/code-optimizer-agent.md +663 -0
- package/assets/opencode/agents/code-validator-agent.md +584 -0
- package/assets/opencode/agents/docs-validator-agent.md +479 -0
- package/assets/opencode/agents/frontend-validator-agent.md +609 -0
- package/assets/opencode/agents/mcp-validator-agent.md +591 -0
- package/assets/opencode/agents/pre-implementation-architect-agent.md +828 -0
- package/assets/opencode/agents/prompt-engineer-agent.md +933 -0
- package/assets/opencode/agents/prompt-pattern-analyzer-agent.md +700 -0
- package/assets/opencode/agents/prompt-quality-validator-agent.md +788 -0
- package/assets/opencode/agents/public-interface-validator-agent.md +706 -0
- package/assets/opencode/agents/release-readiness-agent.md +502 -0
- package/assets/opencode/agents/security-analyst-agent.md +858 -0
- package/assets/opencode/agents/test-architect-agent.md +626 -0
- package/assets/opencode/agents/type-safety-validator-agent.md +697 -0
- package/assets/opencode/agents/workflow-synthesis-agent.md +641 -0
- package/dist/cli.js +12 -414
- package/dist/commands/helpers.d.ts +73 -0
- package/dist/commands/helpers.js +274 -0
- package/dist/commands/setup.d.ts +13 -0
- package/dist/commands/setup.js +93 -0
- package/dist/commands/uninstall.d.ts +3 -0
- package/dist/commands/uninstall.js +126 -0
- package/dist/commands/verify.d.ts +1 -0
- package/dist/commands/verify.js +28 -0
- package/dist/harnesses/claude-code.d.ts +1 -1
- package/dist/harnesses/claude-code.js +3 -1
- package/dist/harnesses/codex.js +6 -5
- package/dist/harnesses/gemini-cli.d.ts +4 -8
- package/dist/harnesses/gemini-cli.js +47 -21
- package/dist/harnesses/index.d.ts +10 -1
- package/dist/harnesses/index.js +11 -2
- package/dist/harnesses/opencode.d.ts +1 -1
- package/dist/harnesses/opencode.js +15 -6
- package/dist/harnesses/types.d.ts +19 -0
- package/dist/harnesses/types.js +2 -0
- package/dist/lib/asset-catalog.js +2 -2
- package/dist/lib/config-merger.d.ts +2 -1
- package/dist/lib/config-merger.js +12 -4
- package/dist/lib/file-ops.d.ts +5 -0
- package/dist/lib/file-ops.js +18 -3
- package/dist/lib/hash.d.ts +1 -1
- package/dist/lib/hash.js +2 -2
- package/dist/lib/manifest.d.ts +30 -1
- package/dist/lib/manifest.js +5 -7
- package/dist/lib/paths.d.ts +16 -1
- package/dist/lib/paths.js +31 -3
- package/dist/lib/settings-merger.d.ts +24 -9
- package/dist/lib/settings-merger.js +57 -22
- package/dist/lib/version.d.ts +2 -0
- package/dist/lib/version.js +10 -0
- package/dist/steps/agents.d.ts +1 -2
- package/dist/steps/agents.js +7 -18
- package/dist/steps/cli.d.ts +53 -0
- package/dist/steps/cli.js +90 -0
- package/dist/steps/commands.d.ts +1 -1
- package/dist/steps/commands.js +20 -71
- package/dist/steps/detect.js +4 -0
- package/dist/steps/mcp.js +7 -15
- package/dist/steps/metrics.d.ts +12 -0
- package/dist/steps/metrics.js +52 -22
- package/dist/steps/shell.js +11 -1
- package/dist/steps/signup.d.ts +2 -2
- package/dist/steps/signup.js +9 -12
- package/dist/steps/verify.js +47 -8
- package/package.json +12 -11
- package/assets/agents/docs-validator-agent.md +0 -490
- package/assets/agents/release-readiness-agent.md +0 -482
- package/assets/commands/agents/aristotle-analyst.md +0 -116
- package/assets/commands/agents/aristotle-explorer.md +0 -93
- package/assets/commands/agents/aristotle-forecaster.md +0 -115
- package/assets/commands/agents/aristotle-validator.md +0 -115
- package/assets/commands/agents/prompt-validate.md +0 -136
- package/assets/commands/agents/workflow-synthesis.md +0 -102
- package/assets/commands/workflows/post-implementation.md +0 -577
- package/assets/commands/workflows/pre-implementation.md +0 -670
- /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 {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
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
|
|
426
|
-
.option("--local-defs", "Save agents/commands locally
|
|
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>;
|