@uluops/setup 0.13.1 → 0.14.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/CHANGELOG.md CHANGED
@@ -4,6 +4,21 @@ All notable changes to `@uluops/setup` will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.14.0] - 2026-10-04
8
+
9
+ ### Changed
10
+
11
+ - **Claude Code: the metrics hook is also registered on `SubagentStart`** (definition-version-dispositions checklist X4-1a). agent-metrics 0.12.0 records which agent definition each subagent was spawned with at SubagentStart and confirms it at SubagentStop. Claude Code loads a subagent's definition at spawn, so a stop-time read alone would record a definition reinstalled mid-run.
12
+ - The same command serves both events; the hook dispatches on `hook_event_name`.
13
+ - The start entry is added only with the default `SubagentStop` event. A `ULUOPS_HOOK_TYPE` override installs exactly the overridden event.
14
+ - `--uninstall` removes UluOps hook entries from every event type present in `settings.json`, not just the ones the current environment would install, so an install made under a different `ULUOPS_HOOK_TYPE` still comes out. User hooks are left in place.
15
+ - The installed-hook check now requires both events, so an install from before 0.14.0 reads as out of date and re-running setup upgrades it.
16
+ - **Pin tracker MCP to 0.27.1 (was 0.20.1) and registry MCP to 0.11.4 (was 0.8.0).** Both pins had fallen several releases behind; under the bump rule in `src/lib/mcp-packages.ts` a setup release stamps whatever it pins, so the old pair would have shipped again. Tracker MCP 0.27.1 uses ops-sdk 6.14.0.
17
+ - The Codex read-only auto-approve lists were checked against the `sideEffects: 'read'` entries in each pinned package's published `dist/config/tool-registry.js` (33 tracker, 32 registry): both already matched, so no change.
18
+ - Tracker MCP ≥ 0.22.0 gates 12 destructive tools behind `ULUOPS_ALLOW_DESTRUCTIVE`. Setup does not write it, so they stay enabled (the pre-0.22 behaviour) and the server logs a boot warning. Setting it is the operator's call, not setup's.
19
+ - `prepublishOnly` now runs `npm test && npm run typecheck && npm run build` (was build only).
20
+ - Bundle `@uluops/agent-metrics` **0.12.0** (previously 0.11.0). Tracker output from the hook buffer now carries `definition_version`, and contended buffer writes are spilled rather than dropped.
21
+
7
22
  ## [0.13.1] - 2026-09-17
8
23
 
9
24
  ### Changed
package/README.md CHANGED
@@ -18,9 +18,9 @@ npx @uluops/setup
18
18
 
19
19
  ## Supported harnesses
20
20
 
21
- Setup 0.13.1 bundles agent-metrics **0.11.0** for hook installation and pins
22
- tracker MCP **0.20.1** and registry MCP **0.8.0** in generated configs. Tracker
23
- MCP uses ops-sdk **6.5.2**. Re-run setup to refresh existing configs and hook
21
+ Setup 0.14.0 bundles agent-metrics **0.12.0** for hook installation and pins
22
+ tracker MCP **0.27.1** and registry MCP **0.11.4** in generated configs. Tracker
23
+ MCP uses ops-sdk **6.14.0**. Re-run setup to refresh existing configs and hook
24
24
  files, then restart the affected MCP connections in your harness.
25
25
 
26
26
  Optional global CLI installs resolve npm's current release when the CLI is
@@ -122,7 +122,7 @@ The installer runs these steps in sequence:
122
122
  2. **Registry username** *(optional)* — Offers to set your registry username, the one-time prerequisite for creating or publishing definitions. Never forced: consumers who only run definitions don't need one, and non-interactive runs skip it silently unless `--username <name>` is supplied.
123
123
  3. **MCP config** — Writes tracker and registry server entries to the harness config
124
124
  4. **Definitions** — Copies pre-rendered agent definition files
125
- 5. **Metrics hook** — Configures a post-agent hook for automatic run capture (Claude Code and Gemini CLI)
125
+ 5. **Metrics hook** — Configures a post-agent hook for automatic run capture (Claude Code and Gemini CLI). On Claude Code it registers the same command on `SubagentStart` and `SubagentStop`. The start event records which agent definition each subagent was spawned with, so saved runs carry each agent's own `definition_version`. A setup from before 0.14.0 is detected and upgraded on re-run.
126
126
  6. **`ulu` CLI** *(optional)* — Offers to install `@uluops/cli` globally. Interactive runs are prompted (default Y); non-interactive runs skip unless `--with-cli` is passed. `--no-cli` always skips. The install is best-effort: if `npm install -g` fails (permissions, nvm prefix, etc.) the rest of setup still completes and a manual install command is printed.
127
127
  7. **Health check** — Verifies both API endpoints are reachable
128
128
 
@@ -327,8 +327,9 @@ Removes only UluOps-managed files: agents, commands, MCP config entries, shell p
327
327
  ## Data & privacy
328
328
 
329
329
  The metrics hook (step 5) captures **agent execution metadata only** — token
