@pleri/olam-cli 0.1.185 → 0.1.188

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 (58) hide show
  1. package/dist/ask/knowledge-pack-builder.d.ts.map +1 -1
  2. package/dist/ask/knowledge-pack-builder.js +5 -0
  3. package/dist/ask/knowledge-pack-builder.js.map +1 -1
  4. package/dist/ask/knowledge-pack.generated.d.ts.map +1 -1
  5. package/dist/ask/knowledge-pack.generated.js +406 -22
  6. package/dist/ask/knowledge-pack.generated.js.map +1 -1
  7. package/dist/commands/auth-status.js +2 -2
  8. package/dist/commands/auth-status.js.map +1 -1
  9. package/dist/commands/auth.js +1 -1
  10. package/dist/commands/auth.js.map +1 -1
  11. package/dist/commands/create.d.ts.map +1 -1
  12. package/dist/commands/create.js +4 -0
  13. package/dist/commands/create.js.map +1 -1
  14. package/dist/commands/install.js +2 -2
  15. package/dist/commands/install.js.map +1 -1
  16. package/dist/commands/services.d.ts.map +1 -1
  17. package/dist/commands/services.js +12 -0
  18. package/dist/commands/services.js.map +1 -1
  19. package/dist/commands/setup.js +1 -1
  20. package/dist/commands/setup.js.map +1 -1
  21. package/dist/commands/status.d.ts.map +1 -1
  22. package/dist/commands/status.js +4 -0
  23. package/dist/commands/status.js.map +1 -1
  24. package/dist/image-digests.json +8 -8
  25. package/dist/index.js +788 -368
  26. package/dist/lib/health-probes.d.ts +14 -0
  27. package/dist/lib/health-probes.d.ts.map +1 -1
  28. package/dist/lib/health-probes.js +41 -3
  29. package/dist/lib/health-probes.js.map +1 -1
  30. package/dist/mcp-server.js +95 -27
  31. package/hermes-bundle/version.json +1 -1
  32. package/host-cp/k8s/manifests/50-deployment.yaml +1 -1
  33. package/host-cp/k8s/manifests/auth-service/50-deployment.yaml +1 -1
  34. package/host-cp/k8s/manifests/chunks-electric/10-serviceaccount.yaml +8 -0
  35. package/host-cp/k8s/manifests/chunks-electric/20-rbac.yaml +27 -0
  36. package/host-cp/k8s/manifests/chunks-electric/30-configmap.yaml +23 -0
  37. package/host-cp/k8s/manifests/chunks-electric/45-pvc.yaml +19 -0
  38. package/host-cp/k8s/manifests/chunks-electric/50-deployment.yaml +84 -0
  39. package/host-cp/k8s/manifests/chunks-electric/60-service.yaml +17 -0
  40. package/host-cp/k8s/manifests/chunks-postgres/10-serviceaccount.yaml +8 -0
  41. package/host-cp/k8s/manifests/chunks-postgres/20-rbac.yaml +29 -0
  42. package/host-cp/k8s/manifests/chunks-postgres/30-configmap.yaml +185 -0
  43. package/host-cp/k8s/manifests/chunks-postgres/45-pvc.yaml +24 -0
  44. package/host-cp/k8s/manifests/chunks-postgres/50-deployment.yaml +101 -0
  45. package/host-cp/k8s/manifests/chunks-postgres/60-service.yaml +24 -0
  46. package/host-cp/k8s/manifests/kg-service/50-deployment.yaml +1 -1
  47. package/host-cp/k8s/manifests/mcp-auth-service/50-deployment.yaml +1 -1
  48. package/host-cp/k8s/manifests/memory-service/50-deployment.yaml +1 -1
  49. package/host-cp/k8s/manifests/plan-chat-service/10-serviceaccount.yaml +8 -0
  50. package/host-cp/k8s/manifests/plan-chat-service/20-rbac.yaml +29 -0
  51. package/host-cp/k8s/manifests/plan-chat-service/30-configmap.yaml +36 -0
  52. package/host-cp/k8s/manifests/plan-chat-service/45-pvc.yaml +24 -0
  53. package/host-cp/k8s/manifests/plan-chat-service/50-deployment.yaml +135 -0
  54. package/host-cp/k8s/manifests/plan-chat-service/60-service.yaml +17 -0
  55. package/host-cp/src/plan-chat-service.mjs +216 -0
  56. package/host-cp/src/pr-cache.mjs +11 -2
  57. package/host-cp/src/server.mjs +36 -20
  58. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5581,7 +5581,8 @@ var init_client = __esm({
5581
5581
 
5582
5582
  // ../core/dist/auth/container.js
5583
5583
  import { execFileSync, spawnSync } from "node:child_process";
5584
- import { existsSync as existsSync10 } from "node:fs";
5584
+ import { chmodSync as chmodSync2, existsSync as existsSync10, mkdtempSync, rmSync, writeFileSync as writeFileSync6 } from "node:fs";
5585
+ import { tmpdir as tmpdir2 } from "node:os";
5585
5586
  import * as path9 from "node:path";
5586
5587
  import { fileURLToPath as fileURLToPath2 } from "node:url";
5587
5588
  function resolveAuthServicePath() {
@@ -5671,28 +5672,41 @@ var init_container = __esm({
5671
5672
  /**
5672
5673
  * `docker run` the auth container. Injects the shared secret so every
5673
5674
  * /credentials* request must present X-Olam-Secret to succeed.
5675
+ *
5676
+ * The secret is written to a 0600-permissioned temp file and passed via
5677
+ * `--env-file` so it never appears in `ps aux` / `/proc/<pid>/cmdline`
5678
+ * during the spawn window.
5674
5679
  */
5675
5680
  runContainer() {
5676
5681
  const secret = getOrCreateSecret();
5677
- execFileSync("docker", [
5678
- "run",
5679
- "--detach",
5680
- "--name",
5681
- this.containerName,
5682
- "--restart",
5683
- "unless-stopped",
5684
- "--publish",
5685
- `${this.port}:9999`,
5686
- "--volume",
5687
- `${this.volume}:/auth-data`,
5688
- "--env",
5689
- `AUTH_BIND=0.0.0.0`,
5690
- "--env",
5691
- `AUTH_DATA_DIR=/auth-data`,
5692
- "--env",
5693
- `OLAM_AUTH_SECRET=${secret}`,
5694
- this.imageTag
5695
- ], { stdio: "pipe" });
5682
+ const tmpDir = mkdtempSync(path9.join(tmpdir2(), "olam-auth-"));
5683
+ const envFilePath = path9.join(tmpDir, "env");
5684
+ writeFileSync6(envFilePath, `OLAM_AUTH_SECRET=${secret}
5685
+ `, { mode: 384 });
5686
+ chmodSync2(envFilePath, 384);
5687
+ try {
5688
+ execFileSync("docker", [
5689
+ "run",
5690
+ "--detach",
5691
+ "--name",
5692
+ this.containerName,
5693
+ "--restart",
5694
+ "unless-stopped",
5695
+ "--publish",
5696
+ `${this.port}:9999`,
5697
+ "--volume",
5698
+ `${this.volume}:/auth-data`,
5699
+ "--env",
5700
+ `AUTH_BIND=0.0.0.0`,
5701
+ "--env",
5702
+ `AUTH_DATA_DIR=/auth-data`,
5703
+ "--env-file",
5704
+ envFilePath,
5705
+ this.imageTag
5706
+ ], { stdio: "pipe" });
5707
+ } finally {
5708
+ rmSync(tmpDir, { recursive: true, force: true });
5709
+ }
5696
5710
  }
5697
5711
  stop() {
5698
5712
  const current = this.status();
@@ -7701,7 +7715,7 @@ async function probeAuthVault(olamHomeOverride) {
7701
7715
  return {
7702
7716
  ok: false,
7703
7717
  message: `auth vault missing at ${vaultPath}`,
7704
- remedy: "Run `olam auth up && olam auth login` to provision the vault."
7718
+ remedy: "Run `olam services up && olam auth login` to provision the vault."
7705
7719
  };
7706
7720
  }
7707
7721
  let parsed;
@@ -7711,14 +7725,14 @@ async function probeAuthVault(olamHomeOverride) {
7711
7725
  return {
7712
7726
  ok: false,
7713
7727
  message: `auth vault malformed: ${err.message}`,
7714
- remedy: "Inspect the accounts.json file; restore from backup or re-run `olam auth up`."
7728
+ remedy: "Inspect the accounts.json file; restore from backup or re-run `olam services up`."
7715
7729
  };
7716
7730
  }
7717
7731
  if (!Array.isArray(parsed)) {
7718
7732
  return {
7719
7733
  ok: false,
7720
7734
  message: "auth vault malformed: expected JSON array at top level",
7721
- remedy: "Restore the vault from backup or re-run `olam auth up && olam auth login`."
7735
+ remedy: "Restore the vault from backup or re-run `olam services up && olam auth login`."
7722
7736
  };
7723
7737
  }
7724
7738
  const accounts = parsed.filter((a) => a !== null && typeof a === "object");
@@ -7766,7 +7780,8 @@ async function probeKgStorage(olamHomeOverride) {
7766
7780
  if (totalBytes >= SOFT_CAP_BYTES) {
7767
7781
  return {
7768
7782
  ok: true,
7769
- message: `KG storage ${formatBytes(totalBytes)} (soft-warn \u2014 exceeds 1.5 GB; consider pruning)`
7783
+ message: `KG storage ${formatBytes(totalBytes)} (soft-warn \u2014 exceeds 1.5 GB; consider pruning)`,
7784
+ remedy: "Prune stale pristines: `rm -rf ~/.olam/kg/<workspace>` or raise OLAM_KG_SOFT_CAP."
7770
7785
  };
7771
7786
  }
7772
7787
  return { ok: true, message: `KG storage ${formatBytes(totalBytes)} (under cap)` };
@@ -21693,12 +21708,12 @@ function nextStepsFor(archetype) {
21693
21708
  ];
21694
21709
  case "bootstrapper":
21695
21710
  return [
21696
- "Start the auth container: `olam auth up`, then `olam auth login`.",
21711
+ "Start the auth container: `olam services up`, then `olam auth login`.",
21697
21712
  "For Cloudflare deployments: `cd packages/cloudflare-worker && pnpm wrangler deploy`."
21698
21713
  ];
21699
21714
  case "admin":
21700
21715
  return [
21701
- "Start the auth container: `olam auth up`, then `olam auth login`.",
21716
+ "Start the auth container: `olam services up`, then `olam auth login`.",
21702
21717
  "Curate workspaces: `olam workspace add <name> --from-config`.",
21703
21718
  "Assign narrower archetypes to teammates (CF side, once slice C lands): use `role.manage`."
21704
21719
  ];
@@ -21893,8 +21908,8 @@ import {
21893
21908
  existsSync as existsSync30,
21894
21909
  mkdirSync as mkdirSync19,
21895
21910
  readdirSync as readdirSync9,
21896
- writeFileSync as writeFileSync15,
21897
- chmodSync as chmodSync4
21911
+ writeFileSync as writeFileSync16,
21912
+ chmodSync as chmodSync5
21898
21913
  } from "node:fs";
21899
21914
  import { join as join36 } from "node:path";
21900
21915
  import { homedir as homedir21, platform } from "node:os";
@@ -22010,7 +22025,7 @@ init_install_root();
22010
22025
 
22011
22026
  // src/lib/k8s-secret-render.ts
22012
22027
  import { spawnSync as spawnSync8 } from "node:child_process";
22013
- import { existsSync as existsSync28, readFileSync as readFileSync24, writeFileSync as writeFileSync14, mkdirSync as mkdirSync18, chmodSync as chmodSync3, renameSync as renameSync5 } from "node:fs";
22028
+ import { existsSync as existsSync28, readFileSync as readFileSync24, writeFileSync as writeFileSync15, mkdirSync as mkdirSync18, chmodSync as chmodSync4, renameSync as renameSync5 } from "node:fs";
22014
22029
  import { join as join34, dirname as dirname21 } from "node:path";
22015
22030
  import { randomBytes as randomBytes6 } from "node:crypto";
22016
22031
  var K8S_SECRETS_STATE_PATH = join34(OLAM_HOME, "k8s-secrets-state.json");
@@ -22110,8 +22125,8 @@ var defaultRunGhTokenCmd = () => {
22110
22125
  var defaultReadFile = (p, enc) => readFileSync24(p, enc);
22111
22126
  var defaultWriteFile = (p, data, mode) => {
22112
22127
  mkdirSync18(dirname21(p), { recursive: true });
22113
- writeFileSync14(p, data, { encoding: "utf8", mode });
22114
- chmodSync3(p, mode);
22128
+ writeFileSync15(p, data, { encoding: "utf8", mode });
22129
+ chmodSync4(p, mode);
22115
22130
  };
22116
22131
  var defaultFileExists = (p) => existsSync28(p);
22117
22132
  function readSecretsState(statePath = K8S_SECRETS_STATE_PATH) {
@@ -22128,8 +22143,8 @@ function readSecretsState(statePath = K8S_SECRETS_STATE_PATH) {
22128
22143
  function writeSecretsState(state, statePath = K8S_SECRETS_STATE_PATH) {
22129
22144
  mkdirSync18(dirname21(statePath), { recursive: true });
22130
22145
  const tmp = `${statePath}.tmp.${process.pid}`;
22131
- writeFileSync14(tmp, JSON.stringify(state, null, 2) + "\n", { encoding: "utf8", mode: 384 });
22132
- chmodSync3(tmp, 384);
22146
+ writeFileSync15(tmp, JSON.stringify(state, null, 2) + "\n", { encoding: "utf8", mode: 384 });
22147
+ chmodSync4(tmp, 384);
22133
22148
  renameSync5(tmp, statePath);
22134
22149
  }
22135
22150
  function resolveSourceValue(source, olamHome5, reuseFromState, rotate, deps) {
@@ -22497,8 +22512,8 @@ function ensureSecrets() {
22497
22512
  continue;
22498
22513
  }
22499
22514
  const hex = randomBytes7(32).toString("hex");
22500
- writeFileSync15(path101, hex + "\n", { encoding: "utf8", mode: 384 });
22501
- chmodSync4(path101, 384);
22515
+ writeFileSync16(path101, hex + "\n", { encoding: "utf8", mode: 384 });
22516
+ chmodSync5(path101, 384);
22502
22517
  printSuccess(`generated ~/.olam/${name}`);
22503
22518
  }
22504
22519
  }
@@ -23647,7 +23662,7 @@ import { homedir as homedir24 } from "node:os";
23647
23662
  import { join as join41 } from "node:path";
23648
23663
 
23649
23664
  // src/lib/memory-secret.ts
23650
- import { existsSync as existsSync33, mkdirSync as mkdirSync22, readFileSync as readFileSync27, statSync as statSync8, writeFileSync as writeFileSync17, renameSync as renameSync6, chmodSync as chmodSync6 } from "node:fs";
23665
+ import { existsSync as existsSync33, mkdirSync as mkdirSync22, readFileSync as readFileSync27, statSync as statSync8, writeFileSync as writeFileSync18, renameSync as renameSync6, chmodSync as chmodSync7 } from "node:fs";
23651
23666
  import { homedir as homedir23 } from "node:os";
23652
23667
  import { join as join40, dirname as dirname23 } from "node:path";
23653
23668
  import { randomBytes as randomBytes8 } from "node:crypto";
@@ -23660,8 +23675,8 @@ function generateSecret() {
23660
23675
  function writeSecretAtPath(path101, value) {
23661
23676
  mkdirSync22(dirname23(path101), { recursive: true });
23662
23677
  const tmp = `${path101}.tmp.${process.pid}`;
23663
- writeFileSync17(tmp, value, { mode: 384 });
23664
- chmodSync6(tmp, 384);
23678
+ writeFileSync18(tmp, value, { mode: 384 });
23679
+ chmodSync7(tmp, 384);
23665
23680
  renameSync6(tmp, path101);
23666
23681
  }
23667
23682
  function readSecretAtPathOrNull(path101) {
@@ -24404,6 +24419,10 @@ async function servicesUp() {
24404
24419
  if (!ready) {
24405
24420
  printError(`olam-auth started but /health did not respond within ${MCP_AUTH_HEALTH_TIMEOUT_MS / 1e3}s.`);
24406
24421
  dumpContainerLogs("olam-auth");
24422
+ printError("\nTry:");
24423
+ printError(" - olam doctor # check service prereqs");
24424
+ printError(" - docker logs olam-auth # full logs");
24425
+ printError(" - docker restart olam-auth # restart");
24407
24426
  return { exitCode: 1 };
24408
24427
  }
24409
24428
  printSuccess("olam-auth started");
@@ -24422,6 +24441,10 @@ async function servicesUp() {
24422
24441
  if (!ready) {
24423
24442
  printError(`olam-mcp-auth started but /health did not respond within ${MCP_AUTH_HEALTH_TIMEOUT_MS / 1e3}s.`);
24424
24443
  dumpContainerLogs("olam-mcp-auth");
24444
+ printError("\nTry:");
24445
+ printError(" - olam doctor # check service prereqs");
24446
+ printError(" - docker logs olam-mcp-auth # full logs");
24447
+ printError(" - docker restart olam-mcp-auth # restart");
24425
24448
  return { exitCode: 1 };
24426
24449
  }
24427
24450
  printSuccess("olam-mcp-auth started");
@@ -24488,6 +24511,10 @@ async function servicesUp() {
24488
24511
  `olam-memory-service started but /agentmemory/livez did not respond within ${MEMORY_SERVICE_HEALTH_TIMEOUT_MS / 1e3}s.`
24489
24512
  );
24490
24513
  dumpContainerLogs("olam-memory-service");
24514
+ printError("\nTry:");
24515
+ printError(" - olam doctor # check service prereqs");
24516
+ printError(" - docker logs olam-memory-service # full logs");
24517
+ printError(" - docker restart olam-memory-service # restart");
24491
24518
  return { exitCode: 1 };
24492
24519
  }
24493
24520
  printSuccess("olam-memory-service started");
@@ -26449,7 +26476,7 @@ ${pc12.dim("Tip: set ANTHROPIC_BASE_URL=" + baseUrl.replace(/\/+$/, "") + "/v1/p
26449
26476
  process.exitCode = 1;
26450
26477
  return;
26451
26478
  }
26452
- printError("Auth container is not reachable. Run `olam auth up` first.");
26479
+ printError("Auth container is not reachable. Run `olam services up` first.");
26453
26480
  process.exitCode = 1;
26454
26481
  return;
26455
26482
  }
@@ -26865,20 +26892,16 @@ codes are explicit: \`3\` = pull failed, \`4\` = protocol mismatch.
26865
26892
 
26866
26893
  ## Quick start
26867
26894
 
26895
+ **Two paths: Kubernetes (default, full-featured) or Docker Compose (lighter, for CI).**
26896
+
26897
+ ### Kubernetes (recommended)
26898
+
26868
26899
  \`\`\`bash
26869
26900
  curl -fsSL https://olam.bar.dev/install | sh
26870
26901
  olam setup
26871
26902
  \`\`\`
26872
26903
 
26873
- That's it. The installer puts \`@pleri/olam-cli\` on your PATH (requires Node.js \u2265 20 and npm). \`olam setup\` installs k3d (if absent), creates a local Kubernetes cluster named \`olam-dev\`, and brings up the full peripheral stack (host-cp, auth-service, mcp-auth-service, kg-service, memory-service). Works on macOS and Linux. No source checkout required.
26874
-
26875
- The setup wizard is **idempotent** \u2014 re-running skips steps that are already complete.
26876
-
26877
- After setup, every world is one call:
26878
-
26879
- \`\`\`bash
26880
- olam create --name my-world --task "audit the auth module for SSRF"
26881
- \`\`\`
26904
+ The installer puts \`@pleri/olam-cli\` on your PATH (requires Node.js \u2265 20 and npm). \`olam setup\` installs k3d (if absent), creates a local Kubernetes cluster named \`olam-dev\`, and brings up the full peripheral stack (host-cp, auth-service, mcp-auth-service, kg-service, memory-service). Works on macOS and Linux. No source checkout required. The setup wizard is **idempotent** \u2014 re-running skips steps that are already complete.
26882
26905
 
26883
26906
  Full setup guide (prereqs, observability, troubleshooting):
26884
26907
  [\`docs/onboarding/k3s-mode-setup.md\`](./docs/onboarding/k3s-mode-setup.md).
@@ -26896,6 +26919,16 @@ This runs three host containers (auth, mcp-auth, kg-service) via docker compose
26896
26919
 
26897
26920
  Full setup guide for compose mode: [\`docs/onboarding/fresh-machine-setup.md\`](./docs/onboarding/fresh-machine-setup.md).
26898
26921
 
26922
+ ### Create your first world
26923
+
26924
+ After setup completes, every world is one call:
26925
+
26926
+ \`\`\`bash
26927
+ olam create --name my-world --task "audit the auth module for SSRF"
26928
+ \`\`\`
26929
+
26930
+ Open the dashboard URL in your browser \u2014 you'll see the world provisioning, credentials flowing in from the vault, and your task dispatching to an in-world Claude session.
26931
+
26899
26932
  ---
26900
26933
 
26901
26934
  ## Setup
@@ -27475,6 +27508,7 @@ Source: \`docs/ONBOARDING.md\`
27475
27508
 
27476
27509
  - **Docker daemon** running (Docker Desktop, or colima on macOS)
27477
27510
  - **Node.js \u2265 20** (\`node --version\`)
27511
+ - **GitHub CLI authenticated** (\`gh auth login\`) \u2014 \`olam setup\` uses \`gh auth token\` to create a GHCR pull secret; skipping this fails on first image pull
27478
27512
  - **Claude Code** (\`claude --version\`) \u2014 authenticated via \`claude auth login\`
27479
27513
  - **Git** with SSH key configured for your repos
27480
27514
 
@@ -27485,7 +27519,7 @@ Source: \`docs/ONBOARDING.md\`
27485
27519
  No source checkout required \u2014 the CLI publishes to npm:
27486
27520
 
27487
27521
  \`\`\`bash
27488
- curl -fsSL https://olam.bar.dev/install | sh # installs @pleri/olam-cli on PATH
27522
+ curl -fsSL https://olam.bar.dev/install | sh # installs @pleri/olam-cli on PATH (PLERI is the GitHub org & npm scope)
27489
27523
  olam setup # k3d cluster + full peripheral stack
27490
27524
  \`\`\`
27491
27525
 
@@ -27496,7 +27530,15 @@ mcp-auth-service, kg-service, and memory-service. Pass
27496
27530
  no cluster). Full guide:
27497
27531
  [\`docs/onboarding/k3s-mode-setup.md\`](onboarding/k3s-mode-setup.md).
27498
27532
 
27499
- ## 2. Register the MCP server (1 minute)
27533
+ ## 2. Verify your setup (1 minute)
27534
+
27535
+ \`\`\`bash
27536
+ olam doctor # runs 8\u201323 checks: auth, services, vault, network
27537
+ \`\`\`
27538
+
27539
+ This diagnoses common issues (Docker daemon, images, credentials, etc.). Any FAIL row shows an actionable remedy \u2014 fix and re-run until all rows PASS.
27540
+
27541
+ ## 3. Register the MCP server (1 minute)
27500
27542
 
27501
27543
  \`\`\`bash
27502
27544
  olam mcp install # default --scope=user
@@ -27509,7 +27551,7 @@ worlds directly. Core tools: \`olam_create\`, \`olam_dispatch\`,
27509
27551
  \`olam_enter\`, \`olam_crystallize\`, \`olam_pr_*\`. Restart Claude Code and
27510
27552
  verify with \`claude mcp list\` (look for \`olam\`).
27511
27553
 
27512
- ## 3. Configure your repos (2 minutes)
27554
+ ## 4. Configure your repos (2 minutes)
27513
27555
 
27514
27556
  Point Olam at the repos a world should clone. Use the interactive
27515
27557
  wizard:
@@ -27524,7 +27566,7 @@ world-runner tier (\`docker\` | \`cloudflare\` | \`cloudflare-isolate\`). See
27524
27566
  [\`docs/architecture/config-spec.md\`](architecture/config-spec.md) for
27525
27567
  the full schema.
27526
27568
 
27527
- ## 4. Create your first world (2 minutes)
27569
+ ## 5. Create your first world (2 minutes)
27528
27570
 
27529
27571
  In Claude Code, say:
27530
27572
 
@@ -27536,9 +27578,9 @@ Claude will:
27536
27578
  1. Create a Docker container (or CF Sandbox) with your repo cloned
27537
27579
  2. Set up git worktrees for isolation
27538
27580
  3. Boot the in-world Claude session and auto-dispatch the task
27539
- 4. Return the Host CP dashboard URL (\`http://127.0.0.1:19000\`)
27581
+ 4. Return the Host CP dashboard URL (\`http://127.0.0.1:19001\`)
27540
27582
 
27541
- ## 5. Dispatch a task (1 minute)
27583
+ ## 6. Dispatch a task (1 minute)
27542
27584
 
27543
27585
  \`\`\`
27544
27586
  Dispatch to the world: investigate and fix the session timeout issue
@@ -27546,7 +27588,7 @@ Dispatch to the world: investigate and fix the session timeout issue
27546
27588
 
27547
27589
  Claude Code runs autonomously inside the world. Every tool call, every decision, every exploration is captured as a thought node.
27548
27590
 
27549
- ## 6. Watch it work (ongoing)
27591
+ ## 7. Watch it work (ongoing)
27550
27592
 
27551
27593
  **Dashboard:** Open the Host CP URL from step 4. You'll see:
27552
27594
  - the **seed of thought** pinned at the top (the immutable task)
@@ -27561,7 +27603,7 @@ Claude Code runs autonomously inside the world. Every tool call, every decision,
27561
27603
  What is the world thinking right now?
27562
27604
  \`\`\`
27563
27605
 
27564
- ## 7. Clean up
27606
+ ## 8. Clean up
27565
27607
 
27566
27608
  \`\`\`
27567
27609
  Crystallize and destroy the world
@@ -27583,7 +27625,7 @@ after \`olam setup\`):
27583
27625
  \`\`\`bash
27584
27626
  olam create --name login-fix --repos my-project --task "Fix session timeout"
27585
27627
  olam dispatch login-fix "investigate and fix the session timeout"
27586
- olam observe login-fix # placeholder; for now attach via the world terminal
27628
+ olam observe login-fix # Alternative: \`olam enter login-fix\` for a shell inside the world (until \`olam observe\` ships)
27587
27629
  olam status login-fix
27588
27630
  olam crystallize login-fix # requires PLERI; otherwise no-op (exit 2)
27589
27631
  olam destroy login-fix # accepts the world ID or name
@@ -27621,11 +27663,38 @@ refresh token never leaves the service.
27621
27663
 
27622
27664
  | Problem | Fix |
27623
27665
  |---------|-----|
27666
+ | Something not working | Run \`olam doctor\` \u2014 it diagnoses the setup and shows remedies for each issue |
27624
27667
  | "Docker not running" | Start Docker Desktop |
27625
27668
  | "No Claude credentials" | Run \`claude auth login\` on the host |
27669
+ | "GHCR pull secret failed" or "401 unauthorized" on first \`olam setup\` | Run \`gh auth login\` and verify with \`gh auth status\` |
27626
27670
  | Dashboard shows empty | Wait for the first dispatch to generate thoughts |
27627
27671
  | "Port already in use" | Another world is running. Use \`olam list\` to check |
27628
27672
  | Session seems stuck | Use \`olam enter <world>\` to open the terminal and check |
27673
+ | **Blank white page at \`localhost:19001\`** | SPA dist not built. Run \`cd packages/host-cp && npm run build:spa\` from the repo root (or just \`npm start\` \u2014 the \`prestart\` hook does it automatically). |
27674
+ | Cloud toggle missing in SPA | Both \`OLAM_CLOUD_URL\` and \`OLAM_SHOWCASE_PASSWORD\` must be set. If only one is set the server logs a \`[cloud]\` warning at startup. |
27675
+
27676
+ ## Bare-node / source-checkout mode
27677
+
27678
+ If you are running host-cp directly from source (not via \`olam setup\`
27679
+ or a pulled Docker image), you need to build the SPA before first boot:
27680
+
27681
+ \`\`\`bash
27682
+ # From the repo root:
27683
+ cd packages/host-cp
27684
+ npm run build:spa # builds plan-chat-spa and stages it into packages/host-cp/dist/
27685
+ npm start # prestart hook runs check:spa first; rebuilds if dist is stale
27686
+ \`\`\`
27687
+
27688
+ \`npm start\` runs \`check:spa\` first. If \`dist/\` is already populated and
27689
+ self-consistent (every asset in \`index.html\` is present on disk) it skips
27690
+ the build and starts immediately. If not, it calls \`build:spa\` to rebuild.
27691
+
27692
+ The \`build:spa\` script triggers a full \`npm run build:ci\` + \`vite build\`
27693
+ chain on a cold checkout (takes ~60s the first time; subsequent runs skip
27694
+ the vite build if \`packages/plan-chat-spa/dist/client/\` is already populated).
27695
+
27696
+ **This is not required when using \`olam setup\`** \u2014 the Docker image has the
27697
+ SPA baked in and host-cp never touches the local \`dist/\` directory.
27629
27698
 
27630
27699
  ## Architecture
27631
27700
 
@@ -27780,16 +27849,18 @@ olam skills source list
27780
27849
 
27781
27850
  ---
27782
27851
 
27783
- ## 5. Start the memory-bridge
27852
+ ## 5. Start the memory service (Docker container)
27784
27853
 
27785
- The memory-bridge is a host process that serves \`127.0.0.1:3111/agentmemory/livez\`. When it's running, \`olam skills sync\` will inject the olam-meta-memory-recall + olam-meta-memory-classify hook blocks into \`~/.claude/settings.json\`. When it's NOT running, the strip half of the auto-migration still fires but no olam-meta blocks land \u2014 meaning operator gets no recall/classify behavior.
27854
+ The memory-service is a Docker container (managed by \`olam services\`) that serves \`127.0.0.1:3111/agentmemory/livez\`. When it's running, \`olam skills sync\` will inject the olam-meta-memory-recall + olam-meta-memory-classify hook blocks into \`~/.claude/settings.json\`. When it's NOT running, the strip half of the auto-migration still fires but no olam-meta blocks land \u2014 meaning operator gets no recall/classify behavior.
27786
27855
 
27787
27856
  \`\`\`bash
27788
27857
  olam memory secret # \u2192 shows the bearer at ~/.olam/memory-secret (auto-generated on first run)
27789
- olam memory start # \u2192 starts the host process; polls livez until ready
27790
- olam memory status # \u2192 pid + livez + secret-set check
27858
+ olam memory start # \u2192 starts the olam-memory-service container; polls livez until ready
27859
+ olam memory status # \u2192 container state + livez + secret-set check
27791
27860
  \`\`\`
27792
27861
 
27862
+ **Note:** \`~/.olam/memory-secret\` is used with the Docker Compose substrate (this guide). For Kubernetes, the file is \`~/.olam/memory-bearer-secret\`. They are the same logical service in different deployment substrates.
27863
+
27793
27864
  Sanity check the live probe:
27794
27865
 
27795
27866
  \`\`\`bash
@@ -27917,6 +27988,7 @@ If the recall hook doesn't fire, run \`olam memory status\` to confirm the bridg
27917
27988
  ## What's NOT in this doc
27918
27989
 
27919
27990
  - Setting up Cloudflare-substrate worlds (separate doc: \`docs/architecture/cf-worlds-spec.md\`).
27991
+ - **Cloud-mode (optional)**: if you want dispatches to run on Cloudflare Sandboxes instead of local Docker, follow [plan-cloud-mode-setup.md](../runbooks/plan-cloud-mode-setup.md) to set \`OLAM_CLOUD_URL\` + \`OLAM_SHOWCASE_PASSWORD\` on host-cp.
27920
27992
  - PLERI thought-graph integration (separate setup; skip-pleri is fine for most operators).
27921
27993
  - Per-project skill overrides (advanced; see Phase B B2 + \`docs/architecture/skill-source-contract.md\`).
27922
27994
  - Cutting an olam release (developer flow, not operator flow; see \`~/.claude/skills/olam-cut-release/SKILL.md\`).
@@ -27943,6 +28015,345 @@ npm uninstall -g @pleri/olam-cli
27943
28015
 
27944
28016
  ---
27945
28017
 
28018
+ ## Setup \u2014 k3d/k3s mode (default substrate, port 19001)
28019
+
28020
+ Source: \`docs/onboarding/k3s-mode-setup.md\`
28021
+
28022
+ # Olam in k3d mode \u2014 definitive setup guide
28023
+
28024
+ > **Audience**: an operator setting up olam on their workstation. k3d mode runs olam's full peripheral stack (host-cp, auth-service, mcp-auth-service, kg-service, memory-service) as a real Kubernetes deployment on a local k3d cluster, with Prometheus + Grafana + Loki + Kyverno for observability.
28025
+ >
28026
+ > **End state**: a local k3d cluster \`olam-dev\`, five peripheral pods at \`1/1 Running\` in the \`olam\` namespace, a \`monitoring\` namespace with kube-prometheus-stack + Grafana, the \`olam\` CLI talking to host-cp inside the cluster.
28027
+ >
28028
+ > **Time**: ~5 minutes warm, ~10 minutes cold (image pulls).
28029
+ >
28030
+ > **k3d on all platforms**: olam uses k3d (k3s wrapped in Docker) on both macOS and Linux. No sudo needed \u2014 k3d only requires a Docker daemon. Same substrate, same mental model, same teardown on every machine.
28031
+
28032
+ k3d is the **default mode** for olam. For the lighter docker-compose mode (3 containers, no cluster), see [fresh-machine-setup.md](fresh-machine-setup.md).
28033
+
28034
+ ---
28035
+
28036
+ ## 0. Prerequisites
28037
+
28038
+ You need these tools installed. \`olam setup\` will prompt to install missing brew-formulae for you on macOS (answer y); on Linux it uses the upstream k3d install script (no sudo needed). Pass \`-y\` to skip all prompts.
28039
+
28040
+ | Tool | Why | Install |
28041
+ |---|---|---|
28042
+ | **Node.js \u2265 20** | The olam CLI runs on Node | \`nvm install 20\` |
28043
+ | **Docker daemon** | k3d runs k3s nodes as Docker containers (required on all platforms) | Docker Desktop (macOS/Windows) or \`sudo apt install docker.io\` (Linux); colima works too |
28044
+ | **colima** (macOS, optional) | Lightweight Docker runtime for macOS | \`brew install colima && colima start --cpu 4 --memory 8 --vm-type=vz --mount-type=virtiofs\` |
28045
+ | **k3d** | Wraps k3s in Docker for local clusters \u2014 works on macOS and Linux, no sudo | \`brew install k3d\` (macOS/Linux with brew) or \`curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh \\| bash\` |
28046
+ | **kubectl** | Cluster operations | \`brew install kubectl\` |
28047
+ | **helm** | Installs Loki + Promtail + Grafana + Prometheus + Kyverno | \`brew install helm\` |
28048
+ | **gh** | ghcr-pull secret + \`gh auth token\` | \`brew install gh && gh auth login\` |
28049
+ | **docker** + \`docker compose\` plugin | Hosts the docker-socket-proxy sibling container | Docker Desktop, or colima ships it |
28050
+ | **jq, curl, openssl** | Shell helpers | macOS defaults |
28051
+ | **Claude Code subscription** | The \`claude\` CLI inside each world consumes your local subscription | \`npm install -g @anthropic-ai/claude-code\` |
28052
+
28053
+ ---
28054
+
28055
+ ## 1. Install the olam CLI
28056
+
28057
+ \`\`\`bash
28058
+ # One-line installer (recommended)
28059
+ curl -fsSL https://olam.bar.dev/install | sh
28060
+
28061
+ # Or via npm directly
28062
+ npm install -g @pleri/olam-cli
28063
+ \`\`\`
28064
+
28065
+ Verify:
28066
+
28067
+ \`\`\`bash
28068
+ olam --version
28069
+ \`\`\`
28070
+
28071
+ The CLI ships every manifest, secret template, and observability install script it needs inside the npm tarball \u2014 no \`git clone\` required.
28072
+
28073
+ ---
28074
+
28075
+ ## 2. Authenticate \`gh\`
28076
+
28077
+ \`\`\`bash
28078
+ gh auth login
28079
+ \`\`\`
28080
+
28081
+ The bootstrap creates a \`ghcr-pull\` Kubernetes Secret from \`gh auth token\` so pulls of \`ghcr.io/pleri/olam-*\` images don't hit anonymous rate limits.
28082
+
28083
+ ---
28084
+
28085
+ ## 3. Bootstrap
28086
+
28087
+ Single command, end-to-end:
28088
+
28089
+ \`\`\`bash
28090
+ olam setup
28091
+ \`\`\`
28092
+
28093
+ Pass \`-y\` to skip all prompts (non-interactive, auto-affirm every step):
28094
+
28095
+ \`\`\`bash
28096
+ olam setup -y
28097
+ \`\`\`
28098
+
28099
+ The command is **idempotent** \u2014 re-running against an existing cluster only does work for incomplete steps. It runs five ordered phases:
28100
+
28101
+ | # | Phase | What it does |
28102
+ |---|---|---|
28103
+ | 0 | **Preflight** | Detects missing tools and prints actionable install commands. Verifies \`gh\` is authenticated and the docker daemon is reachable. |
28104
+ | 1 | **Secrets** | Generates \`~/.olam/{auth-secret,kg-bearer-token,auth-db-secret,mcp-auth-jwt-secret,memory-bearer-secret}\` if absent (32-byte hex, mode 0600). |
28105
+ | 2 | **Colima** (macOS only) | Ensures colima is running; if not, starts it with sensible defaults. Applies \`chmod 666 /var/run/docker.sock\` inside the colima VM (virtiofs mitigation). |
28106
+ | 3 | **Cluster** | \`k3d cluster create olam-dev\` with the gh-config bind. Skipped if cluster exists. (Override the name with \`--cluster-name\`.) |
28107
+ | 4 | **Observability** | Chains the bundled install scripts: Loki + Promtail, Grafana with port-forward + admin secret, kube-prometheus-stack with recording rules, Kyverno admission policy. |
28108
+ | 5 | **Apply manifests + rollout** | Delegates to the existing \`olam upgrade\` flow: namespace, RBAC, secrets, ghcr-pull, host-side docker-socket-proxy, manifest apply, rollout status (per-deployment, 90s timeout), port-forward, \`/health\` verify, audit log. |
28109
+
28110
+ Flag reference:
28111
+
28112
+ \`\`\`bash
28113
+ olam setup --help
28114
+ \`\`\`
28115
+
28116
+ Common overrides:
28117
+
28118
+ - \`-y, --yes\` \u2014 auto-affirm every prompt (non-interactive).
28119
+ - \`--substrate <docker|kubernetes>\` \u2014 force a substrate instead of auto-detecting.
28120
+ - \`--cluster-name <name>\` \u2014 k3d cluster name to create/use (default: \`olam-dev\`).
28121
+ - \`--reuse-cluster <name>\` \u2014 reuse an existing reachable kube context instead of provisioning.
28122
+ - \`--skip-cluster-create\` \u2014 cluster already exists; skip cluster provisioning.
28123
+ - \`--skip-doctor\` \u2014 skip final health check (useful in CI).
28124
+
28125
+ ---
28126
+
28127
+ ## 4. Verify the cluster is healthy
28128
+
28129
+ \`\`\`bash
28130
+ kubectl get pods -n olam
28131
+ \`\`\`
28132
+
28133
+ Expected \u2014 all five \`1/1 Running\`:
28134
+
28135
+ \`\`\`
28136
+ NAME READY STATUS RESTARTS AGE
28137
+ olam-auth-service-... 1/1 Running 0 ~5m
28138
+ olam-host-cp-... 1/1 Running 0 ~5m
28139
+ olam-kg-service-... 1/1 Running 0 ~5m
28140
+ olam-mcp-auth-service-... 1/1 Running 0 ~5m
28141
+ olam-memory-service-... 1/1 Running 0 ~5m
28142
+ \`\`\`
28143
+
28144
+ If something's off:
28145
+
28146
+ \`\`\`bash
28147
+ olam doctor # checks substrate, cluster, pods, secrets
28148
+ olam services status # k8s-aware status table
28149
+ \`\`\`
28150
+
28151
+ ---
28152
+
28153
+ ## 5. Open Grafana
28154
+
28155
+ \`\`\`bash
28156
+ kubectl port-forward -n monitoring svc/olam-grafana 3000:80
28157
+ open http://localhost:3000
28158
+ \`\`\`
28159
+
28160
+ User \`admin\`, password from:
28161
+
28162
+ \`\`\`bash
28163
+ kubectl get secret olam-grafana-admin -n monitoring \\
28164
+ -o jsonpath='{.data.admin-password}' | base64 -d
28165
+ \`\`\`
28166
+
28167
+ Pre-installed dashboards (under "Olam"):
28168
+
28169
+ - **olam-home** \u2014 at-a-glance status across all peripherals.
28170
+ - **host-cp** \u2014 request rate, p50/p95/p99 latency, world counts.
28171
+ - **kg-service** \u2014 classifier hit rate, classify latency, hook traffic.
28172
+ - **request-rate** \u2014 per-route HTTP request rate (uses recording rule \`olam:http_requests:rate5m_by_service_route\`).
28173
+
28174
+ ---
28175
+
28176
+ ## 6. Day-to-day operations
28177
+
28178
+ \`\`\`bash
28179
+ olam doctor # health check across substrate
28180
+ olam services status # peripherals status table (k8s-aware)
28181
+ olam services restart <name> # kubectl rollout restart for one peripheral
28182
+ olam services down # scale all peripherals to 0 replicas
28183
+ olam services up # scale them back to 1
28184
+ \`\`\`
28185
+
28186
+ To pick up a new release after \`npm install -g @pleri/olam-cli@latest\`:
28187
+
28188
+ \`\`\`bash
28189
+ olam upgrade
28190
+ \`\`\`
28191
+
28192
+ The upgrade flow re-applies all manifests (Kubernetes rolls the deployments to the new image digests); persistent volumes survive.
28193
+
28194
+ ---
28195
+
28196
+ ## 7. Tear down
28197
+
28198
+ \`\`\`bash
28199
+ olam implode --dry-run # preview what will be removed
28200
+ olam implode # confirmed: cluster + secrets + state
28201
+ \`\`\`
28202
+
28203
+ \`olam implode\` removes the k3d cluster, the host-side docker-socket-proxy sibling, every container, every secret in \`~/.olam/\`, and the global config. Use it when you want to start completely fresh; otherwise prefer \`olam services down\` or scale to 0.
28204
+
28205
+ ---
28206
+
28207
+ ## Choosing compose mode instead
28208
+
28209
+ To use the lighter 3-container compose path instead:
28210
+
28211
+ \`\`\`bash
28212
+ curl -fsSL https://olam.bar.dev/install | sh
28213
+ olam setup --substrate=docker
28214
+ \`\`\`
28215
+
28216
+ The CLI is substrate-aware: \`olam setup\`, \`olam services up|down|status|restart\`, \`olam upgrade\`, and \`olam doctor\` all route to the correct backend based on \`~/.olam/config.json\`'s \`host.substrate\` value.
28217
+
28218
+ Full compose guide: [\`fresh-machine-setup.md\`](./fresh-machine-setup.md).
28219
+
28220
+ ---
28221
+
28222
+ ## Architecture quick-ref
28223
+
28224
+ \`\`\`
28225
+ \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
28226
+ \u2502 operator's machine \u2502
28227
+ \u2502 \u2502
28228
+ \u2502 ~/.olam/*-secret \u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u25B6 Kubernetes Secrets
28229
+ \u2502 ~/.config/gh \u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u25B6 k3d --volume bind
28230
+ \u2502 \u2502
28231
+ \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502
28232
+ \u2502 \u2502 docker daemon \u2502 \u2502
28233
+ \u2502 \u2502 \u2502 \u2502
28234
+ \u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502
28235
+ \u2502 \u2502 \u2502 k3d node \u2502 \u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
28236
+ \u2502 \u2502 \u2502 cluster \u2502\u25C0\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2502 ghcr.io/pleri/olam-* \u2502
28237
+ \u2502 \u2502 \u2502 olam-dev \u2502 \u2502 \u2502 \u2502 (pulled with gh token) \u2502
28238
+ \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
28239
+ \u2502 \u2502 \u2502 TCP \u2502 \u2502
28240
+ \u2502 \u2502 \u25BC :2375 \u2502 \u2502
28241
+ \u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2510 \u2502
28242
+ \u2502 \u2502 \u2502 docker-socket \u2502 \u2502
28243
+ \u2502 \u2502 \u2502 proxy \u2502 \u2502
28244
+ \u2502 \u2502 \u2502 (sibling \u2502 \u2502
28245
+ \u2502 \u2502 \u2502 container) \u2502 \u2502
28246
+ \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502
28247
+ \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
28248
+ \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
28249
+ \u2502
28250
+ \u25BC k3d nodes via host.k3d.internal:2375
28251
+ \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
28252
+ \u2502 cluster: olam-dev \u2502
28253
+ \u2502 \u2502
28254
+ \u2502 namespace: olam \u2502
28255
+ \u2502 olam-host-cp (1/1 Running) \u2502
28256
+ \u2502 olam-auth-service (1/1 Running) \u2502
28257
+ \u2502 olam-mcp-auth-svc (1/1 Running) \u2502
28258
+ \u2502 olam-kg-service (1/1 Running) \u2502
28259
+ \u2502 olam-memory-service (1/1 Running) \u2502
28260
+ \u2502 \u2502
28261
+ \u2502 namespace: monitoring \u2502
28262
+ \u2502 olam-grafana \u2502
28263
+ \u2502 prometheus-operated \u2502
28264
+ \u2502 loki + promtail \u2502
28265
+ \u2502 kyverno (admission) \u2502
28266
+ \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
28267
+ \`\`\`
28268
+
28269
+ Why the sibling docker-socket-proxy? On macOS, colima exposes \`/var/run/docker.sock\` via virtiofs, which blocks unix-socket bind-mounts into k3d pods. The proxy runs as a normal Docker container on the operator's daemon and exposes the same socket over TCP \`:2375\`. Pods reach it through an ExternalName Service. See [\`docs/test-reports/olam-k3d-on-mac-substrate-decision-eli5.md\`](../test-reports/olam-k3d-on-mac-substrate-decision-eli5.md).
28270
+
28271
+ ---
28272
+
28273
+ ## Common issues
28274
+
28275
+ | Symptom | Fix |
28276
+ |---|---|
28277
+ | \`colima not running\` | \`colima start --cpu 4 --memory 8 --vm-type=vz --mount-type=virtiofs\` |
28278
+ | \`permission denied\` on docker socket | \`colima ssh -- sudo chmod 666 /var/run/docker.sock\` |
28279
+ | Missing tool errors at preflight | Install manually per the prereq table, then re-run \`olam setup\` |
28280
+ | \`helm install\` timeout during observability bootstrap | Set \`OLAM_HELM_TIMEOUT=600s\` (or higher on loaded machines). See [Tuning](#tuning-helm-timeouts-on-resource-constrained-machines) for details. |
28281
+ | \`host-cp\` \`CrashLoopBackOff\` with \`inClusterContext is not in the allowlist\` | Image pre-dates v0.1.161 \u2014 \`npm install -g @pleri/olam-cli@latest && olam upgrade\` |
28282
+ | \`memory-service\` \`CrashLoopBackOff\` with \`port 3111 is already in use\` | Image pre-dates v0.1.163 \u2014 \`npm install -g @pleri/olam-cli@latest && olam upgrade\` |
28283
+ | \`imagePullBackOff\` from \`ghcr.io/pleri/olam-*\` | The bootstrap creates \`ghcr-pull\` from \`gh auth token\`; re-run \`olam setup\` after \`gh auth login\` |
28284
+ | Grafana dashboards missing | \`kubectl rollout restart deploy/olam-grafana -n monitoring\` |
28285
+ | host-cp can't reach docker | \`docker ps \\| grep docker-socket-proxy\` \u2014 restart with \`olam setup --skip-cluster-create\` to re-run only the proxy + manifest-apply steps |
28286
+ | \`helm install\` fails with \`Error: context deadline exceeded\` during observability bootstrap (grafana / loki / kube-prometheus-stack / kyverno) | The Colima VM is sharing CPU/memory with too many other containers. Bump the helm timeout via \`OLAM_HELM_TIMEOUT=900s olam setup\` (default is \`600s\`). On very loaded machines, \`1200s\` is reasonable. Applies to every \`helm install\` step in the observability chain. |
28287
+
28288
+ ### Tuning helm timeouts on resource-constrained machines
28289
+
28290
+ Every observability \`helm install\` (grafana, loki, promtail, kube-prometheus-stack, kyverno) reads \`OLAM_HELM_TIMEOUT\` (default \`600s\`). When the Colima VM is sharing resources with a heavy local workload, charts can take longer than the default to converge \u2014 bump the env var instead of editing scripts:
28291
+
28292
+ \`\`\`bash
28293
+ OLAM_HELM_TIMEOUT=900s olam setup # bootstrap with longer timeout
28294
+ OLAM_HELM_TIMEOUT=1200s olam setup # very loaded machines
28295
+ \`\`\`
28296
+
28297
+ CI Linux runners run unmodified at \`600s\` (dedicated resources). The knob exists for macOS-Colima hosts that share a VM with other docker workloads.
28298
+
28299
+ ### Tuning Prometheus scrape/discovery waits
28300
+
28301
+ The Phase C E2E scripts in \`scripts/e2e/\` poll Prometheus for synthetic-target discovery (\`TARGET_DISCOVERY_TIMEOUT\`, default 240s \u2014 \`cardinality-drop.sh\`, \`kyverno-cardinality-mutate.sh\`, \`dashboards-have-data.sh\`) and then sleep for recording-rule evaluation (\`SCRAPE_WAIT\`, default 70s \u2014 \`dashboards-have-data.sh\`). Both default values cover \u22652 rule-evaluation cycles at the 30s rule interval against a 15s scrape interval. Override on very slow runners:
28302
+
28303
+ \`\`\`bash
28304
+ OLAM_PROM_DISCOVERY_TIMEOUT=300 OLAM_PROM_SCRAPE_WAIT=120 npm run test:ingress-integration
28305
+ \`\`\`
28306
+
28307
+ ### Troubleshooting port-forwards
28308
+
28309
+ **Problem:** connections to a port-forward (e.g. \`localhost:19001\` for host-cp, \`localhost:3000\` for Grafana) suddenly fail with "connection refused".
28310
+
28311
+ **Why:** kubectl port-forwards die when:
28312
+ - The terminal that started them exits
28313
+ - k3d restarts or the cluster reboots
28314
+ - The underlying pod crashes or is redeployed
28315
+ - The local kube context changes
28316
+
28317
+ **Diagnose:**
28318
+ \`\`\`bash
28319
+ ps aux | grep "kubectl port-forward"
28320
+ \`\`\`
28321
+
28322
+ If nothing shows up, the port-forward is dead and needs to be re-established.
28323
+
28324
+ **Fix:**
28325
+
28326
+ Option 1 \u2014 re-establish all port-forwards at once:
28327
+ \`\`\`bash
28328
+ olam services up
28329
+ \`\`\`
28330
+
28331
+ Option 2 \u2014 manually restart the port-forward (canonical command from the setup doc):
28332
+ \`\`\`bash
28333
+ kubectl port-forward -n olam svc/host-cp 19001:19001
28334
+ \`\`\`
28335
+
28336
+ Use \`olam services status\` to see which services are running and which port each binds to locally.
28337
+
28338
+ When everything else fails, tear down and re-create:
28339
+
28340
+ \`\`\`bash
28341
+ olam implode
28342
+ olam setup
28343
+ \`\`\`
28344
+
28345
+ \`olam implode\` removes everything; \`olam setup\` re-creates from scratch.
28346
+
28347
+ ---
28348
+
28349
+ ## What to read next
28350
+
28351
+ - \`olam --help\`, \`olam setup --help\` \u2014 the canonical CLI surface.
28352
+ - [\`docs/architecture/peripheral-services-on-k3s.md\`](../architecture/peripheral-services-on-k3s.md) \u2014 design doc for the k3s peripheral architecture.
28353
+ - [\`docs/test-reports/olam-k3d-on-mac-substrate-decision-eli5.md\`](../test-reports/olam-k3d-on-mac-substrate-decision-eli5.md) \u2014 why the docker-socket-proxy sits where it sits.
28354
+
28355
+ ---
28356
+
27946
28357
  ## Architecture \u2014 the problem olam solves
27947
28358
 
27948
28359
  Source: \`docs/architecture/01-problem.md\`
@@ -29691,6 +30102,11 @@ function registerCreate(program2) {
29691
30102
  if (resolvedTask) {
29692
30103
  printInfo("Task", resolvedTask);
29693
30104
  }
30105
+ if (!opts.json) {
30106
+ console.log(`
30107
+ ${pc14.cyan("Dashboard:")} ${HOST_CP_URL}/plan/${encodeURIComponent(world.id)}`);
30108
+ console.log(`${pc14.cyan("Enter world:")} ${pc14.dim(`olam enter ${world.name}`)}`);
30109
+ }
29694
30110
  if (world.credentialsInjected?.claude) {
29695
30111
  console.log(`
29696
30112
  ${pc14.green("Credentials injected. World is ready for dispatch.")}`);
@@ -30208,6 +30624,7 @@ import * as fs40 from "node:fs";
30208
30624
  import * as http3 from "node:http";
30209
30625
  import * as os22 from "node:os";
30210
30626
  import * as path42 from "node:path";
30627
+ import pc18 from "picocolors";
30211
30628
  var CLI_VERSION2 = process.env["OLAM_CLI_VERSION"] ?? "0.0.0";
30212
30629
  var HOST_CP_PORT2 = 19e3;
30213
30630
  var STATE_ENUM = [
@@ -30334,6 +30751,9 @@ function registerStatus(program2) {
30334
30751
  printHeader("Olam Status");
30335
30752
  printInfo("CLI version", `@pleri/olam-cli@${ms.version}`);
30336
30753
  printInfo("Host CP", ms.host_cp === "running" ? `running on port ${ms.port}` : "stopped");
30754
+ if (ms.host_cp === "stopped") {
30755
+ console.log(pc18.dim(" \u2192 run `olam doctor` to diagnose"));
30756
+ }
30337
30757
  printInfo("Worlds", String(ms.worlds));
30338
30758
  printInfo("Token", ms.token_present ? "present" : "absent");
30339
30759
  if (ms.last_update_check) {
@@ -30404,7 +30824,7 @@ init_context();
30404
30824
  init_output();
30405
30825
  init_host_cp();
30406
30826
  import ora7 from "ora";
30407
- import pc18 from "picocolors";
30827
+ import pc19 from "picocolors";
30408
30828
  async function runDestroy(worldArg, opts, deps) {
30409
30829
  const worlds = deps.listWorlds();
30410
30830
  const world = resolveWorld(worlds, worldArg);
@@ -30412,12 +30832,12 @@ async function runDestroy(worldArg, opts, deps) {
30412
30832
  deps.stderr(`World "${worldArg}" not found.`);
30413
30833
  const suggestions = suggestWorlds(worlds, worldArg);
30414
30834
  if (suggestions.length > 0) {
30415
- deps.stdout(pc18.dim("\n Did you mean:"));
30835
+ deps.stdout(pc19.dim("\n Did you mean:"));
30416
30836
  for (const s of suggestions) {
30417
- deps.stdout(` ${pc18.bold(s.name)} ${pc18.dim(`(${s.id})`)} ${pc18.dim(s.status)}`);
30837
+ deps.stdout(` ${pc19.bold(s.name)} ${pc19.dim(`(${s.id})`)} ${pc19.dim(s.status)}`);
30418
30838
  }
30419
30839
  }
30420
- deps.stdout(pc18.dim("\n Run `olam list` to see all worlds."));
30840
+ deps.stdout(pc19.dim("\n Run `olam list` to see all worlds."));
30421
30841
  return 1;
30422
30842
  }
30423
30843
  const worldId = world.id;
@@ -30796,7 +31216,7 @@ import * as fs42 from "node:fs";
30796
31216
  import * as os24 from "node:os";
30797
31217
  import * as path44 from "node:path";
30798
31218
  import { createInterface as createInterface3 } from "node:readline/promises";
30799
- import pc19 from "picocolors";
31219
+ import pc20 from "picocolors";
30800
31220
  var NPM_PACKAGE = "@pleri/olam-cli";
30801
31221
  var realExec = (cmd, args) => {
30802
31222
  try {
@@ -30953,7 +31373,7 @@ function renderSurvey(survey, opts) {
30953
31373
  const dirtyWorlds = survey.worlds.filter((w) => w.dirty);
30954
31374
  const cleanWorlds = survey.worlds.filter((w) => !w.dirty);
30955
31375
  const worldBytes = survey.worlds.reduce((acc, w) => acc + w.bytes, 0);
30956
- lines.push(pc19.bold(pc19.red("\u2014 olam implode survey \u2014")));
31376
+ lines.push(pc20.bold(pc20.red("\u2014 olam implode survey \u2014")));
30957
31377
  lines.push("");
30958
31378
  lines.push(` containers (olam-*): ${survey.containers.length}`);
30959
31379
  lines.push(` images: ${survey.images.length}`);
@@ -30969,13 +31389,13 @@ function renderSurvey(survey, opts) {
30969
31389
  );
30970
31390
  if (dirtyWorlds.length > 0) {
30971
31391
  lines.push("");
30972
- lines.push(pc19.yellow(` \u26A0 dirty worlds (${dirtyWorlds.length}) \u2014 pass --include-dirty to destroy:`));
31392
+ lines.push(pc20.yellow(` \u26A0 dirty worlds (${dirtyWorlds.length}) \u2014 pass --include-dirty to destroy:`));
30973
31393
  for (const w of dirtyWorlds) {
30974
31394
  lines.push(` - ${w.id} ${formatBytes3(w.bytes)} (${w.note})`);
30975
31395
  }
30976
31396
  }
30977
31397
  lines.push("");
30978
- lines.push(pc19.dim(" Run with --yes to actually destroy. Default is dry-run."));
31398
+ lines.push(pc20.dim(" Run with --yes to actually destroy. Default is dry-run."));
30979
31399
  return lines.join("\n");
30980
31400
  }
30981
31401
  function formatBytes3(n) {
@@ -31150,11 +31570,11 @@ async function runImplode(opts) {
31150
31570
  process.stdout.write("\n");
31151
31571
  process.stdout.write(`To reinstall a fresh copy:
31152
31572
  `);
31153
- process.stdout.write(` ${pc19.cyan(`npm install -g ${NPM_PACKAGE}`)}
31573
+ process.stdout.write(` ${pc20.cyan(`npm install -g ${NPM_PACKAGE}`)}
31154
31574
  `);
31155
- process.stdout.write(` ${pc19.cyan("olam init")}
31575
+ process.stdout.write(` ${pc20.cyan("olam init")}
31156
31576
  `);
31157
- process.stdout.write(` ${pc19.cyan("olam auth login")}
31577
+ process.stdout.write(` ${pc20.cyan("olam auth login")}
31158
31578
  `);
31159
31579
  return result.errors.length > 0 ? 1 : 0;
31160
31580
  }
@@ -31163,7 +31583,7 @@ async function runImplode(opts) {
31163
31583
  init_context();
31164
31584
  init_output();
31165
31585
  import { execSync as execSync9 } from "node:child_process";
31166
- import pc20 from "picocolors";
31586
+ import pc21 from "picocolors";
31167
31587
  var SAFE_IDENT3 = /^[a-z0-9][a-z0-9-]{0,63}$/;
31168
31588
  function buildStartClaudeCommands(containerName, sessionName, task) {
31169
31589
  if (!SAFE_IDENT3.test(containerName)) {
@@ -31227,7 +31647,7 @@ function registerEnter(program2) {
31227
31647
  checkVersionPin2(worldId, worldMeta.workspacePath);
31228
31648
  if (worldMeta.claudeHome) {
31229
31649
  console.log(
31230
- pc20.dim(`# claude-home: ${worldMeta.claudeHome} (per-world Claude Code instance, ADR 045)`)
31650
+ pc21.dim(`# claude-home: ${worldMeta.claudeHome} (per-world Claude Code instance, ADR 045)`)
31231
31651
  );
31232
31652
  }
31233
31653
  }
@@ -31275,7 +31695,7 @@ function registerEnter(program2) {
31275
31695
  }
31276
31696
  console.log("Run these commands in order to enter the world:\n");
31277
31697
  for (const step2 of steps) {
31278
- console.log(` ${pc20.dim(`# ${step2.description}`)}`);
31698
+ console.log(` ${pc21.dim(`# ${step2.description}`)}`);
31279
31699
  if (step2.stdin !== void 0) {
31280
31700
  const escaped = step2.stdin.replace(/'/g, "'\\''");
31281
31701
  console.log(` printf '%s' '${escaped}' | ${step2.command}`);
@@ -31309,11 +31729,11 @@ function registerEnter(program2) {
31309
31729
  return;
31310
31730
  }
31311
31731
  console.log("Run this command to enter the world:\n");
31312
- console.log(` ${pc20.bold(result.command)}`);
31732
+ console.log(` ${pc21.bold(result.command)}`);
31313
31733
  const containerName = `olam-${worldId}-devbox`;
31314
31734
  console.log(
31315
31735
  `
31316
- ${pc20.dim(`Observe dispatch: docker exec -it ${containerName} tmux attach -t olam-dispatch -r`)}`
31736
+ ${pc21.dim(`Observe dispatch: docker exec -it ${containerName} tmux attach -t olam-dispatch -r`)}`
31317
31737
  );
31318
31738
  });
31319
31739
  }
@@ -31557,7 +31977,7 @@ function registerCrystallize(program2, options = {}) {
31557
31977
 
31558
31978
  // src/commands/pr.ts
31559
31979
  init_registry();
31560
- import pc21 from "picocolors";
31980
+ import pc22 from "picocolors";
31561
31981
 
31562
31982
  // ../core/dist/pr-gate/client.js
31563
31983
  var HOST_CONTROL_PLANE_BASE2 = 19080;
@@ -31638,26 +32058,26 @@ async function findGate(id) {
31638
32058
  return null;
31639
32059
  }
31640
32060
  function formatStateBadge(state) {
31641
- if (state === "approve") return pc21.green("approve");
31642
- if (state === "block") return pc21.red("block");
31643
- if (state === "denied") return pc21.gray("denied");
31644
- return pc21.yellow("pending");
32061
+ if (state === "approve") return pc22.green("approve");
32062
+ if (state === "block") return pc22.red("block");
32063
+ if (state === "denied") return pc22.gray("denied");
32064
+ return pc22.yellow("pending");
31645
32065
  }
31646
32066
  function registerPr(program2) {
31647
32067
  const pr = program2.command("pr").description("Review and decide PR-gate requests from running worlds");
31648
32068
  pr.command("list").description("List all PR-gate requests across every running world").action(async () => {
31649
32069
  const all = await fanoutList();
31650
32070
  if (all.length === 0) {
31651
- console.log(pc21.dim("No gates open."));
32071
+ console.log(pc22.dim("No gates open."));
31652
32072
  return;
31653
32073
  }
31654
32074
  printHeader(`${all.length} gate(s)`);
31655
32075
  for (const { world, gate } of all) {
31656
32076
  const badge = formatStateBadge(gate.state);
31657
32077
  console.log(
31658
- ` ${pc21.bold(gate.id.slice(0, 8))} ${badge.padEnd(20)} ${pc21.dim(world.name)} ${pc21.dim(gate.branch)}`
32078
+ ` ${pc22.bold(gate.id.slice(0, 8))} ${badge.padEnd(20)} ${pc22.dim(world.name)} ${pc22.dim(gate.branch)}`
31659
32079
  );
31660
- console.log(` ${pc21.dim(gate.command.slice(0, 100))}`);
32080
+ console.log(` ${pc22.dim(gate.command.slice(0, 100))}`);
31661
32081
  }
31662
32082
  });
31663
32083
  pr.command("show").description("Show full gate detail (diff, command, commits)").argument("<id>", "Gate id (prefix match ok)").action(async (id) => {
@@ -31680,9 +32100,9 @@ function registerPr(program2) {
31680
32100
  if (gate.reason) printInfo("Reason", gate.reason);
31681
32101
  }
31682
32102
  printHeader("Commits");
31683
- console.log(gate.commitLog || pc21.dim(" (empty)"));
32103
+ console.log(gate.commitLog || pc22.dim(" (empty)"));
31684
32104
  printHeader("Diff stat");
31685
- console.log(gate.diffStat || pc21.dim(" (empty)"));
32105
+ console.log(gate.diffStat || pc22.dim(" (empty)"));
31686
32106
  });
31687
32107
  function decideCommand(verb, decision) {
31688
32108
  pr.command(verb).description(`${verb[0].toUpperCase()}${verb.slice(1)} a pending gate`).argument("<id>", "Gate id").option("--reason <reason>", "Short free-text reason").option("--by <name>", "Deciding identity (defaults to $USER)", process.env["USER"] ?? "human").action(async (id, opts) => {
@@ -32135,7 +32555,7 @@ function registerLanes(program2) {
32135
32555
  // src/commands/policy-check.ts
32136
32556
  init_loader2();
32137
32557
  import { execSync as execSync10 } from "node:child_process";
32138
- import pc22 from "picocolors";
32558
+ import pc23 from "picocolors";
32139
32559
 
32140
32560
  // ../../node_modules/balanced-match/dist/esm/index.js
32141
32561
  var balanced = (a, b, str) => {
@@ -33995,7 +34415,7 @@ function registerPolicyCheck(program2) {
33995
34415
  const workspaceRoot = opts.workspace ?? process.cwd();
33996
34416
  const policies = loadPolicies(workspaceRoot);
33997
34417
  if (policies.length === 0) {
33998
- console.log(pc22.dim("policy-check: no policies found in .olam/policies/ \u2014 nothing to enforce"));
34418
+ console.log(pc23.dim("policy-check: no policies found in .olam/policies/ \u2014 nothing to enforce"));
33999
34419
  return;
34000
34420
  }
34001
34421
  const diff = getDiff(opts.base, workspaceRoot);
@@ -34004,11 +34424,11 @@ function registerPolicyCheck(program2) {
34004
34424
  for (const result of results) {
34005
34425
  if (result.passed) continue;
34006
34426
  if (result.severity === "error") {
34007
- console.error(`${pc22.red("policy error")} [${result.policyId}]`);
34427
+ console.error(`${pc23.red("policy error")} [${result.policyId}]`);
34008
34428
  console.error(result.message);
34009
34429
  hasErrorFailure = true;
34010
34430
  } else {
34011
- console.warn(`${pc22.yellow("policy warn")} [${result.policyId}]`);
34431
+ console.warn(`${pc23.yellow("policy warn")} [${result.policyId}]`);
34012
34432
  console.warn(result.message);
34013
34433
  }
34014
34434
  }
@@ -34019,7 +34439,7 @@ function registerPolicyCheck(program2) {
34019
34439
  }
34020
34440
 
34021
34441
  // src/commands/worldspec/compile.ts
34022
- import { existsSync as existsSync46, mkdirSync as mkdirSync29, readFileSync as readFileSync37, writeFileSync as writeFileSync23 } from "node:fs";
34442
+ import { existsSync as existsSync46, mkdirSync as mkdirSync29, readFileSync as readFileSync37, writeFileSync as writeFileSync24 } from "node:fs";
34023
34443
  import { resolve as resolvePath } from "node:path";
34024
34444
  import YAML5 from "yaml";
34025
34445
 
@@ -34885,12 +35305,12 @@ Resolutions:
34885
35305
  const outDir = resolvePath(process.cwd(), opts.out);
34886
35306
  try {
34887
35307
  mkdirSync29(outDir, { recursive: true });
34888
- writeFileSync23(
35308
+ writeFileSync24(
34889
35309
  resolvePath(outDir, "execution-graph.json"),
34890
35310
  graphJson,
34891
35311
  "utf8"
34892
35312
  );
34893
- writeFileSync23(
35313
+ writeFileSync24(
34894
35314
  resolvePath(outDir, "lockfile.json"),
34895
35315
  lockfileJson,
34896
35316
  "utf8"
@@ -34913,7 +35333,7 @@ function getPkgVersion() {
34913
35333
  // src/commands/worldspec/init.ts
34914
35334
  init_exit_codes();
34915
35335
  init_output();
34916
- import { existsSync as existsSync47, mkdirSync as mkdirSync30, readFileSync as readFileSync38, writeFileSync as writeFileSync24 } from "node:fs";
35336
+ import { existsSync as existsSync47, mkdirSync as mkdirSync30, readFileSync as readFileSync38, writeFileSync as writeFileSync25 } from "node:fs";
34917
35337
  import { execSync as execSync11 } from "node:child_process";
34918
35338
  import { basename as basename3, resolve as resolvePath2 } from "node:path";
34919
35339
  function registerWorldspecInit(parent) {
@@ -34947,7 +35367,7 @@ function registerWorldspecInit(parent) {
34947
35367
  const yaml = renderWorldspecYaml(shape);
34948
35368
  try {
34949
35369
  mkdirSync30(targetDir, { recursive: true });
34950
- writeFileSync24(targetFile, yaml, {
35370
+ writeFileSync25(targetFile, yaml, {
34951
35371
  encoding: "utf8",
34952
35372
  flag: opts.force ? "w" : "wx"
34953
35373
  });
@@ -35044,7 +35464,7 @@ function relativeFromCwd(absPath, cwd) {
35044
35464
  }
35045
35465
 
35046
35466
  // src/commands/worldspec/schema.ts
35047
- import { writeFileSync as writeFileSync25 } from "node:fs";
35467
+ import { writeFileSync as writeFileSync26 } from "node:fs";
35048
35468
  import { resolve as resolvePath3 } from "node:path";
35049
35469
 
35050
35470
  // ../../node_modules/zod-to-json-schema/dist/esm/Options.js
@@ -36366,7 +36786,7 @@ function registerWorldspecSchema(parent) {
36366
36786
  if (opts.out) {
36367
36787
  const absPath = resolvePath3(process.cwd(), opts.out);
36368
36788
  try {
36369
- writeFileSync25(absPath, json + "\n", "utf8");
36789
+ writeFileSync26(absPath, json + "\n", "utf8");
36370
36790
  } catch (err) {
36371
36791
  printError(
36372
36792
  `failed to write ${absPath}: ${err.message}`
@@ -36455,7 +36875,7 @@ import * as fs47 from "node:fs";
36455
36875
  import * as path50 from "node:path";
36456
36876
  import { spawnSync as spawnSync23 } from "node:child_process";
36457
36877
  import ora9 from "ora";
36458
- import pc23 from "picocolors";
36878
+ import pc24 from "picocolors";
36459
36879
 
36460
36880
  // src/commands/upgrade-lock.ts
36461
36881
  import * as fs45 from "node:fs";
@@ -36746,7 +37166,7 @@ function extractBundleHash(indexHtml) {
36746
37166
  }
36747
37167
  function runStep2(label, cmd, args, opts = {}) {
36748
37168
  const start = Date.now();
36749
- process.stdout.write(` ${pc23.dim(label.padEnd(34))}`);
37169
+ process.stdout.write(` ${pc24.dim(label.padEnd(34))}`);
36750
37170
  const result = spawnSync23(cmd, [...args], {
36751
37171
  encoding: "utf-8",
36752
37172
  stdio: ["ignore", "pipe", "pipe"],
@@ -36756,7 +37176,7 @@ function runStep2(label, cmd, args, opts = {}) {
36756
37176
  const durationMs = Date.now() - start;
36757
37177
  const ok = result.status === 0 && result.error === void 0;
36758
37178
  const dur = `${(durationMs / 1e3).toFixed(1)}s`;
36759
- process.stdout.write(`${ok ? pc23.green("\u2713") : pc23.red("\u2717")} ${dur}
37179
+ process.stdout.write(`${ok ? pc24.green("\u2713") : pc24.red("\u2717")} ${dur}
36760
37180
  `);
36761
37181
  return {
36762
37182
  ok,
@@ -37086,7 +37506,7 @@ async function runUpgradePullByDigest(deps = {}) {
37086
37506
  if (info.exitCode !== 0) {
37087
37507
  infoSpinner.fail("docker daemon not reachable");
37088
37508
  process.stderr.write(
37089
- `${pc23.red("error")} docker info exited with ${info.exitCode}.
37509
+ `${pc24.red("error")} docker info exited with ${info.exitCode}.
37090
37510
  Ensure Docker Desktop / Colima / Rancher is running, then retry.
37091
37511
  `
37092
37512
  );
@@ -37135,7 +37555,7 @@ async function runUpgradePullByDigest(deps = {}) {
37135
37555
  pullSpinner.fail(`Pull failed for ${failed.map((r) => r.name).join(", ")}`);
37136
37556
  for (const f of failed) {
37137
37557
  process.stderr.write(
37138
- ` ${pc23.red(f.name)} (${f.ref}):
37558
+ ` ${pc24.red(f.name)} (${f.ref}):
37139
37559
  exit=${f.result.exitCode}
37140
37560
  stderr: ${f.result.stderr.split("\n")[0] ?? "(empty)"}
37141
37561
  `
@@ -37156,7 +37576,7 @@ async function runUpgradePullByDigest(deps = {}) {
37156
37576
  if (inspect.exitCode !== 0) {
37157
37577
  handshakeSpinner.fail(`Could not inspect ${name}`);
37158
37578
  process.stderr.write(
37159
- `${pc23.red("error")} docker inspect ${ref} failed: ${inspect.stderr}
37579
+ `${pc24.red("error")} docker inspect ${ref} failed: ${inspect.stderr}
37160
37580
  `
37161
37581
  );
37162
37582
  return { exitCode: EXIT_GENERIC_ERROR, summary: `inspect failed: ${name}` };
@@ -37168,7 +37588,7 @@ async function runUpgradePullByDigest(deps = {}) {
37168
37588
  const decision = checkProtocolOverlap(versions);
37169
37589
  if (!decision.compatible) {
37170
37590
  handshakeSpinner.fail(`Protocol mismatch on ${name}`);
37171
- process.stderr.write(`${pc23.red("error")} ${decision.remedy}
37591
+ process.stderr.write(`${pc24.red("error")} ${decision.remedy}
37172
37592
  `);
37173
37593
  return {
37174
37594
  exitCode: EXIT_PROTOCOL_MISMATCH,
@@ -37215,7 +37635,7 @@ async function runUpgradePullByDigest(deps = {}) {
37215
37635
  const r = tagger(t.from, t.to);
37216
37636
  if (!r.ok) {
37217
37637
  tagSpinner.fail(`docker tag failed for ${t.name}`);
37218
- process.stderr.write(`${pc23.red("error")} ${r.error ?? "docker tag failed"}
37638
+ process.stderr.write(`${pc24.red("error")} ${r.error ?? "docker tag failed"}
37219
37639
  `);
37220
37640
  return { exitCode: EXIT_GENERIC_ERROR, summary: `tag failed: ${t.name}` };
37221
37641
  }
@@ -37233,7 +37653,7 @@ async function runUpgradePullByDigest(deps = {}) {
37233
37653
  if (!proxyResult.ok) {
37234
37654
  proxySpinner.fail("docker-socket-proxy recreate failed");
37235
37655
  process.stderr.write(
37236
- `${pc23.red("error")} docker compose up --force-recreate docker-socket-proxy failed:
37656
+ `${pc24.red("error")} docker compose up --force-recreate docker-socket-proxy failed:
37237
37657
  ${proxyResult.stderr.split("\n").slice(0, 3).join("\n ")}
37238
37658
  `
37239
37659
  );
@@ -37245,7 +37665,7 @@ async function runUpgradePullByDigest(deps = {}) {
37245
37665
  const orphanCheck = inspectContainer("olam-host-cp");
37246
37666
  if (!orphanCheck.ok) {
37247
37667
  process.stderr.write(
37248
- `${pc23.red("error")} docker inspect olam-host-cp failed:
37668
+ `${pc24.red("error")} docker inspect olam-host-cp failed:
37249
37669
  ${orphanCheck.stderr.split("\n").slice(0, 3).join("\n ")}
37250
37670
  `
37251
37671
  );
@@ -37253,13 +37673,13 @@ async function runUpgradePullByDigest(deps = {}) {
37253
37673
  }
37254
37674
  if (orphanCheck.exists && orphanCheck.service !== "olam-host-cp") {
37255
37675
  process.stderr.write(
37256
- `${pc23.yellow("info")} Removing pre-rename orphan container olam-host-cp (old project=${orphanCheck.project || "<none>"}, old service=${orphanCheck.service || "<none>"})
37676
+ `${pc24.yellow("info")} Removing pre-rename orphan container olam-host-cp (old project=${orphanCheck.project || "<none>"}, old service=${orphanCheck.service || "<none>"})
37257
37677
  `
37258
37678
  );
37259
37679
  const rm = removeContainer("olam-host-cp");
37260
37680
  if (!rm.ok) {
37261
37681
  process.stderr.write(
37262
- `${pc23.red("error")} docker rm -f olam-host-cp failed:
37682
+ `${pc24.red("error")} docker rm -f olam-host-cp failed:
37263
37683
  ${rm.stderr.split("\n").slice(0, 3).join("\n ")}
37264
37684
  `
37265
37685
  );
@@ -37275,7 +37695,7 @@ async function runUpgradePullByDigest(deps = {}) {
37275
37695
  if (!composeResult.ok) {
37276
37696
  composeSpinner.fail("compose recreate failed");
37277
37697
  process.stderr.write(
37278
- `${pc23.red("error")} docker compose up --force-recreate olam-host-cp failed:
37698
+ `${pc24.red("error")} docker compose up --force-recreate olam-host-cp failed:
37279
37699
  ${composeResult.stderr.split("\n").slice(0, 3).join("\n ")}
37280
37700
  `
37281
37701
  );
@@ -37288,7 +37708,7 @@ async function runUpgradePullByDigest(deps = {}) {
37288
37708
  if (!authResult.ok) {
37289
37709
  authSpinner.fail("auth-service recreate failed");
37290
37710
  process.stderr.write(
37291
- `${pc23.red("error")} ${authResult.error ?? "unknown failure"}
37711
+ `${pc24.red("error")} ${authResult.error ?? "unknown failure"}
37292
37712
  `
37293
37713
  );
37294
37714
  return { exitCode: EXIT_GENERIC_ERROR, summary: "auth recreate failed" };
@@ -37301,7 +37721,7 @@ async function runUpgradePullByDigest(deps = {}) {
37301
37721
  if (!mcpResult.ok) {
37302
37722
  mcpSpinner.fail("mcp-auth-service recreate failed");
37303
37723
  process.stderr.write(
37304
- `${pc23.red("error")} ${mcpResult.error ?? "unknown failure"}
37724
+ `${pc24.red("error")} ${mcpResult.error ?? "unknown failure"}
37305
37725
  `
37306
37726
  );
37307
37727
  return { exitCode: EXIT_GENERIC_ERROR, summary: "mcp-auth recreate failed" };
@@ -37525,11 +37945,11 @@ manually inspect images with \`docker images olam-*:olam-rollback\`.`
37525
37945
  process.once("SIGINT", releaseOnSignal);
37526
37946
  process.once("SIGTERM", releaseOnSignal);
37527
37947
  try {
37528
- process.stdout.write(` ${pc23.dim("rollback retag (3 ops)".padEnd(34))}`);
37948
+ process.stdout.write(` ${pc24.dim("rollback retag (3 ops)".padEnd(34))}`);
37529
37949
  const swapStart = Date.now();
37530
37950
  const swapResult = performRollbackSwap(PRODUCTION_SWAP_PLAN);
37531
37951
  const swapDur = `${((Date.now() - swapStart) / 1e3).toFixed(1)}s`;
37532
- process.stdout.write(`${swapResult.ok ? pc23.green("\u2713") : pc23.red("\u2717")} ${swapDur}
37952
+ process.stdout.write(`${swapResult.ok ? pc24.green("\u2713") : pc24.red("\u2717")} ${swapDur}
37533
37953
  `);
37534
37954
  if (!swapResult.ok) {
37535
37955
  printError(`Rollback retag failed: ${swapResult.summary}`);
@@ -37539,11 +37959,11 @@ manually inspect images with \`docker images olam-*:olam-rollback\`.`
37539
37959
  printInfo("Rollback", swapResult.summary);
37540
37960
  const composeFile = findComposeFile();
37541
37961
  const authSecret = readAuthSecret2();
37542
- process.stdout.write(` ${pc23.dim("docker compose recreate olam-host-cp".padEnd(34))}`);
37962
+ process.stdout.write(` ${pc24.dim("docker compose recreate olam-host-cp".padEnd(34))}`);
37543
37963
  const composeStart = Date.now();
37544
37964
  const composeResult = runCompose(["up", "-d", "--force-recreate", "--no-deps", "olam-host-cp"], composeFile, buildComposeEnv(authSecret, captureGhToken()));
37545
37965
  const composeDur = `${((Date.now() - composeStart) / 1e3).toFixed(1)}s`;
37546
- process.stdout.write(`${composeResult.ok ? pc23.green("\u2713") : pc23.red("\u2717")} ${composeDur}
37966
+ process.stdout.write(`${composeResult.ok ? pc24.green("\u2713") : pc24.red("\u2717")} ${composeDur}
37547
37967
  `);
37548
37968
  if (!composeResult.ok) {
37549
37969
  printError(
@@ -37554,10 +37974,10 @@ Canonical tags are at :olam-rollback (good); container restart pending. Manually
37554
37974
  process.exitCode = 1;
37555
37975
  return;
37556
37976
  }
37557
- process.stdout.write(` ${pc23.dim("recreate auth-service".padEnd(34))}`);
37977
+ process.stdout.write(` ${pc24.dim("recreate auth-service".padEnd(34))}`);
37558
37978
  const authResult = await recreateAuthService();
37559
37979
  const authDur = `${(authResult.durationMs / 1e3).toFixed(1)}s`;
37560
- process.stdout.write(`${authResult.ok ? pc23.green("\u2713") : pc23.red("\u2717")} ${authDur}
37980
+ process.stdout.write(`${authResult.ok ? pc24.green("\u2713") : pc24.red("\u2717")} ${authDur}
37561
37981
  `);
37562
37982
  if (!authResult.ok) {
37563
37983
  printError(`Auth-service recreate failed: ${authResult.error ?? "unknown"}`);
@@ -37723,7 +38143,7 @@ ${spaResult.stderr}`);
37723
38143
  throw err;
37724
38144
  }
37725
38145
  if (step2.tee) {
37726
- process.stdout.write(` ${pc23.dim(step2.label.padEnd(34))}
38146
+ process.stdout.write(` ${pc24.dim(step2.label.padEnd(34))}
37727
38147
  `);
37728
38148
  const start = Date.now();
37729
38149
  const result = spawnSync23("bash", [scriptPath], {
@@ -37734,7 +38154,7 @@ ${spaResult.stderr}`);
37734
38154
  const durationMs = Date.now() - start;
37735
38155
  const ok = result.status === 0 && result.error === void 0;
37736
38156
  const dur = `${(durationMs / 1e3).toFixed(1)}s`;
37737
- process.stdout.write(` ${pc23.dim(step2.label.padEnd(34))}${ok ? pc23.green("\u2713") : pc23.red("\u2717")} ${dur}
38157
+ process.stdout.write(` ${pc24.dim(step2.label.padEnd(34))}${ok ? pc24.green("\u2713") : pc24.red("\u2717")} ${dur}
37738
38158
  `);
37739
38159
  timings.push({ label: step2.label, durationMs });
37740
38160
  if (!ok) {
@@ -37760,7 +38180,7 @@ ${result.stderr.split("\n").slice(-3).join("\n")}`);
37760
38180
  }
37761
38181
  for (const t of timings) logRow.durations_ms[t.label] = t.durationMs;
37762
38182
  const smokeStart = Date.now();
37763
- process.stdout.write(` ${pc23.dim("smoke (docker create + inspect)".padEnd(34))}`);
38183
+ process.stdout.write(` ${pc24.dim("smoke (docker create + inspect)".padEnd(34))}`);
37764
38184
  const smokeImages = [
37765
38185
  "olam-auth:olam-next",
37766
38186
  "olam-devbox:olam-next",
@@ -37770,7 +38190,7 @@ ${result.stderr.split("\n").slice(-3).join("\n")}`);
37770
38190
  const smokeFailures = smokeResults.filter((r) => !r.ok);
37771
38191
  const smokeDurationMs = Date.now() - smokeStart;
37772
38192
  const smokeDur = `${(smokeDurationMs / 1e3).toFixed(1)}s`;
37773
- process.stdout.write(`${smokeFailures.length === 0 ? pc23.green("\u2713") : pc23.red("\u2717")} ${smokeDur}
38193
+ process.stdout.write(`${smokeFailures.length === 0 ? pc24.green("\u2713") : pc24.red("\u2717")} ${smokeDur}
37774
38194
  `);
37775
38195
  timings.push({ label: "smoke", durationMs: smokeDurationMs });
37776
38196
  if (smokeFailures.length > 0) {
@@ -37797,12 +38217,12 @@ Recovery options:
37797
38217
  process.exitCode = 1;
37798
38218
  return;
37799
38219
  }
37800
- process.stdout.write(` ${pc23.dim("atomic 6-tag swap".padEnd(34))}`);
38220
+ process.stdout.write(` ${pc24.dim("atomic 6-tag swap".padEnd(34))}`);
37801
38221
  const swapStart = Date.now();
37802
38222
  const swapResult = performAtomicSwap(PRODUCTION_SWAP_PLAN);
37803
38223
  const swapDurationMs = Date.now() - swapStart;
37804
38224
  const swapDur = `${(swapDurationMs / 1e3).toFixed(1)}s`;
37805
- process.stdout.write(`${swapResult.ok ? pc23.green("\u2713") : pc23.red("\u2717")} ${swapDur}
38225
+ process.stdout.write(`${swapResult.ok ? pc24.green("\u2713") : pc24.red("\u2717")} ${swapDur}
37806
38226
  `);
37807
38227
  timings.push({ label: "atomic swap", durationMs: swapDurationMs });
37808
38228
  if (!swapResult.ok) {
@@ -37812,7 +38232,7 @@ Recovery options:
37812
38232
  }
37813
38233
  printInfo("Swap", swapResult.summary);
37814
38234
  const composeFile = findComposeFile();
37815
- process.stdout.write(` ${pc23.dim("docker compose recreate".padEnd(34))}`);
38235
+ process.stdout.write(` ${pc24.dim("docker compose recreate".padEnd(34))}`);
37816
38236
  const composeStart = Date.now();
37817
38237
  const composeResult = runCompose(
37818
38238
  ["up", "-d", "--force-recreate"],
@@ -37822,7 +38242,7 @@ Recovery options:
37822
38242
  const composeDurationMs = Date.now() - composeStart;
37823
38243
  const composeOk = composeResult.ok;
37824
38244
  const composeDur = `${(composeDurationMs / 1e3).toFixed(1)}s`;
37825
- process.stdout.write(`${composeOk ? pc23.green("\u2713") : pc23.red("\u2717")} ${composeDur}
38245
+ process.stdout.write(`${composeOk ? pc24.green("\u2713") : pc24.red("\u2717")} ${composeDur}
37826
38246
  `);
37827
38247
  timings.push({ label: "container recreate", durationMs: composeDurationMs });
37828
38248
  if (!composeOk) {
@@ -37838,10 +38258,10 @@ Recovery options:
37838
38258
  process.exitCode = 1;
37839
38259
  return;
37840
38260
  }
37841
- process.stdout.write(` ${pc23.dim("recreate auth-service".padEnd(34))}`);
38261
+ process.stdout.write(` ${pc24.dim("recreate auth-service".padEnd(34))}`);
37842
38262
  const authResult = await recreateAuthService();
37843
38263
  const authDur = `${(authResult.durationMs / 1e3).toFixed(1)}s`;
37844
- process.stdout.write(`${authResult.ok ? pc23.green("\u2713") : pc23.red("\u2717")} ${authDur}
38264
+ process.stdout.write(`${authResult.ok ? pc24.green("\u2713") : pc24.red("\u2717")} ${authDur}
37845
38265
  `);
37846
38266
  timings.push({ label: "auth recreate", durationMs: authResult.durationMs });
37847
38267
  if (!authResult.ok) {
@@ -37856,12 +38276,12 @@ Recovery options:
37856
38276
  process.exitCode = 1;
37857
38277
  return;
37858
38278
  }
37859
- process.stdout.write(` ${pc23.dim("waiting for /health".padEnd(34))}`);
38279
+ process.stdout.write(` ${pc24.dim("waiting for /health".padEnd(34))}`);
37860
38280
  const healthStart = Date.now();
37861
38281
  const healthy = await waitForHealth(1e4);
37862
38282
  const healthDurationMs = Date.now() - healthStart;
37863
38283
  const healthDur = `${(healthDurationMs / 1e3).toFixed(1)}s`;
37864
- process.stdout.write(`${healthy ? pc23.green("\u2713") : pc23.yellow("?")} ${healthDur}
38284
+ process.stdout.write(`${healthy ? pc24.green("\u2713") : pc24.yellow("?")} ${healthDur}
37865
38285
  `);
37866
38286
  timings.push({ label: "/health", durationMs: healthDurationMs });
37867
38287
  if (!healthy) {
@@ -37869,12 +38289,12 @@ Recovery options:
37869
38289
  "Host CP started but /health did not respond within 10s.\n \u2022 Check: docker logs olam-host-cp\n \u2022 If the new SHA is broken: `olam upgrade --rollback` restores the prior set in <30s."
37870
38290
  );
37871
38291
  }
37872
- process.stdout.write(` ${pc23.dim("verify /version/status round-trip".padEnd(34))}`);
38292
+ process.stdout.write(` ${pc24.dim("verify /version/status round-trip".padEnd(34))}`);
37873
38293
  const versionStart = Date.now();
37874
38294
  const versionMatch = await waitForVersionMatch(_targetSha, 9e4);
37875
38295
  const versionDurationMs = Date.now() - versionStart;
37876
38296
  const versionDur = `${(versionDurationMs / 1e3).toFixed(1)}s`;
37877
- process.stdout.write(`${versionMatch.matched ? pc23.green("\u2713") : pc23.yellow("?")} ${versionDur}
38297
+ process.stdout.write(`${versionMatch.matched ? pc24.green("\u2713") : pc24.yellow("?")} ${versionDur}
37878
38298
  `);
37879
38299
  timings.push({ label: "/version/status round-trip", durationMs: versionDurationMs });
37880
38300
  if (!versionMatch.matched) {
@@ -37979,12 +38399,12 @@ init_host_cp();
37979
38399
  init_context();
37980
38400
  init_output();
37981
38401
  import * as http4 from "node:http";
37982
- import pc24 from "picocolors";
38402
+ import pc25 from "picocolors";
37983
38403
  var HOST_CP_PORT3 = 19e3;
37984
38404
  function colorLine(line) {
37985
- if (/\bERROR\b/.test(line)) return pc24.red(line);
37986
- if (/\bWARN\b/.test(line)) return pc24.yellow(line);
37987
- if (/\bINFO\b/.test(line)) return pc24.dim(line);
38405
+ if (/\bERROR\b/.test(line)) return pc25.red(line);
38406
+ if (/\bWARN\b/.test(line)) return pc25.yellow(line);
38407
+ if (/\bINFO\b/.test(line)) return pc25.dim(line);
37988
38408
  return line;
37989
38409
  }
37990
38410
  function buildLogsUrl(worldId, opts, port2 = HOST_CP_PORT3) {
@@ -38081,7 +38501,7 @@ function registerLogs(program2) {
38081
38501
  // src/commands/ps.ts
38082
38502
  init_context();
38083
38503
  init_output();
38084
- import pc25 from "picocolors";
38504
+ import pc26 from "picocolors";
38085
38505
  import { spawnSync as spawnSync24 } from "node:child_process";
38086
38506
  var SAFE_IDENT4 = /^[a-z0-9][a-z0-9-]{0,63}$/;
38087
38507
  function parseDockerTop(stdout) {
@@ -38164,18 +38584,18 @@ function printTable2(rows) {
38164
38584
  const fixedWidth = 5 + 1 + 8 + 1 + 6 + 1 + 6 + 1 + 10 + 1 + 6 + 1;
38165
38585
  const cmdWidth = Math.max(20, cols - fixedWidth);
38166
38586
  const header = [
38167
- pc25.bold(pc25.dim("PID".padEnd(5))),
38168
- pc25.bold(pc25.dim("USER".padEnd(8))),
38169
- pc25.bold(pc25.dim("%CPU".padEnd(6))),
38170
- pc25.bold(pc25.dim("%MEM".padEnd(6))),
38171
- pc25.bold(pc25.dim("STARTED".padEnd(10))),
38172
- pc25.bold(pc25.dim("STATE".padEnd(6))),
38173
- pc25.bold(pc25.dim("COMMAND"))
38587
+ pc26.bold(pc26.dim("PID".padEnd(5))),
38588
+ pc26.bold(pc26.dim("USER".padEnd(8))),
38589
+ pc26.bold(pc26.dim("%CPU".padEnd(6))),
38590
+ pc26.bold(pc26.dim("%MEM".padEnd(6))),
38591
+ pc26.bold(pc26.dim("STARTED".padEnd(10))),
38592
+ pc26.bold(pc26.dim("STATE".padEnd(6))),
38593
+ pc26.bold(pc26.dim("COMMAND"))
38174
38594
  ].join(" ");
38175
38595
  console.log(header);
38176
38596
  for (const row of rows) {
38177
38597
  const cmd = row.command.length > cmdWidth ? row.command.slice(0, cmdWidth - 1) + "\u2026" : row.command;
38178
- const stateFn = row.state.startsWith("R") ? pc25.green : row.state.startsWith("Z") ? pc25.red : pc25.dim;
38598
+ const stateFn = row.state.startsWith("R") ? pc26.green : row.state.startsWith("Z") ? pc26.red : pc26.dim;
38179
38599
  console.log([
38180
38600
  row.pid.padEnd(5),
38181
38601
  row.user.slice(0, 8).padEnd(8),
@@ -38229,7 +38649,7 @@ function registerPs(program2) {
38229
38649
  printTable2(rows);
38230
38650
  if (opts.watch) {
38231
38651
  process.stdout.write(`
38232
- ${pc25.dim(`world: ${worldId} sort: ${sortKey} refresh: 5s Ctrl-C to exit`)}
38652
+ ${pc26.dim(`world: ${worldId} sort: ${sortKey} refresh: 5s Ctrl-C to exit`)}
38233
38653
  `);
38234
38654
  }
38235
38655
  }
@@ -38379,7 +38799,7 @@ init_output();
38379
38799
  import * as fs49 from "node:fs";
38380
38800
  import * as path52 from "node:path";
38381
38801
  import { execSync as execSync12 } from "node:child_process";
38382
- import pc26 from "picocolors";
38802
+ import pc27 from "picocolors";
38383
38803
 
38384
38804
  // src/commands/world.ts
38385
38805
  function getOrCreateWorldCommand(program2) {
@@ -38489,7 +38909,7 @@ async function handleCreate2(worldId, kindArg) {
38489
38909
  const label = r.repo ? `${r.kind}/${r.repo}` : r.kind;
38490
38910
  if (r.ok) {
38491
38911
  printSuccess(`${label}`);
38492
- console.log(` ${pc26.dim(r.tarPath)}`);
38912
+ console.log(` ${pc27.dim(r.tarPath)}`);
38493
38913
  } else {
38494
38914
  printWarning(`${label}: ${r.msg ?? "skipped"}`);
38495
38915
  }
@@ -38679,18 +39099,18 @@ function handleInspect(opts) {
38679
39099
  const label = `${out.kind}/${out.repo}`;
38680
39100
  if (out.outcome === "hit") {
38681
39101
  const size = out.sizeBytes !== void 0 ? ` (${formatBytes4(out.sizeBytes)})` : "";
38682
- printSuccess(`${label.padEnd(24)} HIT ${pc26.dim(out.fingerprint ?? "")}${size}`);
39102
+ printSuccess(`${label.padEnd(24)} HIT ${pc27.dim(out.fingerprint ?? "")}${size}`);
38683
39103
  } else {
38684
39104
  printWarning(`${label.padEnd(24)} MISS ${explainInspectReason(out)}`);
38685
39105
  if (out.expectedTarPath) {
38686
- console.log(` ${pc26.dim("expected: " + out.expectedTarPath)}`);
39106
+ console.log(` ${pc27.dim("expected: " + out.expectedTarPath)}`);
38687
39107
  }
38688
39108
  }
38689
39109
  }
38690
39110
  console.log();
38691
39111
  if (hits === 0) {
38692
39112
  console.log(
38693
- pc26.dim(
39113
+ pc27.dim(
38694
39114
  "No warm snapshot would be restored \u2014 the next `olam create` takes the cold path. See docs/architecture/snapshot-restore.md \xA7 FAQ."
38695
39115
  )
38696
39116
  );
@@ -38702,7 +39122,7 @@ async function handleEvict(opts) {
38702
39122
  if (opts.dryRun) {
38703
39123
  const root = snapshotsDir();
38704
39124
  if (!fs49.existsSync(root)) {
38705
- console.log(pc26.dim("No snapshot dir; nothing to evict."));
39125
+ console.log(pc27.dim("No snapshot dir; nothing to evict."));
38706
39126
  return;
38707
39127
  }
38708
39128
  const allTars = [];
@@ -38735,17 +39155,17 @@ async function handleEvict(opts) {
38735
39155
  console.log();
38736
39156
  for (const t of toEvict) {
38737
39157
  const age = formatAge2(Date.now() - t.mtime);
38738
- console.log(` ${pc26.dim(formatBytes4(t.size).padStart(8))} ${age.padStart(10)} ${t.path}`);
39158
+ console.log(` ${pc27.dim(formatBytes4(t.size).padStart(8))} ${age.padStart(10)} ${t.path}`);
38739
39159
  }
38740
39160
  console.log();
38741
- console.log(pc26.dim(`Total after eviction: ${formatBytes4(remaining)} (cap: ${formatBytes4(maxBytes)})`));
39161
+ console.log(pc27.dim(`Total after eviction: ${formatBytes4(remaining)} (cap: ${formatBytes4(maxBytes)})`));
38742
39162
  return;
38743
39163
  }
38744
39164
  const freed = evictOldSnapshotsWithFlock(maxBytes);
38745
39165
  if (freed > 0) {
38746
39166
  printSuccess(`Evicted ${formatBytes4(freed)} (cap: ${formatBytes4(maxBytes)})`);
38747
39167
  } else {
38748
- console.log(pc26.dim("No eviction needed (or another process held the lock)."));
39168
+ console.log(pc27.dim("No eviction needed (or another process held the lock)."));
38749
39169
  }
38750
39170
  }
38751
39171
  function handleList2(worldIdFilter) {
@@ -38753,7 +39173,7 @@ function handleList2(worldIdFilter) {
38753
39173
  const entries = listSnapshots(worldIdFilter);
38754
39174
  if (entries.length === 0) {
38755
39175
  const where = worldIdFilter ? ` for world "${worldIdFilter}"` : "";
38756
- console.log(pc26.dim(`No snapshots found${where}. Run \`olam world snapshot create <worldId>\` first.`));
39176
+ console.log(pc27.dim(`No snapshots found${where}. Run \`olam world snapshot create <worldId>\` first.`));
38757
39177
  return;
38758
39178
  }
38759
39179
  printHeader(`${entries.length} snapshot(s)`);
@@ -38762,15 +39182,15 @@ function handleList2(worldIdFilter) {
38762
39182
  for (const entry of entries) {
38763
39183
  const { manifest } = entry;
38764
39184
  if (manifest.worldId !== lastWorldId) {
38765
- console.log(pc26.bold(manifest.worldId));
39185
+ console.log(pc27.bold(manifest.worldId));
38766
39186
  lastWorldId = manifest.worldId;
38767
39187
  }
38768
39188
  const repo = manifest.repo ?? "(all repos)";
38769
39189
  const size = formatBytes4(manifest.sizeBytes);
38770
39190
  const age = formatAge2(entry.ageMs);
38771
- const kindColor = manifest.kind === "gems" ? pc26.magenta(manifest.kind) : manifest.kind === "node" ? pc26.cyan(manifest.kind) : pc26.yellow(manifest.kind);
39191
+ const kindColor = manifest.kind === "gems" ? pc27.magenta(manifest.kind) : manifest.kind === "node" ? pc27.cyan(manifest.kind) : pc27.yellow(manifest.kind);
38772
39192
  console.log(
38773
- ` ${kindColor.padEnd(6)} ${pc26.dim(repo.padEnd(24))} ${manifest.fingerprint} ${size.padStart(8)} ${age}`
39193
+ ` ${kindColor.padEnd(6)} ${pc27.dim(repo.padEnd(24))} ${manifest.fingerprint} ${size.padStart(8)} ${age}`
38774
39194
  );
38775
39195
  }
38776
39196
  console.log();
@@ -39122,7 +39542,7 @@ import * as fs52 from "node:fs";
39122
39542
  import * as os30 from "node:os";
39123
39543
  import * as path55 from "node:path";
39124
39544
  import { execFileSync as execFileSync13, execSync as execSync13 } from "node:child_process";
39125
- import pc27 from "picocolors";
39545
+ import pc28 from "picocolors";
39126
39546
 
39127
39547
  // ../core/dist/diagnose/secret-stripper.js
39128
39548
  var SECRET_PATTERNS = [
@@ -39260,23 +39680,23 @@ function registerDiagnose(program2) {
39260
39680
  return;
39261
39681
  }
39262
39682
  if (!opts.quiet) {
39263
- console.log(pc27.cyan("Building diagnostics zip\u2026"));
39683
+ console.log(pc28.cyan("Building diagnostics zip\u2026"));
39264
39684
  }
39265
39685
  try {
39266
39686
  const { zipPath, entries } = await buildDiagnosticsZip();
39267
39687
  if (!opts.quiet) {
39268
- console.log(pc27.green(`Done: ${zipPath}`));
39269
- console.log(pc27.dim(`Contents: ${entries.join(", ")}`));
39688
+ console.log(pc28.green(`Done: ${zipPath}`));
39689
+ console.log(pc28.dim(`Contents: ${entries.join(", ")}`));
39270
39690
  }
39271
39691
  if (opts.upload) {
39272
- console.log(pc27.yellow(
39692
+ console.log(pc28.yellow(
39273
39693
  `Telemetry endpoint not yet provisioned. Share the zip manually:
39274
39694
  File: ${zipPath}
39275
39695
  See docs/runbooks/share-diagnostics.md for instructions.`
39276
39696
  ));
39277
39697
  }
39278
39698
  } catch (err) {
39279
- console.error(pc27.red(`Diagnose failed: ${err.message}`));
39699
+ console.error(pc28.red(`Diagnose failed: ${err.message}`));
39280
39700
  process.exitCode = 1;
39281
39701
  }
39282
39702
  });
@@ -39979,13 +40399,13 @@ function registerDoctor(program2) {
39979
40399
  }
39980
40400
 
39981
40401
  // src/commands/substrate.ts
39982
- import pc29 from "picocolors";
40402
+ import pc30 from "picocolors";
39983
40403
  init_context();
39984
40404
  init_output();
39985
40405
 
39986
40406
  // src/commands/substrate-audit-log.ts
39987
40407
  import * as fs55 from "node:fs";
39988
- import pc28 from "picocolors";
40408
+ import pc29 from "picocolors";
39989
40409
  var VALID_PERIPHERAL_NAMES = PERIPHERALS.map((p) => p.name).sort();
39990
40410
  var DEFAULT_LIMIT = 50;
39991
40411
  function parseAuditLog(raw) {
@@ -40002,8 +40422,8 @@ function parseAuditLog(raw) {
40002
40422
  }
40003
40423
  function formatEntryRow(entry, index) {
40004
40424
  const ts = entry.ts ?? "(no timestamp)";
40005
- const regression = entry.security_regression ? pc28.red("yes") : pc28.green("no");
40006
- const accepted = entry.accepted ? pc28.yellow("yes") : "\u2014";
40425
+ const regression = entry.security_regression ? pc29.red("yes") : pc29.green("no");
40426
+ const accepted = entry.accepted ? pc29.yellow("yes") : "\u2014";
40007
40427
  const fields = (entry.changed_fields ?? []).join(", ") || "\u2014";
40008
40428
  return ` ${String(index + 1).padStart(3)} ${ts} regression=${regression} accepted=${accepted} fields=[${fields}]`;
40009
40429
  }
@@ -40029,7 +40449,7 @@ function handleAuditLog(opts, deps = {}) {
40029
40449
  raw = readFileSyncImpl(auditLogPath, "utf8");
40030
40450
  } catch (err) {
40031
40451
  stderr.write(
40032
- `${pc28.red("error:")} could not read audit log at ${auditLogPath}: ${err instanceof Error ? err.message : String(err)}
40452
+ `${pc29.red("error:")} could not read audit log at ${auditLogPath}: ${err instanceof Error ? err.message : String(err)}
40033
40453
  `
40034
40454
  );
40035
40455
  return 1;
@@ -40038,7 +40458,7 @@ function handleAuditLog(opts, deps = {}) {
40038
40458
  if (opts.peripheral) {
40039
40459
  if (!VALID_PERIPHERAL_NAMES.includes(opts.peripheral)) {
40040
40460
  stderr.write(
40041
- `${pc28.red("error:")} unknown peripheral "${opts.peripheral}". Valid names: ${VALID_PERIPHERAL_NAMES.join(", ")}
40461
+ `${pc29.red("error:")} unknown peripheral "${opts.peripheral}". Valid names: ${VALID_PERIPHERAL_NAMES.join(", ")}
40042
40462
  `
40043
40463
  );
40044
40464
  return 1;
@@ -40049,7 +40469,7 @@ function handleAuditLog(opts, deps = {}) {
40049
40469
  const sinceMs = Date.parse(opts.since);
40050
40470
  if (Number.isNaN(sinceMs)) {
40051
40471
  stderr.write(
40052
- `${pc28.red("error:")} invalid --since date "${opts.since}". Expected ISO-8601 (e.g. 2026-05-20T00:00:00Z).
40472
+ `${pc29.red("error:")} invalid --since date "${opts.since}". Expected ISO-8601 (e.g. 2026-05-20T00:00:00Z).
40053
40473
  `
40054
40474
  );
40055
40475
  return 1;
@@ -40104,9 +40524,9 @@ async function defaultCountWorlds() {
40104
40524
  }
40105
40525
  function formatBetaLine(cfg) {
40106
40526
  if (cfg.host.substrate === "compose") {
40107
- return `Substrate: ${pc29.bold("compose")}`;
40527
+ return `Substrate: ${pc30.bold("compose")}`;
40108
40528
  }
40109
- return `Substrate: ${pc29.bold("kubernetes")} (beta until ${BETA_EXPIRY_DATE}, flavor=k3s)`;
40529
+ return `Substrate: ${pc30.bold("kubernetes")} (beta until ${BETA_EXPIRY_DATE}, flavor=k3s)`;
40110
40530
  }
40111
40531
  async function handleGet(deps = {}) {
40112
40532
  const read = deps.readConfig ?? readConfig;
@@ -40128,7 +40548,7 @@ async function handleSet(target, deps = {}) {
40128
40548
  void runDoctorFn;
40129
40549
  if (target !== "compose" && target !== "kubernetes") {
40130
40550
  stderr.write(
40131
- `${pc29.red("error:")} unsupported substrate "${target}". Expected: compose | kubernetes.
40551
+ `${pc30.red("error:")} unsupported substrate "${target}". Expected: compose | kubernetes.
40132
40552
  `
40133
40553
  );
40134
40554
  return 1;
@@ -40137,7 +40557,7 @@ async function handleSet(target, deps = {}) {
40137
40557
  const current = read();
40138
40558
  if (current.host.substrate === targetSubstrate) {
40139
40559
  stdout.write(
40140
- `Substrate already set to ${pc29.bold(targetSubstrate)}. No change.
40560
+ `Substrate already set to ${pc30.bold(targetSubstrate)}. No change.
40141
40561
  `
40142
40562
  );
40143
40563
  return 0;
@@ -40147,23 +40567,23 @@ async function handleSet(target, deps = {}) {
40147
40567
  worldsCount = await countWorlds();
40148
40568
  } catch (err) {
40149
40569
  stderr.write(
40150
- `${pc29.yellow("warn:")} could not list worlds (${err instanceof Error ? err.message : String(err)}); assuming none exist and proceeding.
40570
+ `${pc30.yellow("warn:")} could not list worlds (${err instanceof Error ? err.message : String(err)}); assuming none exist and proceeding.
40151
40571
  `
40152
40572
  );
40153
40573
  worldsCount = 0;
40154
40574
  }
40155
40575
  if (worldsCount > 0) {
40156
40576
  stderr.write(
40157
- `${pc29.red("error:")} ${worldsCount} world(s) exist on the current substrate (${pc29.bold(
40577
+ `${pc30.red("error:")} ${worldsCount} world(s) exist on the current substrate (${pc30.bold(
40158
40578
  current.host.substrate
40159
40579
  )}). Switching substrates abandons their state.
40160
40580
  `
40161
40581
  );
40162
- stderr.write(` Run ${pc29.bold("olam destroy --all")} first, then re-run this command.
40582
+ stderr.write(` Run ${pc30.bold("olam destroy --all")} first, then re-run this command.
40163
40583
  `);
40164
40584
  return 1;
40165
40585
  }
40166
- stdout.write(`Running pre-flight for ${pc29.bold(targetSubstrate)} substrate\u2026
40586
+ stdout.write(`Running pre-flight for ${pc30.bold(targetSubstrate)} substrate\u2026
40167
40587
  `);
40168
40588
  let doctorResult;
40169
40589
  try {
@@ -40174,18 +40594,18 @@ async function handleSet(target, deps = {}) {
40174
40594
  }
40175
40595
  } catch (err) {
40176
40596
  stderr.write(
40177
- `${pc29.red("error:")} pre-flight crashed: ${err instanceof Error ? err.message : String(err)}
40597
+ `${pc30.red("error:")} pre-flight crashed: ${err instanceof Error ? err.message : String(err)}
40178
40598
  `
40179
40599
  );
40180
40600
  return 1;
40181
40601
  }
40182
40602
  if (doctorResult.exitCode !== 0) {
40183
40603
  stderr.write(
40184
- `${pc29.red("error:")} pre-flight failed for ${pc29.bold(targetSubstrate)} substrate.
40604
+ `${pc30.red("error:")} pre-flight failed for ${pc30.bold(targetSubstrate)} substrate.
40185
40605
  `
40186
40606
  );
40187
40607
  stderr.write(
40188
- ` Run ${pc29.bold(
40608
+ ` Run ${pc30.bold(
40189
40609
  `olam doctor${targetSubstrate === "kubernetes" ? " --substrate=kubernetes" : ""}`
40190
40610
  )} to see what's missing, fix the named prereqs, then re-run.
40191
40611
  `
@@ -40202,14 +40622,14 @@ async function handleSet(target, deps = {}) {
40202
40622
  stdout.write(
40203
40623
  `
40204
40624
  Kubernetes substrate is in beta until ${BETA_EXPIRY_DATE}.
40205
- Rollback: ${pc29.bold("olam substrate set compose")} (preserves compose worlds you create after this).
40206
- Next: ${pc29.bold("olam upgrade")} to deploy host-cp to your kubectl context.
40625
+ Rollback: ${pc30.bold("olam substrate set compose")} (preserves compose worlds you create after this).
40626
+ Next: ${pc30.bold("olam upgrade")} to deploy host-cp to your kubectl context.
40207
40627
  `
40208
40628
  );
40209
40629
  } else {
40210
40630
  stdout.write(
40211
40631
  `
40212
- Next: ${pc29.bold("olam upgrade")} to redeploy host-cp on the compose substrate.
40632
+ Next: ${pc30.bold("olam upgrade")} to redeploy host-cp on the compose substrate.
40213
40633
  `
40214
40634
  );
40215
40635
  }
@@ -40713,7 +41133,7 @@ import path81 from "node:path";
40713
41133
  import { createInterface as createInterface4 } from "node:readline";
40714
41134
 
40715
41135
  // src/lib/shell-rc.ts
40716
- import { copyFileSync as copyFileSync5, existsSync as existsSync62, readFileSync as readFileSync52, renameSync as renameSync8, writeFileSync as writeFileSync30 } from "node:fs";
41136
+ import { copyFileSync as copyFileSync5, existsSync as existsSync62, readFileSync as readFileSync52, renameSync as renameSync8, writeFileSync as writeFileSync31 } from "node:fs";
40717
41137
  import path58 from "node:path";
40718
41138
  function appendIdempotent(opts) {
40719
41139
  const { rcPath, marker, contentLine, clock = () => /* @__PURE__ */ new Date() } = opts;
@@ -40731,7 +41151,7 @@ function appendIdempotent(opts) {
40731
41151
  const trailing = contentLine.endsWith("\n") ? "" : "\n";
40732
41152
  const nextContent = `${content}${separator}${contentLine}${trailing}`;
40733
41153
  const tmpPath = `${rcPath}.olam-tmp.${process.pid}`;
40734
- writeFileSync30(tmpPath, nextContent, { encoding: "utf-8" });
41154
+ writeFileSync31(tmpPath, nextContent, { encoding: "utf-8" });
40735
41155
  renameSync8(tmpPath, rcPath);
40736
41156
  return { status: "appended", backupPath };
40737
41157
  }
@@ -41335,7 +41755,7 @@ async function phase2_5ProvisionCluster(substrate, clusterName, opts, deps, reus
41335
41755
  return {
41336
41756
  ok: false,
41337
41757
  message: `k3d cluster create ${clusterName} failed (exit ${createResult.status ?? "signal"})`,
41338
- remedy: `Run manually: k3d cluster create ${clusterName} --wait --timeout 90s`
41758
+ remedy: `Run manually: k3d cluster create ${clusterName} --volume ~/.config/gh:/host/.config/gh --wait --timeout 90s`
41339
41759
  };
41340
41760
  }
41341
41761
  const ctxResult = captureSpawnSync("kubectl", ["config", "current-context"]);
@@ -41853,7 +42273,7 @@ import * as fs82 from "node:fs";
41853
42273
  import * as os46 from "node:os";
41854
42274
  import * as path84 from "node:path";
41855
42275
  import { execSync as execSync15 } from "node:child_process";
41856
- import pc30 from "picocolors";
42276
+ import pc31 from "picocolors";
41857
42277
 
41858
42278
  // src/lib/symlink-reconcile.ts
41859
42279
  import * as fs80 from "node:fs";
@@ -42005,37 +42425,37 @@ async function doUpdate(opts, _exec = defaultExec, _reconcile = reconcileSkillSy
42005
42425
  writeLastStable(prevVersion);
42006
42426
  }
42007
42427
  if (!quiet) {
42008
- console.log(pc30.cyan(`Installing ${PACKAGE_NAME}@${channel}\u2026`));
42428
+ console.log(pc31.cyan(`Installing ${PACKAGE_NAME}@${channel}\u2026`));
42009
42429
  }
42010
42430
  const installResult = _exec(`npm install -g ${PACKAGE_NAME}@${channel}`);
42011
42431
  if (installResult.exitCode !== 0) {
42012
42432
  logUpdateFailure(installResult.stderr);
42013
42433
  if (!quiet) {
42014
- console.error(pc30.red("Update failed."));
42434
+ console.error(pc31.red("Update failed."));
42015
42435
  }
42016
42436
  const prev = readLastStable();
42017
42437
  if (prev) {
42018
42438
  if (!quiet) {
42019
- console.log(pc30.yellow(`Restoring to ${prev}\u2026`));
42439
+ console.log(pc31.yellow(`Restoring to ${prev}\u2026`));
42020
42440
  }
42021
42441
  const restoreResult = _exec(`npm install -g ${PACKAGE_NAME}@${prev}`);
42022
42442
  if (restoreResult.exitCode !== 0) {
42023
42443
  if (!quiet) {
42024
- console.error(pc30.red(
42444
+ console.error(pc31.red(
42025
42445
  `Restore also failed. Run: npm install -g ${PACKAGE_NAME}@${prev} manually.`
42026
42446
  ));
42027
42447
  }
42028
42448
  } else if (!quiet) {
42029
- console.log(pc30.yellow(`Restored to ${prev}.`));
42449
+ console.log(pc31.yellow(`Restored to ${prev}.`));
42030
42450
  }
42031
42451
  } else if (!quiet) {
42032
- console.error(pc30.red("No previous version cached; cannot auto-restore."));
42452
+ console.error(pc31.red("No previous version cached; cannot auto-restore."));
42033
42453
  }
42034
42454
  return { action: "restored", prevVersion: prev ?? void 0, exitCode: 11 };
42035
42455
  }
42036
42456
  const newVersion = getCurrentVersion(_exec) ?? void 0;
42037
42457
  if (!quiet && newVersion) {
42038
- console.log(pc30.green(`Updated to ${newVersion}.`));
42458
+ console.log(pc31.green(`Updated to ${newVersion}.`));
42039
42459
  }
42040
42460
  const npmRootResult = _getNpmRoot("npm root -g");
42041
42461
  let symlinkResult = { added: [], removed: [] };
@@ -42047,10 +42467,10 @@ async function doUpdate(opts, _exec = defaultExec, _reconcile = reconcileSkillSy
42047
42467
  symlinkResult = { added: rec.added, removed: rec.removed };
42048
42468
  if (!quiet && (rec.added.length > 0 || rec.removed.length > 0)) {
42049
42469
  if (rec.added.length > 0) {
42050
- console.log(pc30.dim(`Skills added: ${rec.added.join(", ")}`));
42470
+ console.log(pc31.dim(`Skills added: ${rec.added.join(", ")}`));
42051
42471
  }
42052
42472
  if (rec.removed.length > 0) {
42053
- console.log(pc30.dim(`Skills removed (dangling): ${rec.removed.join(", ")}`));
42473
+ console.log(pc31.dim(`Skills removed (dangling): ${rec.removed.join(", ")}`));
42054
42474
  }
42055
42475
  }
42056
42476
  }
@@ -42144,7 +42564,7 @@ function registerUpdate(program2) {
42144
42564
  // src/commands/begin.ts
42145
42565
  init_host_cp();
42146
42566
  init_open_url();
42147
- import pc31 from "picocolors";
42567
+ import pc32 from "picocolors";
42148
42568
  async function doBegin(opts, _startFn = startHostCp, _openFn = openUrl) {
42149
42569
  const prevExitCode = process.exitCode;
42150
42570
  await _startFn({ showToken: opts.showToken });
@@ -42154,7 +42574,7 @@ async function doBegin(opts, _startFn = startHostCp, _openFn = openUrl) {
42154
42574
  const token = readToken();
42155
42575
  if (token) {
42156
42576
  const base = `http://127.0.0.1:${HOST_CP_PORT}/`;
42157
- console.log(pc31.dim(`Opening ${base}`));
42577
+ console.log(pc32.dim(`Opening ${base}`));
42158
42578
  _openFn(`${base}?token=${token}`);
42159
42579
  }
42160
42580
  }
@@ -42302,7 +42722,7 @@ function registerConfig(program2) {
42302
42722
  // src/commands/repos.ts
42303
42723
  init_global_config();
42304
42724
  init_output();
42305
- import pc32 from "picocolors";
42725
+ import pc33 from "picocolors";
42306
42726
 
42307
42727
  // src/commands/repos-list-json.ts
42308
42728
  init_skill_sources();
@@ -42337,14 +42757,14 @@ function registerRepos(program2) {
42337
42757
  return;
42338
42758
  }
42339
42759
  if (all.length === 0) {
42340
- console.log(pc32.dim("0 repo(s) registered. Add one with: olam repos add --name <n> --path <p>"));
42760
+ console.log(pc33.dim("0 repo(s) registered. Add one with: olam repos add --name <n> --path <p>"));
42341
42761
  return;
42342
42762
  }
42343
42763
  printHeader(`${all.length} repo(s)`);
42344
42764
  for (const r of all) {
42345
42765
  const when = new Date(r.addedAt).toISOString().slice(0, 10);
42346
42766
  console.log(
42347
- ` ${pc32.bold(r.name.padEnd(24))} ${r.path.padEnd(48)} ${pc32.dim(when)}`
42767
+ ` ${pc33.bold(r.name.padEnd(24))} ${r.path.padEnd(48)} ${pc33.dim(when)}`
42348
42768
  );
42349
42769
  }
42350
42770
  });
@@ -42389,7 +42809,7 @@ function registerRepos(program2) {
42389
42809
  // src/commands/runbooks.ts
42390
42810
  init_global_config();
42391
42811
  init_output();
42392
- import pc33 from "picocolors";
42812
+ import pc34 from "picocolors";
42393
42813
  function asMessage2(err) {
42394
42814
  return err instanceof Error ? err.message : String(err);
42395
42815
  }
@@ -42408,13 +42828,13 @@ function renderRunbookList(runbooks, opts) {
42408
42828
  );
42409
42829
  }
42410
42830
  if (runbooks.length === 0) {
42411
- return pc33.dim("0 runbook(s). Add one with: olam runbooks add <name> --repos <repo>");
42831
+ return pc34.dim("0 runbook(s). Add one with: olam runbooks add <name> --repos <repo>");
42412
42832
  }
42413
- const lines = [pc33.bold(`${runbooks.length} runbook(s)`)];
42833
+ const lines = [pc34.bold(`${runbooks.length} runbook(s)`)];
42414
42834
  for (const rb of runbooks) {
42415
42835
  const when = new Date(rb.updatedAt).toISOString().slice(0, 10);
42416
42836
  const repoList = rb.repos.join(", ");
42417
- lines.push(` ${pc33.bold(rb.name.padEnd(24))} ${repoList.padEnd(40)} ${pc33.dim(when)}`);
42837
+ lines.push(` ${pc34.bold(rb.name.padEnd(24))} ${repoList.padEnd(40)} ${pc34.dim(when)}`);
42418
42838
  }
42419
42839
  return lines.join("\n");
42420
42840
  }
@@ -42463,7 +42883,7 @@ function parsePortFlags(ports) {
42463
42883
  }
42464
42884
  function formatConflict(c) {
42465
42885
  const occupantStr = c.occupant.type === "olam-world" ? `in use by world "${c.occupant.worldId}" (olam)` : `in use by PID ${c.occupant.pid ?? "unknown"} (non-olam process)`;
42466
- return ` ${pc33.red("\u2717")} ${c.repoName}.${c.serviceName}:${c.port} \u2014 ${occupantStr}`;
42886
+ return ` ${pc34.red("\u2717")} ${c.repoName}.${c.serviceName}:${c.port} \u2014 ${occupantStr}`;
42467
42887
  }
42468
42888
  function registerRunbooks(program2) {
42469
42889
  const runbooks = program2.command("runbooks").description("Manage runbooks in the global config");
@@ -42523,17 +42943,17 @@ ${conflicts.length} port conflict(s). Stop the conflicting processes or update p
42523
42943
  return;
42524
42944
  }
42525
42945
  console.log(
42526
- pc33.dim(
42946
+ pc34.dim(
42527
42947
  `olam runbooks apply: port validation passed for "${name}" (repos: ${rb.repos.join(", ")}).`
42528
42948
  )
42529
42949
  );
42530
42950
  console.log(
42531
- pc33.dim(
42951
+ pc34.dim(
42532
42952
  `Hint: use "olam create --repos ${rb.repos.join(" ")}${opts.task ? ` --task "${opts.task}"` : ""}${opts.name ? ` --name ${opts.name}` : ""}" to create the world.`
42533
42953
  )
42534
42954
  );
42535
42955
  console.log(
42536
- pc33.yellow('Phase D will wire --runbook directly. For now, use "olam create --repos ..." above.')
42956
+ pc34.yellow('Phase D will wire --runbook directly. For now, use "olam create --repos ..." above.')
42537
42957
  );
42538
42958
  } catch (err) {
42539
42959
  printError(asMessage2(err));
@@ -42551,7 +42971,7 @@ ${conflicts.length} port conflict(s). Stop the conflicting processes or update p
42551
42971
  return;
42552
42972
  }
42553
42973
  if (rows.length === 0) {
42554
- console.log(pc33.dim(`runbook "${name}" declares no ports.`));
42974
+ console.log(pc34.dim(`runbook "${name}" declares no ports.`));
42555
42975
  return;
42556
42976
  }
42557
42977
  for (const row of rows) {
@@ -42559,7 +42979,7 @@ ${conflicts.length} port conflict(s). Stop the conflicting processes or update p
42559
42979
  const conflict = conflicts.find((c) => c.port === row.port);
42560
42980
  if (conflict) console.log(formatConflict(conflict));
42561
42981
  } else {
42562
- console.log(` ${pc33.green("\u2713")} ${row.repoName}.${row.serviceName}:${row.port} \u2014 free`);
42982
+ console.log(` ${pc34.green("\u2713")} ${row.repoName}.${row.serviceName}:${row.port} \u2014 free`);
42563
42983
  }
42564
42984
  }
42565
42985
  if (conflicts.length > 0) {
@@ -42569,7 +42989,7 @@ ${conflicts.length} port conflict(s). Stop the conflicting processes or update p
42569
42989
  );
42570
42990
  process.exitCode = 1;
42571
42991
  } else {
42572
- console.log(pc33.green("\n\u2713 all ports free"));
42992
+ console.log(pc34.green("\n\u2713 all ports free"));
42573
42993
  }
42574
42994
  } catch (err) {
42575
42995
  printError(asMessage2(err));
@@ -42582,10 +43002,10 @@ ${conflicts.length} port conflict(s). Stop the conflicting processes or update p
42582
43002
  init_skill_sources();
42583
43003
  init_output();
42584
43004
  import * as readline2 from "node:readline";
42585
- import pc34 from "picocolors";
43005
+ import pc35 from "picocolors";
42586
43006
 
42587
43007
  // src/commands/flywheel/install-shims.ts
42588
- import { copyFileSync as copyFileSync9, existsSync as existsSync91, mkdirSync as mkdirSync54, readFileSync as readFileSync78, writeFileSync as writeFileSync45 } from "node:fs";
43008
+ import { copyFileSync as copyFileSync9, existsSync as existsSync91, mkdirSync as mkdirSync54, readFileSync as readFileSync78, writeFileSync as writeFileSync46 } from "node:fs";
42589
43009
  import { homedir as homedir52 } from "node:os";
42590
43010
  import { dirname as dirname50, join as join92 } from "node:path";
42591
43011
 
@@ -42685,7 +43105,7 @@ function installOne(spec, targetDir, opts) {
42685
43105
  if (!existsSync91(targetPath)) {
42686
43106
  if (opts.dryRun !== true) {
42687
43107
  mkdirSync54(dirname50(targetPath), { recursive: true });
42688
- writeFileSync45(targetPath, newContent, { mode: 493 });
43108
+ writeFileSync46(targetPath, newContent, { mode: 493 });
42689
43109
  }
42690
43110
  return { basename: spec.basename, action: "written", targetPath };
42691
43111
  }
@@ -42695,7 +43115,7 @@ function installOne(spec, targetDir, opts) {
42695
43115
  }
42696
43116
  if (isOlamGeneratedShim(existing)) {
42697
43117
  if (opts.dryRun !== true) {
42698
- writeFileSync45(targetPath, newContent, { mode: 493 });
43118
+ writeFileSync46(targetPath, newContent, { mode: 493 });
42699
43119
  }
42700
43120
  return { basename: spec.basename, action: "overwritten", targetPath };
42701
43121
  }
@@ -42703,7 +43123,7 @@ function installOne(spec, targetDir, opts) {
42703
43123
  const backupPath = `${targetPath}.shim-backup-${Math.floor(Date.now() / 1e3)}`;
42704
43124
  if (opts.dryRun !== true) {
42705
43125
  copyFileSync9(targetPath, backupPath);
42706
- writeFileSync45(targetPath, newContent, { mode: 493 });
43126
+ writeFileSync46(targetPath, newContent, { mode: 493 });
42707
43127
  }
42708
43128
  return { basename: spec.basename, action: "overwritten", targetPath, backupPath };
42709
43129
  }
@@ -42767,10 +43187,10 @@ function defaultTrustPrompt(gitUrl) {
42767
43187
  return new Promise((resolve28) => {
42768
43188
  const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
42769
43189
  process.stdout.write(
42770
- `${pc34.yellow("Trust gate:")} register "${gitUrl}" as a skill source?
43190
+ `${pc35.yellow("Trust gate:")} register "${gitUrl}" as a skill source?
42771
43191
  This grants the source permission to symlink artifacts into
42772
43192
  ~/.claude/ on every \`olam skills sync\`.
42773
- Type ${pc34.bold("y")} to add + trust, anything else to cancel: `
43193
+ Type ${pc35.bold("y")} to add + trust, anything else to cancel: `
42774
43194
  );
42775
43195
  rl.question("", (a) => {
42776
43196
  rl.close();
@@ -42786,8 +43206,8 @@ function defaultSourcePrefixPrompt(input2) {
42786
43206
  const scopeLabel = cfg.prefixScope !== void 0 && cfg.prefixScope.length > 0 ? ` (scope: ${cfg.prefixScope.join(",")})` : "";
42787
43207
  process.stdout.write(
42788
43208
  `
42789
- ${pc34.cyan("Source-config:")} ${input2.sourceName} suggests prefix ${pc34.bold(prefixLabel)}${scopeLabel}.
42790
- Adopt for this host? ${pc34.dim("[Y/n] ")}`
43209
+ ${pc35.cyan("Source-config:")} ${input2.sourceName} suggests prefix ${pc35.bold(prefixLabel)}${scopeLabel}.
43210
+ Adopt for this host? ${pc35.dim("[Y/n] ")}`
42791
43211
  );
42792
43212
  rl.question("", (a) => {
42793
43213
  rl.close();
@@ -42799,7 +43219,7 @@ function defaultPostAddPrompt(input2) {
42799
43219
  return new Promise((resolve28) => {
42800
43220
  const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
42801
43221
  process.stdout.write(`
42802
- ${pc34.bold("Sync now?")} ${pc34.dim("[Y/n] ")}`);
43222
+ ${pc35.bold("Sync now?")} ${pc35.dim("[Y/n] ")}`);
42803
43223
  rl.question("", (syncAnswer) => {
42804
43224
  const sync = !/^n(o)?$/i.test(syncAnswer.trim());
42805
43225
  if (input2.hookAlreadyInstalled) {
@@ -42808,7 +43228,7 @@ ${pc34.bold("Sync now?")} ${pc34.dim("[Y/n] ")}`);
42808
43228
  return;
42809
43229
  }
42810
43230
  process.stdout.write(
42811
- `${pc34.bold("Install SessionStart hook so future sessions auto-sync?")} ${pc34.dim("[Y/n] ")}`
43231
+ `${pc35.bold("Install SessionStart hook so future sessions auto-sync?")} ${pc35.dim("[Y/n] ")}`
42812
43232
  );
42813
43233
  rl.question("", (hookAnswer) => {
42814
43234
  rl.close();
@@ -42865,7 +43285,7 @@ function registerSkillsSource(program2) {
42865
43285
  }
42866
43286
  if (all.length === 0) {
42867
43287
  console.log(
42868
- pc34.dim("0 skill source(s) registered. Add one with: olam skills source add --name <n> --git-url <url>")
43288
+ pc35.dim("0 skill source(s) registered. Add one with: olam skills source add --name <n> --git-url <url>")
42869
43289
  );
42870
43290
  return;
42871
43291
  }
@@ -42886,19 +43306,19 @@ function registerSkillsSource(program2) {
42886
43306
  for (let i = 0; i < all.length; i += 1) {
42887
43307
  const s = all[i];
42888
43308
  const when = new Date(s.addedAt).toISOString().slice(0, 10);
42889
- const sha = s.lastPulledSha ? s.lastPulledSha.slice(0, 8) : pc34.dim("(unpulled)");
42890
- const ord = pc34.dim(`[${i + 1}]`);
42891
- const prefixCol = s.prefix ? pc34.cyan(s.prefix.padEnd(12)) : pc34.dim("\u2014".padEnd(12));
43309
+ const sha = s.lastPulledSha ? s.lastPulledSha.slice(0, 8) : pc35.dim("(unpulled)");
43310
+ const ord = pc35.dim(`[${i + 1}]`);
43311
+ const prefixCol = s.prefix ? pc35.cyan(s.prefix.padEnd(12)) : pc35.dim("\u2014".padEnd(12));
42892
43312
  const scopeDisplay = s.prefixScope !== void 0 ? s.prefixScope.join(",") : DEFAULT_SCOPE_REPR;
42893
- const scopeCol = showScopeCol ? ` ${pc34.yellow(scopeDisplay.padEnd(12))}` : "";
43313
+ const scopeCol = showScopeCol ? ` ${pc35.yellow(scopeDisplay.padEnd(12))}` : "";
42894
43314
  let originCol = "";
42895
43315
  if (showOriginCol) {
42896
43316
  const eff = resolveEffectivePrefix(s, sourceConfigs[i]);
42897
- const tag = eff.origin === "operator" ? pc34.dim("(operator)") : eff.origin === "source" ? pc34.dim("(source)") : "";
43317
+ const tag = eff.origin === "operator" ? pc35.dim("(operator)") : eff.origin === "source" ? pc35.dim("(source)") : "";
42898
43318
  originCol = ` ${tag.padEnd(10)}`;
42899
43319
  }
42900
43320
  console.log(
42901
- ` ${ord} ${pc34.bold(s.id.padEnd(14))} ${s.name.padEnd(24)} ${s.branch.padEnd(12)} ${sha.padEnd(12)} ${prefixCol}${originCol}${scopeCol} ${pc34.dim(when)} ${pc34.dim(s.gitUrl)}`
43321
+ ` ${ord} ${pc35.bold(s.id.padEnd(14))} ${s.name.padEnd(24)} ${s.branch.padEnd(12)} ${sha.padEnd(12)} ${prefixCol}${originCol}${scopeCol} ${pc35.dim(when)} ${pc35.dim(s.gitUrl)}`
42902
43322
  );
42903
43323
  }
42904
43324
  });
@@ -43280,35 +43700,35 @@ function registerSkillsSource(program2) {
43280
43700
  console.log(JSON.stringify(payload, null, 2));
43281
43701
  return;
43282
43702
  }
43283
- console.log(pc34.bold("\u25B8 registered"));
43284
- console.log(` ${pc34.bold("id:")} ${entry.id}`);
43285
- console.log(` ${pc34.bold("name:")} ${entry.name}`);
43286
- console.log(` ${pc34.bold("gitUrl:")} ${entry.gitUrl}`);
43287
- console.log(` ${pc34.bold("branch:")} ${entry.branch}`);
43288
- console.log(` ${pc34.bold("addedAt:")} ${when}`);
43289
- console.log(` ${pc34.bold("lastPulledSha:")} ${entry.lastPulledSha ?? pc34.dim("(unpulled)")}`);
43290
- console.log(` ${pc34.bold("clonePath:")} ${clonePath}`);
43703
+ console.log(pc35.bold("\u25B8 registered"));
43704
+ console.log(` ${pc35.bold("id:")} ${entry.id}`);
43705
+ console.log(` ${pc35.bold("name:")} ${entry.name}`);
43706
+ console.log(` ${pc35.bold("gitUrl:")} ${entry.gitUrl}`);
43707
+ console.log(` ${pc35.bold("branch:")} ${entry.branch}`);
43708
+ console.log(` ${pc35.bold("addedAt:")} ${when}`);
43709
+ console.log(` ${pc35.bold("lastPulledSha:")} ${entry.lastPulledSha ?? pc35.dim("(unpulled)")}`);
43710
+ console.log(` ${pc35.bold("clonePath:")} ${clonePath}`);
43291
43711
  let sourceConfig;
43292
43712
  try {
43293
43713
  sourceConfig = readSourceConfig(clonePath, entry.id);
43294
43714
  } catch {
43295
43715
  sourceConfig = void 0;
43296
43716
  }
43297
- console.log(pc34.bold("\u25B8 source-config (from clone)"));
43717
+ console.log(pc35.bold("\u25B8 source-config (from clone)"));
43298
43718
  if (sourceConfig === void 0) {
43299
- console.log(` ${pc34.dim("(no shared/source-config.yaml in clone)")}`);
43719
+ console.log(` ${pc35.dim("(no shared/source-config.yaml in clone)")}`);
43300
43720
  } else {
43301
- console.log(` ${pc34.bold("prefix:")} ${sourceConfig.prefix ?? pc34.dim("\u2014")}`);
43302
- console.log(` ${pc34.bold("prefixScope:")} ${sourceConfig.prefixScope?.join(",") ?? pc34.dim("\u2014")}`);
43721
+ console.log(` ${pc35.bold("prefix:")} ${sourceConfig.prefix ?? pc35.dim("\u2014")}`);
43722
+ console.log(` ${pc35.bold("prefixScope:")} ${sourceConfig.prefixScope?.join(",") ?? pc35.dim("\u2014")}`);
43303
43723
  }
43304
- console.log(pc34.bold("\u25B8 operator overrides"));
43305
- console.log(` ${pc34.bold("prefix:")} ${entry.prefix ?? pc34.dim("\u2014")}`);
43306
- console.log(` ${pc34.bold("prefixScope:")} ${entry.prefixScope?.join(",") ?? pc34.dim("\u2014")}`);
43307
- console.log(` ${pc34.bold("lastSeen:")} ${entry.lastSeenSourcePrefix ? JSON.stringify(entry.lastSeenSourcePrefix) : pc34.dim("\u2014")}`);
43724
+ console.log(pc35.bold("\u25B8 operator overrides"));
43725
+ console.log(` ${pc35.bold("prefix:")} ${entry.prefix ?? pc35.dim("\u2014")}`);
43726
+ console.log(` ${pc35.bold("prefixScope:")} ${entry.prefixScope?.join(",") ?? pc35.dim("\u2014")}`);
43727
+ console.log(` ${pc35.bold("lastSeen:")} ${entry.lastSeenSourcePrefix ? JSON.stringify(entry.lastSeenSourcePrefix) : pc35.dim("\u2014")}`);
43308
43728
  const eff = resolveEffectivePrefix(entry, sourceConfig);
43309
- console.log(pc34.bold(`\u25B8 effective ${pc34.dim(`(origin: ${eff.origin})`)}`));
43310
- console.log(` ${pc34.bold("prefix:")} ${eff.prefix ?? pc34.dim("\u2014")}`);
43311
- console.log(` ${pc34.bold("prefixScope:")} ${eff.prefixScope?.join(",") ?? pc34.dim("\u2014")}`);
43729
+ console.log(pc35.bold(`\u25B8 effective ${pc35.dim(`(origin: ${eff.origin})`)}`));
43730
+ console.log(` ${pc35.bold("prefix:")} ${eff.prefix ?? pc35.dim("\u2014")}`);
43731
+ console.log(` ${pc35.bold("prefixScope:")} ${eff.prefixScope?.join(",") ?? pc35.dim("\u2014")}`);
43312
43732
  });
43313
43733
  source.command("set-prefix").description(
43314
43734
  "Set the deploy prefix for a registered skill source (skills+agents deploy as <prefix>:<canonical-name>)"
@@ -43402,7 +43822,7 @@ import * as fs84 from "node:fs";
43402
43822
  import * as os47 from "node:os";
43403
43823
  import * as path85 from "node:path";
43404
43824
  import * as readline3 from "node:readline";
43405
- import pc35 from "picocolors";
43825
+ import pc36 from "picocolors";
43406
43826
 
43407
43827
  // src/lib/skills-apply-overlays.ts
43408
43828
  init_markdown_merger();
@@ -43415,9 +43835,9 @@ import {
43415
43835
  readdirSync as readdirSync27,
43416
43836
  readFileSync as readFileSync79,
43417
43837
  readlinkSync as readlinkSync4,
43418
- rmSync as rmSync9,
43838
+ rmSync as rmSync10,
43419
43839
  statSync as statSync27,
43420
- writeFileSync as writeFileSync46
43840
+ writeFileSync as writeFileSync47
43421
43841
  } from "node:fs";
43422
43842
  import { homedir as homedir53 } from "node:os";
43423
43843
  import { basename as basename8, dirname as dirname51, isAbsolute as isAbsolute4, join as join93, relative as relative5, resolve as resolve22 } from "node:path";
@@ -43493,7 +43913,7 @@ function ensureRealDir(p) {
43493
43913
  if (stat.isSymbolicLink()) {
43494
43914
  const targetRaw = readlinkSync4(p);
43495
43915
  const target = isAbsolute4(targetRaw) ? targetRaw : resolve22(dirname51(p), targetRaw);
43496
- rmSync9(p);
43916
+ rmSync10(p);
43497
43917
  mkdirSync55(p, { recursive: true });
43498
43918
  if (existsSync92(target) && statSync27(target).isDirectory()) {
43499
43919
  for (const entry of readdirSync27(target)) {
@@ -43534,7 +43954,7 @@ function mergeOne(upstreamPath, overlayPath, destPath2, label, dryRun, messages)
43534
43954
  }
43535
43955
  if (!dryRun) {
43536
43956
  mkdirSync55(dirname51(destPath2), { recursive: true });
43537
- writeFileSync46(destPath2, result.merged, "utf8");
43957
+ writeFileSync47(destPath2, result.merged, "utf8");
43538
43958
  }
43539
43959
  messages.push(`MERGED ${label} \u2192 ${destPath2}${dryRun ? " (dry-run)" : ""}`);
43540
43960
  return { ok: true };
@@ -43706,13 +44126,13 @@ function defaultSourcePrefixSyncPrompt(input2) {
43706
44126
  let line;
43707
44127
  if (input2.kind === "first-time") {
43708
44128
  line = `
43709
- ${pc35.cyan("Source-config:")} ${input2.sourceName} suggests prefix ${pc35.bold(newLabel)}.
43710
- Adopt for this host? ${pc35.dim("[Y/n] ")}`;
44129
+ ${pc36.cyan("Source-config:")} ${input2.sourceName} suggests prefix ${pc36.bold(newLabel)}.
44130
+ Adopt for this host? ${pc36.dim("[Y/n] ")}`;
43711
44131
  } else {
43712
44132
  const oldLabel = formatSourcePrefix(input2.priorConfig);
43713
44133
  line = `
43714
- ${pc35.cyan("Source-config CHANGED:")} ${input2.sourceName} changed from ${pc35.bold(oldLabel)} to ${pc35.bold(newLabel)}.
43715
- Accept change? ${pc35.dim("[Y/n] ")}`;
44134
+ ${pc36.cyan("Source-config CHANGED:")} ${input2.sourceName} changed from ${pc36.bold(oldLabel)} to ${pc36.bold(newLabel)}.
44135
+ Accept change? ${pc36.dim("[Y/n] ")}`;
43716
44136
  }
43717
44137
  process.stdout.write(line);
43718
44138
  rl.question("", (a) => {
@@ -43761,9 +44181,9 @@ async function resolveAtlasUserWithPicker(cliOverride, opts) {
43761
44181
  const OTHER_OPTION = "[Other (type a new name)]";
43762
44182
  const choices = [...members, OTHER_OPTION];
43763
44183
  process.stdout.write("\n");
43764
- process.stdout.write(pc35.bold("First sync detected \u2014 pick your member name:\n"));
44184
+ process.stdout.write(pc36.bold("First sync detected \u2014 pick your member name:\n"));
43765
44185
  choices.forEach((choice, i) => {
43766
- process.stdout.write(` ${pc35.dim(String(i + 1) + ".")} ${choice}
44186
+ process.stdout.write(` ${pc36.dim(String(i + 1) + ".")} ${choice}
43767
44187
  `);
43768
44188
  });
43769
44189
  process.stdout.write("\n");
@@ -43798,7 +44218,7 @@ async function resolveAtlasUserWithPicker(cliOverride, opts) {
43798
44218
  const claudeDirPath = opts?._testClaudeDir ?? (process.env["OLAM_CLAUDE_DIR"] ?? path85.join(os47.homedir(), ".claude"));
43799
44219
  fs84.mkdirSync(claudeDirPath, { recursive: true });
43800
44220
  fs84.writeFileSync(path85.join(claudeDirPath, ".atlas-user"), picked + "\n", "utf8");
43801
- process.stdout.write(pc35.green(`\u2713 atlas-user set to "${picked}" (written to ${path85.join(claudeDirPath, ".atlas-user")})
44221
+ process.stdout.write(pc36.green(`\u2713 atlas-user set to "${picked}" (written to ${path85.join(claudeDirPath, ".atlas-user")})
43802
44222
  `));
43803
44223
  return picked;
43804
44224
  }
@@ -43841,21 +44261,21 @@ function printSyncSummary(summary2, dryRun) {
43841
44261
  if (summary2.deploy) {
43842
44262
  console.log(` symlinks made: ${summary2.deploy.linked}`);
43843
44263
  if (summary2.deploy.shadowBackups.length > 0) {
43844
- console.log(` ${pc35.yellow("shadow backups:")} ${summary2.deploy.shadowBackups.length}`);
43845
- for (const p of summary2.deploy.shadowBackups) console.log(` ${pc35.dim(p)}`);
44264
+ console.log(` ${pc36.yellow("shadow backups:")} ${summary2.deploy.shadowBackups.length}`);
44265
+ for (const p of summary2.deploy.shadowBackups) console.log(` ${pc36.dim(p)}`);
43846
44266
  }
43847
44267
  }
43848
44268
  if (summary2.collisions.length > 0) {
43849
- console.log(` ${pc35.yellow("[conflict] name collisions:")} ${summary2.collisions.length}`);
44269
+ console.log(` ${pc36.yellow("[conflict] name collisions:")} ${summary2.collisions.length}`);
43850
44270
  for (const c of summary2.collisions) {
43851
44271
  const winnerIdShort = c.winnerSourceId.slice(0, 8);
43852
44272
  console.log(
43853
- ` ${pc35.bold(`${c.bucket}/${c.basename}`)}: ${c.loserSourceIds.length + 1} sources export \u2014 using source [${winnerIdShort}]`
44273
+ ` ${pc36.bold(`${c.bucket}/${c.basename}`)}: ${c.loserSourceIds.length + 1} sources export \u2014 using source [${winnerIdShort}]`
43854
44274
  );
43855
- console.log(` ${pc35.dim("(winner)")} ${c.winnerSourcePath}`);
44275
+ console.log(` ${pc36.dim("(winner)")} ${c.winnerSourcePath}`);
43856
44276
  for (let i = 0; i < c.loserSourcePaths.length; i += 1) {
43857
44277
  const loserIdShort = c.loserSourceIds[i].slice(0, 8);
43858
- console.log(` ${pc35.dim(`(skipped, source ${loserIdShort})`)} ${c.loserSourcePaths[i]}`);
44278
+ console.log(` ${pc36.dim(`(skipped, source ${loserIdShort})`)} ${c.loserSourcePaths[i]}`);
43859
44279
  }
43860
44280
  }
43861
44281
  }
@@ -43863,33 +44283,33 @@ function printSyncSummary(summary2, dryRun) {
43863
44283
  console.log(` hooks added: ${summary2.merge.hooksAdded}`);
43864
44284
  console.log(` permissions: ${summary2.merge.permissionsCount}`);
43865
44285
  if (summary2.merge.backupPath) {
43866
- console.log(` settings backup: ${pc35.dim(summary2.merge.backupPath)}`);
44286
+ console.log(` settings backup: ${pc36.dim(summary2.merge.backupPath)}`);
43867
44287
  }
43868
44288
  if (summary2.merge.dualWriteDeduped > 0) {
43869
- console.log(` ${pc35.dim(`dual-write deduped: ${summary2.merge.dualWriteDeduped} (atlas-shipped hook redundant with olam-meta block)`)}`);
44289
+ console.log(` ${pc36.dim(`dual-write deduped: ${summary2.merge.dualWriteDeduped} (atlas-shipped hook redundant with olam-meta block)`)}`);
43870
44290
  for (const cmd of summary2.merge.dualWriteDroppedCommands) {
43871
- console.log(` ${pc35.dim("(dropped)")} ${cmd.slice(0, 120)}${cmd.length > 120 ? "\u2026" : ""}`);
44291
+ console.log(` ${pc36.dim("(dropped)")} ${cmd.slice(0, 120)}${cmd.length > 120 ? "\u2026" : ""}`);
43872
44292
  }
43873
44293
  }
43874
44294
  }
43875
44295
  if (summary2.metaHooks) {
43876
44296
  const mh = summary2.metaHooks;
43877
- const memLabel = mh.servicesStatus.memory ? pc35.green("up") : pc35.dim("down");
43878
- console.log(` meta-hooks: mode=${mh.mode} \xB7 memory=${memLabel}${mh.servicesStatus.memoryDetail ? pc35.dim(` (${mh.servicesStatus.memoryDetail})`) : ""}`);
44297
+ const memLabel = mh.servicesStatus.memory ? pc36.green("up") : pc36.dim("down");
44298
+ console.log(` meta-hooks: mode=${mh.mode} \xB7 memory=${memLabel}${mh.servicesStatus.memoryDetail ? pc36.dim(` (${mh.servicesStatus.memoryDetail})`) : ""}`);
43879
44299
  if (mh.autoMigrated && mh.autoMigrated.strippedCount > 0) {
43880
44300
  console.log(
43881
- ` ${pc35.cyan("~ auto-migrated:")} stripped ${mh.autoMigrated.strippedCount} atlas-toolbox-shipped agentmemory hook entry(ies); replaced by olam-injected blocks`
44301
+ ` ${pc36.cyan("~ auto-migrated:")} stripped ${mh.autoMigrated.strippedCount} atlas-toolbox-shipped agentmemory hook entry(ies); replaced by olam-injected blocks`
43882
44302
  );
43883
44303
  }
43884
44304
  if (mh.blocksAdded.length > 0) {
43885
- console.log(` ${pc35.green("+ injected:")} ${mh.blocksAdded.join(", ")}`);
44305
+ console.log(` ${pc36.green("+ injected:")} ${mh.blocksAdded.join(", ")}`);
43886
44306
  }
43887
44307
  if (mh.blocksRemoved.length > 0) {
43888
- console.log(` ${pc35.yellow("- stripped:")} ${mh.blocksRemoved.join(", ")}`);
44308
+ console.log(` ${pc36.yellow("- stripped:")} ${mh.blocksRemoved.join(", ")}`);
43889
44309
  }
43890
44310
  if (mh.snapshotError) {
43891
- console.log(` ${pc35.red("! snapshot FAILED:")} ${mh.snapshotError}`);
43892
- console.log(` ${pc35.red(" (migrate-hooks-back will not be able to undo this sync)")}`);
44311
+ console.log(` ${pc36.red("! snapshot FAILED:")} ${mh.snapshotError}`);
44312
+ console.log(` ${pc36.red(" (migrate-hooks-back will not be able to undo this sync)")}`);
43893
44313
  }
43894
44314
  }
43895
44315
  if (summary2.prefixRewrites.length > 0) {
@@ -43901,14 +44321,14 @@ function printSyncSummary(summary2, dryRun) {
43901
44321
  const winnerName = allSources.find((s) => s.sourceId === col.winnerSourceId)?.name ?? col.winnerSourceId.slice(0, 8);
43902
44322
  const loserNames = col.loserSourceIds.map((id) => allSources.find((s) => s.sourceId === id)?.name ?? id.slice(0, 8)).join(", ");
43903
44323
  console.log(
43904
- ` ${pc35.yellow(`\u26A0 prefix collision: '${col.prefix}' used by ${winnerName} (winner) + ${loserNames}; first-registered wins`)}`
44324
+ ` ${pc36.yellow(`\u26A0 prefix collision: '${col.prefix}' used by ${winnerName} (winner) + ${loserNames}; first-registered wins`)}`
43905
44325
  );
43906
44326
  }
43907
44327
  }
43908
44328
  console.log();
43909
44329
  for (const s of summary2.perSource) {
43910
44330
  const sub = s.fromSubscriptionsFile ? "(subscribed)" : "(all categories)";
43911
- console.log(` ${pc35.bold(s.name.padEnd(24))} ${s.artifactCount} artifacts \xB7 ${s.categories.join(", ") || "(none)"} ${pc35.dim(sub)}`);
44331
+ console.log(` ${pc36.bold(s.name.padEnd(24))} ${s.artifactCount} artifacts \xB7 ${s.categories.join(", ") || "(none)"} ${pc36.dim(sub)}`);
43912
44332
  }
43913
44333
  }
43914
44334
  function registerSkills(program2) {
@@ -43986,7 +44406,7 @@ function registerSkills(program2) {
43986
44406
  return;
43987
44407
  }
43988
44408
  if (entries.length === 0) {
43989
- console.log(pc35.dim('0 deployed artifact(s). Run "olam skills sync" first.'));
44409
+ console.log(pc36.dim('0 deployed artifact(s). Run "olam skills sync" first.'));
43990
44410
  return;
43991
44411
  }
43992
44412
  const byBucket = /* @__PURE__ */ new Map();
@@ -43997,10 +44417,10 @@ function registerSkills(program2) {
43997
44417
  }
43998
44418
  printHeader(`${entries.length} deployed artifact(s)`);
43999
44419
  for (const [bucket, list] of byBucket.entries()) {
44000
- console.log(` ${pc35.bold(bucket)} (${list.length})`);
44420
+ console.log(` ${pc36.bold(bucket)} (${list.length})`);
44001
44421
  for (const e of list) {
44002
- const src = e.sourceId ? `[${e.sourceId}]` : pc35.yellow("[unknown]");
44003
- console.log(` ${e.name.padEnd(40)} ${pc35.dim(src)} \u2192 ${pc35.dim(e.target)}`);
44422
+ const src = e.sourceId ? `[${e.sourceId}]` : pc36.yellow("[unknown]");
44423
+ console.log(` ${e.name.padEnd(40)} ${pc36.dim(src)} \u2192 ${pc36.dim(e.target)}`);
44004
44424
  }
44005
44425
  }
44006
44426
  });
@@ -44013,10 +44433,10 @@ function registerSkills(program2) {
44013
44433
  return;
44014
44434
  }
44015
44435
  for (const e of matches2) {
44016
- console.log(`${pc35.bold("bucket:")} ${e.bucket}`);
44017
- console.log(`${pc35.bold("name:")} ${e.name}`);
44018
- console.log(`${pc35.bold("target:")} ${e.target}`);
44019
- console.log(`${pc35.bold("source:")} ${e.sourceId ?? pc35.dim("(unknown \u2014 not from a registered olam source)")}`);
44436
+ console.log(`${pc36.bold("bucket:")} ${e.bucket}`);
44437
+ console.log(`${pc36.bold("name:")} ${e.name}`);
44438
+ console.log(`${pc36.bold("target:")} ${e.target}`);
44439
+ console.log(`${pc36.bold("source:")} ${e.sourceId ?? pc36.dim("(unknown \u2014 not from a registered olam source)")}`);
44020
44440
  console.log();
44021
44441
  }
44022
44442
  });
@@ -44111,7 +44531,7 @@ function registerSkillsHook(program2) {
44111
44531
  // src/commands/skills-onboard.ts
44112
44532
  init_skill_sources();
44113
44533
  init_output();
44114
- import pc36 from "picocolors";
44534
+ import pc37 from "picocolors";
44115
44535
  function asMessage5(err) {
44116
44536
  return err instanceof Error ? err.message : String(err);
44117
44537
  }
@@ -44264,7 +44684,7 @@ function registerSkillsOnboard(program2) {
44264
44684
  }
44265
44685
  printInfo("sync", `${syncedArtifacts} artifact(s) deployed`);
44266
44686
  console.log();
44267
- console.log(pc36.dim(" Open a new Claude Code session to pick up the deployed skills."));
44687
+ console.log(pc37.dim(" Open a new Claude Code session to pick up the deployed skills."));
44268
44688
  });
44269
44689
  }
44270
44690
 
@@ -44619,7 +45039,7 @@ init_atlas_hook_strip();
44619
45039
  init_output();
44620
45040
  import * as fs88 from "node:fs";
44621
45041
  import * as path88 from "node:path";
44622
- import pc37 from "picocolors";
45042
+ import pc38 from "picocolors";
44623
45043
  var MIGRATE_HOOKS_COMMAND = "migrate-hooks";
44624
45044
  function settingsHasOlamMetaSentinel(settings) {
44625
45045
  for (const stage of ["PreToolUse", "PostToolUse"]) {
@@ -44656,12 +45076,12 @@ function printSummary(candidates2, opts) {
44656
45076
  return;
44657
45077
  }
44658
45078
  const verb = opts.dryRun ? "would strip" : "stripped";
44659
- console.log(pc37.bold(`${verb} ${candidates2.length} atlas-toolbox-shipped agentmemory hook entry(ies):`));
45079
+ console.log(pc38.bold(`${verb} ${candidates2.length} atlas-toolbox-shipped agentmemory hook entry(ies):`));
44660
45080
  for (const c of candidates2) {
44661
45081
  const matcher = c.matcher ?? "*";
44662
45082
  const cmdPreview = c.command.length > 120 ? `${c.command.slice(0, 117)}...` : c.command;
44663
- console.log(` ${pc37.dim(`[${c.stage}]`)} matcher=${pc37.cyan(matcher)} pattern=${pc37.yellow(c.matchedPattern)}`);
44664
- console.log(` ${pc37.dim(cmdPreview)}`);
45083
+ console.log(` ${pc38.dim(`[${c.stage}]`)} matcher=${pc38.cyan(matcher)} pattern=${pc38.yellow(c.matchedPattern)}`);
45084
+ console.log(` ${pc38.dim(cmdPreview)}`);
44665
45085
  }
44666
45086
  if (opts.snapshotPath) {
44667
45087
  console.log();
@@ -44784,7 +45204,7 @@ function registerSkillsMigrateHooksBack(program2) {
44784
45204
  init_skill_sources();
44785
45205
  init_output();
44786
45206
  import * as fs89 from "node:fs";
44787
- import pc38 from "picocolors";
45207
+ import pc39 from "picocolors";
44788
45208
  function asMessage10(err) {
44789
45209
  return err instanceof Error ? err.message : String(err);
44790
45210
  }
@@ -44808,7 +45228,7 @@ function printBackupRows(backups) {
44808
45228
  for (const b of backups) {
44809
45229
  const when = new Date(b.epochSeconds * 1e3).toISOString().slice(0, 10);
44810
45230
  console.log(
44811
- ` ${pc38.dim(formatAge3(b.ageMs).padStart(6))} ${formatSize(b.sizeBytes).padStart(7)} ${pc38.dim(when)} ${b.bucket}/${pc38.bold(b.basename)}`
45231
+ ` ${pc39.dim(formatAge3(b.ageMs).padStart(6))} ${formatSize(b.sizeBytes).padStart(7)} ${pc39.dim(when)} ${b.bucket}/${pc39.bold(b.basename)}`
44812
45232
  );
44813
45233
  }
44814
45234
  }
@@ -44818,11 +45238,11 @@ function registerSkillsShadowBackups(program2) {
44818
45238
  sb.command("list").description("List all shadow-backup files under ~/.claude/").action(() => {
44819
45239
  const all = listShadowBackups();
44820
45240
  if (all.length === 0) {
44821
- console.log(pc38.dim("No shadow-backup files under ~/.claude/."));
45241
+ console.log(pc39.dim("No shadow-backup files under ~/.claude/."));
44822
45242
  return;
44823
45243
  }
44824
45244
  printHeader(`${all.length} shadow backup(s)`);
44825
- console.log(pc38.dim(" age size created bucket/basename"));
45245
+ console.log(pc39.dim(" age size created bucket/basename"));
44826
45246
  printBackupRows(all);
44827
45247
  });
44828
45248
  sb.command("prune").description("Delete shadow-backup files older than a duration (e.g. 30d) OR all of them with --all --force").option("--older-than <duration>", "Delete backups older than this duration (e.g. 30d, 7d, 24h, 2w)", "30d").option("--all", "Delete every shadow-backup file (requires --force)").option("--force", "Confirm deletion when --all is used").option("--dry-run", "Show what would be deleted without deleting").action((opts) => {
@@ -44849,13 +45269,13 @@ function registerSkillsShadowBackups(program2) {
44849
45269
  const result = pruneShadowBackups(pruneOpts);
44850
45270
  const action = opts.dryRun ? "would delete" : "deleted";
44851
45271
  if (result.deleted.length === 0) {
44852
- console.log(pc38.dim(`No shadow-backups match \u2014 ${result.skipped.length} kept`));
45272
+ console.log(pc39.dim(`No shadow-backups match \u2014 ${result.skipped.length} kept`));
44853
45273
  return;
44854
45274
  }
44855
45275
  printHeader(`${action} ${result.deleted.length} shadow backup(s) (${result.skipped.length} kept)`);
44856
45276
  printBackupRows(result.deleted);
44857
45277
  if (opts.dryRun) {
44858
- console.log(pc38.dim("\n(dry-run \u2014 re-run without --dry-run to delete)"));
45278
+ console.log(pc39.dim("\n(dry-run \u2014 re-run without --dry-run to delete)"));
44859
45279
  } else {
44860
45280
  printSuccess(`pruned ${result.deleted.length} backup(s)`);
44861
45281
  }
@@ -44884,7 +45304,7 @@ function registerSkillsShadowBackups(program2) {
44884
45304
  init_skill_sources();
44885
45305
  init_output();
44886
45306
  import * as readline4 from "node:readline";
44887
- import pc39 from "picocolors";
45307
+ import pc40 from "picocolors";
44888
45308
  function asMessage11(err) {
44889
45309
  return err instanceof Error ? err.message : String(err);
44890
45310
  }
@@ -44907,16 +45327,16 @@ async function confirmRepair(check) {
44907
45327
  }
44908
45328
  function printCheck(check) {
44909
45329
  if (check.healthy) {
44910
- console.log(` ${pc39.green("\u2713")} ${pc39.bold(check.name.padEnd(22))} ${pc39.dim(check.description)}`);
45330
+ console.log(` ${pc40.green("\u2713")} ${pc40.bold(check.name.padEnd(22))} ${pc40.dim(check.description)}`);
44911
45331
  if (check.details && check.details.length > 0) {
44912
- for (const d of check.details) console.log(` ${pc39.dim(d)}`);
45332
+ for (const d of check.details) console.log(` ${pc40.dim(d)}`);
44913
45333
  }
44914
45334
  } else {
44915
- console.log(` ${pc39.red("\u2717")} ${pc39.bold(check.name.padEnd(22))} ${pc39.yellow(check.issue ?? "unhealthy")}`);
44916
- console.log(` ${pc39.dim(check.description)}`);
45335
+ console.log(` ${pc40.red("\u2717")} ${pc40.bold(check.name.padEnd(22))} ${pc40.yellow(check.issue ?? "unhealthy")}`);
45336
+ console.log(` ${pc40.dim(check.description)}`);
44917
45337
  if (check.details) {
44918
- for (const d of check.details.slice(0, 10)) console.log(` ${pc39.dim("\xB7 " + d)}`);
44919
- if (check.details.length > 10) console.log(` ${pc39.dim(`\u2026 and ${check.details.length - 10} more`)}`);
45338
+ for (const d of check.details.slice(0, 10)) console.log(` ${pc40.dim("\xB7 " + d)}`);
45339
+ if (check.details.length > 10) console.log(` ${pc40.dim(`\u2026 and ${check.details.length - 10} more`)}`);
44920
45340
  }
44921
45341
  }
44922
45342
  }
@@ -44947,7 +45367,7 @@ function registerSkillsDoctor(program2) {
44947
45367
  console.log();
44948
45368
  printWarning(`${unhealthy.length} of ${checks.length} check(s) report issues`);
44949
45369
  if (opts.checkOnly) {
44950
- console.log(pc39.dim("(--check-only \u2014 exiting without repair)"));
45370
+ console.log(pc40.dim("(--check-only \u2014 exiting without repair)"));
44951
45371
  process.exitCode = 1;
44952
45372
  return;
44953
45373
  }
@@ -44955,19 +45375,19 @@ function registerSkillsDoctor(program2) {
44955
45375
  let skipped = 0;
44956
45376
  for (const check of unhealthy) {
44957
45377
  if (!check.repair) {
44958
- console.log(pc39.dim(` (no auto-repair for ${check.name} \u2014 operator-attention required)`));
45378
+ console.log(pc40.dim(` (no auto-repair for ${check.name} \u2014 operator-attention required)`));
44959
45379
  skipped += 1;
44960
45380
  continue;
44961
45381
  }
44962
45382
  const shouldRepair = opts.autoFix ? true : await confirmRepair(check);
44963
45383
  if (!shouldRepair) {
44964
- console.log(pc39.dim(` skipped: ${check.name}`));
45384
+ console.log(pc40.dim(` skipped: ${check.name}`));
44965
45385
  skipped += 1;
44966
45386
  continue;
44967
45387
  }
44968
45388
  try {
44969
45389
  await check.repair();
44970
- console.log(pc39.green(` repaired: ${check.name}`));
45390
+ console.log(pc40.green(` repaired: ${check.name}`));
44971
45391
  repaired += 1;
44972
45392
  } catch (err) {
44973
45393
  printError(` repair failed for ${check.name}: ${asMessage11(err)}`);
@@ -45898,7 +46318,7 @@ function registerMcpAdd(cmd) {
45898
46318
 
45899
46319
  // src/commands/mcp/list.ts
45900
46320
  init_output();
45901
- import pc40 from "picocolors";
46321
+ import pc41 from "picocolors";
45902
46322
  function registerMcpList(cmd) {
45903
46323
  cmd.command("list").description("List all registered MCP credentials").action(async () => {
45904
46324
  const client = getMcpAuthClient();
@@ -45913,8 +46333,8 @@ function registerMcpList(cmd) {
45913
46333
  }
45914
46334
  const mcps = data.mcps ?? [];
45915
46335
  if (mcps.length === 0) {
45916
- console.log(pc40.dim("No MCP credentials registered."));
45917
- console.log(pc40.dim("Add one with: olam mcp add <service>"));
46336
+ console.log(pc41.dim("No MCP credentials registered."));
46337
+ console.log(pc41.dim("Add one with: olam mcp add <service>"));
45918
46338
  return;
45919
46339
  }
45920
46340
  const [c0, c1, c2, c3] = [16, 20, 10, 24];
@@ -45925,12 +46345,12 @@ function registerMcpList(cmd) {
45925
46345
  "ENV VAR".padEnd(c3),
45926
46346
  "STATUS"
45927
46347
  ].join(" ");
45928
- console.log(pc40.dim(header));
45929
- console.log(pc40.dim("\u2500".repeat(header.length)));
46348
+ console.log(pc41.dim(header));
46349
+ console.log(pc41.dim("\u2500".repeat(header.length)));
45930
46350
  for (const m of mcps) {
45931
- const status2 = !m.validated ? pc40.yellow("unvalidated") : m.expired ? pc40.red("expired") : pc40.green("active");
46351
+ const status2 = !m.validated ? pc41.yellow("unvalidated") : m.expired ? pc41.red("expired") : pc41.green("active");
45932
46352
  const row = [
45933
- pc40.cyan(m.service.padEnd(c0)),
46353
+ pc41.cyan(m.service.padEnd(c0)),
45934
46354
  m.label.padEnd(c1).slice(0, c1),
45935
46355
  m.type.padEnd(c2),
45936
46356
  (m.envName ?? "\u2014").padEnd(c3).slice(0, c3),
@@ -45958,13 +46378,13 @@ function registerMcpRemove(cmd) {
45958
46378
 
45959
46379
  // src/commands/mcp/status.ts
45960
46380
  init_output();
45961
- import pc41 from "picocolors";
46381
+ import pc42 from "picocolors";
45962
46382
  function formatExpiry(expiresAt) {
45963
46383
  if (!expiresAt) return "\u2014";
45964
46384
  const ms = expiresAt - Date.now();
45965
- if (ms <= 0) return pc41.red("expired");
46385
+ if (ms <= 0) return pc42.red("expired");
45966
46386
  const hours = ms / (1e3 * 60 * 60);
45967
- if (hours < 1) return pc41.yellow(`${Math.ceil(ms / 6e4)}m`);
46387
+ if (hours < 1) return pc42.yellow(`${Math.ceil(ms / 6e4)}m`);
45968
46388
  return `${hours.toFixed(1)}h`;
45969
46389
  }
45970
46390
  function registerMcpStatus(cmd) {
@@ -45981,14 +46401,14 @@ function registerMcpStatus(cmd) {
45981
46401
  const mcps = data.mcps ?? [];
45982
46402
  printHeader(`MCP Credentials (${mcps.length})`);
45983
46403
  if (mcps.length === 0) {
45984
- console.log(pc41.dim("No credentials registered."));
46404
+ console.log(pc42.dim("No credentials registered."));
45985
46405
  return;
45986
46406
  }
45987
46407
  for (const m of mcps) {
45988
- const stateColor = !m.validated ? pc41.yellow : m.expired ? pc41.red : pc41.green;
46408
+ const stateColor = !m.validated ? pc42.yellow : m.expired ? pc42.red : pc42.green;
45989
46409
  const stateLabel = !m.validated ? "unvalidated" : m.expired ? "expired" : "active";
45990
46410
  console.log(`
45991
- ${pc41.cyan(m.service)} ${stateColor(`[${stateLabel}]`)}`);
46411
+ ${pc42.cyan(m.service)} ${stateColor(`[${stateLabel}]`)}`);
45992
46412
  console.log(` label: ${m.label}`);
45993
46413
  console.log(` type: ${m.type}`);
45994
46414
  if (m.envName) console.log(` env var: ${m.envName}`);
@@ -46003,7 +46423,7 @@ function registerMcpStatus(cmd) {
46003
46423
  // src/commands/mcp/import.ts
46004
46424
  init_output();
46005
46425
  import * as readline6 from "node:readline";
46006
- import pc42 from "picocolors";
46426
+ import pc43 from "picocolors";
46007
46427
 
46008
46428
  // src/commands/mcp/import-discovery.ts
46009
46429
  import * as fs92 from "node:fs";
@@ -46173,13 +46593,13 @@ async function validateMcpEntry(entry) {
46173
46593
  // src/commands/mcp/import.ts
46174
46594
  async function multiSelectPicker(entries) {
46175
46595
  if (entries.length === 0) return [];
46176
- console.log("\n" + pc42.bold("Discovered MCP servers:"));
46596
+ console.log("\n" + pc43.bold("Discovered MCP servers:"));
46177
46597
  entries.forEach((e, i) => {
46178
46598
  console.log(
46179
- ` ${pc42.dim(`[${i + 1}]`)} ${pc42.cyan(e.name.padEnd(20))} ${pc42.dim(e.sourceLabel)}`
46599
+ ` ${pc43.dim(`[${i + 1}]`)} ${pc43.cyan(e.name.padEnd(20))} ${pc43.dim(e.sourceLabel)}`
46180
46600
  );
46181
46601
  });
46182
- console.log("\n" + pc42.dim('Enter numbers to import (e.g. 1,2,3 or "all" or Enter to skip):'));
46602
+ console.log("\n" + pc43.dim('Enter numbers to import (e.g. 1,2,3 or "all" or Enter to skip):'));
46183
46603
  const answer = await new Promise((resolve28) => {
46184
46604
  const rl = readline6.createInterface({ input: process.stdin, output: process.stdout });
46185
46605
  rl.question("> ", (ans) => {
@@ -46206,7 +46626,7 @@ function registerMcpImport(cmd) {
46206
46626
  const repoPaths = opts.repoPaths ? opts.repoPaths.split(",").map((s) => s.trim()) : void 0;
46207
46627
  const { entries, sources, durationMs } = await discoverMcpSources(repoPaths);
46208
46628
  if (entries.length === 0) {
46209
- console.log(pc42.dim("No MCP servers found in any source path."));
46629
+ console.log(pc43.dim("No MCP servers found in any source path."));
46210
46630
  return;
46211
46631
  }
46212
46632
  printInfo("Sources", sources.length > 0 ? sources.join(", ") : "none");
@@ -46219,15 +46639,15 @@ function registerMcpImport(cmd) {
46219
46639
  candidates2 = filtered;
46220
46640
  }
46221
46641
  if (skippedCount > 0) {
46222
- console.log(pc42.dim(`skipped: ${skippedCount} already registered`));
46642
+ console.log(pc43.dim(`skipped: ${skippedCount} already registered`));
46223
46643
  }
46224
46644
  if (candidates2.length === 0) {
46225
- console.log(pc42.dim("Nothing new to import. Use --reimport to force."));
46645
+ console.log(pc43.dim("Nothing new to import. Use --reimport to force."));
46226
46646
  return;
46227
46647
  }
46228
46648
  const selected = await multiSelectPicker(candidates2);
46229
46649
  if (selected.length === 0) {
46230
- console.log(pc42.dim("No servers selected."));
46650
+ console.log(pc43.dim("No servers selected."));
46231
46651
  return;
46232
46652
  }
46233
46653
  console.log(`
@@ -46238,16 +46658,16 @@ Importing ${selected.length} server(s)\u2026`);
46238
46658
  let validated = false;
46239
46659
  let validationReason = "skipped";
46240
46660
  if (opts.validate !== false) {
46241
- process.stdout.write(` ${pc42.dim("\u2192")} ${entry.name} validating\u2026 `);
46661
+ process.stdout.write(` ${pc43.dim("\u2192")} ${entry.name} validating\u2026 `);
46242
46662
  const vr = await validateMcpEntry(entry);
46243
46663
  validated = vr.validated;
46244
46664
  validationReason = vr.reason;
46245
46665
  process.stdout.write(
46246
- validated ? pc42.green("ok\n") : pc42.yellow(`unvalidated (${vr.reason})
46666
+ validated ? pc43.green("ok\n") : pc43.yellow(`unvalidated (${vr.reason})
46247
46667
  `)
46248
46668
  );
46249
46669
  } else {
46250
- console.log(` ${pc42.dim("\u2192")} ${entry.name} ${pc42.dim("(validation skipped)")}`);
46670
+ console.log(` ${pc43.dim("\u2192")} ${entry.name} ${pc43.dim("(validation skipped)")}`);
46251
46671
  }
46252
46672
  if (validated) validatedCount++;
46253
46673
  const result = await client.staticAdd({
@@ -46262,21 +46682,21 @@ Importing ${selected.length} server(s)\u2026`);
46262
46682
  }
46263
46683
  }
46264
46684
  console.log("");
46265
- console.log(pc42.green(`\u2713 Imported ${importedCount}/${selected.length}`));
46685
+ console.log(pc43.green(`\u2713 Imported ${importedCount}/${selected.length}`));
46266
46686
  if (validatedCount > 0) {
46267
- console.log(pc42.dim(` ${validatedCount} validated, ${importedCount - validatedCount} unvalidated`));
46687
+ console.log(pc43.dim(` ${validatedCount} validated, ${importedCount - validatedCount} unvalidated`));
46268
46688
  }
46269
46689
  });
46270
46690
  }
46271
46691
 
46272
46692
  // src/commands/mcp/revoke.ts
46273
46693
  init_output();
46274
- import pc43 from "picocolors";
46694
+ import pc44 from "picocolors";
46275
46695
  function registerMcpRevoke(cmd) {
46276
46696
  cmd.command("revoke <user> <world> <service>").description("Revoke a user's MCP service entitlement (multi-tenant mode only)").action(async (user, world, service) => {
46277
46697
  const multiTenant = (process.env["OLAM_MCP_MULTI_TENANT"] ?? "").toLowerCase() === "true";
46278
46698
  if (!multiTenant) {
46279
- console.warn(pc43.yellow("\u26A0 revocation only meaningful in multi_tenant mode \u2014 no-op"));
46699
+ console.warn(pc44.yellow("\u26A0 revocation only meaningful in multi_tenant mode \u2014 no-op"));
46280
46700
  return;
46281
46701
  }
46282
46702
  const baseUrl = process.env["OLAM_MCP_AUTH_SERVICE_URL"] ?? "http://127.0.0.1:9998";
@@ -46305,8 +46725,8 @@ function registerMcpRevoke(cmd) {
46305
46725
  process.exitCode = 1;
46306
46726
  return;
46307
46727
  }
46308
- console.log(pc43.green(`\u2713 Revoked: ${user} / ${world} / ${service}`));
46309
- console.log(pc43.dim(" Next fetch-creds call returns 403; token cleared on next merge."));
46728
+ console.log(pc44.green(`\u2713 Revoked: ${user} / ${world} / ${service}`));
46729
+ console.log(pc44.dim(" Next fetch-creds call returns 403; token cleared on next merge."));
46310
46730
  });
46311
46731
  }
46312
46732
 
@@ -46849,7 +47269,7 @@ function registerMemoryUninstall(cmd) {
46849
47269
  // src/commands/memory/mode.ts
46850
47270
  init_schema2();
46851
47271
  init_output();
46852
- import { existsSync as existsSync106, readFileSync as readFileSync88, writeFileSync as writeFileSync52 } from "node:fs";
47272
+ import { existsSync as existsSync106, readFileSync as readFileSync88, writeFileSync as writeFileSync53 } from "node:fs";
46853
47273
  import { join as join101 } from "node:path";
46854
47274
  import * as readline7 from "node:readline/promises";
46855
47275
  import { parse as parseYaml8, stringify as stringifyYaml6 } from "yaml";
@@ -46873,7 +47293,7 @@ function readConfigYaml(absPath) {
46873
47293
  }
46874
47294
  function writeConfigYaml(absPath, parsed) {
46875
47295
  const out = stringifyYaml6(parsed, { aliasDuplicateObjects: false });
46876
- writeFileSync52(absPath, out, "utf-8");
47296
+ writeFileSync53(absPath, out, "utf-8");
46877
47297
  }
46878
47298
  async function defaultPromptText(question) {
46879
47299
  const rl = readline7.createInterface({ input: process.stdin, output: process.stdout });
@@ -47351,7 +47771,7 @@ function registerMemoryStats(cmd) {
47351
47771
  }
47352
47772
 
47353
47773
  // src/commands/memory/install-hooks.ts
47354
- import { copyFileSync as copyFileSync12, existsSync as existsSync108, mkdirSync as mkdirSync61, readFileSync as readFileSync89, writeFileSync as writeFileSync53 } from "node:fs";
47774
+ import { copyFileSync as copyFileSync12, existsSync as existsSync108, mkdirSync as mkdirSync61, readFileSync as readFileSync89, writeFileSync as writeFileSync54 } from "node:fs";
47355
47775
  import { homedir as homedir58 } from "node:os";
47356
47776
  import { dirname as dirname58, join as join103, resolve as resolve26 } from "node:path";
47357
47777
  import { fileURLToPath as fileURLToPath9 } from "node:url";
@@ -47378,7 +47798,7 @@ function installOne2(basename17, sourceDir, targetDir, opts) {
47378
47798
  if (!existsSync108(targetPath)) {
47379
47799
  if (opts.dryRun !== true) {
47380
47800
  mkdirSync61(dirname58(targetPath), { recursive: true });
47381
- writeFileSync53(targetPath, newContent, { mode: 493 });
47801
+ writeFileSync54(targetPath, newContent, { mode: 493 });
47382
47802
  }
47383
47803
  return { basename: basename17, action: "written", targetPath };
47384
47804
  }
@@ -47390,7 +47810,7 @@ function installOne2(basename17, sourceDir, targetDir, opts) {
47390
47810
  const backupPath = `${targetPath}.agentmemory-hook-backup-${Math.floor(Date.now() / 1e3)}`;
47391
47811
  if (opts.dryRun !== true) {
47392
47812
  copyFileSync12(targetPath, backupPath);
47393
- writeFileSync53(targetPath, newContent, { mode: 493 });
47813
+ writeFileSync54(targetPath, newContent, { mode: 493 });
47394
47814
  }
47395
47815
  return { basename: basename17, action: "force-overwritten", targetPath, backupPath };
47396
47816
  }
@@ -47974,7 +48394,7 @@ function registerKgWatchCommand(kg) {
47974
48394
  }
47975
48395
 
47976
48396
  // src/commands/kg-classify.ts
47977
- import pc44 from "picocolors";
48397
+ import pc45 from "picocolors";
47978
48398
  init_output();
47979
48399
  function formatSavedTokens(n) {
47980
48400
  if (n >= 1e6) return `~${(n / 1e6).toFixed(1)}M`;
@@ -47989,7 +48409,7 @@ function registerKgClassifyCommand(kg) {
47989
48409
  process.stdout.write(JSON.stringify(result, null, 2) + "\n");
47990
48410
  return;
47991
48411
  }
47992
- const routeStr = result.route === "kg" ? pc44.cyan("kg") : result.route === "grep" ? pc44.magenta("grep") : pc44.yellow("both");
48412
+ const routeStr = result.route === "kg" ? pc45.cyan("kg") : result.route === "grep" ? pc45.magenta("grep") : pc45.yellow("both");
47993
48413
  printInfo("route", `${routeStr} (layer ${result.layer}, took ${result.took_ms}ms)`);
47994
48414
  printInfo("confidence", String(result.confidence));
47995
48415
  printInfo("reason", result.reason);
@@ -48019,7 +48439,7 @@ function registerKgClassifyCommand(kg) {
48019
48439
  }
48020
48440
 
48021
48441
  // src/commands/kg-doctor.ts
48022
- import pc45 from "picocolors";
48442
+ import pc46 from "picocolors";
48023
48443
  init_output();
48024
48444
  function formatUptime(seconds) {
48025
48445
  if (!Number.isFinite(seconds) || seconds < 0) return "?";
@@ -48181,12 +48601,12 @@ async function runKgDoctor(opts, deps = {}) {
48181
48601
  } else {
48182
48602
  printHeader("kg-service doctor");
48183
48603
  for (const p of probes) {
48184
- const badge = p.status === "ok" ? pc45.green("\u2713") : p.status === "warn" ? pc45.yellow("\u2298") : pc45.red("\u2717");
48604
+ const badge = p.status === "ok" ? pc46.green("\u2713") : p.status === "warn" ? pc46.yellow("\u2298") : pc46.red("\u2717");
48185
48605
  const label = `${badge} ${p.name}`;
48186
48606
  const detail = p.detail ?? "";
48187
48607
  printInfo(label, detail);
48188
48608
  if (p.remedy) {
48189
- process.stderr.write(` ${pc45.dim("remedy:")} ${p.remedy}
48609
+ process.stderr.write(` ${pc46.dim("remedy:")} ${p.remedy}
48190
48610
  `);
48191
48611
  }
48192
48612
  }
@@ -49490,7 +49910,7 @@ ${formatRedivergencePrompt(persona_a, persona_b, score, void 0, void 0, threshol
49490
49910
  }
49491
49911
 
49492
49912
  // src/commands/flywheel/ping.ts
49493
- import { mkdirSync as mkdirSync65, writeFileSync as writeFileSync57 } from "node:fs";
49913
+ import { mkdirSync as mkdirSync65, writeFileSync as writeFileSync58 } from "node:fs";
49494
49914
  import { homedir as homedir65 } from "node:os";
49495
49915
  import { dirname as dirname62, join as join109 } from "node:path";
49496
49916
  var COLD_START_BUDGET_GOOD_MS = 200;
@@ -49510,7 +49930,7 @@ function readOlamVersion() {
49510
49930
  function writeBaseline(record) {
49511
49931
  const baselinePath = join109(homedir65(), ".local", "share", "olam", "flywheel-baseline.json");
49512
49932
  mkdirSync65(dirname62(baselinePath), { recursive: true });
49513
- writeFileSync57(baselinePath, JSON.stringify(record, null, 2) + "\n", "utf8");
49933
+ writeFileSync58(baselinePath, JSON.stringify(record, null, 2) + "\n", "utf8");
49514
49934
  return baselinePath;
49515
49935
  }
49516
49936
  function registerFlywheelPing(parent) {
@@ -49555,7 +49975,7 @@ import {
49555
49975
  readFileSync as readFileSync97,
49556
49976
  readdirSync as readdirSync32,
49557
49977
  statSync as statSync32,
49558
- writeFileSync as writeFileSync58
49978
+ writeFileSync as writeFileSync59
49559
49979
  } from "node:fs";
49560
49980
  import { spawnSync as spawnSync31 } from "node:child_process";
49561
49981
  import { homedir as homedir66 } from "node:os";
@@ -50035,10 +50455,10 @@ function initMember(opts) {
50035
50455
  }
50036
50456
  try {
50037
50457
  mkdirSync66(join110(memberDir, "skills.overrides"), { recursive: true });
50038
- writeFileSync58(join110(memberDir, "skills.overrides", ".gitkeep"), "");
50458
+ writeFileSync59(join110(memberDir, "skills.overrides", ".gitkeep"), "");
50039
50459
  mkdirSync66(join110(memberDir, "agents.overrides"), { recursive: true });
50040
- writeFileSync58(join110(memberDir, "agents.overrides", ".gitkeep"), "");
50041
- writeFileSync58(
50460
+ writeFileSync59(join110(memberDir, "agents.overrides", ".gitkeep"), "");
50461
+ writeFileSync59(
50042
50462
  join110(memberDir, "README.md"),
50043
50463
  `# Member overlays for \`${memberName}\`
50044
50464
 
@@ -50110,7 +50530,7 @@ function migrateOverlays(opts = {}) {
50110
50530
  continue;
50111
50531
  }
50112
50532
  if (opts.dryRun !== true) {
50113
- writeFileSync58(filePath, newContent, "utf8");
50533
+ writeFileSync59(filePath, newContent, "utf8");
50114
50534
  }
50115
50535
  summary2.modified += 1;
50116
50536
  summary2.totalReplacements += totalReplacements;
@@ -50353,7 +50773,7 @@ function registerFlywheelSessionStart(parent) {
50353
50773
  // src/commands/flywheel/install-sessionstart-hook.ts
50354
50774
  init_merge_settings();
50355
50775
  init_output();
50356
- import { existsSync as existsSync114, copyFileSync as copyFileSync16, mkdirSync as mkdirSync67, readFileSync as readFileSync99, unlinkSync as unlinkSync25, writeFileSync as writeFileSync59 } from "node:fs";
50776
+ import { existsSync as existsSync114, copyFileSync as copyFileSync16, mkdirSync as mkdirSync67, readFileSync as readFileSync99, unlinkSync as unlinkSync25, writeFileSync as writeFileSync60 } from "node:fs";
50357
50777
  import { homedir as homedir68 } from "node:os";
50358
50778
  import { dirname as dirname64, join as join112 } from "node:path";
50359
50779
  var SESSIONSTART_HOOK_STAGE = "SessionStart";
@@ -50443,7 +50863,7 @@ function uninstallSessionStartHook(filePath) {
50443
50863
  delete next.hooks.SessionStart;
50444
50864
  }
50445
50865
  }
50446
- writeFileSync59(filePath, JSON.stringify(next, null, 2) + "\n");
50866
+ writeFileSync60(filePath, JSON.stringify(next, null, 2) + "\n");
50447
50867
  return { status: "removed", filePath };
50448
50868
  }
50449
50869
  function registerFlywheelInstallSessionStartHook(parent) {
@@ -50910,7 +51330,7 @@ import * as childProcess2 from "node:child_process";
50910
51330
  import * as fs99 from "node:fs";
50911
51331
  import * as os54 from "node:os";
50912
51332
  import * as path99 from "node:path";
50913
- import pc46 from "picocolors";
51333
+ import pc47 from "picocolors";
50914
51334
  var YOLO_BOOT_DELAY_MS = 8e3;
50915
51335
  var CAPTURE_DELAY_MS = 4e3;
50916
51336
  var TMUX_PROBE_PATHS = [
@@ -51137,13 +51557,13 @@ function registerYolo(program2) {
51137
51557
  if (opts.list) {
51138
51558
  const windows = listYoloWindows();
51139
51559
  if (windows.length === 0) {
51140
- console.log(pc46.dim("No active yolo windows found (tmux session 0)."));
51560
+ console.log(pc47.dim("No active yolo windows found (tmux session 0)."));
51141
51561
  return;
51142
51562
  }
51143
51563
  printHeader(`${windows.length} yolo window(s)`);
51144
51564
  for (const w of windows) {
51145
- const wt = w.worktreePath ? pc46.dim(w.worktreePath) : pc46.dim("(no worktree)");
51146
- console.log(` ${pc46.bold(w.name.padEnd(24))} ${wt}`);
51565
+ const wt = w.worktreePath ? pc47.dim(w.worktreePath) : pc47.dim("(no worktree)");
51566
+ console.log(` ${pc47.bold(w.name.padEnd(24))} ${wt}`);
51147
51567
  }
51148
51568
  return;
51149
51569
  }
@@ -51190,7 +51610,7 @@ function registerYolo(program2) {
51190
51610
  printInfo("Attach", result.attachHint);
51191
51611
  if (result.yoloFallbackUsed) {
51192
51612
  console.log(
51193
- pc46.dim(
51613
+ pc47.dim(
51194
51614
  " [note] yolo alias not found on PATH \u2014 used ~/.local/bin/claude --dangerously-skip-permissions"
51195
51615
  )
51196
51616
  );