@uluops/setup 0.9.4 → 0.9.6

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/README.md CHANGED
@@ -137,10 +137,18 @@ npx @uluops/setup [options]
137
137
  --harness <single-name> (fail-fast conflict error).
138
138
  --signup Create account from terminal (email + password)
139
139
  --scope <mode> MCP config scope: "global" or "local" (default: global)
140
- --local-defs Save definitions to ./uluops/ for review
140
+ --local-defs Install definitions into ./uluops/ (project-scoped)
141
+ instead of the harness's home directory
141
142
  --shell Write API key export to shell profile
142
143
  --with-cli Install @uluops/cli globally (skip prompt)
143
144
  --no-cli Skip @uluops/cli install (skip prompt)
145
+ --with-agent-metrics-cli
146
+ Install @uluops/agent-metrics globally (skip prompt)
147
+ --no-agent-metrics-cli
148
+ Skip @uluops/agent-metrics install (skip prompt)
149
+ --no-metrics Skip the agent-metrics hook install (no hook
150
+ configured, no tool files copied). The downstream
151
+ @uluops/agent-metrics CLI prompt is also suppressed.
144
152
  --skip-validation Accept API key without server verification
145
153
  --list Show available agents and workflows without installing
146
154
  --verify Check installation health: manifest, files, MCP config, API connectivity (no changes)
@@ -159,7 +167,7 @@ npx @uluops/setup [options]
159
167
  Displays all agents and workflows included in the current version of the setup tool.
160
168
 
161
169
  ```text
162
- ⟨u⟩ ulu·ops v0.8.1 — available agents and workflows
170
+ ⟨u⟩ ulu·ops v0.9.5 — available agents and workflows
163
171
 
164
172
  WORKFLOWS
165
173
  /workflows:post-implementation Iterative validation after coding
@@ -178,7 +186,7 @@ Displays all agents and workflows included in the current version of the setup t
178
186
  Validates your current installation against the local manifest and checks API connectivity.
179
187
 
180
188
  ```text
181
- ⟨u⟩ ulu·ops Installation Check v0.8.1
189
+ ⟨u⟩ ulu·ops Installation Check v0.9.5
182
190
 
183
191
  ✓ Manifest found (~/.uluops/manifest.json)
184
192
  ✓ All 23 agents present in ~/.claude/agents/
@@ -217,8 +225,8 @@ npx @uluops/setup --api-key ulr_abc123 --all-detected -y
217
225
  # Local MCP config (project-scoped)
218
226
  npx @uluops/setup --scope local
219
227
 
220
- # Preview without changes
221
- npx @uluops/setup --dry-run --api-key ulr_abc123
228
+ # Preview without changes while offline
229
+ npx @uluops/setup --dry-run --api-key ulr_abc123 --skip-validation
222
230
 
223
231
  # Persist API key in shell profile (~/.zshrc, ~/.bashrc, etc.)
224
232
  npx @uluops/setup --shell
@@ -228,6 +236,12 @@ npx @uluops/setup --with-cli
228
236
 
229
237
  # Skip the CLI prompt entirely (interactive runs default to asking)
230
238
  npx @uluops/setup --no-cli