330
- counts, durations, model and agent names — into a **local buffer** on your
331
- machine. The hook itself sends nothing anywhere: data reaches the UluOps
330
+ counts, durations, model and agent names, and (from agent-metrics 0.12.0) the
331
+ version, path and content hash of the agent definition file that ran — into a
332
+ **local buffer** on your machine. The hook itself sends nothing anywhere: data reaches the UluOps
332
333
  tracker only when a run is explicitly saved (by you, or by tooling you run).
333
334
  Artifact content being validated is never stored — only validation results.
334
335
 
@@ -7,7 +7,7 @@
7
7
  import { join } from "node:path";
8
8
  import { ULUOPS_SERVERS, } from "./types.js";
9
9
  import { readConfig, mergeUluopsMcp, removeUluopsMcp, writeConfig, } from "../lib/config-merger.js";
10
- import { readSettings, writeSettings, mergeUluopsHook, removeUluopsHook, hasUluopsHook, } from "../lib/settings-merger.js";
10
+ import { readSettings, writeSettings, mergeUluopsHook, removeUluopsHook, hasUluopsHook, claudeManagedHookTypes, } from "../lib/settings-merger.js";
11
11
  import { getClaudeHome, getClaudeJsonPath } from "../lib/paths.js";
12
12
  import { serialize } from "../lib/write-coordinator.js";
13
13
  class ClaudeCodeMcpConfig {
@@ -39,8 +39,9 @@ class ClaudeCodeHooks {
39
39
  // collide today".
40
40
  await serialize(settingsPath, async () => {
41
41
  const settings = await readSettings(settingsPath);
42
- // Claude Code uses SubagentStop as the default event for auto-save
43
- const merged = mergeUluopsHook(settings, hookCommand);
42
+ // Claude Code uses SubagentStop as the default event for auto-save, plus
43
+ // SubagentStart for definition capture (agent-metrics 0.12.0).
44
+ const merged = claudeManagedHookTypes().reduce((acc, type) => mergeUluopsHook(acc, hookCommand, type), settings);
44
45
  await writeSettings(settingsPath, merged);
45
46
  });
46
47
  return true;
@@ -50,13 +51,19 @@ class ClaudeCodeHooks {
50
51
  return;
51
52
  await serialize(settingsPath, async () => {
52
53
  const settings = await readSettings(settingsPath);
53
- const cleaned = removeUluopsHook(settings);
54
+ // Every event type present, not just the ones the current env would install:
55
+ // an install made under a different ULUOPS_HOOK_TYPE (or before SubagentStart was
56
+ // managed) must still come out. isUluopsMatcher identifies ours; user hooks stay.
57
+ const types = new Set([...claudeManagedHookTypes(), ...Object.keys(settings.hooks ?? {})]);
58
+ const cleaned = [...types].reduce((acc, type) => removeUluopsHook(acc, type), settings);
54
59
  await writeSettings(settingsPath, cleaned);
55
60
  });
56
61
  }
57
62
  async check(settingsPath) {
58
63
  const settings = await readSettings(settingsPath);
59
- return hasUluopsHook(settings);
64
+ // Every managed event must be present: an install from before 0.14.0 has
65
+ // SubagentStop only, and reads as needing the upgrade.
66
+ return claudeManagedHookTypes().every((type) => hasUluopsHook(settings, type));
60
67
  }
61
68
  }
62
69
  const home = getClaudeHome();
@@ -22,11 +22,11 @@
22
22
  * MCP launch. A pin is not a publish; the probe is what enforces that here.
23
23
  */
24
24
  export declare const OPS_MCP_PACKAGE = "@uluops/ops-mcp";
25
- export declare const OPS_MCP_VERSION = "0.20.1";
26
- export declare const OPS_MCP_SPEC: "@uluops/ops-mcp@0.20.1";
25
+ export declare const OPS_MCP_VERSION = "0.27.1";
26
+ export declare const OPS_MCP_SPEC: "@uluops/ops-mcp@0.27.1";
27
27
  export declare const REGISTRY_MCP_PACKAGE = "@uluops/registry-mcp";
28
- export declare const REGISTRY_MCP_VERSION = "0.8.0";
29
- export declare const REGISTRY_MCP_SPEC: "@uluops/registry-mcp@0.8.0";
28
+ export declare const REGISTRY_MCP_VERSION = "0.11.4";
29
+ export declare const REGISTRY_MCP_SPEC: "@uluops/registry-mcp@0.11.4";
30
30
  /** Probe targets: the pinned versions the harness will actually resolve. */
31
31
  export declare const MCP_PROBE_TARGETS: readonly {
32
32
  pkg: string;
@@ -22,10 +22,10 @@
22
22
  * MCP launch. A pin is not a publish; the probe is what enforces that here.
23
23
  */
24
24
  export const OPS_MCP_PACKAGE = "@uluops/ops-mcp";
25
- export const OPS_MCP_VERSION = "0.20.1";
25
+ export const OPS_MCP_VERSION = "0.27.1";
26
26
  export const OPS_MCP_SPEC = `${OPS_MCP_PACKAGE}@${OPS_MCP_VERSION}`;
27
27
  export const REGISTRY_MCP_PACKAGE = "@uluops/registry-mcp";
28
- export const REGISTRY_MCP_VERSION = "0.8.0";
28
+ export const REGISTRY_MCP_VERSION = "0.11.4";
29
29
  export const REGISTRY_MCP_SPEC = `${REGISTRY_MCP_PACKAGE}@${REGISTRY_MCP_VERSION}`;
30
30
  /** Probe targets: the pinned versions the harness will actually resolve. */
31
31
  export const MCP_PROBE_TARGETS = [
@@ -33,6 +33,18 @@ export interface HarnessSettings {
33
33
  export declare const CLAUDE_HOOK_TYPES: Set<string>;
34
34
  /** Default Claude Code hook event used when no override is configured. */
35
35
  export declare const DEFAULT_CLAUDE_HOOK_TYPE = "SubagentStop";
36
+ /**
37
+ * The companion event installed beside the default one (agent-metrics 0.12.0,
38
+ * dvc checklist X4-1). agent-metrics records which agent definition a subagent was
39
+ * spawned with at SubagentStart and confirms it at SubagentStop; Claude Code loads a
40
+ * subagent's definition at spawn, so a stop-time read alone would record a
41
+ * definition reinstalled mid-run. Same command: the hook dispatches on
42
+ * `hook_event_name`. Installed only with the default event — a user who overrode
43
+ * the event type (ULUOPS_HOOK_TYPE) gets exactly what they asked for.
44
+ */
45
+ export declare const CLAUDE_SPAWN_HOOK_TYPE = "SubagentStart";
46
+ /** The hook event types setup manages for Claude Code, given the resolved primary type. */
47
+ export declare function claudeManagedHookTypes(primary?: string): string[];
36
48
  export interface HookProbeResult {
37
49
  hookType: string;
38
50
  supported: boolean;
@@ -37,6 +37,7 @@ const HOOK_OWNERSHIP_SIGNATURE = "agent-metrics/dist/hook.js";
37
37
  * Exported for that test only — runtime callers should use `probeHookSupport`.
38
38
  */
39
39
  export const CLAUDE_HOOK_TYPES = new Set([
40
+ "SubagentStart",
40
41
  "SubagentStop",
41
42
  "PreToolUse",
42
43
  "PostToolUse",
@@ -45,6 +46,20 @@ export const CLAUDE_HOOK_TYPES = new Set([
45
46
  ]);
46
47
  /** Default Claude Code hook event used when no override is configured. */
47
48
  export const DEFAULT_CLAUDE_HOOK_TYPE = "SubagentStop";
49
+ /**
50
+ * The companion event installed beside the default one (agent-metrics 0.12.0,
51
+ * dvc checklist X4-1). agent-metrics records which agent definition a subagent was
52
+ * spawned with at SubagentStart and confirms it at SubagentStop; Claude Code loads a
53
+ * subagent's definition at spawn, so a stop-time read alone would record a
54
+ * definition reinstalled mid-run. Same command: the hook dispatches on
55
+ * `hook_event_name`. Installed only with the default event — a user who overrode
56
+ * the event type (ULUOPS_HOOK_TYPE) gets exactly what they asked for.
57
+ */
58
+ export const CLAUDE_SPAWN_HOOK_TYPE = "SubagentStart";
59
+ /** The hook event types setup manages for Claude Code, given the resolved primary type. */
60
+ export function claudeManagedHookTypes(primary = getDefaultHookEventType()) {
61
+ return primary === DEFAULT_CLAUDE_HOOK_TYPE ? [primary, CLAUDE_SPAWN_HOOK_TYPE] : [primary];
62
+ }
48
63
  /** Configurable hook type via env var. Falls back to SubagentStop. */
49
64
  function getDefaultHookEventType() {
50
65
  return process.env["ULUOPS_HOOK_TYPE"] ?? DEFAULT_CLAUDE_HOOK_TYPE;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uluops/setup",
3
- "version": "0.13.1",
3
+ "version": "0.14.0",
4
4
  "description": "Zero-friction installer for UluOps agentic harnesses",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -13,6 +13,7 @@
13
13
  "mcp",
14
14
  "agents",
15
15
  "claude",
16
+ "codex",
16
17
  "opencode",
17
18
  "agentic",
18
19
  "harness",
@@ -45,11 +46,11 @@
45
46
  "typecheck": "tsc -p tsconfig.build.json --noEmit && tsc -p tsconfig.test.json --noEmit",
46
47
  "test": "vitest run",
47
48
  "test:watch": "vitest watch",
48
- "prepublishOnly": "npm run build"
49
+ "prepublishOnly": "npm test && npm run typecheck && npm run build"
49
50
  },
50
51
  "dependencies": {
51
52
  "@inquirer/prompts": "8.6.0",
52
- "@uluops/agent-metrics": "0.11.0",
53
+ "@uluops/agent-metrics": "0.12.0",
53
54
  "chalk": "5.6.2",
54
55
  "commander": "15.0.0",
55
56
  "jsonc-parser": "3.3.1"