239
+
240
+ # Install the agent-metrics CLI globally alongside the metrics hook
241
+ npx @uluops/setup --with-agent-metrics-cli
242
+
243
+ # Skip the agent-metrics CLI prompt entirely
244
+ npx @uluops/setup --no-agent-metrics-cli
231
245
  ```
232
246
 
233
247
  ## How updates work
@@ -273,7 +287,7 @@ Removes only UluOps-managed files: agents, commands, MCP config entries, shell p
273
287
 
274
288
  - **Node.js:** >= 20.0.0
275
289
  - **Platform:** Linux, macOS, or WSL2 (native Windows not supported)
276
- - **Harness:** Claude Code, OpenCode, or Gemini CLI
290
+ - **Harness:** Claude Code, OpenCode, Gemini CLI, or Codex
277
291
  - **Auth:** UluOps API key ([get one here](https://app.uluops.ai/settings/api-keys))
278
292
 
279
293
  ---
package/dist/cli.js CHANGED
@@ -27,6 +27,7 @@ async function main() {
27
27
  .option("--no-cli", "Skip @uluops/cli install without prompting (takes precedence over --with-cli)")
28
28
  .option("--with-agent-metrics-cli", "Install @uluops/agent-metrics globally without prompting")
29
29
  .option("--no-agent-metrics-cli", "Skip @uluops/agent-metrics install without prompting (takes precedence over --with-agent-metrics-cli)")
30
+ .option("--no-metrics", "Skip the agent-metrics hook install (no hook configured, no tool files copied)")
30
31
  .option("--skip-validation", "Accept API key without verifying", false)
31
32
  .option("--list", "Show available agents and workflows without installing")
32
33
  .option("--verify", "Check existing installation health")
@@ -131,6 +132,7 @@ async function main() {
131
132
  cli: opts.cli,
132
133
  withAgentMetricsCli: opts.withAgentMetricsCli,
133
134
  agentMetricsCli: opts.agentMetricsCli,
135
+ noMetrics: !opts.metrics,
134
136
  skipValidation: opts.skipValidation,
135
137
  dryRun: opts.dryRun,
136
138
  yes: opts.yes,
@@ -41,6 +41,7 @@ export declare function installSkillsDefs(profile: HarnessProfile, opts: {
41
41
  /** Install agent-metrics hook and tool files (Claude Code only). */
42
42
  export declare function configureMetricsStep(profile: HarnessProfile, opts: {
43
43
  dryRun: boolean;
44
+ noMetrics?: boolean;
44
45
  }): Promise<MetricsResult>;
45
46
  /**
46
47
  * Decide whether to install `@uluops/cli` globally and do it (or not).
@@ -205,6 +205,15 @@ export async function installSkillsDefs(profile, opts, prev) {
205
205
  }
206
206
  /** Install agent-metrics hook and tool files (Claude Code only). */
207
207
  export async function configureMetricsStep(profile, opts) {
208
+ if (opts.noMetrics) {
209
+ info(chalk.dim(`Metrics hook skipped (--no-metrics)`));
210
+ return {
211
+ toolFilesCopied: 0,
212
+ hookConfigured: false,
213
+ hooksInstalledVersion: null,
214
+ skippedReason: "no-metrics-flag",
215
+ };
216
+ }
208
217
  if (!profile.hooks) {
209
218
  info(chalk.dim(`Metrics hooks not supported for ${profile.displayName}`));
210
219
  return { toolFilesCopied: 0, hookConfigured: false, hooksInstalledVersion: null };
@@ -13,5 +13,11 @@ interface RunSetupOpts {
13
13
  cli?: boolean;
14
14
  withAgentMetricsCli?: boolean;
15
15
  agentMetricsCli?: boolean;
16
+ /**
17
+ * When true, skip the agent-metrics hook step entirely. configureMetricsStep
18
+ * short-circuits with a "skipped via --no-metrics" status. The agent-metrics
19
+ * CLI prompt is also suppressed downstream (no hook → no CLI gate).
20
+ */
21
+ noMetrics?: boolean;
16
22
  }
17
23
  export declare function runSetup(opts: RunSetupOpts): Promise<void>;
@@ -3,7 +3,7 @@ export interface CommandEntry {
3
3
  description: string;
4
4
  model: string;
5
5
  }
6
- /** Get all agent command entries from assets. */
6
+ /** Get all agent command entries from the canonical catalog. */
7
7
  export declare function getAgentCommands(): Promise<CommandEntry[]>;
8
- /** Get all workflow command entries from assets. */
8
+ /** Get all workflow command entries from the canonical catalog. */
9
9
  export declare function getWorkflowCommands(): Promise<CommandEntry[]>;
@@ -1,6 +1,15 @@
1
1
  import { readdir, readFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
  import { ASSETS_DIR } from "./paths.js";
4
+ /**
5
+ * Canonical command-catalog source. `assets/claude-code/commands/` is the
6
+ * reference set of markdown command definitions; other harnesses (codex,
7
+ * gemini-cli, opencode) are rendered from this source at install time and
8
+ * do not ship parallel command-markdown trees. `printAgentList` therefore
9
+ * reads from here regardless of which harness the user has installed —
10
+ * the listing is the catalog, not a per-harness manifest.
11
+ */
12
+ const CATALOG_COMMANDS_DIR = join(ASSETS_DIR, "claude-code", "commands");
4
13
  /**
5
14
  * Parse YAML-like frontmatter from a markdown file.
6
15
  * Returns key-value pairs between the opening and closing `---`.
@@ -46,11 +55,11 @@ async function scanCommandDir(dir) {
46
55
  }
47
56
  return entries.sort((a, b) => a.name.localeCompare(b.name));
48
57
  }
49
- /** Get all agent command entries from assets. */
58
+ /** Get all agent command entries from the canonical catalog. */
50
59
  export async function getAgentCommands() {
51
- return scanCommandDir(join(ASSETS_DIR, "claude-code", "commands", "agents"));
60
+ return scanCommandDir(join(CATALOG_COMMANDS_DIR, "agents"));
52
61
  }
53
- /** Get all workflow command entries from assets. */
62
+ /** Get all workflow command entries from the canonical catalog. */
54
63
  export async function getWorkflowCommands() {
55
- return scanCommandDir(join(ASSETS_DIR, "claude-code", "commands", "workflows"));
64
+ return scanCommandDir(join(CATALOG_COMMANDS_DIR, "workflows"));
56
65
  }
@@ -156,13 +156,13 @@ export async function printAgentList() {
156
156
  console.log();
157
157
  }
158
158
  if (agents.length > 0) {
159
- info(`${chalk.bold("AGENTS")} (run individually)${" ".repeat(26)}${chalk.dim("MODEL")}`);
159
+ info(`${chalk.bold("AGENTS")} (run individually)${" ".repeat(30)}${chalk.dim("MODEL")}`);
160
160
  for (const agent of agents) {
161
161
  const cmd = `/agents:${agent.name}`;
162
- const desc = agent.description.length > 17
163
- ? agent.description.slice(0, 14) + "..."
162
+ const desc = agent.description.length > 21
163
+ ? agent.description.slice(0, 18) + "..."
164
164
  : agent.description;
165
- info(` ${chalk.cyan(cmd.padEnd(34))}${desc.padEnd(17)}${chalk.dim(agent.model)}`);
165
+ info(` ${chalk.cyan(cmd.padEnd(34))}${desc.padEnd(22)}${chalk.dim(agent.model)}`);
166
166
  }
167
167
  console.log();
168
168
  }
@@ -21,11 +21,11 @@
21
21
  * the latest version was reachable.
22
22
  */
23
23
  export declare const OPS_MCP_PACKAGE = "@uluops/ops-mcp";
24
- export declare const OPS_MCP_VERSION = "0.3.1";
25
- export declare const OPS_MCP_SPEC: "@uluops/ops-mcp@0.3.1";
24
+ export declare const OPS_MCP_VERSION = "0.4.3";
25
+ export declare const OPS_MCP_SPEC: "@uluops/ops-mcp@0.4.3";
26
26
  export declare const REGISTRY_MCP_PACKAGE = "@uluops/registry-mcp";
27
- export declare const REGISTRY_MCP_VERSION = "0.2.7";
28
- export declare const REGISTRY_MCP_SPEC: "@uluops/registry-mcp@0.2.7";
27
+ export declare const REGISTRY_MCP_VERSION = "0.2.9";
28
+ export declare const REGISTRY_MCP_SPEC: "@uluops/registry-mcp@0.2.9";
29
29
  /**
30
30
  * Bare package names for the npm availability probe. The probe checks
31
31
  * existence on the registry, not version-specific resolvability, so it
@@ -21,10 +21,10 @@
21
21
  * the latest version was reachable.
22
22
  */
23
23
  export const OPS_MCP_PACKAGE = "@uluops/ops-mcp";
24
- export const OPS_MCP_VERSION = "0.3.1";
24
+ export const OPS_MCP_VERSION = "0.4.3";
25
25
  export const OPS_MCP_SPEC = `${OPS_MCP_PACKAGE}@${OPS_MCP_VERSION}`;
26
26
  export const REGISTRY_MCP_PACKAGE = "@uluops/registry-mcp";
27
- export const REGISTRY_MCP_VERSION = "0.2.7";
27
+ export const REGISTRY_MCP_VERSION = "0.2.9";
28
28
  export const REGISTRY_MCP_SPEC = `${REGISTRY_MCP_PACKAGE}@${REGISTRY_MCP_VERSION}`;
29
29
  /**
30
30
  * Bare package names for the npm availability probe. The probe checks
@@ -1,7 +1,15 @@
1
1
  import type { AuthResult } from "./auth.js";
2
2
  /**
3
- * Advisory password hints. Returns warning strings for inquirer display,
4
- * but all are non-blocking — server validation is the authority.
3
+ * Pure advisory check: returns the first hint message that applies to the
4
+ * password, or null if none apply. No I/O. Server validation remains the
5
+ * authority — hints exist only to nudge the user toward likely-acceptable
6
+ * inputs before round-tripping to the server.
7
+ * @internal Exported for testing only — not part of the public API.
8
+ */
9
+ declare function getPasswordHint(password: string): string | null;
10
+ /**
11
+ * Inquirer validate wrapper. Always returns true (hints are non-blocking)
12
+ * and emits the pure-computed hint via console.warn for display.
5
13
  * @internal Exported for testing only — not part of the public API.
6
14
  */
7
15
  declare function hintPassword(password: string): true;
@@ -13,4 +21,4 @@ declare function validateEmail(email: string): string | true;
13
21
  */
14
22
  export declare function signup(): Promise<AuthResult>;
15
23
  /** @internal Exported for testing only — not part of the public API. */
16
- export { hintPassword, validateEmail };
24
+ export { hintPassword, getPasswordHint, validateEmail };
@@ -1,20 +1,33 @@
1
1
  const API_BASE = "https://api.uluops.ai/api/v1";
2
2
  /**
3
- * Advisory password hints. Returns warning strings for inquirer display,
4
- * but all are non-blocking — server validation is the authority.
3
+ * Pure advisory check: returns the first hint message that applies to the
4
+ * password, or null if none apply. No I/O. Server validation remains the
5
+ * authority — hints exist only to nudge the user toward likely-acceptable
6
+ * inputs before round-tripping to the server.
5
7
  * @internal Exported for testing only — not part of the public API.
6
8
  */
7
- function hintPassword(password) {
9
+ function getPasswordHint(password) {
8
10
  if (password.length < 8)
9
- console.warn(" ⚠ Hint: server may require at least 8 characters");
10
- else if (password.length > 128)
11
- console.warn(" ⚠ Hint: server may reject passwords over 128 characters");
12
- else if (!/[a-z]/.test(password))
13
- console.warn(" ⚠ Hint: server may require a lowercase letter");
14
- else if (!/[A-Z]/.test(password))
15
- console.warn(" ⚠ Hint: server may require an uppercase letter");
16
- else if (!/[0-9]/.test(password))
17
- console.warn(" ⚠ Hint: server may require a number");
11
+ return " ⚠ Hint: server may require at least 8 characters";
12
+ if (password.length > 128)
13
+ return " ⚠ Hint: server may reject passwords over 128 characters";
14
+ if (!/[a-z]/.test(password))
15
+ return " ⚠ Hint: server may require a lowercase letter";
16
+ if (!/[A-Z]/.test(password))
17
+ return " ⚠ Hint: server may require an uppercase letter";
18
+ if (!/[0-9]/.test(password))
19
+ return " ⚠ Hint: server may require a number";
20
+ return null;
21
+ }
22
+ /**
23
+ * Inquirer validate wrapper. Always returns true (hints are non-blocking)
24
+ * and emits the pure-computed hint via console.warn for display.
25
+ * @internal Exported for testing only — not part of the public API.
26
+ */
27
+ function hintPassword(password) {
28
+ const hint = getPasswordHint(password);
29
+ if (hint !== null)
30
+ console.warn(hint);
18
31
  return true;
19
32
  }
20
33
  /** @internal Exported for testing only — not part of the public API. */
@@ -111,4 +124,4 @@ async function callApi(url, method, body, bearerToken, validate) {
111
124
  throw new Error(`Signup failed (${res.status}): ${message}`);
112
125
  }
113
126
  /** @internal Exported for testing only — not part of the public API. */
114
- export { hintPassword, validateEmail };
127
+ export { hintPassword, getPasswordHint, validateEmail };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uluops/setup",
3
- "version": "0.9.4",
3
+ "version": "0.9.6",
4
4
  "description": "Zero-friction installer for UluOps agentic harnesses",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -23,9 +23,6 @@
23
23
  "bin": {
24
24
  "uluops-setup": "./dist/cli.js"
25
25
  },
26
- "exports": {
27
- "./cli": "./dist/cli.js"
28
- },
29
26
  "files": [
30
27
  "dist/cli.js",
31
28
  "dist/cli.d.ts",