@pleri/olam-cli 0.1.198 → 0.1.200

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 (70) hide show
  1. package/dist/ask/knowledge-pack.generated.d.ts.map +1 -1
  2. package/dist/ask/knowledge-pack.generated.js +3 -1
  3. package/dist/ask/knowledge-pack.generated.js.map +1 -1
  4. package/dist/commands/auth.d.ts.map +1 -1
  5. package/dist/commands/auth.js +23 -8
  6. package/dist/commands/auth.js.map +1 -1
  7. package/dist/commands/bootstrap.d.ts.map +1 -1
  8. package/dist/commands/bootstrap.js +4 -0
  9. package/dist/commands/bootstrap.js.map +1 -1
  10. package/dist/commands/create.d.ts.map +1 -1
  11. package/dist/commands/create.js +3 -0
  12. package/dist/commands/create.js.map +1 -1
  13. package/dist/commands/flywheel/diversity-check.d.ts +1 -1
  14. package/dist/commands/flywheel/diversity-check.js +1 -1
  15. package/dist/commands/flywheel/k5-score.d.ts +1 -1
  16. package/dist/commands/flywheel/k5-score.js +1 -1
  17. package/dist/commands/flywheel/k5-validate.d.ts +1 -1
  18. package/dist/commands/init.js +1 -1
  19. package/dist/commands/init.js.map +1 -1
  20. package/dist/commands/kg-mirror.d.ts +16 -0
  21. package/dist/commands/kg-mirror.d.ts.map +1 -1
  22. package/dist/commands/kg-mirror.js +94 -0
  23. package/dist/commands/kg-mirror.js.map +1 -1
  24. package/dist/commands/ps.d.ts.map +1 -1
  25. package/dist/commands/ps.js +7 -3
  26. package/dist/commands/ps.js.map +1 -1
  27. package/dist/commands/refresh.js +1 -1
  28. package/dist/commands/refresh.js.map +1 -1
  29. package/dist/commands/services.d.ts +10 -2
  30. package/dist/commands/services.d.ts.map +1 -1
  31. package/dist/commands/services.js +45 -39
  32. package/dist/commands/services.js.map +1 -1
  33. package/dist/commands/skills-100x.d.ts +34 -0
  34. package/dist/commands/skills-100x.d.ts.map +1 -0
  35. package/dist/commands/{skills-10x.js → skills-100x.js} +138 -41
  36. package/dist/commands/skills-100x.js.map +1 -0
  37. package/dist/commands/skills-install-model-router.d.ts +20 -0
  38. package/dist/commands/skills-install-model-router.d.ts.map +1 -0
  39. package/dist/commands/skills-install-model-router.js +55 -0
  40. package/dist/commands/skills-install-model-router.js.map +1 -0
  41. package/dist/commands/skills.d.ts.map +1 -1
  42. package/dist/commands/skills.js +2 -0
  43. package/dist/commands/skills.js.map +1 -1
  44. package/dist/commands/status.d.ts.map +1 -1
  45. package/dist/commands/status.js +0 -1
  46. package/dist/commands/status.js.map +1 -1
  47. package/dist/commands/workspace.d.ts.map +1 -1
  48. package/dist/commands/workspace.js +1 -2
  49. package/dist/commands/workspace.js.map +1 -1
  50. package/dist/image-digests.json +8 -8
  51. package/dist/index.js +1236 -756
  52. package/dist/index.js.map +1 -1
  53. package/dist/lib/bootstrap-kubernetes.d.ts +24 -2
  54. package/dist/lib/bootstrap-kubernetes.d.ts.map +1 -1
  55. package/dist/lib/bootstrap-kubernetes.js +100 -7
  56. package/dist/lib/bootstrap-kubernetes.js.map +1 -1
  57. package/dist/lib/help-groups.js +1 -1
  58. package/dist/lib/help-groups.js.map +1 -1
  59. package/dist/mcp-server.js +547 -346
  60. package/hermes-bundle/version.json +1 -1
  61. package/hooks/model-router.py +445 -0
  62. package/host-cp/k8s/manifests/50-deployment.yaml +1 -1
  63. package/host-cp/k8s/manifests/auth-service/50-deployment.yaml +1 -1
  64. package/host-cp/k8s/manifests/kg-service/50-deployment.yaml +1 -1
  65. package/host-cp/k8s/manifests/mcp-auth-service/50-deployment.yaml +1 -1
  66. package/host-cp/k8s/manifests/memory-service/50-deployment.yaml +1 -1
  67. package/package.json +2 -1
  68. package/dist/commands/skills-10x.d.ts +0 -23
  69. package/dist/commands/skills-10x.d.ts.map +0 -1
  70. package/dist/commands/skills-10x.js.map +0 -1
package/dist/index.js CHANGED
@@ -5568,7 +5568,7 @@ async function safeText(res) {
5568
5568
  }
5569
5569
  }
5570
5570
  function sleep(ms) {
5571
- return new Promise((resolve30) => setTimeout(resolve30, ms));
5571
+ return new Promise((resolve31) => setTimeout(resolve31, ms));
5572
5572
  }
5573
5573
  var DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, RETRY_COUNT, RETRY_BACKOFF_MS, AuthClient;
5574
5574
  var init_client = __esm({
@@ -5721,7 +5721,7 @@ function resolveAuthServicePath() {
5721
5721
  return path10.join(pkgsDir, "auth-service");
5722
5722
  }
5723
5723
  function sleep2(ms) {
5724
- return new Promise((resolve30) => setTimeout(resolve30, ms));
5724
+ return new Promise((resolve31) => setTimeout(resolve31, ms));
5725
5725
  }
5726
5726
  var DEFAULT_PORT, DEFAULT_VOLUME, DEFAULT_CONTAINER, DEFAULT_IMAGE, AuthContainerController;
5727
5727
  var init_container = __esm({
@@ -6032,7 +6032,7 @@ var init_network = __esm({
6032
6032
  // ../adapters/dist/docker/pull.js
6033
6033
  import { spawn } from "node:child_process";
6034
6034
  function spawnAsync(cmd, args, opts = {}) {
6035
- return new Promise((resolve30) => {
6035
+ return new Promise((resolve31) => {
6036
6036
  const child = spawn(cmd, [...args], {
6037
6037
  stdio: ["ignore", "pipe", "pipe"],
6038
6038
  signal: opts.signal
@@ -6046,10 +6046,10 @@ function spawnAsync(cmd, args, opts = {}) {
6046
6046
  stderr += chunk.toString();
6047
6047
  });
6048
6048
  child.on("error", (err) => {
6049
- resolve30({ exitCode: -1, stdout, stderr: stderr + err.message });
6049
+ resolve31({ exitCode: -1, stdout, stderr: stderr + err.message });
6050
6050
  });
6051
6051
  child.on("close", (code) => {
6052
- resolve30({ exitCode: code ?? -1, stdout, stderr });
6052
+ resolve31({ exitCode: code ?? -1, stdout, stderr });
6053
6053
  });
6054
6054
  });
6055
6055
  }
@@ -6614,7 +6614,7 @@ var demuxStream, execInContainer;
6614
6614
  var init_exec = __esm({
6615
6615
  "../adapters/dist/docker/exec.js"() {
6616
6616
  "use strict";
6617
- demuxStream = (stream) => new Promise((resolve30, reject) => {
6617
+ demuxStream = (stream) => new Promise((resolve31, reject) => {
6618
6618
  const stdoutChunks = [];
6619
6619
  const stderrChunks = [];
6620
6620
  const stdout = new PassThrough();
@@ -6628,7 +6628,7 @@ var init_exec = __esm({
6628
6628
  stream.pipe(stdout);
6629
6629
  }
6630
6630
  stream.on("end", () => {
6631
- resolve30({
6631
+ resolve31({
6632
6632
  stdout: Buffer.concat(stdoutChunks).toString("utf-8"),
6633
6633
  stderr: Buffer.concat(stderrChunks).toString("utf-8")
6634
6634
  });
@@ -7088,7 +7088,7 @@ var init_connection = __esm({
7088
7088
  // -----------------------------------------------------------------------
7089
7089
  async exec(host, command) {
7090
7090
  const client = await this.getConnection(host);
7091
- return new Promise((resolve30, reject) => {
7091
+ return new Promise((resolve31, reject) => {
7092
7092
  client.exec(command, (err, stream) => {
7093
7093
  if (err) {
7094
7094
  reject(new Error(`SSH exec failed on ${host}: ${err.message}`));
@@ -7103,7 +7103,7 @@ var init_connection = __esm({
7103
7103
  stderr += data.toString();
7104
7104
  });
7105
7105
  stream.on("close", (code) => {
7106
- resolve30({
7106
+ resolve31({
7107
7107
  exitCode: code ?? 0,
7108
7108
  stdout: stdout.trimEnd(),
7109
7109
  stderr: stderr.trimEnd()
@@ -7134,10 +7134,10 @@ var init_connection = __esm({
7134
7134
  throw new Error(`No SSH configuration found for host: ${host}`);
7135
7135
  }
7136
7136
  const client = new SSHClient();
7137
- return new Promise((resolve30, reject) => {
7137
+ return new Promise((resolve31, reject) => {
7138
7138
  client.on("ready", () => {
7139
7139
  this.connections.set(host, client);
7140
- resolve30(client);
7140
+ resolve31(client);
7141
7141
  }).on("error", (err) => {
7142
7142
  this.connections.delete(host);
7143
7143
  reject(new Error(`SSH connection to ${host} failed: ${err.message}`));
@@ -9539,8 +9539,8 @@ import { execFileSync as execFileSync4 } from "node:child_process";
9539
9539
  import * as fs17 from "node:fs";
9540
9540
  import * as os11 from "node:os";
9541
9541
  import * as path19 from "node:path";
9542
- function expandHome2(p, homedir76) {
9543
- return p.replace(/^~(?=$|\/|\\)/, homedir76());
9542
+ function expandHome2(p, homedir77) {
9543
+ return p.replace(/^~(?=$|\/|\\)/, homedir77());
9544
9544
  }
9545
9545
  function sanitizeRepoFilename(name) {
9546
9546
  const sanitized = name.replace(/[^A-Za-z0-9._-]/g, "_");
@@ -9563,7 +9563,7 @@ ${stderr}`;
9563
9563
  }
9564
9564
  function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
9565
9565
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync4(cmd, args, opts));
9566
- const homedir76 = deps.homedir ?? (() => os11.homedir());
9566
+ const homedir77 = deps.homedir ?? (() => os11.homedir());
9567
9567
  const baselineDir = path19.join(workspacePath, ".olam", "baseline");
9568
9568
  try {
9569
9569
  fs17.mkdirSync(baselineDir, { recursive: true });
@@ -9579,7 +9579,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
9579
9579
  continue;
9580
9580
  const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
9581
9581
  const outPath = path19.join(baselineDir, filename);
9582
- const repoPath = expandHome2(repo.path, homedir76);
9582
+ const repoPath = expandHome2(repo.path, homedir77);
9583
9583
  if (!fs17.existsSync(repoPath)) {
9584
9584
  writeBaselineFile(outPath, `# repo: ${repo.name}
9585
9585
  # (skipped: path ${repoPath} does not exist)
@@ -9699,21 +9699,21 @@ function extractStderr(err) {
9699
9699
  }
9700
9700
  function carryUncommittedEdits(repos, workspacePath, deps = {}) {
9701
9701
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync4(cmd, args, opts));
9702
- const homedir76 = deps.homedir ?? (() => os11.homedir());
9703
- const existsSync120 = deps.existsSync ?? ((p) => fs17.existsSync(p));
9702
+ const homedir77 = deps.homedir ?? (() => os11.homedir());
9703
+ const existsSync122 = deps.existsSync ?? ((p) => fs17.existsSync(p));
9704
9704
  const copyFileSync17 = deps.copyFileSync ?? ((src, dest) => fs17.copyFileSync(src, dest));
9705
- const mkdirSync72 = deps.mkdirSync ?? ((dirPath, opts) => {
9705
+ const mkdirSync73 = deps.mkdirSync ?? ((dirPath, opts) => {
9706
9706
  fs17.mkdirSync(dirPath, opts);
9707
9707
  });
9708
9708
  const plans = [];
9709
9709
  for (const repo of repos) {
9710
9710
  if (!repo.path)
9711
9711
  continue;
9712
- const repoPath = expandHome2(repo.path, homedir76);
9712
+ const repoPath = expandHome2(repo.path, homedir77);
9713
9713
  const worktreePath = path19.join(workspacePath, repo.name);
9714
- if (!existsSync120(repoPath))
9714
+ if (!existsSync122(repoPath))
9715
9715
  continue;
9716
- if (!existsSync120(worktreePath)) {
9716
+ if (!existsSync122(worktreePath)) {
9717
9717
  console.warn(`[carry] ${repo.name}: world worktree ${worktreePath} missing; skipping carry for this repo`);
9718
9718
  continue;
9719
9719
  }
@@ -9773,10 +9773,10 @@ function carryUncommittedEdits(repos, workspacePath, deps = {}) {
9773
9773
  for (const rel of plan.diff.untracked) {
9774
9774
  const src = path19.join(plan.repoPath, rel);
9775
9775
  const dest = path19.join(plan.worktreePath, rel);
9776
- if (!existsSync120(src))
9776
+ if (!existsSync122(src))
9777
9777
  continue;
9778
9778
  try {
9779
- mkdirSync72(path19.dirname(dest), { recursive: true });
9779
+ mkdirSync73(path19.dirname(dest), { recursive: true });
9780
9780
  copyFileSync17(src, dest);
9781
9781
  } catch (err) {
9782
9782
  const msg = err instanceof Error ? err.message : String(err);
@@ -11425,7 +11425,7 @@ var init_auto_dispatch_task = __esm({
11425
11425
  this.name = "TaskDispatchError";
11426
11426
  }
11427
11427
  };
11428
- DEFAULT_SLEEP = (ms) => new Promise((resolve30) => setTimeout(resolve30, ms));
11428
+ DEFAULT_SLEEP = (ms) => new Promise((resolve31) => setTimeout(resolve31, ms));
11429
11429
  }
11430
11430
  });
11431
11431
 
@@ -11660,7 +11660,7 @@ var init_schema4 = __esm({
11660
11660
  env: external_exports.record(external_exports.string().min(1), external_exports.record(external_exports.string().min(1), external_exports.string())).optional(),
11661
11661
  updatedAt: external_exports.number().int().nonnegative()
11662
11662
  });
11663
- MetaHookBlockKindSchema = external_exports.enum(["memory-recall", "memory-classify"]);
11663
+ MetaHookBlockKindSchema = external_exports.enum(["memory-recall", "memory-classify", "model-router"]);
11664
11664
  GlobalConfigSchema = external_exports.object({
11665
11665
  schemaVersion: external_exports.literal(1),
11666
11666
  repos: external_exports.array(RepoEntrySchema).optional().default([]),
@@ -15417,7 +15417,7 @@ function isCloudflaredAvailable() {
15417
15417
  }
15418
15418
  }
15419
15419
  function startTunnel(port2) {
15420
- return new Promise((resolve30, reject) => {
15420
+ return new Promise((resolve31, reject) => {
15421
15421
  const child = spawn3("cloudflared", ["tunnel", "--url", `http://localhost:${port2}`], {
15422
15422
  stdio: ["ignore", "pipe", "pipe"],
15423
15423
  detached: false
@@ -15439,7 +15439,7 @@ function startTunnel(port2) {
15439
15439
  if (match2) {
15440
15440
  resolved = true;
15441
15441
  clearTimeout(timeout);
15442
- resolve30(match2[0]);
15442
+ resolve31(match2[0]);
15443
15443
  }
15444
15444
  }
15445
15445
  child.stdout?.on("data", scan);
@@ -15526,8 +15526,8 @@ var init_dashboard = __esm({
15526
15526
  }
15527
15527
  throw err;
15528
15528
  }
15529
- await new Promise((resolve30, reject) => {
15530
- this.server.on("listening", resolve30);
15529
+ await new Promise((resolve31, reject) => {
15530
+ this.server.on("listening", resolve31);
15531
15531
  this.server.on("error", reject);
15532
15532
  });
15533
15533
  this.info = { localUrl: `http://localhost:${port2}` };
@@ -15573,8 +15573,8 @@ var init_dashboard = __esm({
15573
15573
  async stop() {
15574
15574
  stopTunnel();
15575
15575
  if (this.server) {
15576
- await new Promise((resolve30) => {
15577
- this.server.close(() => resolve30());
15576
+ await new Promise((resolve31) => {
15577
+ this.server.close(() => resolve31());
15578
15578
  });
15579
15579
  this.server = null;
15580
15580
  }
@@ -15903,8 +15903,8 @@ async function findHostCpContainer() {
15903
15903
  const docker3 = new Dockerode2(resolveDockerHostOptions());
15904
15904
  let timer = null;
15905
15905
  const listing = docker3.listContainers({ all: true }).then((cs) => cs);
15906
- const timeout = new Promise((resolve30) => {
15907
- timer = setTimeout(() => resolve30(null), DOCKER_PROBE_TIMEOUT_MS);
15906
+ const timeout = new Promise((resolve31) => {
15907
+ timer = setTimeout(() => resolve31(null), DOCKER_PROBE_TIMEOUT_MS);
15908
15908
  });
15909
15909
  let containers;
15910
15910
  try {
@@ -16688,7 +16688,7 @@ async function ensureOlamPostgresSingleton(options = {}) {
16688
16688
  };
16689
16689
  }
16690
16690
  function sleep3(ms) {
16691
- return new Promise((resolve30) => setTimeout(resolve30, ms));
16691
+ return new Promise((resolve31) => setTimeout(resolve31, ms));
16692
16692
  }
16693
16693
  var DEFAULT_POSTGRES_NETWORK, DEFAULT_POSTGRES_CONTAINER, DEFAULT_POSTGRES_HOST_PORT, DEFAULT_POSTGRES_IMAGE, DEFAULT_POSTGRES_USER, DEFAULT_POSTGRES_PASSWORD, DEFAULT_POSTGRES_DB, DEFAULT_POSTGRES_READY_TIMEOUT_MS;
16694
16694
  var init_postgres_init_helpers = __esm({
@@ -18399,17 +18399,143 @@ var init_memory_classify = __esm({
18399
18399
  }
18400
18400
  });
18401
18401
 
18402
+ // ../core/dist/meta-hooks/model-router.js
18403
+ import * as fs69 from "node:fs";
18404
+ function buildModelRouterHookEntry() {
18405
+ return {
18406
+ hooks: [
18407
+ {
18408
+ type: "command",
18409
+ command: `OLAM_META_SENTINEL=${OLAM_META_MODEL_ROUTER_SENTINEL}; ${OLAM_META_NOOP_GUARD3} python3 "${OLAM_META_MODEL_ROUTER_SCRIPT_PATH}"`,
18410
+ timeout: OLAM_META_MODEL_ROUTER_TIMEOUT_MS
18411
+ }
18412
+ ]
18413
+ };
18414
+ }
18415
+ function computeModelRouterUninstall(settings) {
18416
+ const matchers = settings.hooks?.UserPromptSubmit;
18417
+ if (!Array.isArray(matchers) || matchers.length === 0) {
18418
+ return { status: "not-found" };
18419
+ }
18420
+ let changed = false;
18421
+ const filteredMatchers = [];
18422
+ for (const matcher of matchers) {
18423
+ const innerHooks = matcher.hooks ?? [];
18424
+ const keptInner = innerHooks.filter((h) => {
18425
+ if (typeof h.command === "string" && h.command.includes(OLAM_META_MODEL_ROUTER_SENTINEL)) {
18426
+ changed = true;
18427
+ return false;
18428
+ }
18429
+ return true;
18430
+ });
18431
+ if (keptInner.length === 0 && innerHooks.length > 0) {
18432
+ changed = true;
18433
+ continue;
18434
+ }
18435
+ if (keptInner.length === innerHooks.length) {
18436
+ filteredMatchers.push(matcher);
18437
+ } else {
18438
+ filteredMatchers.push({ ...matcher, hooks: keptInner });
18439
+ }
18440
+ }
18441
+ if (!changed)
18442
+ return { status: "not-found" };
18443
+ const next = {
18444
+ ...settings,
18445
+ hooks: {
18446
+ ...settings.hooks,
18447
+ UserPromptSubmit: filteredMatchers
18448
+ }
18449
+ };
18450
+ if (filteredMatchers.length === 0) {
18451
+ const otherStages = Object.keys(next.hooks ?? {}).filter((k) => k !== "UserPromptSubmit");
18452
+ if (otherStages.length === 0) {
18453
+ delete next.hooks;
18454
+ } else {
18455
+ delete next.hooks.UserPromptSubmit;
18456
+ }
18457
+ }
18458
+ return { status: "removed", settingsAfter: next };
18459
+ }
18460
+ function matchModelRouterSentinel(commandLine) {
18461
+ return commandLine.includes(OLAM_META_MODEL_ROUTER_SENTINEL);
18462
+ }
18463
+ var OLAM_META_MODEL_ROUTER_SENTINEL, OLAM_META_MODEL_ROUTER_STAGE, OLAM_META_MODEL_ROUTER_TIMEOUT_MS, OLAM_META_MODEL_ROUTER_SCRIPT_PATH, OLAM_META_MODEL_ROUTER_SCRIPT_BASENAME, OLAM_META_NOOP_GUARD3;
18464
+ var init_model_router = __esm({
18465
+ "../core/dist/meta-hooks/model-router.js"() {
18466
+ "use strict";
18467
+ OLAM_META_MODEL_ROUTER_SENTINEL = "olam-meta-model-router-v1";
18468
+ OLAM_META_MODEL_ROUTER_STAGE = "UserPromptSubmit";
18469
+ OLAM_META_MODEL_ROUTER_TIMEOUT_MS = 5e3;
18470
+ OLAM_META_MODEL_ROUTER_SCRIPT_PATH = "$HOME/.claude/hooks/model-router.py";
18471
+ OLAM_META_MODEL_ROUTER_SCRIPT_BASENAME = "model-router.py";
18472
+ OLAM_META_NOOP_GUARD3 = "command -v olam >/dev/null 2>&1 || exit 0;";
18473
+ }
18474
+ });
18475
+
18476
+ // ../core/dist/meta-hooks/model-router-deploy.js
18477
+ import { existsSync as existsSync77, mkdirSync as mkdirSync45, readFileSync as readFileSync66, writeFileSync as writeFileSync41 } from "node:fs";
18478
+ import { homedir as homedir43 } from "node:os";
18479
+ import { dirname as dirname39, join as join75, resolve as resolve20 } from "node:path";
18480
+ import { fileURLToPath as fileURLToPath8 } from "node:url";
18481
+ function resolveModelRouterSourcePath() {
18482
+ const here3 = dirname39(fileURLToPath8(import.meta.url));
18483
+ const candidates2 = [
18484
+ // (1) in-repo tsc dist: core/dist/meta-hooks → ../../../cli/hooks
18485
+ resolve20(here3, "..", "..", "..", "cli", "hooks", MODEL_ROUTER_SCRIPT_BASENAME),
18486
+ // (1b) in-repo src (tsx / vitest): core/src/meta-hooks → ../../../cli/hooks
18487
+ resolve20(here3, "..", "..", "..", "cli", "hooks", MODEL_ROUTER_SCRIPT_BASENAME),
18488
+ // (2) bundled CLI: dist/<bundle> → ../hooks (hooks is sibling of dist)
18489
+ resolve20(here3, "..", "hooks", MODEL_ROUTER_SCRIPT_BASENAME),
18490
+ resolve20(here3, "..", "..", "hooks", MODEL_ROUTER_SCRIPT_BASENAME)
18491
+ ];
18492
+ for (const candidate of candidates2) {
18493
+ if (existsSync77(candidate))
18494
+ return candidate;
18495
+ }
18496
+ return candidates2[0];
18497
+ }
18498
+ function deployModelRouterScript(opts = {}) {
18499
+ const targetDir = opts.targetDir ?? join75(homedir43(), ".claude", "hooks");
18500
+ const targetPath = join75(targetDir, MODEL_ROUTER_SCRIPT_BASENAME);
18501
+ const sourcePath = opts.sourcePath ?? resolveModelRouterSourcePath();
18502
+ if (!existsSync77(sourcePath)) {
18503
+ return { basename: MODEL_ROUTER_SCRIPT_BASENAME, action: "source-missing", targetPath };
18504
+ }
18505
+ const newContent = readFileSync66(sourcePath, "utf8");
18506
+ if (existsSync77(targetPath)) {
18507
+ const existing = readFileSync66(targetPath, "utf8");
18508
+ if (existing === newContent) {
18509
+ return { basename: MODEL_ROUTER_SCRIPT_BASENAME, action: "unchanged", targetPath };
18510
+ }
18511
+ }
18512
+ if (opts.dryRun !== true) {
18513
+ mkdirSync45(dirname39(targetPath), { recursive: true });
18514
+ writeFileSync41(targetPath, newContent, { mode: 493 });
18515
+ }
18516
+ return { basename: MODEL_ROUTER_SCRIPT_BASENAME, action: "written", targetPath };
18517
+ }
18518
+ var MODEL_ROUTER_SCRIPT_BASENAME;
18519
+ var init_model_router_deploy = __esm({
18520
+ "../core/dist/meta-hooks/model-router-deploy.js"() {
18521
+ "use strict";
18522
+ MODEL_ROUTER_SCRIPT_BASENAME = "model-router.py";
18523
+ }
18524
+ });
18525
+
18402
18526
  // ../core/dist/meta-hooks/index.js
18403
18527
  var init_meta_hooks = __esm({
18404
18528
  "../core/dist/meta-hooks/index.js"() {
18405
18529
  "use strict";
18406
18530
  init_memory_recall();
18407
18531
  init_memory_classify();
18532
+ init_model_router();
18533
+ init_model_router_deploy();
18408
18534
  }
18409
18535
  });
18410
18536
 
18411
18537
  // ../core/dist/skill-sync/settings-merger.js
18412
- import * as fs69 from "node:fs";
18538
+ import * as fs70 from "node:fs";
18413
18539
  import * as os39 from "node:os";
18414
18540
  import * as path68 from "node:path";
18415
18541
  function claudeSettingsPath() {
@@ -18478,28 +18604,28 @@ function tagOlam(entry) {
18478
18604
  return { ...entry, [OLAM_SKILLS_MARKER]: true };
18479
18605
  }
18480
18606
  function readJson(file) {
18481
- return JSON.parse(fs69.readFileSync(file, "utf-8"));
18607
+ return JSON.parse(fs70.readFileSync(file, "utf-8"));
18482
18608
  }
18483
18609
  function rotateBackups(backupDir) {
18484
- if (!fs69.existsSync(backupDir))
18610
+ if (!fs70.existsSync(backupDir))
18485
18611
  return;
18486
- const files = fs69.readdirSync(backupDir).filter((f) => f.endsWith(".json")).map((f) => ({ name: f, full: path68.join(backupDir, f), mtime: fs69.statSync(path68.join(backupDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
18612
+ const files = fs70.readdirSync(backupDir).filter((f) => f.endsWith(".json")).map((f) => ({ name: f, full: path68.join(backupDir, f), mtime: fs70.statSync(path68.join(backupDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
18487
18613
  for (const f of files.slice(BACKUP_RETENTION)) {
18488
18614
  try {
18489
- fs69.unlinkSync(f.full);
18615
+ fs70.unlinkSync(f.full);
18490
18616
  } catch {
18491
18617
  }
18492
18618
  }
18493
18619
  }
18494
18620
  function backupSettings() {
18495
18621
  const src = claudeSettingsPath();
18496
- if (!fs69.existsSync(src))
18622
+ if (!fs70.existsSync(src))
18497
18623
  return void 0;
18498
18624
  const dir = settingsBackupDir();
18499
- fs69.mkdirSync(dir, { recursive: true });
18625
+ fs70.mkdirSync(dir, { recursive: true });
18500
18626
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
18501
18627
  const dest = path68.join(dir, `settings-${stamp}.json`);
18502
- fs69.copyFileSync(src, dest);
18628
+ fs70.copyFileSync(src, dest);
18503
18629
  rotateBackups(dir);
18504
18630
  return dest;
18505
18631
  }
@@ -18507,7 +18633,7 @@ function mergeSettings(input2) {
18507
18633
  const settingsPath = claudeSettingsPath();
18508
18634
  const backupPath = backupSettings();
18509
18635
  let base = {};
18510
- if (fs69.existsSync(settingsPath)) {
18636
+ if (fs70.existsSync(settingsPath)) {
18511
18637
  try {
18512
18638
  base = readJson(settingsPath);
18513
18639
  } catch {
@@ -18575,10 +18701,10 @@ function mergeSettings(input2) {
18575
18701
  ...input2.permissionFiles.length > 0 ? { allow: [...permSet] } : {}
18576
18702
  }
18577
18703
  };
18578
- fs69.mkdirSync(path68.dirname(settingsPath), { recursive: true });
18704
+ fs70.mkdirSync(path68.dirname(settingsPath), { recursive: true });
18579
18705
  const tmp = `${settingsPath}.tmp-${process.pid}`;
18580
- fs69.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n", { mode: 420 });
18581
- fs69.renameSync(tmp, settingsPath);
18706
+ fs70.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n", { mode: 420 });
18707
+ fs70.renameSync(tmp, settingsPath);
18582
18708
  return { backupPath, hooksAdded, permissionsCount: permSet.size, dualWriteDeduped, dualWriteDroppedCommands };
18583
18709
  }
18584
18710
  var OLAM_SKILLS_MARKER, BACKUP_RETENTION, DUAL_WRITE_DEDUP_RULES;
@@ -18635,7 +18761,7 @@ var init_schema5 = __esm({
18635
18761
 
18636
18762
  // ../core/dist/skill-sync/per-project-override.js
18637
18763
  import { execFileSync as execFileSync16 } from "node:child_process";
18638
- import * as fs70 from "node:fs";
18764
+ import * as fs71 from "node:fs";
18639
18765
  import * as path69 from "node:path";
18640
18766
  import { parse as parseYaml6 } from "yaml";
18641
18767
  function findProjectOverride(startDir) {
@@ -18643,8 +18769,8 @@ function findProjectOverride(startDir) {
18643
18769
  const root = path69.parse(dir).root;
18644
18770
  while (true) {
18645
18771
  const candidate = path69.join(dir, PROJECT_OVERRIDE_RELATIVE_PATH);
18646
- if (fs70.existsSync(candidate) && fs70.statSync(candidate).isFile()) {
18647
- const raw = fs70.readFileSync(candidate, "utf-8");
18772
+ if (fs71.existsSync(candidate) && fs71.statSync(candidate).isFile()) {
18773
+ const raw = fs71.readFileSync(candidate, "utf-8");
18648
18774
  let parsed;
18649
18775
  try {
18650
18776
  parsed = parseYaml6(raw);
@@ -18703,7 +18829,7 @@ var init_per_project_override = __esm({
18703
18829
  });
18704
18830
 
18705
18831
  // ../core/dist/lib/file-lock.js
18706
- import * as fs71 from "node:fs";
18832
+ import * as fs72 from "node:fs";
18707
18833
  import * as os40 from "node:os";
18708
18834
  import * as path70 from "node:path";
18709
18835
  function defaultIsPidAlive(pid) {
@@ -18716,11 +18842,11 @@ function defaultIsPidAlive(pid) {
18716
18842
  }
18717
18843
  }
18718
18844
  function sleep7(ms) {
18719
- return new Promise((resolve30) => setTimeout(resolve30, ms));
18845
+ return new Promise((resolve31) => setTimeout(resolve31, ms));
18720
18846
  }
18721
18847
  function readLockMeta(lockPath) {
18722
18848
  try {
18723
- const raw = fs71.readFileSync(lockPath, "utf-8");
18849
+ const raw = fs72.readFileSync(lockPath, "utf-8");
18724
18850
  const parsed = JSON.parse(raw);
18725
18851
  if (typeof parsed?.pid === "number" && typeof parsed?.hostname === "string" && typeof parsed?.timestamp === "number") {
18726
18852
  return parsed;
@@ -18739,12 +18865,12 @@ function isLockStale(meta, opts) {
18739
18865
  }
18740
18866
  function tryAcquireOnce(lockPath, meta, opts) {
18741
18867
  try {
18742
- fs71.mkdirSync(path70.dirname(lockPath), { recursive: true });
18743
- const fd = fs71.openSync(lockPath, "wx", 384);
18868
+ fs72.mkdirSync(path70.dirname(lockPath), { recursive: true });
18869
+ const fd = fs72.openSync(lockPath, "wx", 384);
18744
18870
  try {
18745
- fs71.writeSync(fd, JSON.stringify(meta));
18871
+ fs72.writeSync(fd, JSON.stringify(meta));
18746
18872
  } finally {
18747
- fs71.closeSync(fd);
18873
+ fs72.closeSync(fd);
18748
18874
  }
18749
18875
  return true;
18750
18876
  } catch (err) {
@@ -18754,14 +18880,14 @@ function tryAcquireOnce(lockPath, meta, opts) {
18754
18880
  const existing = readLockMeta(lockPath);
18755
18881
  if (existing === void 0) {
18756
18882
  try {
18757
- fs71.unlinkSync(lockPath);
18883
+ fs72.unlinkSync(lockPath);
18758
18884
  } catch {
18759
18885
  }
18760
18886
  return tryAcquireOnce(lockPath, meta, opts);
18761
18887
  }
18762
18888
  if (isLockStale(existing, opts)) {
18763
18889
  try {
18764
- fs71.unlinkSync(lockPath);
18890
+ fs72.unlinkSync(lockPath);
18765
18891
  } catch {
18766
18892
  }
18767
18893
  return tryAcquireOnce(lockPath, meta, opts);
@@ -18791,7 +18917,7 @@ async function acquireFileLock(lockDir, options = {}) {
18791
18917
  lockPath,
18792
18918
  release: () => {
18793
18919
  try {
18794
- fs71.unlinkSync(lockPath);
18920
+ fs72.unlinkSync(lockPath);
18795
18921
  } catch {
18796
18922
  }
18797
18923
  }
@@ -18831,13 +18957,13 @@ var init_file_lock = __esm({
18831
18957
  });
18832
18958
 
18833
18959
  // ../core/dist/lib/min-version-filter.js
18834
- import { existsSync as existsSync78, readFileSync as readFileSync68 } from "node:fs";
18960
+ import { existsSync as existsSync80, readFileSync as readFileSync70 } from "node:fs";
18835
18961
  function readOlamMinVersion(filepath) {
18836
- if (!existsSync78(filepath))
18962
+ if (!existsSync80(filepath))
18837
18963
  return void 0;
18838
18964
  let text;
18839
18965
  try {
18840
- text = readFileSync68(filepath, "utf8");
18966
+ text = readFileSync70(filepath, "utf8");
18841
18967
  } catch {
18842
18968
  return void 0;
18843
18969
  }
@@ -18895,11 +19021,11 @@ var init_min_version_filter = __esm({
18895
19021
  });
18896
19022
 
18897
19023
  // ../core/dist/skill-sync/overlay-scan.js
18898
- import * as fs72 from "node:fs";
19024
+ import * as fs73 from "node:fs";
18899
19025
  import * as path71 from "node:path";
18900
19026
  function scanOverlayReferences(overlayRoot, basenames, caps = DEFAULT_CAPS) {
18901
19027
  const result = /* @__PURE__ */ new Map();
18902
- if (!fs72.existsSync(overlayRoot)) {
19028
+ if (!fs73.existsSync(overlayRoot)) {
18903
19029
  return result;
18904
19030
  }
18905
19031
  if (basenames.length === 0) {
@@ -18908,13 +19034,13 @@ function scanOverlayReferences(overlayRoot, basenames, caps = DEFAULT_CAPS) {
18908
19034
  const mdFiles = [];
18909
19035
  let overlayRootReal;
18910
19036
  try {
18911
- overlayRootReal = fs72.realpathSync(overlayRoot);
19037
+ overlayRootReal = fs73.realpathSync(overlayRoot);
18912
19038
  } catch {
18913
19039
  return result;
18914
19040
  }
18915
19041
  for (const subdir of OVERRIDE_SUBDIRS) {
18916
19042
  const dir = path71.join(overlayRoot, subdir);
18917
- if (!fs72.existsSync(dir))
19043
+ if (!fs73.existsSync(dir))
18918
19044
  continue;
18919
19045
  walkMarkdown(dir, mdFiles, caps.maxFiles);
18920
19046
  }
@@ -18922,7 +19048,7 @@ function scanOverlayReferences(overlayRoot, basenames, caps = DEFAULT_CAPS) {
18922
19048
  for (const filepath of mdFiles) {
18923
19049
  let realFile;
18924
19050
  try {
18925
- realFile = fs72.realpathSync(filepath);
19051
+ realFile = fs73.realpathSync(filepath);
18926
19052
  } catch (err) {
18927
19053
  const code = err.code;
18928
19054
  if (code === "ENOENT" || code === "EACCES")
@@ -18935,12 +19061,12 @@ function scanOverlayReferences(overlayRoot, basenames, caps = DEFAULT_CAPS) {
18935
19061
  }
18936
19062
  let content;
18937
19063
  try {
18938
- const stat = fs72.statSync(filepath);
19064
+ const stat = fs73.statSync(filepath);
18939
19065
  totalBytes += stat.size;
18940
19066
  if (totalBytes > caps.maxTotalBytes) {
18941
19067
  throw new Error(`[overlay-scan] aborted: overlay tree exceeds ${caps.maxTotalBytes} total bytes. Check OLAM_CLAUDE_DIR / overlay paths are correctly scoped.`);
18942
19068
  }
18943
- content = fs72.readFileSync(filepath, "utf8");
19069
+ content = fs73.readFileSync(filepath, "utf8");
18944
19070
  } catch (err) {
18945
19071
  const code = err.code;
18946
19072
  if (code === "ENOENT" || code === "EACCES") {
@@ -18962,7 +19088,7 @@ function scanOverlayReferences(overlayRoot, basenames, caps = DEFAULT_CAPS) {
18962
19088
  function walkMarkdown(dir, out, cap) {
18963
19089
  let entries;
18964
19090
  try {
18965
- entries = fs72.readdirSync(dir, { withFileTypes: true });
19091
+ entries = fs73.readdirSync(dir, { withFileTypes: true });
18966
19092
  } catch (err) {
18967
19093
  if (err.code === "ENOENT")
18968
19094
  return;
@@ -18997,7 +19123,7 @@ var init_overlay_scan = __esm({
18997
19123
  });
18998
19124
 
18999
19125
  // ../core/dist/skill-sync/settings-json-lock.js
19000
- import * as fs73 from "node:fs";
19126
+ import * as fs74 from "node:fs";
19001
19127
  import * as os41 from "node:os";
19002
19128
  import * as path72 from "node:path";
19003
19129
  function defaultSettingsJsonLockPath() {
@@ -19014,11 +19140,11 @@ function defaultIsPidAlive2(pid) {
19014
19140
  }
19015
19141
  }
19016
19142
  function sleep8(ms) {
19017
- return new Promise((resolve30) => setTimeout(resolve30, ms));
19143
+ return new Promise((resolve31) => setTimeout(resolve31, ms));
19018
19144
  }
19019
19145
  function readLockMeta2(lockPath) {
19020
19146
  try {
19021
- const raw = fs73.readFileSync(lockPath, "utf-8");
19147
+ const raw = fs74.readFileSync(lockPath, "utf-8");
19022
19148
  const parsed = JSON.parse(raw);
19023
19149
  if (typeof parsed?.pid === "number" && typeof parsed?.hostname === "string" && typeof parsed?.timestamp === "number") {
19024
19150
  return parsed;
@@ -19041,12 +19167,12 @@ function isLockStale2(meta, opts) {
19041
19167
  function tryAcquireOnce2(lockPath, meta, opts) {
19042
19168
  for (let attempt = 0; attempt <= MAX_STEAL_ATTEMPTS; attempt += 1) {
19043
19169
  try {
19044
- fs73.mkdirSync(path72.dirname(lockPath), { recursive: true });
19045
- const fd = fs73.openSync(lockPath, "wx", 384);
19170
+ fs74.mkdirSync(path72.dirname(lockPath), { recursive: true });
19171
+ const fd = fs74.openSync(lockPath, "wx", 384);
19046
19172
  try {
19047
- fs73.writeSync(fd, JSON.stringify(meta));
19173
+ fs74.writeSync(fd, JSON.stringify(meta));
19048
19174
  } finally {
19049
- fs73.closeSync(fd);
19175
+ fs74.closeSync(fd);
19050
19176
  }
19051
19177
  return true;
19052
19178
  } catch (err) {
@@ -19064,9 +19190,9 @@ function tryAcquireOnce2(lockPath, meta, opts) {
19064
19190
  }
19065
19191
  const victimPath = `${lockPath}.victim-${process.pid}-${attempt}-${Date.now()}`;
19066
19192
  try {
19067
- fs73.renameSync(lockPath, victimPath);
19193
+ fs74.renameSync(lockPath, victimPath);
19068
19194
  try {
19069
- fs73.unlinkSync(victimPath);
19195
+ fs74.unlinkSync(victimPath);
19070
19196
  } catch {
19071
19197
  }
19072
19198
  } catch (err) {
@@ -19098,7 +19224,7 @@ async function acquireSettingsJsonLock(options = {}) {
19098
19224
  lockPath,
19099
19225
  release: () => {
19100
19226
  try {
19101
- fs73.unlinkSync(lockPath);
19227
+ fs74.unlinkSync(lockPath);
19102
19228
  } catch {
19103
19229
  }
19104
19230
  }
@@ -19201,7 +19327,7 @@ var init_services_status = __esm({
19201
19327
 
19202
19328
  // ../core/dist/skill-sources/meta-hooks-migration-snapshot.js
19203
19329
  import * as crypto10 from "node:crypto";
19204
- import * as fs74 from "node:fs";
19330
+ import * as fs75 from "node:fs";
19205
19331
  import * as os42 from "node:os";
19206
19332
  import * as path73 from "node:path";
19207
19333
  function migrationSnapshotsDir2() {
@@ -19219,41 +19345,41 @@ function writeMetaHooksSnapshot(originalSettings) {
19219
19345
  };
19220
19346
  const validated = MetaHooksMigrationSnapshotSchema.parse(snapshot);
19221
19347
  const dir = migrationSnapshotsDir2();
19222
- fs74.mkdirSync(dir, { recursive: true });
19348
+ fs75.mkdirSync(dir, { recursive: true });
19223
19349
  const stamp = validated.takenAt.replace(/[:.]/g, "-");
19224
19350
  const rand = crypto10.randomBytes(3).toString("hex");
19225
19351
  const file = path73.join(dir, `${META_HOOKS_SNAPSHOT_PREFIX}${stamp}-${process.pid}-${rand}.json`);
19226
- fs74.writeFileSync(file, JSON.stringify(validated, null, 2) + "\n", { mode: 384 });
19352
+ fs75.writeFileSync(file, JSON.stringify(validated, null, 2) + "\n", { mode: 384 });
19227
19353
  return file;
19228
19354
  }
19229
19355
  function readMetaHooksSnapshot(filePath) {
19230
- if (!fs74.existsSync(filePath)) {
19356
+ if (!fs75.existsSync(filePath)) {
19231
19357
  throw new Error(`snapshot file not found: ${filePath}`);
19232
19358
  }
19233
- const raw = fs74.readFileSync(filePath, "utf-8");
19359
+ const raw = fs75.readFileSync(filePath, "utf-8");
19234
19360
  const parsed = JSON.parse(raw);
19235
19361
  return MetaHooksMigrationSnapshotSchema.parse(parsed);
19236
19362
  }
19237
19363
  function findLatestMetaHooksSnapshot() {
19238
19364
  const dir = migrationSnapshotsDir2();
19239
- if (!fs74.existsSync(dir))
19365
+ if (!fs75.existsSync(dir))
19240
19366
  return void 0;
19241
- const candidates2 = fs74.readdirSync(dir).filter((n) => n.startsWith(META_HOOKS_SNAPSHOT_PREFIX) && n.endsWith(".json")).sort().reverse();
19367
+ const candidates2 = fs75.readdirSync(dir).filter((n) => n.startsWith(META_HOOKS_SNAPSHOT_PREFIX) && n.endsWith(".json")).sort().reverse();
19242
19368
  if (candidates2.length === 0)
19243
19369
  return void 0;
19244
19370
  return path73.join(dir, candidates2[0]);
19245
19371
  }
19246
19372
  function restoreSettingsFromSnapshot(snapshot, settingsPath) {
19247
19373
  if (snapshot.originalSettings === null) {
19248
- if (fs74.existsSync(settingsPath)) {
19249
- fs74.unlinkSync(settingsPath);
19374
+ if (fs75.existsSync(settingsPath)) {
19375
+ fs75.unlinkSync(settingsPath);
19250
19376
  }
19251
19377
  return;
19252
19378
  }
19253
- fs74.mkdirSync(path73.dirname(settingsPath), { recursive: true });
19379
+ fs75.mkdirSync(path73.dirname(settingsPath), { recursive: true });
19254
19380
  const tmp = `${settingsPath}.tmp-restore-${process.pid}-${Date.now()}`;
19255
- fs74.writeFileSync(tmp, JSON.stringify(snapshot.originalSettings, null, 2) + "\n");
19256
- fs74.renameSync(tmp, settingsPath);
19381
+ fs75.writeFileSync(tmp, JSON.stringify(snapshot.originalSettings, null, 2) + "\n");
19382
+ fs75.renameSync(tmp, settingsPath);
19257
19383
  }
19258
19384
  var META_HOOKS_SNAPSHOT_SCHEMA_VERSION, META_HOOKS_SNAPSHOT_PREFIX, SettingsLooseSchema, MetaHooksMigrationSnapshotSchema;
19259
19385
  var init_meta_hooks_migration_snapshot = __esm({
@@ -19393,6 +19519,8 @@ function decideTargetBlocks(opts) {
19393
19519
  target.add("memory-recall");
19394
19520
  if (wantMemory && !disabled.has("memory-classify"))
19395
19521
  target.add("memory-classify");
19522
+ if (!disabled.has("model-router"))
19523
+ target.add("model-router");
19396
19524
  return target;
19397
19525
  }
19398
19526
  function injectMetaHooks(opts) {
@@ -19400,6 +19528,7 @@ function injectMetaHooks(opts) {
19400
19528
  let working = JSON.parse(JSON.stringify(opts.currentSettings ?? {}));
19401
19529
  const blocksAdded = [];
19402
19530
  const blocksRemoved = [];
19531
+ const blocksSkippedForeign = [];
19403
19532
  const memoryRecallPresent = hasMemoryRecallBlock(working);
19404
19533
  if (target.has("memory-recall")) {
19405
19534
  if (!memoryRecallPresent) {
@@ -19430,10 +19559,30 @@ function injectMetaHooks(opts) {
19430
19559
  }
19431
19560
  }
19432
19561
  }
19562
+ const modelRouterPresent = hasModelRouterBlock(working);
19563
+ if (target.has("model-router")) {
19564
+ if (!modelRouterPresent) {
19565
+ if (hasForeignModelRouterEntry(working)) {
19566
+ blocksSkippedForeign.push("model-router");
19567
+ } else {
19568
+ working = appendBlock(working, OLAM_META_MODEL_ROUTER_STAGE, buildModelRouterHookEntry());
19569
+ blocksAdded.push("model-router");
19570
+ }
19571
+ }
19572
+ } else {
19573
+ if (modelRouterPresent) {
19574
+ const r = computeModelRouterUninstall(working);
19575
+ if (r.status === "removed" && r.settingsAfter) {
19576
+ working = r.settingsAfter;
19577
+ blocksRemoved.push("model-router");
19578
+ }
19579
+ }
19580
+ }
19433
19581
  return {
19434
19582
  nextSettings: working,
19435
19583
  blocksAdded,
19436
19584
  blocksRemoved,
19585
+ blocksSkippedForeign,
19437
19586
  mode: opts.mode ?? "auto"
19438
19587
  };
19439
19588
  }
@@ -19467,6 +19616,40 @@ function hasMemoryClassifyBlock(settings) {
19467
19616
  }
19468
19617
  return false;
19469
19618
  }
19619
+ function hasModelRouterBlock(settings) {
19620
+ const entries = settings.hooks?.UserPromptSubmit;
19621
+ if (!Array.isArray(entries))
19622
+ return false;
19623
+ for (const matcher of entries) {
19624
+ const inner = matcher?.hooks ?? [];
19625
+ if (!Array.isArray(inner))
19626
+ continue;
19627
+ for (const h of inner) {
19628
+ if (typeof h?.command === "string" && matchModelRouterSentinel(h.command))
19629
+ return true;
19630
+ }
19631
+ }
19632
+ return false;
19633
+ }
19634
+ function hasForeignModelRouterEntry(settings) {
19635
+ const entries = settings.hooks?.UserPromptSubmit;
19636
+ if (!Array.isArray(entries))
19637
+ return false;
19638
+ for (const matcher of entries) {
19639
+ const inner = matcher?.hooks ?? [];
19640
+ if (!Array.isArray(inner))
19641
+ continue;
19642
+ for (const h of inner) {
19643
+ if (typeof h?.command !== "string")
19644
+ continue;
19645
+ if (matchModelRouterSentinel(h.command))
19646
+ continue;
19647
+ if (h.command.includes(OLAM_META_MODEL_ROUTER_SCRIPT_BASENAME))
19648
+ return true;
19649
+ }
19650
+ }
19651
+ return false;
19652
+ }
19470
19653
  function appendBlock(settings, stage, entry) {
19471
19654
  const next = { ...settings };
19472
19655
  const hooks = { ...settings.hooks ?? {} };
@@ -19485,7 +19668,7 @@ var init_meta_hook_injector = __esm({
19485
19668
 
19486
19669
  // ../core/dist/lib/markdown-merger.js
19487
19670
  import { createHash as createHash9 } from "node:crypto";
19488
- import { readFileSync as readFileSync72, existsSync as existsSync81, statSync as statSync23 } from "node:fs";
19671
+ import { readFileSync as readFileSync74, existsSync as existsSync83, statSync as statSync23 } from "node:fs";
19489
19672
  function parseFrontmatter3(text) {
19490
19673
  const match2 = FM_RE2.exec(text);
19491
19674
  if (match2 === null)
@@ -19614,9 +19797,9 @@ function mergeMarkdown(upstreamText, overlayText, labelForError, upstreamPath, o
19614
19797
  return { merged: fmBlock !== "" ? fmBlock + mergedBody : mergedBody };
19615
19798
  }
19616
19799
  function sha256OfPath(p) {
19617
- if (!existsSync81(p) || !statSync23(p).isFile())
19800
+ if (!existsSync83(p) || !statSync23(p).isFile())
19618
19801
  return "MISSING";
19619
- return createHash9("sha256").update(readFileSync72(p)).digest("hex");
19802
+ return createHash9("sha256").update(readFileSync74(p)).digest("hex");
19620
19803
  }
19621
19804
  var FM_RE2, H2_RE;
19622
19805
  var init_markdown_merger = __esm({
@@ -19628,7 +19811,7 @@ var init_markdown_merger = __esm({
19628
19811
  });
19629
19812
 
19630
19813
  // ../core/dist/skill-sync/managed-merge.js
19631
- import * as fs75 from "node:fs";
19814
+ import * as fs76 from "node:fs";
19632
19815
  import * as path74 from "node:path";
19633
19816
  function materializeMergedSkill(opts) {
19634
19817
  const { sourceId, sourcePath, deployBasename, mergedContent, claudeDir: claudeDir2 } = opts;
@@ -19638,12 +19821,12 @@ function materializeMergedSkill(opts) {
19638
19821
  if (!(managedResolved === sourceRoot || managedResolved.startsWith(sourceRoot + path74.sep))) {
19639
19822
  throw new Error(`[managed-merge] refusing to materialize: deployBasename "${deployBasename}" escapes managed root "${sourceRoot}" (resolved to "${managedResolved}")`);
19640
19823
  }
19641
- fs75.mkdirSync(managedDir, { recursive: true });
19824
+ fs76.mkdirSync(managedDir, { recursive: true });
19642
19825
  const skillMdPath = path74.join(managedDir, "SKILL.md");
19643
19826
  const tmpPath = `${skillMdPath}.tmp-${process.pid}-${Date.now()}`;
19644
- fs75.writeFileSync(tmpPath, mergedContent);
19645
- fs75.renameSync(tmpPath, skillMdPath);
19646
- const baseEntries = fs75.readdirSync(sourcePath);
19827
+ fs76.writeFileSync(tmpPath, mergedContent);
19828
+ fs76.renameSync(tmpPath, skillMdPath);
19829
+ const baseEntries = fs76.readdirSync(sourcePath);
19647
19830
  for (const entry of baseEntries) {
19648
19831
  if (entry === "SKILL.md")
19649
19832
  continue;
@@ -19651,13 +19834,13 @@ function materializeMergedSkill(opts) {
19651
19834
  const targetAbsolute = path74.join(sourcePath, entry);
19652
19835
  const targetRelative = path74.relative(managedDir, targetAbsolute);
19653
19836
  try {
19654
- fs75.lstatSync(linkPath);
19655
- fs75.rmSync(linkPath, { recursive: true, force: true });
19837
+ fs76.lstatSync(linkPath);
19838
+ fs76.rmSync(linkPath, { recursive: true, force: true });
19656
19839
  } catch {
19657
19840
  }
19658
- fs75.symlinkSync(targetRelative, linkPath);
19841
+ fs76.symlinkSync(targetRelative, linkPath);
19659
19842
  }
19660
- const managedEntries = fs75.readdirSync(managedDir);
19843
+ const managedEntries = fs76.readdirSync(managedDir);
19661
19844
  const baseEntrySet = new Set(baseEntries);
19662
19845
  for (const entry of managedEntries) {
19663
19846
  if (entry === "SKILL.md")
@@ -19665,7 +19848,7 @@ function materializeMergedSkill(opts) {
19665
19848
  if (!baseEntrySet.has(entry)) {
19666
19849
  const stalePath = path74.join(managedDir, entry);
19667
19850
  try {
19668
- fs75.rmSync(stalePath, { recursive: true, force: true });
19851
+ fs76.rmSync(stalePath, { recursive: true, force: true });
19669
19852
  } catch {
19670
19853
  }
19671
19854
  }
@@ -19673,7 +19856,7 @@ function materializeMergedSkill(opts) {
19673
19856
  return managedDir;
19674
19857
  }
19675
19858
  function cleanMergedDir(claudeDir2) {
19676
- fs75.rmSync(path74.join(claudeDir2, ".olam-merged"), { recursive: true, force: true });
19859
+ fs76.rmSync(path74.join(claudeDir2, ".olam-merged"), { recursive: true, force: true });
19677
19860
  }
19678
19861
  var init_managed_merge = __esm({
19679
19862
  "../core/dist/skill-sync/managed-merge.js"() {
@@ -19812,7 +19995,7 @@ var init_prefix_rules = __esm({
19812
19995
  });
19813
19996
 
19814
19997
  // ../core/dist/skill-sync/prefix-deploy.js
19815
- import * as fs76 from "node:fs";
19998
+ import * as fs77 from "node:fs";
19816
19999
  import * as path75 from "node:path";
19817
20000
  function buildSourcePrefixMap(sources) {
19818
20001
  const byId = /* @__PURE__ */ new Map();
@@ -19868,7 +20051,7 @@ function applyPrefixRewrites(baseArtifacts, sourceMap, claudeDir2, dryRun) {
19868
20051
  }
19869
20052
  if (artifact.kind === "skill") {
19870
20053
  const skillMdPath = path75.join(artifact.sourcePath, "SKILL.md");
19871
- const content = fs76.readFileSync(skillMdPath);
20054
+ const content = fs77.readFileSync(skillMdPath);
19872
20055
  const rewritten = rewriteFrontmatterName(content, () => renamedFrontmatterName);
19873
20056
  const managedDir = materializeMergedSkill({
19874
20057
  sourceId: artifact.sourceId,
@@ -19880,7 +20063,7 @@ function applyPrefixRewrites(baseArtifacts, sourceMap, claudeDir2, dryRun) {
19880
20063
  artifact.sourcePath = managedDir;
19881
20064
  artifact.deployBasename = renamed;
19882
20065
  } else {
19883
- const content = artifact.resolvedContent !== void 0 ? artifact.resolvedContent : fs76.readFileSync(artifact.sourcePath);
20066
+ const content = artifact.resolvedContent !== void 0 ? artifact.resolvedContent : fs77.readFileSync(artifact.sourcePath);
19884
20067
  const rewritten = rewriteFrontmatterName(content, () => renamedFrontmatterName);
19885
20068
  artifact.resolvedContent = rewritten;
19886
20069
  artifact.deployBasename = renamed;
@@ -19925,19 +20108,19 @@ var init_prefix_deploy = __esm({
19925
20108
  });
19926
20109
 
19927
20110
  // ../core/dist/skill-sync/resolve-source-config.js
19928
- import { readFileSync as readFileSync74, existsSync as existsSync82 } from "node:fs";
19929
- import { join as join83 } from "node:path";
20111
+ import { readFileSync as readFileSync76, existsSync as existsSync84 } from "node:fs";
20112
+ import { join as join84 } from "node:path";
19930
20113
  import { parse as parseYaml7 } from "yaml";
19931
20114
  function sourceConfigPath(clonePath) {
19932
- return join83(clonePath, "shared", "source-config.yaml");
20115
+ return join84(clonePath, "shared", "source-config.yaml");
19933
20116
  }
19934
20117
  function readSourceConfig(clonePath, sourceId) {
19935
20118
  const path106 = sourceConfigPath(clonePath);
19936
- if (!existsSync82(path106))
20119
+ if (!existsSync84(path106))
19937
20120
  return void 0;
19938
20121
  let raw;
19939
20122
  try {
19940
- raw = readFileSync74(path106, "utf-8");
20123
+ raw = readFileSync76(path106, "utf-8");
19941
20124
  } catch (err) {
19942
20125
  emitMalformedWarning(sourceId, `read failed: ${errToMsg(err)}`);
19943
20126
  return void 0;
@@ -20032,7 +20215,7 @@ var init_resolve_source_config = __esm({
20032
20215
  });
20033
20216
 
20034
20217
  // ../core/dist/skill-sync/engine.js
20035
- import * as fs77 from "node:fs";
20218
+ import * as fs78 from "node:fs";
20036
20219
  import * as os43 from "node:os";
20037
20220
  import * as path76 from "node:path";
20038
20221
  function resolveAtlasUser(override) {
@@ -20040,8 +20223,8 @@ function resolveAtlasUser(override) {
20040
20223
  return override;
20041
20224
  const claudeDir2 = process.env["OLAM_CLAUDE_DIR"] || path76.join(os43.homedir(), ".claude");
20042
20225
  const f = path76.join(claudeDir2, ".atlas-user");
20043
- if (fs77.existsSync(f)) {
20044
- return fs77.readFileSync(f, "utf-8").trim() || void 0;
20226
+ if (fs78.existsSync(f)) {
20227
+ return fs78.readFileSync(f, "utf-8").trim() || void 0;
20045
20228
  }
20046
20229
  return void 0;
20047
20230
  }
@@ -20053,7 +20236,7 @@ async function syncSkills(opts = {}) {
20053
20236
  const perSource = [];
20054
20237
  for (const source of sources) {
20055
20238
  const clonePath = skillSourceClonePath(source.id);
20056
- if (!fs77.existsSync(clonePath))
20239
+ if (!fs78.existsSync(clonePath))
20057
20240
  continue;
20058
20241
  const { artifacts, subscription } = await withFileLock(clonePath, () => {
20059
20242
  const pinRef = projectOverride?.override.pin?.[source.id];
@@ -20093,7 +20276,7 @@ async function syncSkills(opts = {}) {
20093
20276
  const overlayArtifacts = memberOverlaysEnabled ? projectFilteredArtifacts.filter((a) => a.kind === "overlay") : [];
20094
20277
  const effectiveSources = sources.map((s) => {
20095
20278
  const clonePath = skillSourceClonePath(s.id);
20096
- const sourceConfig = fs77.existsSync(clonePath) ? readSourceConfig(clonePath, s.id) : void 0;
20279
+ const sourceConfig = fs78.existsSync(clonePath) ? readSourceConfig(clonePath, s.id) : void 0;
20097
20280
  const eff = resolveEffectivePrefix(s, sourceConfig);
20098
20281
  const entry = {
20099
20282
  id: s.id,
@@ -20200,12 +20383,12 @@ async function syncSkills(opts = {}) {
20200
20383
  let basePath;
20201
20384
  if (overlay.targetKind === "skill") {
20202
20385
  basePath = path76.join(base.sourcePath, "SKILL.md");
20203
- baseContent = fs77.readFileSync(basePath, "utf-8");
20386
+ baseContent = fs78.readFileSync(basePath, "utf-8");
20204
20387
  } else {
20205
20388
  basePath = base.sourcePath;
20206
- baseContent = fs77.readFileSync(basePath, "utf-8");
20389
+ baseContent = fs78.readFileSync(basePath, "utf-8");
20207
20390
  }
20208
- const overlayContent = fs77.readFileSync(overlay.sourcePath, "utf-8");
20391
+ const overlayContent = fs78.readFileSync(overlay.sourcePath, "utf-8");
20209
20392
  const label = `${overlay.sourceId}/${overlay.deployBasename}`;
20210
20393
  const mergeResult = mergeMarkdown(baseContent, overlayContent, label, basePath, overlay.sourcePath);
20211
20394
  if ("error" in mergeResult) {
@@ -20287,24 +20470,34 @@ async function injectMetaHooksIntoSettings(opts) {
20287
20470
  ...memoryProbe.detail !== void 0 ? { memoryDetail: memoryProbe.detail } : {}
20288
20471
  };
20289
20472
  const settingsFile = claudeSettingsPath();
20473
+ let configDisabled = [];
20474
+ try {
20475
+ const cfg = readGlobalConfig();
20476
+ configDisabled = cfg.metaHooksDisabled ?? [];
20477
+ } catch {
20478
+ }
20479
+ const disabledBlocks = Array.from(/* @__PURE__ */ new Set([
20480
+ ...configDisabled,
20481
+ ...opts.metaHooksDisabled ?? []
20482
+ ]));
20290
20483
  let snapshotError;
20291
20484
  let stripCandidates = [];
20292
20485
  const result = await withSettingsJsonLock(() => {
20293
20486
  let currentSettings = {};
20294
20487
  let settingsExisted = false;
20295
- if (fs77.existsSync(settingsFile)) {
20488
+ if (fs78.existsSync(settingsFile)) {
20296
20489
  settingsExisted = true;
20297
20490
  try {
20298
- const raw = fs77.readFileSync(settingsFile, "utf-8");
20491
+ const raw = fs78.readFileSync(settingsFile, "utf-8");
20299
20492
  currentSettings = raw.trim() ? JSON.parse(raw) : {};
20300
20493
  } catch {
20301
20494
  try {
20302
- const raw = fs77.readFileSync(settingsFile);
20495
+ const raw = fs78.readFileSync(settingsFile);
20303
20496
  const bakDir = path76.join(path76.dirname(settingsFile), ".malformed-backups");
20304
- fs77.mkdirSync(bakDir, { recursive: true });
20497
+ fs78.mkdirSync(bakDir, { recursive: true });
20305
20498
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
20306
20499
  const bakFile = path76.join(bakDir, `settings.json.malformed.${stamp}.bak`);
20307
- fs77.writeFileSync(bakFile, raw, { mode: 384 });
20500
+ fs78.writeFileSync(bakFile, raw, { mode: 384 });
20308
20501
  snapshotError = `settings.json was malformed; original bytes preserved at ${bakFile}`;
20309
20502
  } catch (bakErr) {
20310
20503
  snapshotError = `settings.json malformed AND .bak write failed: ${bakErr instanceof Error ? bakErr.message : String(bakErr)}`;
@@ -20315,16 +20508,6 @@ async function injectMetaHooksIntoSettings(opts) {
20315
20508
  }
20316
20509
  stripCandidates = findStripCandidates(currentSettings);
20317
20510
  const settingsForInject = stripCandidates.length > 0 ? applyStrip(currentSettings, stripCandidates).nextSettings : currentSettings;
20318
- let configDisabled = [];
20319
- try {
20320
- const cfg = readGlobalConfig();
20321
- configDisabled = cfg.metaHooksDisabled ?? [];
20322
- } catch {
20323
- }
20324
- const disabledBlocks = Array.from(/* @__PURE__ */ new Set([
20325
- ...configDisabled,
20326
- ...opts.metaHooksDisabled ?? []
20327
- ]));
20328
20511
  const inject = injectMetaHooks({
20329
20512
  servicesStatus: servicesStatus2,
20330
20513
  currentSettings: settingsForInject,
@@ -20354,17 +20537,34 @@ async function injectMetaHooksIntoSettings(opts) {
20354
20537
  } catch {
20355
20538
  }
20356
20539
  }
20357
- fs77.mkdirSync(path76.dirname(settingsFile), { recursive: true });
20540
+ fs78.mkdirSync(path76.dirname(settingsFile), { recursive: true });
20358
20541
  const tmpPath = `${settingsFile}.tmp-${process.pid}-${Date.now()}`;
20359
- fs77.writeFileSync(tmpPath, JSON.stringify(inject.nextSettings, null, 2) + "\n");
20360
- fs77.renameSync(tmpPath, settingsFile);
20542
+ fs78.writeFileSync(tmpPath, JSON.stringify(inject.nextSettings, null, 2) + "\n");
20543
+ fs78.renameSync(tmpPath, settingsFile);
20361
20544
  return inject;
20362
20545
  }, { reason: `syncSkills meta-hook injection (mode=${mode})` });
20546
+ let scriptDeploy;
20547
+ const modelRouterTargeted = mode !== "never" && !disabledBlocks.includes("model-router");
20548
+ if (modelRouterTargeted) {
20549
+ try {
20550
+ scriptDeploy = deployModelRouterScript({
20551
+ targetDir: path76.join(claudeDir(), "hooks")
20552
+ });
20553
+ } catch (err) {
20554
+ scriptDeploy = {
20555
+ basename: "model-router.py",
20556
+ action: "source-missing",
20557
+ targetPath: `${err instanceof Error ? err.message : String(err)}`
20558
+ };
20559
+ }
20560
+ }
20363
20561
  return {
20364
20562
  mode: result.mode,
20365
20563
  servicesStatus: servicesStatus2,
20366
20564
  blocksAdded: result.blocksAdded,
20367
20565
  blocksRemoved: result.blocksRemoved,
20566
+ ...result.blocksSkippedForeign.length > 0 ? { blocksSkippedForeign: result.blocksSkippedForeign } : {},
20567
+ ...scriptDeploy !== void 0 ? { scriptDeploy } : {},
20368
20568
  ...snapshotError !== void 0 ? { snapshotError } : {},
20369
20569
  ...stripCandidates.length > 0 ? { autoMigrated: { strippedCount: stripCandidates.length, stripCandidates } } : {}
20370
20570
  };
@@ -20389,6 +20589,7 @@ var init_engine = __esm({
20389
20589
  init_trust_audit_log();
20390
20590
  init_atlas_hook_strip();
20391
20591
  init_meta_hook_injector();
20592
+ init_model_router_deploy();
20392
20593
  init_markdown_merger();
20393
20594
  init_managed_merge();
20394
20595
  init_prefix_deploy();
@@ -20398,7 +20599,7 @@ var init_engine = __esm({
20398
20599
  });
20399
20600
 
20400
20601
  // ../core/dist/skill-sync/shadow-backup-manager.js
20401
- import * as fs78 from "node:fs";
20602
+ import * as fs79 from "node:fs";
20402
20603
  import * as path77 from "node:path";
20403
20604
  function listShadowBackups(opts = {}) {
20404
20605
  const claude = opts.claudeDirOverride ?? claudeDir();
@@ -20406,11 +20607,11 @@ function listShadowBackups(opts = {}) {
20406
20607
  const out = [];
20407
20608
  for (const bucket of SHADOW_BACKUP_BUCKETS) {
20408
20609
  const bucketDir = path77.join(claude, bucket);
20409
- if (!fs78.existsSync(bucketDir))
20610
+ if (!fs79.existsSync(bucketDir))
20410
20611
  continue;
20411
20612
  let entries;
20412
20613
  try {
20413
- entries = fs78.readdirSync(bucketDir);
20614
+ entries = fs79.readdirSync(bucketDir);
20414
20615
  } catch {
20415
20616
  continue;
20416
20617
  }
@@ -20424,7 +20625,7 @@ function listShadowBackups(opts = {}) {
20424
20625
  const full = path77.join(bucketDir, name);
20425
20626
  let sizeBytes = 0;
20426
20627
  try {
20427
- const st = fs78.statSync(full);
20628
+ const st = fs79.statSync(full);
20428
20629
  if (st.isDirectory())
20429
20630
  continue;
20430
20631
  sizeBytes = st.size;
@@ -20480,7 +20681,7 @@ function pruneShadowBackups(opts) {
20480
20681
  }
20481
20682
  if (!opts.dryRun) {
20482
20683
  try {
20483
- fs78.unlinkSync(b.path);
20684
+ fs79.unlinkSync(b.path);
20484
20685
  } catch {
20485
20686
  skipped.push(b);
20486
20687
  continue;
@@ -20492,7 +20693,7 @@ function pruneShadowBackups(opts) {
20492
20693
  }
20493
20694
  function restoreShadowBackup(opts) {
20494
20695
  const abs = path77.resolve(opts.backupPath);
20495
- if (!fs78.existsSync(abs)) {
20696
+ if (!fs79.existsSync(abs)) {
20496
20697
  throw new Error(`backup file not found: ${abs}`);
20497
20698
  }
20498
20699
  const basename17 = path77.basename(abs);
@@ -20502,13 +20703,13 @@ function restoreShadowBackup(opts) {
20502
20703
  }
20503
20704
  const originalBasename = basename17.slice(0, basename17.length - match2[0].length);
20504
20705
  const originalPath = path77.join(path77.dirname(abs), originalBasename);
20505
- if (fs78.existsSync(originalPath) && !opts.force) {
20706
+ if (fs79.existsSync(originalPath) && !opts.force) {
20506
20707
  throw new Error(`original path already occupied: ${originalPath}. Move/rename it first OR re-run with --force.`);
20507
20708
  }
20508
- if (opts.force && fs78.existsSync(originalPath)) {
20509
- fs78.unlinkSync(originalPath);
20709
+ if (opts.force && fs79.existsSync(originalPath)) {
20710
+ fs79.unlinkSync(originalPath);
20510
20711
  }
20511
- fs78.renameSync(abs, originalPath);
20712
+ fs79.renameSync(abs, originalPath);
20512
20713
  return { restoredTo: originalPath };
20513
20714
  }
20514
20715
  var SHADOW_BACKUP_BUCKETS, SHADOW_BACKUP_SUFFIX_RE;
@@ -20522,7 +20723,7 @@ var init_shadow_backup_manager = __esm({
20522
20723
  });
20523
20724
 
20524
20725
  // ../core/dist/global-config/repos.js
20525
- import * as fs79 from "node:fs";
20726
+ import * as fs80 from "node:fs";
20526
20727
  import * as os44 from "node:os";
20527
20728
  import * as path78 from "node:path";
20528
20729
  function expandPath(p) {
@@ -20540,7 +20741,7 @@ function addRepo(entry) {
20540
20741
  throw new Error(`repo "${entry.name}" already registered. Use "olam repos update" to change its path.`);
20541
20742
  }
20542
20743
  const resolvedPath = expandPath(entry.path);
20543
- if (!fs79.existsSync(resolvedPath)) {
20744
+ if (!fs80.existsSync(resolvedPath)) {
20544
20745
  throw new Error(`path "${entry.path}" does not exist. Verify the path is correct.`);
20545
20746
  }
20546
20747
  const now = Date.now();
@@ -20569,7 +20770,7 @@ function updateRepo(name, updates) {
20569
20770
  throw new Error(`repo "${name}" is not registered. Run "olam repos list" to see registered repos.`);
20570
20771
  }
20571
20772
  const resolvedUpdatePath = updates.path !== void 0 ? expandPath(updates.path) : void 0;
20572
- if (resolvedUpdatePath !== void 0 && !fs79.existsSync(resolvedUpdatePath)) {
20773
+ if (resolvedUpdatePath !== void 0 && !fs80.existsSync(resolvedUpdatePath)) {
20573
20774
  throw new Error(`path "${updates.path}" does not exist. Verify the path is correct.`);
20574
20775
  }
20575
20776
  const existing = config.repos[idx];
@@ -20638,7 +20839,7 @@ var init_global_config = __esm({
20638
20839
  });
20639
20840
 
20640
20841
  // ../core/dist/skill-sources/doctor-checks.js
20641
- import * as fs80 from "node:fs";
20842
+ import * as fs81 from "node:fs";
20642
20843
  import * as path79 from "node:path";
20643
20844
  import * as os45 from "node:os";
20644
20845
  function claudeDirInternal3() {
@@ -20654,11 +20855,11 @@ function checkStateFileParse() {
20654
20855
  healthy: true,
20655
20856
  description: `~/.olam state file (${filePath})`
20656
20857
  };
20657
- if (!fs80.existsSync(filePath)) {
20858
+ if (!fs81.existsSync(filePath)) {
20658
20859
  result.details = ["(file does not yet exist \u2014 will be created on first write)"];
20659
20860
  return result;
20660
20861
  }
20661
- const raw = fs80.readFileSync(filePath, "utf-8");
20862
+ const raw = fs81.readFileSync(filePath, "utf-8");
20662
20863
  let parsed;
20663
20864
  try {
20664
20865
  parsed = JSON.parse(raw);
@@ -20668,8 +20869,8 @@ function checkStateFileParse() {
20668
20869
  result.details = [err instanceof Error ? err.message : String(err)];
20669
20870
  result.repair = () => {
20670
20871
  const aside = `${filePath}.corrupt-${Math.floor(Date.now() / 1e3)}`;
20671
- fs80.renameSync(filePath, aside);
20672
- fs80.writeFileSync(filePath, JSON.stringify({ schemaVersion: 1, repos: [], runbooks: [], skillSources: [] }, null, 2));
20872
+ fs81.renameSync(filePath, aside);
20873
+ fs81.writeFileSync(filePath, JSON.stringify({ schemaVersion: 1, repos: [], runbooks: [], skillSources: [] }, null, 2));
20673
20874
  };
20674
20875
  return result;
20675
20876
  }
@@ -20680,7 +20881,7 @@ function checkStateFileParse() {
20680
20881
  result.details = validation.error.issues.map((e) => `${e.path.join(".")}: ${e.message}`);
20681
20882
  result.repair = () => {
20682
20883
  const aside = `${filePath}.corrupt-${Math.floor(Date.now() / 1e3)}`;
20683
- fs80.copyFileSync(filePath, aside);
20884
+ fs81.copyFileSync(filePath, aside);
20684
20885
  const base = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
20685
20886
  const next = {
20686
20887
  ...base,
@@ -20689,7 +20890,7 @@ function checkStateFileParse() {
20689
20890
  runbooks: [],
20690
20891
  skillSources: []
20691
20892
  };
20692
- fs80.writeFileSync(filePath, JSON.stringify(next, null, 2));
20893
+ fs81.writeFileSync(filePath, JSON.stringify(next, null, 2));
20693
20894
  };
20694
20895
  return result;
20695
20896
  }
@@ -20701,15 +20902,15 @@ function checkDanglingSymlinks() {
20701
20902
  const dangling = [];
20702
20903
  for (const bucket of buckets) {
20703
20904
  const dir = path79.join(claude, bucket);
20704
- if (!fs80.existsSync(dir))
20905
+ if (!fs81.existsSync(dir))
20705
20906
  continue;
20706
- for (const name of fs80.readdirSync(dir)) {
20907
+ for (const name of fs81.readdirSync(dir)) {
20707
20908
  const linkPath = path79.join(dir, name);
20708
20909
  try {
20709
- const lst = fs80.lstatSync(linkPath);
20910
+ const lst = fs81.lstatSync(linkPath);
20710
20911
  if (!lst.isSymbolicLink())
20711
20912
  continue;
20712
- if (!fs80.existsSync(linkPath)) {
20913
+ if (!fs81.existsSync(linkPath)) {
20713
20914
  dangling.push(linkPath);
20714
20915
  }
20715
20916
  } catch {
@@ -20727,7 +20928,7 @@ function checkDanglingSymlinks() {
20727
20928
  result.repair = () => {
20728
20929
  for (const p of dangling) {
20729
20930
  try {
20730
- fs80.unlinkSync(p);
20931
+ fs81.unlinkSync(p);
20731
20932
  } catch {
20732
20933
  }
20733
20934
  }
@@ -20742,19 +20943,19 @@ function checkOrphanedSnapshots() {
20742
20943
  healthy: true,
20743
20944
  description: `orphaned migration snapshots under ${dir}`
20744
20945
  };
20745
- if (!fs80.existsSync(dir)) {
20946
+ if (!fs81.existsSync(dir)) {
20746
20947
  return result;
20747
20948
  }
20748
20949
  const orphans = [];
20749
- for (const name of fs80.readdirSync(dir)) {
20950
+ for (const name of fs81.readdirSync(dir)) {
20750
20951
  if (!name.endsWith(".json"))
20751
20952
  continue;
20752
20953
  const full = path79.join(dir, name);
20753
20954
  try {
20754
- const stat = fs80.statSync(full);
20955
+ const stat = fs81.statSync(full);
20755
20956
  if (!stat.isFile())
20756
20957
  continue;
20757
- const raw = fs80.readFileSync(full, "utf-8");
20958
+ const raw = fs81.readFileSync(full, "utf-8");
20758
20959
  let parsed;
20759
20960
  try {
20760
20961
  parsed = JSON.parse(raw);
@@ -20779,7 +20980,7 @@ function checkOrphanedSnapshots() {
20779
20980
  result.repair = () => {
20780
20981
  for (const o of orphans) {
20781
20982
  try {
20782
- fs80.unlinkSync(o.path);
20983
+ fs81.unlinkSync(o.path);
20783
20984
  } catch {
20784
20985
  }
20785
20986
  }
@@ -20794,12 +20995,12 @@ function checkSentinelDrift() {
20794
20995
  healthy: true,
20795
20996
  description: `olam-skills sentinel block in ${filePath}`
20796
20997
  };
20797
- if (!fs80.existsSync(filePath)) {
20998
+ if (!fs81.existsSync(filePath)) {
20798
20999
  return result;
20799
21000
  }
20800
21001
  let parsed;
20801
21002
  try {
20802
- parsed = JSON.parse(fs80.readFileSync(filePath, "utf-8"));
21003
+ parsed = JSON.parse(fs81.readFileSync(filePath, "utf-8"));
20803
21004
  } catch {
20804
21005
  return result;
20805
21006
  }
@@ -20840,7 +21041,7 @@ function checkSentinelDrift() {
20840
21041
  backupSettings();
20841
21042
  } catch {
20842
21043
  }
20843
- const next = JSON.parse(fs80.readFileSync(filePath, "utf-8"));
21044
+ const next = JSON.parse(fs81.readFileSync(filePath, "utf-8"));
20844
21045
  if (!next.hooks)
20845
21046
  return;
20846
21047
  for (const stage of Object.keys(next.hooks)) {
@@ -20863,7 +21064,7 @@ function checkSentinelDrift() {
20863
21064
  return bad === void 0;
20864
21065
  });
20865
21066
  }
20866
- fs80.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
21067
+ fs81.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
20867
21068
  };
20868
21069
  }
20869
21070
  return result;
@@ -20888,7 +21089,7 @@ function checkMemberNameMissing() {
20888
21089
  }
20889
21090
  const claudeDir2 = claudeDirInternal3();
20890
21091
  const atlasUserPath = path79.join(claudeDir2, ".atlas-user");
20891
- const value = fs80.existsSync(atlasUserPath) ? fs80.readFileSync(atlasUserPath, "utf-8").trim() : "";
21092
+ const value = fs81.existsSync(atlasUserPath) ? fs81.readFileSync(atlasUserPath, "utf-8").trim() : "";
20892
21093
  if (value.length > 0) {
20893
21094
  result.details = [`atlas-user: ${value}`];
20894
21095
  return result;
@@ -20897,9 +21098,9 @@ function checkMemberNameMissing() {
20897
21098
  result.issue = "atlas-toolbox source registered but ~/.claude/.atlas-user not set";
20898
21099
  const clonePath = skillSourceClonePath(atlasSource.id);
20899
21100
  const membersDir = path79.join(clonePath, "members");
20900
- const existing = fs80.existsSync(membersDir) ? fs80.readdirSync(membersDir).filter((e) => {
21101
+ const existing = fs81.existsSync(membersDir) ? fs81.readdirSync(membersDir).filter((e) => {
20901
21102
  try {
20902
- return fs80.statSync(path79.join(membersDir, e)).isDirectory();
21103
+ return fs81.statSync(path79.join(membersDir, e)).isDirectory();
20903
21104
  } catch {
20904
21105
  return false;
20905
21106
  }
@@ -20914,7 +21115,7 @@ function checkMemberNameMissing() {
20914
21115
  function checkMemberOverlayDrift() {
20915
21116
  const claudeDir2 = claudeDirInternal3();
20916
21117
  const atlasUserPath = path79.join(claudeDir2, ".atlas-user");
20917
- const atlasUser = fs80.existsSync(atlasUserPath) ? fs80.readFileSync(atlasUserPath, "utf-8").trim() : "";
21118
+ const atlasUser = fs81.existsSync(atlasUserPath) ? fs81.readFileSync(atlasUserPath, "utf-8").trim() : "";
20918
21119
  if (atlasUser.length === 0) {
20919
21120
  return [];
20920
21121
  }
@@ -20931,11 +21132,11 @@ function checkMemberOverlayDrift() {
20931
21132
  const results = [];
20932
21133
  for (const kind of ["skills", "agents"]) {
20933
21134
  const localRoot = path79.join(claudeDir2, `${kind}.overrides`);
20934
- if (!fs80.existsSync(localRoot))
21135
+ if (!fs81.existsSync(localRoot))
20935
21136
  continue;
20936
21137
  let entries;
20937
21138
  try {
20938
- entries = fs80.readdirSync(localRoot);
21139
+ entries = fs81.readdirSync(localRoot);
20939
21140
  } catch {
20940
21141
  continue;
20941
21142
  }
@@ -20943,7 +21144,7 @@ function checkMemberOverlayDrift() {
20943
21144
  const localFile = path79.join(localRoot, entry);
20944
21145
  let stat;
20945
21146
  try {
20946
- stat = fs80.statSync(localFile);
21147
+ stat = fs81.statSync(localFile);
20947
21148
  } catch {
20948
21149
  continue;
20949
21150
  }
@@ -21119,7 +21320,7 @@ __export(project_sweep_exports, {
21119
21320
  walkProjectRoot: () => walkProjectRoot
21120
21321
  });
21121
21322
  import * as path80 from "node:path";
21122
- import { readdirSync as readdirSync26, lstatSync as lstatSync6, statSync as statSync26, existsSync as existsSync87 } from "node:fs";
21323
+ import { readdirSync as readdirSync26, lstatSync as lstatSync6, statSync as statSync26, existsSync as existsSync89 } from "node:fs";
21123
21324
  function isSkipped(basename17, extra) {
21124
21325
  if (DEFAULT_SKIP.has(basename17))
21125
21326
  return true;
@@ -21198,7 +21399,7 @@ function makeRealFsAdapter() {
21198
21399
  const s = statSync26(p, { throwIfNoEntry: true });
21199
21400
  return { isDirectory: () => s.isDirectory(), mtimeMs: s.mtimeMs };
21200
21401
  },
21201
- existsSync: (p) => existsSync87(p)
21402
+ existsSync: (p) => existsSync89(p)
21202
21403
  };
21203
21404
  }
21204
21405
  function walkProjectRoot(rootPath, opts = {}) {
@@ -21224,7 +21425,7 @@ __export(kg_eager_exports, {
21224
21425
  runEagerKgBuild: () => runEagerKgBuild,
21225
21426
  writeQueue: () => writeQueue
21226
21427
  });
21227
- import * as fs81 from "node:fs";
21428
+ import * as fs82 from "node:fs";
21228
21429
  import * as path81 from "node:path";
21229
21430
  import * as os46 from "node:os";
21230
21431
  function defaultQueuePath() {
@@ -21232,9 +21433,9 @@ function defaultQueuePath() {
21232
21433
  return path81.join(stateDir, "kg-pending.jsonl");
21233
21434
  }
21234
21435
  function readQueue(queuePath) {
21235
- if (!fs81.existsSync(queuePath))
21436
+ if (!fs82.existsSync(queuePath))
21236
21437
  return [];
21237
- const raw = fs81.readFileSync(queuePath, "utf-8");
21438
+ const raw = fs82.readFileSync(queuePath, "utf-8");
21238
21439
  const entries = [];
21239
21440
  for (const line of raw.split("\n")) {
21240
21441
  const trimmed = line.trim();
@@ -21248,16 +21449,16 @@ function readQueue(queuePath) {
21248
21449
  return entries;
21249
21450
  }
21250
21451
  function writeQueue(queuePath, entries) {
21251
- fs81.mkdirSync(path81.dirname(queuePath), { recursive: true });
21452
+ fs82.mkdirSync(path81.dirname(queuePath), { recursive: true });
21252
21453
  const content = entries.map((e) => JSON.stringify(e)).join("\n") + (entries.length > 0 ? "\n" : "");
21253
- fs81.writeFileSync(queuePath, content, "utf-8");
21454
+ fs82.writeFileSync(queuePath, content, "utf-8");
21254
21455
  }
21255
21456
  function appendQueue(queuePath, repos, nowMs) {
21256
21457
  if (repos.length === 0)
21257
21458
  return;
21258
- fs81.mkdirSync(path81.dirname(queuePath), { recursive: true });
21459
+ fs82.mkdirSync(path81.dirname(queuePath), { recursive: true });
21259
21460
  const lines = repos.map((r) => JSON.stringify({ path: r.path, addedAt: nowMs })).join("\n") + "\n";
21260
- fs81.appendFileSync(queuePath, lines, "utf-8");
21461
+ fs82.appendFileSync(queuePath, lines, "utf-8");
21261
21462
  }
21262
21463
  async function defaultBuildOne(_repo) {
21263
21464
  return { ok: true, ms: 0 };
@@ -21397,27 +21598,27 @@ var init_install_shared = __esm({
21397
21598
  });
21398
21599
 
21399
21600
  // src/commands/memory/_paths.ts
21400
- import { homedir as homedir52 } from "node:os";
21401
- import { join as join92, dirname as dirname49 } from "node:path";
21402
- import { fileURLToPath as fileURLToPath8 } from "node:url";
21601
+ import { homedir as homedir53 } from "node:os";
21602
+ import { join as join93, dirname as dirname50 } from "node:path";
21603
+ import { fileURLToPath as fileURLToPath9 } from "node:url";
21403
21604
  var OLAM_HOME5, MEMORY_PID_PATH, MEMORY_LOG_PATH, MEMORY_DATA_DIR, MEMORY_REST_PORT, MEMORY_LIVEZ_URL, here, candidates, MEMORY_SERVICE_CANDIDATES;
21404
21605
  var init_paths2 = __esm({
21405
21606
  "src/commands/memory/_paths.ts"() {
21406
21607
  "use strict";
21407
- OLAM_HOME5 = join92(homedir52(), ".olam");
21408
- MEMORY_PID_PATH = join92(OLAM_HOME5, "memory.pid");
21409
- MEMORY_LOG_PATH = join92(OLAM_HOME5, "memory-service.log");
21410
- MEMORY_DATA_DIR = join92(OLAM_HOME5, "memory-data");
21608
+ OLAM_HOME5 = join93(homedir53(), ".olam");
21609
+ MEMORY_PID_PATH = join93(OLAM_HOME5, "memory.pid");
21610
+ MEMORY_LOG_PATH = join93(OLAM_HOME5, "memory-service.log");
21611
+ MEMORY_DATA_DIR = join93(OLAM_HOME5, "memory-data");
21411
21612
  MEMORY_REST_PORT = 3111;
21412
21613
  MEMORY_LIVEZ_URL = `http://localhost:${MEMORY_REST_PORT}/agentmemory/livez`;
21413
- here = dirname49(fileURLToPath8(import.meta.url));
21614
+ here = dirname50(fileURLToPath9(import.meta.url));
21414
21615
  candidates = [
21415
21616
  // 1. Workspace dev (built): packages/cli/dist/commands/memory/_paths.js → packages/cli → packages/memory-service
21416
- join92(here, "..", "..", "..", "..", "memory-service"),
21617
+ join93(here, "..", "..", "..", "..", "memory-service"),
21417
21618
  // 2. Workspace bundled: packages/cli/dist/index.js → packages/cli → packages/memory-service
21418
- join92(here, "..", "..", "memory-service"),
21619
+ join93(here, "..", "..", "memory-service"),
21419
21620
  // 3. CWD fallback
21420
- join92(process.cwd(), "packages", "memory-service")
21621
+ join93(process.cwd(), "packages", "memory-service")
21421
21622
  ];
21422
21623
  MEMORY_SERVICE_CANDIDATES = candidates;
21423
21624
  }
@@ -21526,16 +21727,16 @@ __export(machine_schema_exports, {
21526
21727
  readMachineConfig: () => readMachineConfig,
21527
21728
  writeMachineConfig: () => writeMachineConfig
21528
21729
  });
21529
- import * as fs85 from "node:fs";
21730
+ import * as fs86 from "node:fs";
21530
21731
  import * as path86 from "node:path";
21531
21732
  import * as os48 from "node:os";
21532
21733
  import { parse as parseYaml8, stringify as stringifyYaml6 } from "yaml";
21533
21734
  function readMachineConfig(configPath) {
21534
21735
  const p = configPath ?? DEFAULT_CONFIG_PATH;
21535
- if (!fs85.existsSync(p))
21736
+ if (!fs86.existsSync(p))
21536
21737
  return null;
21537
21738
  try {
21538
- const raw = fs85.readFileSync(p, "utf-8");
21739
+ const raw = fs86.readFileSync(p, "utf-8");
21539
21740
  const parsed = parseYaml8(raw);
21540
21741
  return MachineConfigSchema.parse(parsed);
21541
21742
  } catch {
@@ -21544,8 +21745,8 @@ function readMachineConfig(configPath) {
21544
21745
  }
21545
21746
  function writeMachineConfig(config, configPath) {
21546
21747
  const p = configPath ?? DEFAULT_CONFIG_PATH;
21547
- fs85.mkdirSync(path86.dirname(p), { recursive: true });
21548
- fs85.writeFileSync(p, stringifyYaml6({ ...config }), { mode: 420 });
21748
+ fs86.mkdirSync(path86.dirname(p), { recursive: true });
21749
+ fs86.writeFileSync(p, stringifyYaml6({ ...config }), { mode: 420 });
21549
21750
  }
21550
21751
  function initMachineConfig(opts = {}) {
21551
21752
  const configPath = opts.configPath ?? DEFAULT_CONFIG_PATH;
@@ -21671,7 +21872,7 @@ function registerWorkspace(program2) {
21671
21872
  process.exitCode = 1;
21672
21873
  }
21673
21874
  });
21674
- workspace.command("remove").description("Delete a workspace (does NOT touch worlds that already referenced it)").argument("<name>", "Workspace name").option("--force", "Skip confirmation", false).action((name, _opts) => {
21875
+ workspace.command("remove").description("Delete a workspace (does NOT touch worlds that already referenced it)").argument("<name>", "Workspace name").action((name) => {
21675
21876
  try {
21676
21877
  if (removeWorkspace(name)) {
21677
21878
  printSuccess(`Removed workspace "${name}"`);
@@ -22040,7 +22241,7 @@ function runGlobalInit(opts) {
22040
22241
  }
22041
22242
  }
22042
22243
  function registerInit(program2) {
22043
- program2.command("init").description("Initialize olam in the current project or globally").option("--path <path>", "Project root path", process.cwd()).option("--skip-pleri", "Skip Pleri setup (deprecated \u2014 PLERI is always optional)").option("--global", "Write only ~/.olam/config.json (global scope); skip per-repo .olam/config.yaml").option("--project", "Write .olam/config.yaml in the nearest git repo (per-repo scope; default when --global is absent)").option("--yes / -y", "Auto-affirm prompts (non-interactive)").action(async (opts) => {
22244
+ program2.command("init").description("Initialize olam in the current project or globally").option("--path <path>", "Project root path", process.cwd()).option("--skip-pleri", "No-op (deprecated \u2014 PLERI is always optional; accepted for backward compat but has no effect)").option("--global", "Write only ~/.olam/config.json (global scope); skip per-repo .olam/config.yaml").option("--project", "Write .olam/config.yaml in the nearest git repo (per-repo scope; default when --global is absent)").option("--yes / -y", "Auto-affirm prompts (non-interactive)").action(async (opts) => {
22044
22245
  if (opts.global) {
22045
22246
  try {
22046
22247
  const result = runGlobalInit({});
@@ -22594,7 +22795,7 @@ async function kubectlWrap(args, opts = {}) {
22594
22795
  const spawnImpl = opts.spawnImpl ?? spawn4;
22595
22796
  const stdout = [];
22596
22797
  const stderr = [];
22597
- return new Promise((resolve30) => {
22798
+ return new Promise((resolve31) => {
22598
22799
  let resolved = false;
22599
22800
  let killTimer = null;
22600
22801
  let sigkillTimer = null;
@@ -22609,7 +22810,7 @@ async function kubectlWrap(args, opts = {}) {
22609
22810
  clearTimeout(sigkillTimer);
22610
22811
  sigkillTimer = null;
22611
22812
  }
22612
- resolve30(r);
22813
+ resolve31(r);
22613
22814
  }
22614
22815
  let child;
22615
22816
  try {
@@ -22618,7 +22819,7 @@ async function kubectlWrap(args, opts = {}) {
22618
22819
  env: { ...process.env, ...opts.env ?? {} }
22619
22820
  });
22620
22821
  } catch (err) {
22621
- resolve30({
22822
+ resolve31({
22622
22823
  ok: false,
22623
22824
  stdout: "",
22624
22825
  stderr: err instanceof Error ? err.message : String(err),
@@ -23134,7 +23335,7 @@ function runLiveTask(label, cmd, args, opts) {
23134
23335
  const startMs = Date.now();
23135
23336
  const settle = opts.settle ?? "auto";
23136
23337
  const useSpinner = !opts.verbose && Boolean(process.stdout.isTTY);
23137
- return new Promise((resolve30) => {
23338
+ return new Promise((resolve31) => {
23138
23339
  const child = spawn5(cmd, [...args], {
23139
23340
  env: opts.env ?? process.env,
23140
23341
  stdio: ["ignore", "pipe", "pipe"]
@@ -23198,7 +23399,7 @@ function runLiveTask(label, cmd, args, opts) {
23198
23399
  );
23199
23400
  }
23200
23401
  }
23201
- resolve30({ ok, exitCode: code, durationMs, logPath });
23402
+ resolve31({ ok, exitCode: code, durationMs, logPath });
23202
23403
  };
23203
23404
  child.on("error", (err) => {
23204
23405
  chunks.push(`
@@ -23263,10 +23464,17 @@ function preflight(opts) {
23263
23464
  }
23264
23465
  printSuccess("gh authenticated");
23265
23466
  if (!runCapture("docker", ["info"]).ok) {
23266
- printError("docker daemon unreachable \u2014 start Docker Desktop or colima");
23267
- process.exit(1);
23467
+ if (platform() === "darwin") {
23468
+ printWarning(
23469
+ "docker daemon not reachable yet \u2014 starting the container runtime next"
23470
+ );
23471
+ } else {
23472
+ printError("docker daemon unreachable \u2014 start Docker Desktop or colima");
23473
+ process.exit(1);
23474
+ }
23475
+ } else {
23476
+ printSuccess("docker daemon reachable");
23268
23477
  }
23269
- printSuccess("docker daemon reachable");
23270
23478
  }
23271
23479
  function ensureSecrets() {
23272
23480
  step("1/7 \u2014 operator secrets");
@@ -23285,6 +23493,60 @@ function ensureSecrets() {
23285
23493
  printSuccess(`generated ~/.olam/secrets/${name}`);
23286
23494
  }
23287
23495
  }
23496
+ function resolveMacRuntime(preferred, dockerDesktopInstalled) {
23497
+ if (preferred) return preferred;
23498
+ return dockerDesktopInstalled ? "docker-desktop" : "colima";
23499
+ }
23500
+ function isDockerDesktopInstalled() {
23501
+ return existsSync31("/Applications/Docker.app");
23502
+ }
23503
+ function dockerDaemonReachable() {
23504
+ return runCapture("docker", ["info"]).ok;
23505
+ }
23506
+ function ensureContainerRuntime(opts) {
23507
+ if (platform() !== "darwin") return;
23508
+ const runtime = resolveMacRuntime(opts.preferredRuntime, isDockerDesktopInstalled());
23509
+ if (runtime === "external-k8s") {
23510
+ step("2/7 \u2014 container runtime (external-k8s)");
23511
+ printInfo(
23512
+ "runtime",
23513
+ "preferred_runtime=external-k8s \u2014 not managing Docker Desktop/Colima"
23514
+ );
23515
+ return;
23516
+ }
23517
+ if (runtime === "docker-desktop") {
23518
+ ensureDockerDesktop();
23519
+ return;
23520
+ }
23521
+ ensureColima();
23522
+ }
23523
+ function ensureDockerDesktop() {
23524
+ step("2/7 \u2014 Docker Desktop (macOS)");
23525
+ if (runCapture("docker", ["context", "use", "desktop-linux"]).ok) {
23526
+ printSuccess("docker context \u2192 desktop-linux");
23527
+ } else {
23528
+ printWarning(
23529
+ "could not select the 'desktop-linux' docker context \u2014 using the current context"
23530
+ );
23531
+ }
23532
+ if (dockerDaemonReachable()) {
23533
+ printSuccess("Docker Desktop daemon reachable");
23534
+ return;
23535
+ }
23536
+ printWarning("Docker Desktop not running \u2014 starting (open -a Docker)");
23537
+ runCapture("open", ["-a", "Docker"]);
23538
+ for (let waited = 0; waited < 90; waited += 3) {
23539
+ spawnSync10("sleep", ["3"]);
23540
+ if (dockerDaemonReachable()) {
23541
+ printSuccess(`Docker Desktop daemon reachable (after ~${waited + 3}s)`);
23542
+ return;
23543
+ }
23544
+ }
23545
+ printError(
23546
+ "Docker Desktop did not become ready within 90s \u2014 start it manually and re-run `olam bootstrap`"
23547
+ );
23548
+ process.exit(1);
23549
+ }
23288
23550
  function ensureColima() {
23289
23551
  if (platform() !== "darwin") return;
23290
23552
  step("2/7 \u2014 colima (macOS)");
@@ -23868,7 +24130,8 @@ async function runBootstrapKubernetes(rawOpts) {
23868
24130
  skipPrepull: rawOpts.skipPrepull ?? false,
23869
24131
  verbose,
23870
24132
  verboseObservability: rawOpts.verboseObservability ?? false,
23871
- hostCpDevPath: rawOpts.hostCpDevPath
24133
+ hostCpDevPath: rawOpts.hostCpDevPath,
24134
+ preferredRuntime: rawOpts.preferredRuntime
23872
24135
  };
23873
24136
  printHeader("olam setup \u2014 k3s mode");
23874
24137
  printInfo(
@@ -23877,7 +24140,7 @@ async function runBootstrapKubernetes(rawOpts) {
23877
24140
  );
23878
24141
  preflight(opts);
23879
24142
  ensureSecrets();
23880
- ensureColima();
24143
+ ensureContainerRuntime(opts);
23881
24144
  ensureCluster(opts);
23882
24145
  await installObservability(opts);
23883
24146
  applyPeripheralServicesManifests();
@@ -23939,7 +24202,11 @@ async function runBootstrap2(opts, deps = {}) {
23939
24202
  skipClusterCreate: opts.skipClusterCreate ?? false,
23940
24203
  skipPrepull: opts.skipPrepull ?? false,
23941
24204
  verbose: opts.verbose ?? false,
23942
- hostCpDevPath: opts.hostCpDevPath
24205
+ hostCpDevPath: opts.hostCpDevPath,
24206
+ // Honour the operator's Phase 0 substrate-picker choice. When unset,
24207
+ // bootstrap-kubernetes auto-detects (prefers an installed Docker
24208
+ // Desktop over imposing Colima).
24209
+ preferredRuntime: cfg.host.preferred_runtime
23943
24210
  });
23944
24211
  return { exitCode: k8s.exitCode, summary: k8s.summary };
23945
24212
  }
@@ -24322,10 +24589,10 @@ async function confirm(message) {
24322
24589
  if (!process.stdin.isTTY) return true;
24323
24590
  const { createInterface: createInterface12 } = await import("node:readline");
24324
24591
  const rl = createInterface12({ input: process.stdin, output: process.stdout });
24325
- return new Promise((resolve30) => {
24592
+ return new Promise((resolve31) => {
24326
24593
  rl.question(`${message} [y/N] `, (answer) => {
24327
24594
  rl.close();
24328
- resolve30(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
24595
+ resolve31(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
24329
24596
  });
24330
24597
  });
24331
24598
  }
@@ -24797,7 +25064,7 @@ var KgServiceContainerController = class {
24797
25064
  }
24798
25065
  };
24799
25066
  function sleep4(ms) {
24800
- return new Promise((resolve30) => setTimeout(resolve30, ms));
25067
+ return new Promise((resolve31) => setTimeout(resolve31, ms));
24801
25068
  }
24802
25069
 
24803
25070
  // src/commands/memory-service-container.ts
@@ -25020,7 +25287,7 @@ var MemoryServiceContainerController = class {
25020
25287
  }
25021
25288
  };
25022
25289
  function sleep5(ms) {
25023
- return new Promise((resolve30) => setTimeout(resolve30, ms));
25290
+ return new Promise((resolve31) => setTimeout(resolve31, ms));
25024
25291
  }
25025
25292
 
25026
25293
  // src/lib/peripheral-registry.ts
@@ -25615,7 +25882,7 @@ var McpAuthContainerController = class {
25615
25882
  }
25616
25883
  };
25617
25884
  function sleep6(ms) {
25618
- return new Promise((resolve30) => setTimeout(resolve30, ms));
25885
+ return new Promise((resolve31) => setTimeout(resolve31, ms));
25619
25886
  }
25620
25887
  var K8S_NAMESPACE2 = "olam";
25621
25888
  function assertK8sContext(configPath) {
@@ -26058,39 +26325,32 @@ async function servicesUp(deps = {}) {
26058
26325
  printInfo("olam-memory-service", `:${MEMORY_SERVICE_PORT}`);
26059
26326
  return { exitCode: 0 };
26060
26327
  }
26061
- function servicesDown() {
26062
- const auth = new AuthContainerController();
26063
- const mcpAuth = new McpAuthContainerController();
26064
- const kgService = new KgServiceContainerController();
26065
- const memoryService = new MemoryServiceContainerController();
26066
- let exitCode = 0;
26067
- try {
26068
- auth.stop();
26069
- printSuccess("olam-auth stopped.");
26070
- } catch (err) {
26071
- printError(`olam-auth: ${err instanceof Error ? err.message : String(err)}`);
26072
- exitCode = 1;
26073
- }
26074
- try {
26075
- mcpAuth.stop();
26076
- printSuccess("olam-mcp-auth stopped.");
26077
- } catch (err) {
26078
- printError(`olam-mcp-auth: ${err instanceof Error ? err.message : String(err)}`);
26079
- exitCode = 1;
26080
- }
26081
- try {
26082
- kgService.stop();
26083
- printSuccess("olam-kg-service stopped.");
26084
- } catch (err) {
26085
- printError(`olam-kg-service: ${err instanceof Error ? err.message : String(err)}`);
26086
- exitCode = 1;
26328
+ function servicesDown(opts = {}) {
26329
+ const { include } = opts;
26330
+ const services = [
26331
+ { name: "olam-auth", stop: () => new AuthContainerController().stop() },
26332
+ { name: "olam-mcp-auth", stop: () => new McpAuthContainerController().stop() },
26333
+ { name: "olam-kg-service", stop: () => new KgServiceContainerController().stop() },
26334
+ { name: "olam-memory-service", stop: () => new MemoryServiceContainerController().stop() }
26335
+ ];
26336
+ const known = new Set(services.map((s) => s.name));
26337
+ if (include && include.length > 0) {
26338
+ for (const name of include) {
26339
+ if (!known.has(name)) {
26340
+ printError(`--include: unknown service '${name}'; known: ${[...known].join(", ")}`);
26341
+ }
26342
+ }
26087
26343
  }
26088
- try {
26089
- memoryService.stop();
26090
- printSuccess("olam-memory-service stopped.");
26091
- } catch (err) {
26092
- printError(`olam-memory-service: ${err instanceof Error ? err.message : String(err)}`);
26093
- exitCode = 1;
26344
+ let exitCode = 0;
26345
+ for (const svc of services) {
26346
+ if (include && include.length > 0 && !include.includes(svc.name)) continue;
26347
+ try {
26348
+ svc.stop();
26349
+ printSuccess(`${svc.name} stopped.`);
26350
+ } catch (err) {
26351
+ printError(`${svc.name}: ${err instanceof Error ? err.message : String(err)}`);
26352
+ exitCode = 1;
26353
+ }
26094
26354
  }
26095
26355
  return { exitCode };
26096
26356
  }
@@ -26148,13 +26408,23 @@ function registerServices(program2) {
26148
26408
  if (result.exitCode !== 0) process.exitCode = result.exitCode;
26149
26409
  }
26150
26410
  });
26151
- services.command("down").description("Stop all service containers").action(async () => {
26411
+ services.command("down").description("Stop all service containers").option(
26412
+ "--include <name>",
26413
+ "Stop only the named service container (repeatable). Known names: olam-auth, olam-mcp-auth, olam-kg-service, olam-memory-service. When omitted, all containers are stopped.",
26414
+ (val, acc) => [...acc, val],
26415
+ []
26416
+ ).action(async (opts) => {
26152
26417
  const cfg = readConfig();
26153
26418
  if (cfg.host.substrate === "kubernetes") {
26419
+ if (opts.include.length > 0) {
26420
+ process.stderr.write(
26421
+ "[services down] --include is not supported on kubernetes substrate; stopping all services\n"
26422
+ );
26423
+ }
26154
26424
  const result = await servicesDownKubernetes();
26155
26425
  if (result.exitCode !== 0) process.exitCode = result.exitCode;
26156
26426
  } else {
26157
- const result = servicesDown();
26427
+ const result = servicesDown({ include: opts.include });
26158
26428
  if (result.exitCode !== 0) process.exitCode = result.exitCode;
26159
26429
  }
26160
26430
  });
@@ -26218,14 +26488,14 @@ async function probePortForwardLiveness(deps = {}) {
26218
26488
  return probe2("127.0.0.1", PORT_FORWARD_PORT, TCP_PROBE_TIMEOUT_MS);
26219
26489
  }
26220
26490
  function realTcpProbe(host, port2, timeoutMs) {
26221
- return new Promise((resolve30) => {
26491
+ return new Promise((resolve31) => {
26222
26492
  const socket = new net3.Socket();
26223
26493
  let done = false;
26224
26494
  function finish(result) {
26225
26495
  if (done) return;
26226
26496
  done = true;
26227
26497
  socket.destroy();
26228
- resolve30(result);
26498
+ resolve31(result);
26229
26499
  }
26230
26500
  const timer = setTimeout(() => finish(false), timeoutMs);
26231
26501
  socket.once("connect", () => {
@@ -26563,12 +26833,12 @@ function appendAuditEntry(entry, auditLogPath, writeFileSyncImpl) {
26563
26833
  async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}, peripheral) {
26564
26834
  const auditLogPath = deps.auditLogPath ?? MANIFEST_REFRESH_AUDIT_LOG;
26565
26835
  const readdirSync34 = deps.readdirSync ?? fs35.readdirSync;
26566
- const readFileSync108 = deps.readFileSync ?? fs35.readFileSync;
26836
+ const readFileSync110 = deps.readFileSync ?? fs35.readFileSync;
26567
26837
  const writeFileSyncImpl = deps.writeFileSync ?? fs35.writeFileSync;
26568
- const existsSync120 = deps.existsSync ?? fs35.existsSync;
26838
+ const existsSync122 = deps.existsSync ?? fs35.existsSync;
26569
26839
  const now = deps.now ? deps.now() : /* @__PURE__ */ new Date();
26570
26840
  const targetDir = peripheral ? path36.join(manifestsDir, peripheral) : manifestsDir;
26571
- if (!existsSync120(targetDir)) {
26841
+ if (!existsSync122(targetDir)) {
26572
26842
  return {
26573
26843
  ok: false,
26574
26844
  message: peripheral ? `peripheral manifests directory not found: ${targetDir}` : `manifests directory not found: ${targetDir}`
@@ -26589,7 +26859,7 @@ async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}, per
26589
26859
  const filePath = path36.join(targetDir, file);
26590
26860
  let content;
26591
26861
  try {
26592
- content = readFileSync108(filePath, "utf8");
26862
+ content = readFileSync110(filePath, "utf8");
26593
26863
  } catch {
26594
26864
  continue;
26595
26865
  }
@@ -26845,11 +27115,11 @@ async function checkSecretPreCondition(context, deps) {
26845
27115
  }
26846
27116
  async function applyConfigMapSubstitution(context, manifestsDir, deps) {
26847
27117
  const wrap = deps.kubectlWrapImpl ?? kubectlWrap;
26848
- const readFileSync108 = deps.readFileSyncImpl ?? fs36.readFileSync;
27118
+ const readFileSync110 = deps.readFileSyncImpl ?? fs36.readFileSync;
26849
27119
  const configMapPath = path37.join(manifestsDir, "30-configmap.yaml");
26850
27120
  let rawYaml;
26851
27121
  try {
26852
- rawYaml = readFileSync108(configMapPath, "utf8");
27122
+ rawYaml = readFileSync110(configMapPath, "utf8");
26853
27123
  } catch (err) {
26854
27124
  return `Failed to read ConfigMap at ${configMapPath}: ${err instanceof Error ? err.message : String(err)}`;
26855
27125
  }
@@ -28124,10 +28394,10 @@ function emptyMigrationState() {
28124
28394
  return { version: 1, migrated: {} };
28125
28395
  }
28126
28396
  function readMigrationState(statePath, deps) {
28127
- const existsSync120 = deps.existsSync ?? fs40.existsSync;
28128
- const readFileSync108 = deps.readFileSync ?? ((p) => fs40.readFileSync(p, "utf-8"));
28129
- if (!existsSync120(statePath)) return emptyMigrationState();
28130
- const raw = readFileSync108(statePath);
28397
+ const existsSync122 = deps.existsSync ?? fs40.existsSync;
28398
+ const readFileSync110 = deps.readFileSync ?? ((p) => fs40.readFileSync(p, "utf-8"));
28399
+ if (!existsSync122(statePath)) return emptyMigrationState();
28400
+ const raw = readFileSync110(statePath);
28131
28401
  let parsed;
28132
28402
  try {
28133
28403
  parsed = JSON.parse(raw);
@@ -28144,17 +28414,17 @@ function readMigrationState(statePath, deps) {
28144
28414
  return parsed;
28145
28415
  }
28146
28416
  function writeMigrationStateAtomic(statePath, state, deps) {
28147
- const writeFileSync65 = deps.writeFileSync ?? ((p, d) => fs40.writeFileSync(p, d, "utf-8"));
28417
+ const writeFileSync67 = deps.writeFileSync ?? ((p, d) => fs40.writeFileSync(p, d, "utf-8"));
28148
28418
  const renameSync21 = deps.renameSync ?? fs40.renameSync;
28149
28419
  const tmpPath = `${statePath}.tmp`;
28150
- writeFileSync65(tmpPath, JSON.stringify(state, null, 2) + "\n");
28420
+ writeFileSync67(tmpPath, JSON.stringify(state, null, 2) + "\n");
28151
28421
  renameSync21(tmpPath, statePath);
28152
28422
  }
28153
28423
  function readLocalAccounts(accountsPath, deps) {
28154
- const existsSync120 = deps.existsSync ?? fs40.existsSync;
28155
- const readFileSync108 = deps.readFileSync ?? ((p) => fs40.readFileSync(p, "utf-8"));
28156
- if (!existsSync120(accountsPath)) return null;
28157
- const raw = readFileSync108(accountsPath);
28424
+ const existsSync122 = deps.existsSync ?? fs40.existsSync;
28425
+ const readFileSync110 = deps.readFileSync ?? ((p) => fs40.readFileSync(p, "utf-8"));
28426
+ if (!existsSync122(accountsPath)) return null;
28427
+ const raw = readFileSync110(accountsPath);
28158
28428
  let parsed;
28159
28429
  try {
28160
28430
  parsed = JSON.parse(raw);
@@ -29039,18 +29309,31 @@ ${pc13.dim("Tip: set ANTHROPIC_BASE_URL=" + baseUrl.replace(/\/+$/, "") + "/v1/p
29039
29309
  auth.command("revoke-anthropic-token").description("Revoke an Anthropic proxy token on the remote auth-worker (g4)").requiredOption("--remote <url>", "Auth-worker base URL").requiredOption("--token-hash <hash>", "Token hash to revoke (from issue or list output)").action(async (opts) => {
29040
29310
  const baseUrl = opts.remote;
29041
29311
  printHeader("Auth worker \u2014 revoke Anthropic proxy token");
29042
- console.log(`
29312
+ const serviceToken = resolveCfAccessServiceToken();
29313
+ let remoteOpts;
29314
+ if (serviceToken) {
29315
+ console.log(`
29316
+ ${pc13.dim("Using CF Access service token (machine-to-machine; no cookie needed).")}`);
29317
+ remoteOpts = {
29318
+ baseUrl,
29319
+ cfAccessClientId: serviceToken.clientId,
29320
+ cfAccessClientSecret: serviceToken.clientSecret
29321
+ };
29322
+ } else {
29323
+ console.log(`
29043
29324
  Open ${pc13.cyan(baseUrl.replace(/\/+$/, "") + "/v1/oauth/start")} in a browser to authenticate via CF Access SSO.`);
29044
- console.log(` Once you've completed SSO, paste your CF_Authorization cookie below.
29325
+ console.log(` Once you've completed SSO, paste your CF_Authorization cookie below.
29045
29326
  `);
29046
- const rawCookie = await promptLine(` ${pc13.dim("CF_Authorization cookie:")} `);
29047
- if (!rawCookie) {
29048
- printError("No cookie provided. Aborting.");
29049
- process.exitCode = 1;
29050
- return;
29327
+ const rawCookie = await promptLine(` ${pc13.dim("CF_Authorization cookie:")} `);
29328
+ if (!rawCookie) {
29329
+ printError("No cookie provided. Aborting.");
29330
+ process.exitCode = 1;
29331
+ return;
29332
+ }
29333
+ remoteOpts = { baseUrl, cfAuthCookie: rawCookie };
29051
29334
  }
29052
29335
  try {
29053
- const revoked = await remoteRevokeAnthropicToken({ baseUrl, cfAuthCookie: rawCookie }, opts.tokenHash);
29336
+ const revoked = await remoteRevokeAnthropicToken(remoteOpts, opts.tokenHash);
29054
29337
  if (revoked) {
29055
29338
  printSuccess(`Token ${opts.tokenHash} revoked.`);
29056
29339
  } else {
@@ -31342,6 +31625,7 @@ Top-level commands (run \`olam <command> --help\` for flags and subcommands):
31342
31625
  - \`olam enter\` \u2014 Open terminal to a world
31343
31626
  - \`olam evict\` \u2014 Evict oldest snapshots until total size \u2264 cap (default 5GB; override via OLAM_SNAPSHOT_MAX_BYTES)
31344
31627
  - \`olam get\` \u2014 Print the active substrate
31628
+ - \`olam graph\` \u2014 Query the cross-repo graph: locate a symbol, its relationships, or browse a repo (POST /v1/graph)
31345
31629
  - \`olam hermes\` \u2014 Hermes integration commands
31346
31630
  - \`olam host-cp\` \u2014 Manage the Olam host control plane container
31347
31631
  - \`olam implode\` \u2014 Destroy ALL local olam install and configs (dry-run by default)
@@ -31349,6 +31633,7 @@ Top-level commands (run \`olam <command> --help\` for flags and subcommands):
31349
31633
  - \`olam inspect\` \u2014 Diagnose warm-create cache hits/misses for a workspace (read-only; mutates nothing)
31350
31634
  - \`olam install\` \u2014 Pick an archetype preset for this Olam install
31351
31635
  - \`olam install-hook\` \u2014 Install kg-service hook (idempotent). --for hermes targets ~/.hermes/; default targets .claude/settings.json
31636
+ - \`olam install-model-router\` \u2014 Deploy the model-router.py UserPromptSubmit hook script to ~/.claude/hooks/ (idempotent; auto-run by
31352
31637
  - \`olam issue-anthropic-token\` \u2014 Mint a new Anthropic proxy token via the remote auth-worker (g4)
31353
31638
  - \`olam keys\` \u2014 Manage LLM API keys stored at ~/.olam/keys.yaml
31354
31639
  - \`olam kg\` \u2014 Knowledge-graph operations (kg-service container)
@@ -31403,7 +31688,7 @@ Top-level commands (run \`olam <command> --help\` for flags and subcommands):
31403
31688
  - \`olam substrate\` \u2014 Manage deployment substrate (beta)
31404
31689
  - \`olam sync\` \u2014 Sync registered skill sources to ~/.claude/
31405
31690
  - \`olam tls-install\` \u2014 Provision a locally-trusted TLS cert (mkcert) for the Traefik IngressRoute
31406
- - \`olam uninstall\` \u2014 Remove /10x: chain skill symlinks from ~/.claude/skills (preserves user-authored skills + non-chain skill sources)
31691
+ - \`olam uninstall\` \u2014 Remove /100x: chain skill symlinks from ~/.claude/skills (preserves user-authored skills + non-chain skill sources)
31407
31692
  - \`olam uninstall-hook\` \u2014 Remove kg-service PreToolUse hook from .claude/settings.json (sentinel-matched; surgical)
31408
31693
  - \`olam unset-prefix\` \u2014 Remove the deploy prefix from a registered skill source (reverts to canonical deploy names)
31409
31694
  - \`olam unset-prefix-scope\` \u2014 Remove the prefix-scope override from a registered skill source (reverts to default: both skill and agent are renamed)
@@ -31609,12 +31894,12 @@ async function runRepl(deps = {}) {
31609
31894
  closed = true;
31610
31895
  onClose?.();
31611
31896
  });
31612
- const ask = () => new Promise((resolve30) => {
31613
- if (closed) return resolve30(null);
31614
- onClose = () => resolve30(null);
31897
+ const ask = () => new Promise((resolve31) => {
31898
+ if (closed) return resolve31(null);
31899
+ onClose = () => resolve31(null);
31615
31900
  rl.question(pc14.cyan("olam ask> "), (line) => {
31616
31901
  onClose = null;
31617
- resolve30(line);
31902
+ resolve31(line);
31618
31903
  });
31619
31904
  });
31620
31905
  try {
@@ -32152,15 +32437,15 @@ var AGENTMEMORY_LOCAL_URL = "http://host.docker.internal:3111";
32152
32437
  var HOST_CP_URL = "http://127.0.0.1:19000";
32153
32438
  async function readHostCpTokenForCreate() {
32154
32439
  try {
32155
- const { default: fs107 } = await import("node:fs");
32440
+ const { default: fs108 } = await import("node:fs");
32156
32441
  const { default: os60 } = await import("node:os");
32157
32442
  const { default: path106 } = await import("node:path");
32158
32443
  const tp = path106.join(
32159
32444
  process.env.OLAM_HOME ?? path106.join(os60.homedir(), ".olam"),
32160
32445
  "host-cp.token"
32161
32446
  );
32162
- if (!fs107.existsSync(tp)) return null;
32163
- return fs107.readFileSync(tp, "utf-8").trim();
32447
+ if (!fs108.existsSync(tp)) return null;
32448
+ return fs108.readFileSync(tp, "utf-8").trim();
32164
32449
  } catch {
32165
32450
  return null;
32166
32451
  }
@@ -32172,7 +32457,7 @@ function registerCreate(program2) {
32172
32457
  ).option("--devbox-image <ref>", "Override the default devbox image (full registry/name:tag or @sha256: ref)").option("--allow-custom-registry", "Allow --devbox-image refs outside ghcr.io/pleri/* (logs a warning)").option("--runbook <name>", "Named runbook profile from ~/.olam/config.json").option(
32173
32458
  "--claude-home <id-or-path>",
32174
32459
  "Use a per-world Claude Code HOME (multi-account isolation; see docs/decisions/045-claude-home-override.md)"
32175
- ).action(async (opts) => {
32460
+ ).option("--json", "Emit machine-readable JSON on success (suppresses interactive hints)").action(async (opts) => {
32176
32461
  const { resolveDevboxImageOverride: resolveDevboxImageOverride2, decideAllowlist: decideAllowlist2 } = await Promise.resolve().then(() => (init_registry_allowlist(), registry_allowlist_exports));
32177
32462
  const overrideRef = resolveDevboxImageOverride2(opts.devboxImage);
32178
32463
  if (overrideRef) {
@@ -32660,12 +32945,12 @@ function defaultNameFromPrompt(prompt) {
32660
32945
  }
32661
32946
  async function readHostCpToken3() {
32662
32947
  try {
32663
- const { default: fs107 } = await import("node:fs");
32948
+ const { default: fs108 } = await import("node:fs");
32664
32949
  const { default: os60 } = await import("node:os");
32665
32950
  const { default: path106 } = await import("node:path");
32666
32951
  const tp = path106.join(os60.homedir(), ".olam", "host-cp.token");
32667
- if (!fs107.existsSync(tp)) return null;
32668
- const raw = fs107.readFileSync(tp, "utf-8").trim();
32952
+ if (!fs108.existsSync(tp)) return null;
32953
+ const raw = fs108.readFileSync(tp, "utf-8").trim();
32669
32954
  return raw.length > 0 ? raw : null;
32670
32955
  } catch {
32671
32956
  return null;
@@ -33039,7 +33324,7 @@ function parseRuntimeStatus(raw) {
33039
33324
  last_event_age_seconds
33040
33325
  };
33041
33326
  }
33042
- var fetchWorldRuntimeStatus = (worldId, token) => new Promise((resolve30) => {
33327
+ var fetchWorldRuntimeStatus = (worldId, token) => new Promise((resolve31) => {
33043
33328
  const opts = {
33044
33329
  host: "127.0.0.1",
33045
33330
  port: HOST_CP_PORT2,
@@ -33051,7 +33336,7 @@ var fetchWorldRuntimeStatus = (worldId, token) => new Promise((resolve30) => {
33051
33336
  const req = http3.request(opts, (res) => {
33052
33337
  if (res.statusCode !== 200) {
33053
33338
  res.resume();
33054
- return resolve30(null);
33339
+ return resolve31(null);
33055
33340
  }
33056
33341
  let body = "";
33057
33342
  res.setEncoding("utf-8");
@@ -33061,17 +33346,17 @@ var fetchWorldRuntimeStatus = (worldId, token) => new Promise((resolve30) => {
33061
33346
  res.on("end", () => {
33062
33347
  try {
33063
33348
  const parsed = parseRuntimeStatus(JSON.parse(body));
33064
- resolve30(parsed);
33349
+ resolve31(parsed);
33065
33350
  } catch {
33066
- resolve30(null);
33351
+ resolve31(null);
33067
33352
  }
33068
33353
  });
33069
- res.on("error", () => resolve30(null));
33354
+ res.on("error", () => resolve31(null));
33070
33355
  });
33071
- req.on("error", () => resolve30(null));
33356
+ req.on("error", () => resolve31(null));
33072
33357
  req.on("timeout", () => {
33073
33358
  req.destroy();
33074
- resolve30(null);
33359
+ resolve31(null);
33075
33360
  });
33076
33361
  req.end();
33077
33362
  });
@@ -33127,7 +33412,7 @@ async function getMachineStatus(_probe, _loadCtx, _readToken) {
33127
33412
  };
33128
33413
  }
33129
33414
  function registerStatus(program2) {
33130
- program2.command("status").description("Show machine status, or world details when a world ID is given").argument("[world]", "World ID \u2014 omit to show machine status").option("--json", "Output as JSON").option("--pretty", "Render world status as a human-readable table (engine-aware view)").action(async (worldId, opts) => {
33415
+ program2.command("status").description("Show machine status, or world details when a world ID is given").argument("[world]", "World ID \u2014 omit to show machine status").option("--json", "Output as JSON").action(async (worldId, opts) => {
33131
33416
  if (!worldId) {
33132
33417
  const ms = await getMachineStatus();
33133
33418
  if (opts.json) {
@@ -33261,12 +33546,12 @@ async function readlineConfirm(world) {
33261
33546
 
33262
33547
  `
33263
33548
  );
33264
- return new Promise((resolve30) => {
33549
+ return new Promise((resolve31) => {
33265
33550
  rl.question(
33266
33551
  `Destroy ${pc20.bold(world.name)}? This cannot be undone. [y/N] `,
33267
33552
  (answer) => {
33268
33553
  rl.close();
33269
- resolve30(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
33554
+ resolve31(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
33270
33555
  }
33271
33556
  );
33272
33557
  });
@@ -33621,14 +33906,14 @@ function printTable(entries) {
33621
33906
  async function confirmInteractive() {
33622
33907
  process.stdout.write(" Type `yes` to proceed: ");
33623
33908
  const buf = [];
33624
- return new Promise((resolve30) => {
33909
+ return new Promise((resolve31) => {
33625
33910
  const onData = (chunk) => {
33626
33911
  buf.push(chunk);
33627
33912
  if (Buffer.concat(buf).toString("utf-8").includes("\n")) {
33628
33913
  process.stdin.removeListener("data", onData);
33629
33914
  process.stdin.pause();
33630
33915
  const answer = Buffer.concat(buf).toString("utf-8").trim();
33631
- resolve30(answer.toLowerCase() === "yes");
33916
+ resolve31(answer.toLowerCase() === "yes");
33632
33917
  }
33633
33918
  };
33634
33919
  process.stdin.resume();
@@ -39824,10 +40109,10 @@ async function confirm2(message) {
39824
40109
  if (!process.stdin.isTTY) return true;
39825
40110
  const { createInterface: createInterface12 } = await import("node:readline");
39826
40111
  const rl = createInterface12({ input: process.stdin, output: process.stdout });
39827
- return new Promise((resolve30) => {
40112
+ return new Promise((resolve31) => {
39828
40113
  rl.question(`${message} [y/N] `, (answer) => {
39829
40114
  rl.close();
39830
- resolve30(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
40115
+ resolve31(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
39831
40116
  });
39832
40117
  });
39833
40118
  }
@@ -41071,7 +41356,15 @@ function registerPs(program2) {
41071
41356
  process.exitCode = 1;
41072
41357
  return;
41073
41358
  }
41074
- const sortKey = ["cpu", "mem", "pid"].includes(opts.sort) ? opts.sort : "cpu";
41359
+ const VALID_SORT_KEYS = ["cpu", "mem", "pid"];
41360
+ if (!VALID_SORT_KEYS.includes(opts.sort)) {
41361
+ printError(
41362
+ `Invalid --sort key "${opts.sort}". Valid values: ${VALID_SORT_KEYS.join(", ")}.`
41363
+ );
41364
+ process.exitCode = 1;
41365
+ return;
41366
+ }
41367
+ const sortKey = opts.sort;
41075
41368
  const containerName = `olam-${worldId}-devbox`;
41076
41369
  let watchInterval;
41077
41370
  function fetchAndPrint() {
@@ -41811,7 +42104,7 @@ async function refreshWorld(worldId, portOffset, standaloneDir, opts) {
41811
42104
  return { worldId, ok: true };
41812
42105
  }
41813
42106
  function registerRefresh(program2) {
41814
- program2.command("refresh").description("Hot-refresh a running world's per-world CP from the local checkout").argument("[world]", "World ID").option("--all", "Refresh every running world sequentially (overrides positional arg)").option("--no-restart", "Copy files but skip CP restart (for debugging)").option("--skip-build", "Skip the prerequisite server.mjs presence check").action(async (worldId, opts) => {
42107
+ program2.command("refresh").description("Hot-refresh a running world's per-world container-CP bundle (packages/control-plane/standalone/ \u2014 legacy per-world CP surface)").argument("[world]", "World ID").option("--all", "Refresh every running world sequentially (overrides positional arg)").option("--no-restart", "Copy files but skip CP restart (for debugging)").option("--skip-build", "Skip the prerequisite server.mjs presence check").action(async (worldId, opts) => {
41815
42108
  if (!opts.all && !worldId) {
41816
42109
  printError("Specify a world ID or use --all to refresh all running worlds.");
41817
42110
  process.exitCode = 1;
@@ -42497,7 +42790,7 @@ async function runPeripheralProbes(peripheral, startPosition, kubectlContext, wr
42497
42790
  })();
42498
42791
  rows.push({ name: `${peripheral.name} ready`, result: reachableResult, position: startPosition });
42499
42792
  const pfLivenessResult = await (async () => {
42500
- return new Promise((resolve30) => {
42793
+ return new Promise((resolve31) => {
42501
42794
  const socket = new net4.Socket();
42502
42795
  let done = false;
42503
42796
  const finish = (alive) => {
@@ -42505,9 +42798,9 @@ async function runPeripheralProbes(peripheral, startPosition, kubectlContext, wr
42505
42798
  done = true;
42506
42799
  socket.destroy();
42507
42800
  if (alive) {
42508
- resolve30({ ok: true, message: `${peripheral.name} port-forward live on :${peripheral.port}` });
42801
+ resolve31({ ok: true, message: `${peripheral.name} port-forward live on :${peripheral.port}` });
42509
42802
  } else {
42510
- resolve30({
42803
+ resolve31({
42511
42804
  ok: true,
42512
42805
  warn: true,
42513
42806
  message: `${peripheral.name} port-forward not live on :${peripheral.port}`,
@@ -43735,8 +44028,8 @@ function registerCompletion(program2) {
43735
44028
  init_cli_version();
43736
44029
  init_health_probes();
43737
44030
  import { spawn as spawn8, spawnSync as spawnSync29 } from "node:child_process";
43738
- import { existsSync as existsSync90, readFileSync as readFileSync78 } from "node:fs";
43739
- import { homedir as homedir53 } from "node:os";
44031
+ import { existsSync as existsSync92, readFileSync as readFileSync80 } from "node:fs";
44032
+ import { homedir as homedir54 } from "node:os";
43740
44033
  import path84 from "node:path";
43741
44034
  import { createInterface as createInterface5 } from "node:readline";
43742
44035
 
@@ -43983,9 +44276,9 @@ async function pickSkillSourcePhase(opts, deps) {
43983
44276
  }
43984
44277
 
43985
44278
  // src/commands/setup-phase-5b-project-sweep.ts
43986
- import { homedir as homedir50 } from "node:os";
44279
+ import { homedir as homedir51 } from "node:os";
43987
44280
  import * as path82 from "node:path";
43988
- import * as fs82 from "node:fs";
44281
+ import * as fs83 from "node:fs";
43989
44282
  async function loadWalkFn() {
43990
44283
  const m = await Promise.resolve().then(() => (init_project_sweep(), project_sweep_exports));
43991
44284
  return m.walkProjectRoot;
@@ -44016,9 +44309,9 @@ async function runProjectSweepPhase(opts, deps, sweepDeps = {}) {
44016
44309
  if (opts.skipProjectSweep) {
44017
44310
  return { ok: true, skipped: true, message: "skipped via --skip-project-sweep" };
44018
44311
  }
44019
- const home = deps.home ?? homedir50();
44312
+ const home = deps.home ?? homedir51();
44020
44313
  const projectsRoot = opts.projects ?? path82.join(home, "Projects");
44021
- const existsSyncFn = sweepDeps.existsSync ?? fs82.existsSync;
44314
+ const existsSyncFn = sweepDeps.existsSync ?? fs83.existsSync;
44022
44315
  if (!existsSyncFn(projectsRoot)) {
44023
44316
  return {
44024
44317
  ok: true,
@@ -44119,7 +44412,7 @@ async function runProjectSweepPhase(opts, deps, sweepDeps = {}) {
44119
44412
  }
44120
44413
 
44121
44414
  // src/commands/setup-phase-8-kg-hook.ts
44122
- import * as fs83 from "node:fs";
44415
+ import * as fs84 from "node:fs";
44123
44416
  import * as path83 from "node:path";
44124
44417
  import * as os47 from "node:os";
44125
44418
  async function loadMergeHookFn() {
@@ -44149,7 +44442,7 @@ async function runKgHookPhase(opts, _deps, kgDeps = {}) {
44149
44442
  message: `dry-run: would install KG hook into ${settingsPath}`
44150
44443
  };
44151
44444
  }
44152
- const mkdirFn = kgDeps.mkdirSync ?? ((p, o) => fs83.mkdirSync(p, o));
44445
+ const mkdirFn = kgDeps.mkdirSync ?? ((p, o) => fs84.mkdirSync(p, o));
44153
44446
  try {
44154
44447
  mkdirFn(path83.dirname(settingsPath), { recursive: true });
44155
44448
  } catch (err) {
@@ -44237,10 +44530,10 @@ var NEXT_STEPS_DOCS_KUBERNETES = [
44237
44530
  "https://github.com/pleri/olam/blob/main/docs/architecture/config-spec.md \u2014 workspace .olam/config.yaml schema",
44238
44531
  "https://github.com/pleri/olam/blob/main/docs/k8s/SETUP.md \u2014 k3d operator guide"
44239
44532
  ];
44240
- var defaultSpawn2 = (cmd, args) => new Promise((resolve30) => {
44533
+ var defaultSpawn2 = (cmd, args) => new Promise((resolve31) => {
44241
44534
  const child = spawn8(cmd, [...args], { stdio: "inherit" });
44242
- child.on("exit", (code) => resolve30({ status: code }));
44243
- child.on("error", () => resolve30({ status: 1 }));
44535
+ child.on("exit", (code) => resolve31({ status: code }));
44536
+ child.on("error", () => resolve31({ status: 1 }));
44244
44537
  });
44245
44538
  var defaultPrompt = (question, defaultYes) => {
44246
44539
  if (!process.stdin.isTTY) {
@@ -44250,18 +44543,18 @@ var defaultPrompt = (question, defaultYes) => {
44250
44543
  );
44251
44544
  return Promise.resolve(defaultYes);
44252
44545
  }
44253
- return new Promise((resolve30) => {
44546
+ return new Promise((resolve31) => {
44254
44547
  const rl = createInterface5({ input: process.stdin, output: process.stdout });
44255
44548
  const suffix = defaultYes ? " [Y/n]: " : " [y/N]: ";
44256
44549
  rl.question(`${question}${suffix}`, (answer) => {
44257
44550
  rl.close();
44258
44551
  const t = answer.trim().toLowerCase();
44259
- if (t === "") resolve30(defaultYes);
44260
- else if (t === "y" || t === "yes") resolve30(true);
44261
- else if (t === "n" || t === "no") resolve30(false);
44262
- else resolve30(defaultYes);
44552
+ if (t === "") resolve31(defaultYes);
44553
+ else if (t === "y" || t === "yes") resolve31(true);
44554
+ else if (t === "n" || t === "no") resolve31(false);
44555
+ else resolve31(defaultYes);
44263
44556
  });
44264
- rl.on("close", () => resolve30(defaultYes));
44557
+ rl.on("close", () => resolve31(defaultYes));
44265
44558
  });
44266
44559
  };
44267
44560
  var CLUSTER_NAME_RE = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;
@@ -44281,9 +44574,9 @@ function resolveSubstrate(opts, deps) {
44281
44574
  if (opts.substrate === "kubernetes") return "kubernetes";
44282
44575
  if (opts.substrate === "docker") return "docker";
44283
44576
  const configPath = deps.configPath ?? OLAM_CONFIG_PATH;
44284
- if (existsSync90(configPath)) {
44577
+ if (existsSync92(configPath)) {
44285
44578
  try {
44286
- const raw = readFileSync78(configPath, "utf8");
44579
+ const raw = readFileSync80(configPath, "utf8");
44287
44580
  const parsed = JSON.parse(raw);
44288
44581
  const host = parsed.host;
44289
44582
  if (host?.substrate === "kubernetes") return "kubernetes";
@@ -44350,9 +44643,9 @@ async function phase0SubstratePicker(opts, deps) {
44350
44643
  return { ok: true, skipped: true, message: "skipped via --skip-substrate-picker" };
44351
44644
  }
44352
44645
  const configPath = deps.configPath ?? OLAM_CONFIG_PATH;
44353
- if (existsSync90(configPath)) {
44646
+ if (existsSync92(configPath)) {
44354
44647
  try {
44355
- const raw = readFileSync78(configPath, "utf8");
44648
+ const raw = readFileSync80(configPath, "utf8");
44356
44649
  const parsed = JSON.parse(raw);
44357
44650
  const host = parsed.host;
44358
44651
  if (host?.substrate !== void 0 && host?.preferred_runtime !== void 0) {
@@ -44402,9 +44695,9 @@ async function phase0SubstratePicker(opts, deps) {
44402
44695
  const choice = SUBSTRATE_CHOICES[Number(pickedIndex)] ?? DEFAULT_SUBSTRATE_CHOICE;
44403
44696
  if (choice.requirePinnedContext) {
44404
44697
  let hasPinnedContext = false;
44405
- if (existsSync90(configPath)) {
44698
+ if (existsSync92(configPath)) {
44406
44699
  try {
44407
- const raw = readFileSync78(configPath, "utf8");
44700
+ const raw = readFileSync80(configPath, "utf8");
44408
44701
  const parsed = JSON.parse(raw);
44409
44702
  const host = parsed.host;
44410
44703
  hasPinnedContext = typeof host?.kubectl_context_pinned === "string" && host.kubectl_context_pinned.length > 0;
@@ -44561,7 +44854,7 @@ async function phase1SystemCheck(substrate, deps) {
44561
44854
  };
44562
44855
  }
44563
44856
  const platform2 = String(deps.osPlatform ?? process.platform);
44564
- const home = deps.home ?? homedir53();
44857
+ const home = deps.home ?? homedir54();
44565
44858
  const colimaLint = probeColimaKubernetesEnabled({ platform: platform2, home });
44566
44859
  if (colimaLint.ok && "warn" in colimaLint && colimaLint.warn === true) {
44567
44860
  const lintWithWarn = colimaLint;
@@ -44700,8 +44993,8 @@ async function phase2_5ProvisionCluster(substrate, clusterName, opts, deps, reus
44700
44993
  process.stdout.write(`Creating k3d cluster ${clusterName}...
44701
44994
  `);
44702
44995
  const volumes = [];
44703
- const ghConfigDir = `${homedir53()}/.config/gh`;
44704
- if (existsSync90(ghConfigDir)) {
44996
+ const ghConfigDir = `${homedir54()}/.config/gh`;
44997
+ if (existsSync92(ghConfigDir)) {
44705
44998
  volumes.push("--volume", `${ghConfigDir}:/host/.config/gh`);
44706
44999
  } else {
44707
45000
  process.stdout.write(
@@ -44710,7 +45003,7 @@ async function phase2_5ProvisionCluster(substrate, clusterName, opts, deps, reus
44710
45003
  );
44711
45004
  }
44712
45005
  if (opts.hostCpDevPath) {
44713
- if (!existsSync90(opts.hostCpDevPath)) {
45006
+ if (!existsSync92(opts.hostCpDevPath)) {
44714
45007
  return {
44715
45008
  ok: false,
44716
45009
  message: `--host-cp-dev-path ${opts.hostCpDevPath} does not exist`,
@@ -44875,7 +45168,7 @@ async function phase3_5K3dHttpsBootstrap(substrate, opts, _deps) {
44875
45168
  const result = await ensureTlsInstalled();
44876
45169
  let hostsWarning = "";
44877
45170
  try {
44878
- const hostsBody = readFileSync78("/etc/hosts", "utf-8");
45171
+ const hostsBody = readFileSync80("/etc/hosts", "utf-8");
44879
45172
  if (!/^[^#\n]*\bolam\.local\b/m.test(hostsBody)) {
44880
45173
  hostsWarning = " Add to /etc/hosts: echo '127.0.0.1 olam.local' | sudo tee -a /etc/hosts";
44881
45174
  }
@@ -44901,7 +45194,7 @@ async function phase4ShellInit(opts, deps) {
44901
45194
  if (opts.skipShellInit) {
44902
45195
  return { ok: true, skipped: true, message: "skipped via --skip-shell-init" };
44903
45196
  }
44904
- const home = deps.home ?? homedir53();
45197
+ const home = deps.home ?? homedir54();
44905
45198
  const shellEnv = deps.shellEnv ?? process.env.SHELL;
44906
45199
  const rcPath = resolveShellRc(home, shellEnv);
44907
45200
  if (rcPath === null) {
@@ -45415,24 +45708,24 @@ function registerSetupLinuxGate(program2) {
45415
45708
  }
45416
45709
 
45417
45710
  // src/commands/update.ts
45418
- import * as fs86 from "node:fs";
45711
+ import * as fs87 from "node:fs";
45419
45712
  import * as os49 from "node:os";
45420
45713
  import * as path87 from "node:path";
45421
45714
  import { execSync as execSync15 } from "node:child_process";
45422
45715
  import pc33 from "picocolors";
45423
45716
 
45424
45717
  // src/lib/symlink-reconcile.ts
45425
- import * as fs84 from "node:fs";
45718
+ import * as fs85 from "node:fs";
45426
45719
  import * as path85 from "node:path";
45427
45720
  var realFs = {
45428
- readdirSync: (p) => fs84.readdirSync(p),
45429
- existsSync: (p) => fs84.existsSync(p),
45430
- lstatSync: (p) => fs84.lstatSync(p),
45431
- readlinkSync: (p) => fs84.readlinkSync(p),
45432
- symlinkSync: (t, l) => fs84.symlinkSync(t, l),
45433
- unlinkSync: (p) => fs84.unlinkSync(p),
45721
+ readdirSync: (p) => fs85.readdirSync(p),
45722
+ existsSync: (p) => fs85.existsSync(p),
45723
+ lstatSync: (p) => fs85.lstatSync(p),
45724
+ readlinkSync: (p) => fs85.readlinkSync(p),
45725
+ symlinkSync: (t, l) => fs85.symlinkSync(t, l),
45726
+ unlinkSync: (p) => fs85.unlinkSync(p),
45434
45727
  mkdirSync: (p, o) => {
45435
- fs84.mkdirSync(p, o);
45728
+ fs85.mkdirSync(p, o);
45436
45729
  }
45437
45730
  };
45438
45731
  function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir2, _fs = realFs) {
@@ -45526,22 +45819,22 @@ function getCurrentVersion(_exec = defaultExec) {
45526
45819
  }
45527
45820
  function readLastStable(file = LAST_STABLE_FILE) {
45528
45821
  try {
45529
- const v = fs86.readFileSync(file, "utf-8").trim();
45822
+ const v = fs87.readFileSync(file, "utf-8").trim();
45530
45823
  return v || null;
45531
45824
  } catch {
45532
45825
  return null;
45533
45826
  }
45534
45827
  }
45535
45828
  function writeLastStable(version, file = LAST_STABLE_FILE) {
45536
- fs86.mkdirSync(path87.dirname(file), { recursive: true });
45537
- fs86.writeFileSync(file, version, { mode: 420 });
45829
+ fs87.mkdirSync(path87.dirname(file), { recursive: true });
45830
+ fs87.writeFileSync(file, version, { mode: 420 });
45538
45831
  }
45539
45832
  function logUpdateFailure(stderr) {
45540
45833
  const ts = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
45541
45834
  const logFile = path87.join(LOG_DIR2, `update-${ts}.log`);
45542
45835
  try {
45543
- fs86.mkdirSync(LOG_DIR2, { recursive: true });
45544
- fs86.appendFileSync(logFile, `[update-failure ${(/* @__PURE__ */ new Date()).toISOString()}]
45836
+ fs87.mkdirSync(LOG_DIR2, { recursive: true });
45837
+ fs87.appendFileSync(logFile, `[update-failure ${(/* @__PURE__ */ new Date()).toISOString()}]
45545
45838
  ${stderr}
45546
45839
  `, "utf-8");
45547
45840
  } catch {
@@ -45762,7 +46055,7 @@ function registerBegin(program2) {
45762
46055
  // src/commands/config.ts
45763
46056
  init_global_config();
45764
46057
  init_store2();
45765
- import * as fs87 from "node:fs";
46058
+ import * as fs88 from "node:fs";
45766
46059
  import { createRequire as createRequire4 } from "node:module";
45767
46060
  var _require4 = createRequire4(import.meta.url);
45768
46061
  var { parse: parseWithMap } = _require4("json-source-map");
@@ -45779,14 +46072,14 @@ function registerConfig(program2) {
45779
46072
  const config = program2.command("config").description("Manage global olam configuration");
45780
46073
  config.command("validate [path]").description("Validate ~/.olam/config.json (or a custom path) against the schema").action((filePath) => {
45781
46074
  const resolvedPath = filePath ?? globalConfigPath();
45782
- if (!fs87.existsSync(resolvedPath)) {
46075
+ if (!fs88.existsSync(resolvedPath)) {
45783
46076
  process.stderr.write(`config file not found: ${resolvedPath}
45784
46077
  `);
45785
46078
  process.exit(1);
45786
46079
  }
45787
46080
  let raw;
45788
46081
  try {
45789
- raw = fs87.readFileSync(resolvedPath, "utf-8");
46082
+ raw = fs88.readFileSync(resolvedPath, "utf-8");
45790
46083
  } catch (err) {
45791
46084
  const msg = err instanceof Error ? err.message : String(err);
45792
46085
  process.stderr.write(`cannot read ${resolvedPath}: ${msg}
@@ -46234,9 +46527,9 @@ import * as readline3 from "node:readline";
46234
46527
  import pc37 from "picocolors";
46235
46528
 
46236
46529
  // src/commands/flywheel/install-shims.ts
46237
- import { copyFileSync as copyFileSync9, existsSync as existsSync94, mkdirSync as mkdirSync56, readFileSync as readFileSync82, writeFileSync as writeFileSync48 } from "node:fs";
46238
- import { homedir as homedir56 } from "node:os";
46239
- import { dirname as dirname52, join as join96 } from "node:path";
46530
+ import { copyFileSync as copyFileSync9, existsSync as existsSync96, mkdirSync as mkdirSync57, readFileSync as readFileSync84, writeFileSync as writeFileSync50 } from "node:fs";
46531
+ import { homedir as homedir57 } from "node:os";
46532
+ import { dirname as dirname53, join as join97 } from "node:path";
46240
46533
 
46241
46534
  // src/lib/shim-generator.ts
46242
46535
  var SHIM_SPECS = Object.freeze([
@@ -46299,7 +46592,7 @@ ${argsBlock}
46299
46592
  // src/commands/flywheel/install-shims.ts
46300
46593
  var SHIM_HEADER_MARKER = "# AUTO-GENERATED by `olam flywheel install-shims`";
46301
46594
  function refreshShims(opts = {}) {
46302
- const targetDir = opts.targetDir ?? join96(homedir56(), ".claude", "scripts");
46595
+ const targetDir = opts.targetDir ?? join97(homedir57(), ".claude", "scripts");
46303
46596
  const results = [];
46304
46597
  let written = 0;
46305
46598
  let overwritten = 0;
@@ -46329,22 +46622,22 @@ function isOlamGeneratedShim(text) {
46329
46622
  return text.includes(SHIM_HEADER_MARKER);
46330
46623
  }
46331
46624
  function installOne(spec, targetDir, opts) {
46332
- const targetPath = join96(targetDir, spec.basename);
46625
+ const targetPath = join97(targetDir, spec.basename);
46333
46626
  const newContent = generateShim(spec);
46334
- if (!existsSync94(targetPath)) {
46627
+ if (!existsSync96(targetPath)) {
46335
46628
  if (opts.dryRun !== true) {
46336
- mkdirSync56(dirname52(targetPath), { recursive: true });
46337
- writeFileSync48(targetPath, newContent, { mode: 493 });
46629
+ mkdirSync57(dirname53(targetPath), { recursive: true });
46630
+ writeFileSync50(targetPath, newContent, { mode: 493 });
46338
46631
  }
46339
46632
  return { basename: spec.basename, action: "written", targetPath };
46340
46633
  }
46341
- const existing = readFileSync82(targetPath, "utf8");
46634
+ const existing = readFileSync84(targetPath, "utf8");
46342
46635
  if (existing === newContent) {
46343
46636
  return { basename: spec.basename, action: "unchanged", targetPath };
46344
46637
  }
46345
46638
  if (isOlamGeneratedShim(existing)) {
46346
46639
  if (opts.dryRun !== true) {
46347
- writeFileSync48(targetPath, newContent, { mode: 493 });
46640
+ writeFileSync50(targetPath, newContent, { mode: 493 });
46348
46641
  }
46349
46642
  return { basename: spec.basename, action: "overwritten", targetPath };
46350
46643
  }
@@ -46352,7 +46645,7 @@ function installOne(spec, targetDir, opts) {
46352
46645
  const backupPath = `${targetPath}.shim-backup-${Math.floor(Date.now() / 1e3)}`;
46353
46646
  if (opts.dryRun !== true) {
46354
46647
  copyFileSync9(targetPath, backupPath);
46355
- writeFileSync48(targetPath, newContent, { mode: 493 });
46648
+ writeFileSync50(targetPath, newContent, { mode: 493 });
46356
46649
  }
46357
46650
  return { basename: spec.basename, action: "overwritten", targetPath, backupPath };
46358
46651
  }
@@ -46360,7 +46653,7 @@ function installOne(spec, targetDir, opts) {
46360
46653
  }
46361
46654
  function registerFlywheelInstallShims(parent) {
46362
46655
  parent.command("install-shims").description("Install backwards-compat bash shims under ~/.claude/scripts/ that delegate to olam flywheel <subcmd>").option("--force", "overwrite existing non-shim files (backs them up to .shim-backup-<ts>)").option("--dry-run", "preview which shims would be written without modifying disk").option("--target-dir <path>", "override target directory (default: ~/.claude/scripts/); for tests").action((opts) => {
46363
- const targetDir = opts.targetDir ?? join96(homedir56(), ".claude", "scripts");
46656
+ const targetDir = opts.targetDir ?? join97(homedir57(), ".claude", "scripts");
46364
46657
  const summary2 = refreshShims(opts);
46365
46658
  const lines = [];
46366
46659
  const dryRunSuffix = opts.dryRun === true ? " (dry-run)" : "";
@@ -46413,7 +46706,7 @@ async function decideTrust(opts) {
46413
46706
  return { granted: !denied, method: "interactive" };
46414
46707
  }
46415
46708
  function defaultTrustPrompt(gitUrl) {
46416
- return new Promise((resolve30) => {
46709
+ return new Promise((resolve31) => {
46417
46710
  const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
46418
46711
  process.stdout.write(
46419
46712
  `${pc37.yellow("Trust gate:")} register "${gitUrl}" as a skill source?
@@ -46423,12 +46716,12 @@ Trust this source? ${pc37.dim("[Y/n] ")}`
46423
46716
  );
46424
46717
  rl.question("", (a) => {
46425
46718
  rl.close();
46426
- resolve30(a);
46719
+ resolve31(a);
46427
46720
  });
46428
46721
  });
46429
46722
  }
46430
46723
  function defaultSourcePrefixPrompt(input2) {
46431
- return new Promise((resolve30) => {
46724
+ return new Promise((resolve31) => {
46432
46725
  const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
46433
46726
  const cfg = input2.newConfig;
46434
46727
  const prefixLabel = cfg.prefix !== void 0 ? `'${cfg.prefix}:'` : "(no prefix)";
@@ -46440,12 +46733,12 @@ Adopt for this host? ${pc37.dim("[Y/n] ")}`
46440
46733
  );
46441
46734
  rl.question("", (a) => {
46442
46735
  rl.close();
46443
- resolve30(!/^n(o)?$/i.test(a.trim()));
46736
+ resolve31(!/^n(o)?$/i.test(a.trim()));
46444
46737
  });
46445
46738
  });
46446
46739
  }
46447
46740
  function defaultPostAddPrompt(input2) {
46448
- return new Promise((resolve30) => {
46741
+ return new Promise((resolve31) => {
46449
46742
  const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
46450
46743
  process.stdout.write(`
46451
46744
  ${pc37.bold("Sync now?")} ${pc37.dim("[Y/n] ")}`);
@@ -46453,7 +46746,7 @@ ${pc37.bold("Sync now?")} ${pc37.dim("[Y/n] ")}`);
46453
46746
  const sync = !/^n(o)?$/i.test(syncAnswer.trim());
46454
46747
  if (input2.hookAlreadyInstalled) {
46455
46748
  rl.close();
46456
- resolve30({ syncNow: sync, installHook: false });
46749
+ resolve31({ syncNow: sync, installHook: false });
46457
46750
  return;
46458
46751
  }
46459
46752
  process.stdout.write(
@@ -46462,7 +46755,7 @@ ${pc37.bold("Sync now?")} ${pc37.dim("[Y/n] ")}`);
46462
46755
  rl.question("", (hookAnswer) => {
46463
46756
  rl.close();
46464
46757
  const installHook = !/^n(o)?$/i.test(hookAnswer.trim());
46465
- resolve30({ syncNow: sync, installHook });
46758
+ resolve31({ syncNow: sync, installHook });
46466
46759
  });
46467
46760
  });
46468
46761
  });
@@ -47119,7 +47412,7 @@ function registerSkillsSource(program2) {
47119
47412
  // src/commands/skills.ts
47120
47413
  init_skill_sources();
47121
47414
  init_output();
47122
- import * as fs88 from "node:fs";
47415
+ import * as fs89 from "node:fs";
47123
47416
  import * as os50 from "node:os";
47124
47417
  import * as path88 from "node:path";
47125
47418
  import * as readline4 from "node:readline";
@@ -47130,18 +47423,18 @@ init_markdown_merger();
47130
47423
  init_file_lock();
47131
47424
  import {
47132
47425
  copyFileSync as copyFileSync10,
47133
- existsSync as existsSync95,
47426
+ existsSync as existsSync97,
47134
47427
  lstatSync as lstatSync8,
47135
- mkdirSync as mkdirSync57,
47428
+ mkdirSync as mkdirSync58,
47136
47429
  readdirSync as readdirSync28,
47137
- readFileSync as readFileSync83,
47430
+ readFileSync as readFileSync85,
47138
47431
  readlinkSync as readlinkSync4,
47139
47432
  rmSync as rmSync11,
47140
47433
  statSync as statSync28,
47141
- writeFileSync as writeFileSync49
47434
+ writeFileSync as writeFileSync51
47142
47435
  } from "node:fs";
47143
- import { homedir as homedir57 } from "node:os";
47144
- import { basename as basename8, dirname as dirname53, isAbsolute as isAbsolute4, join as join97, relative as relative5, resolve as resolve23 } from "node:path";
47436
+ import { homedir as homedir58 } from "node:os";
47437
+ import { basename as basename8, dirname as dirname54, isAbsolute as isAbsolute4, join as join98, relative as relative5, resolve as resolve24 } from "node:path";
47145
47438
 
47146
47439
  // src/commands/flywheel/sanitize-persona-output.ts
47147
47440
  var FORBIDDEN_HEADERS = [
@@ -47203,23 +47496,23 @@ function registerFlywheelSanitizePersonaOutput(parent) {
47203
47496
 
47204
47497
  // src/lib/skills-apply-overlays.ts
47205
47498
  function claudeRoot(opts) {
47206
- return opts.claudeDir ?? opts.fixtureRoot ?? join97(homedir57(), ".claude");
47499
+ return opts.claudeDir ?? opts.fixtureRoot ?? join98(homedir58(), ".claude");
47207
47500
  }
47208
47501
  function ensureRealDir(p) {
47209
- if (!existsSync95(p)) {
47210
- mkdirSync57(p, { recursive: true });
47502
+ if (!existsSync97(p)) {
47503
+ mkdirSync58(p, { recursive: true });
47211
47504
  return;
47212
47505
  }
47213
47506
  const stat = lstatSync8(p);
47214
47507
  if (stat.isSymbolicLink()) {
47215
47508
  const targetRaw = readlinkSync4(p);
47216
- const target = isAbsolute4(targetRaw) ? targetRaw : resolve23(dirname53(p), targetRaw);
47509
+ const target = isAbsolute4(targetRaw) ? targetRaw : resolve24(dirname54(p), targetRaw);
47217
47510
  rmSync11(p);
47218
- mkdirSync57(p, { recursive: true });
47219
- if (existsSync95(target) && statSync28(target).isDirectory()) {
47511
+ mkdirSync58(p, { recursive: true });
47512
+ if (existsSync97(target) && statSync28(target).isDirectory()) {
47220
47513
  for (const entry of readdirSync28(target)) {
47221
- const src = join97(target, entry);
47222
- const dest = join97(p, entry);
47514
+ const src = join98(target, entry);
47515
+ const dest = join98(p, entry);
47223
47516
  const srcStat = lstatSync8(src);
47224
47517
  if (srcStat.isDirectory()) {
47225
47518
  try {
@@ -47241,8 +47534,8 @@ function postMergeSanitize(mergedText, label) {
47241
47534
  return { ok: false, reason: `[post-merge-sanitize] ${label} merged output failed sanitizer: ${result.reason}` };
47242
47535
  }
47243
47536
  function mergeOne(upstreamPath, overlayPath, destPath2, label, dryRun, messages) {
47244
- const upstreamText = readFileSync83(upstreamPath, "utf8");
47245
- const overlayText = readFileSync83(overlayPath, "utf8");
47537
+ const upstreamText = readFileSync85(upstreamPath, "utf8");
47538
+ const overlayText = readFileSync85(overlayPath, "utf8");
47246
47539
  const result = mergeMarkdown(upstreamText, overlayText, label, upstreamPath, overlayPath);
47247
47540
  if ("error" in result) {
47248
47541
  messages.push(`ERROR ${result.error.reason}`);
@@ -47254,15 +47547,15 @@ function mergeOne(upstreamPath, overlayPath, destPath2, label, dryRun, messages)
47254
47547
  return { ok: false, kind: "sanitize" };
47255
47548
  }
47256
47549
  if (!dryRun) {
47257
- mkdirSync57(dirname53(destPath2), { recursive: true });
47258
- writeFileSync49(destPath2, result.merged, "utf8");
47550
+ mkdirSync58(dirname54(destPath2), { recursive: true });
47551
+ writeFileSync51(destPath2, result.merged, "utf8");
47259
47552
  }
47260
47553
  messages.push(`MERGED ${label} \u2192 ${destPath2}${dryRun ? " (dry-run)" : ""}`);
47261
47554
  return { ok: true };
47262
47555
  }
47263
47556
  function isNewAgentOverlay(overlayPath) {
47264
47557
  try {
47265
- const text = readFileSync83(overlayPath, "utf8");
47558
+ const text = readFileSync85(overlayPath, "utf8");
47266
47559
  const { fm } = parseFrontmatter3(text);
47267
47560
  return fm["overlay-intent"] === "new-agent";
47268
47561
  } catch {
@@ -47271,18 +47564,18 @@ function isNewAgentOverlay(overlayPath) {
47271
47564
  }
47272
47565
  function copyNewAgent(overlayPath, destPath2, label, dryRun, messages) {
47273
47566
  if (!dryRun) {
47274
- mkdirSync57(dirname53(destPath2), { recursive: true });
47567
+ mkdirSync58(dirname54(destPath2), { recursive: true });
47275
47568
  copyFileSync10(overlayPath, destPath2);
47276
47569
  }
47277
47570
  messages.push(`NEW-AGENT ${label} \u2192 ${destPath2}${dryRun ? " (dry-run)" : ""}`);
47278
47571
  }
47279
47572
  function walkSkillsOverlays(skillsOverridesDir, skillsDir, opts, result) {
47280
- if (!existsSync95(skillsOverridesDir)) return;
47573
+ if (!existsSync97(skillsOverridesDir)) return;
47281
47574
  for (const skillName of readdirSync28(skillsOverridesDir)) {
47282
- const overlaySkillDir = join97(skillsOverridesDir, skillName);
47575
+ const overlaySkillDir = join98(skillsOverridesDir, skillName);
47283
47576
  if (!statSync28(overlaySkillDir).isDirectory()) continue;
47284
- const upstreamSkillDir = join97(skillsDir, skillName);
47285
- if (!existsSync95(upstreamSkillDir)) {
47577
+ const upstreamSkillDir = join98(skillsDir, skillName);
47578
+ if (!existsSync97(upstreamSkillDir)) {
47286
47579
  result.messages.push(`SKIP ${skillName}: no upstream skill at ${upstreamSkillDir} (skill overlays require an upstream skill dir)`);
47287
47580
  continue;
47288
47581
  }
@@ -47295,7 +47588,7 @@ function walkOverlayTree(overlayRoot, upstreamRoot, labelPrefix, opts, result, i
47295
47588
  while (stack.length > 0) {
47296
47589
  const current = stack.pop();
47297
47590
  for (const entry of readdirSync28(current)) {
47298
- const overlayPath = join97(current, entry);
47591
+ const overlayPath = join98(current, entry);
47299
47592
  const stat = lstatSync8(overlayPath);
47300
47593
  if (stat.isDirectory()) {
47301
47594
  stack.push(overlayPath);
@@ -47303,17 +47596,17 @@ function walkOverlayTree(overlayRoot, upstreamRoot, labelPrefix, opts, result, i
47303
47596
  }
47304
47597
  if (!stat.isFile() && !stat.isSymbolicLink()) continue;
47305
47598
  const rel = relative5(overlayRoot, overlayPath);
47306
- const upstreamPath = join97(upstreamRoot, rel);
47599
+ const upstreamPath = join98(upstreamRoot, rel);
47307
47600
  const label = `${labelPrefix} ${rel}`;
47308
47601
  if (!entry.endsWith(".md")) {
47309
47602
  if (!opts.dryRun) {
47310
- mkdirSync57(dirname53(upstreamPath), { recursive: true });
47603
+ mkdirSync58(dirname54(upstreamPath), { recursive: true });
47311
47604
  copyFileSync10(overlayPath, upstreamPath);
47312
47605
  }
47313
47606
  result.messages.push(`COPY ${label} \u2192 ${upstreamPath}${opts.dryRun === true ? " (dry-run)" : ""}`);
47314
47607
  continue;
47315
47608
  }
47316
- if (!existsSync95(upstreamPath)) {
47609
+ if (!existsSync97(upstreamPath)) {
47317
47610
  if (isAgentsContext && isNewAgentOverlay(overlayPath)) {
47318
47611
  copyNewAgent(overlayPath, upstreamPath, label, opts.dryRun === true, result.messages);
47319
47612
  result.newAgentsCreated += 1;
@@ -47322,7 +47615,7 @@ function walkOverlayTree(overlayRoot, upstreamRoot, labelPrefix, opts, result, i
47322
47615
  result.renameHalts += 1;
47323
47616
  } else {
47324
47617
  if (!opts.dryRun) {
47325
- mkdirSync57(dirname53(upstreamPath), { recursive: true });
47618
+ mkdirSync58(dirname54(upstreamPath), { recursive: true });
47326
47619
  copyFileSync10(overlayPath, upstreamPath);
47327
47620
  }
47328
47621
  result.messages.push(`NEW-FILE ${label} \u2192 ${upstreamPath}${opts.dryRun === true ? " (dry-run)" : ""}`);
@@ -47342,16 +47635,16 @@ function walkOverlayTree(overlayRoot, upstreamRoot, labelPrefix, opts, result, i
47342
47635
  }
47343
47636
  }
47344
47637
  function walkAgentsOverlays(agentsOverridesDir, agentsDir, opts, result) {
47345
- if (!existsSync95(agentsOverridesDir)) return;
47638
+ if (!existsSync97(agentsOverridesDir)) return;
47346
47639
  ensureRealDir(agentsDir);
47347
47640
  walkOverlayTree(agentsOverridesDir, agentsDir, "agent", opts, result, true);
47348
47641
  }
47349
47642
  async function applyOverlays(opts = {}) {
47350
47643
  const root = claudeRoot(opts);
47351
- const skillsDir = join97(root, "skills");
47352
- const agentsDir = join97(root, "agents");
47353
- const skillsOverridesDir = join97(root, "skills.overrides");
47354
- const agentsOverridesDir = join97(root, "agents.overrides");
47644
+ const skillsDir = join98(root, "skills");
47645
+ const agentsDir = join98(root, "agents");
47646
+ const skillsOverridesDir = join98(root, "skills.overrides");
47647
+ const agentsOverridesDir = join98(root, "agents.overrides");
47355
47648
  const result = {
47356
47649
  rc: 0,
47357
47650
  skillsMerged: 0,
@@ -47394,6 +47687,44 @@ function formatSummary(result) {
47394
47687
  return lines.join("\n") + "\n";
47395
47688
  }
47396
47689
 
47690
+ // src/commands/skills-install-model-router.ts
47691
+ init_model_router_deploy();
47692
+ init_output();
47693
+ function registerSkillsInstallModelRouter(skills) {
47694
+ skills.command("install-model-router").description("Deploy the model-router.py UserPromptSubmit hook script to ~/.claude/hooks/ (idempotent; auto-run by `olam skills sync`)").option("--dry-run", "preview the action without writing to disk").option("--target-dir <path>", "override target directory (default: ~/.claude/hooks/); for tests").option("--source-path <path>", "override canonical source path; for tests").action((opts) => {
47695
+ try {
47696
+ const result = deployModelRouterScript({
47697
+ ...opts.sourcePath !== void 0 ? { sourcePath: opts.sourcePath } : {},
47698
+ ...opts.targetDir !== void 0 ? { targetDir: opts.targetDir } : {},
47699
+ ...opts.dryRun !== void 0 ? { dryRun: opts.dryRun } : {}
47700
+ });
47701
+ const dryRunSuffix = opts.dryRun === true ? " (dry-run)" : "";
47702
+ switch (result.action) {
47703
+ case "written":
47704
+ process.stdout.write(` WRITTEN ${result.targetPath}${dryRunSuffix}
47705
+ `);
47706
+ break;
47707
+ case "unchanged":
47708
+ process.stdout.write(` UNCHANGED ${result.targetPath}
47709
+ `);
47710
+ break;
47711
+ case "source-missing":
47712
+ printError(
47713
+ `canonical model-router.py source not found \u2014 olam install may be corrupt. Expected at packages/cli/hooks/model-router.py.`
47714
+ );
47715
+ process.exitCode = 2;
47716
+ return;
47717
+ }
47718
+ process.stdout.write(`
47719
+ model-router hook script ready at ${result.targetPath}
47720
+ `);
47721
+ } catch (err) {
47722
+ printError(`[install-model-router-error] ${err instanceof Error ? err.message : "unknown error"}`);
47723
+ process.exitCode = 2;
47724
+ }
47725
+ });
47726
+ }
47727
+
47397
47728
  // src/commands/skills.ts
47398
47729
  function asMessage4(err) {
47399
47730
  return err instanceof Error ? err.message : String(err);
@@ -47401,11 +47732,11 @@ function asMessage4(err) {
47401
47732
  var ATLAS_USER_PICKER_RE = /^[a-z0-9][a-z0-9_-]{0,38}$/;
47402
47733
  function listMemberNames(clonePath) {
47403
47734
  const membersDir = path88.join(clonePath, "members");
47404
- if (!fs88.existsSync(membersDir)) return [];
47735
+ if (!fs89.existsSync(membersDir)) return [];
47405
47736
  try {
47406
- return fs88.readdirSync(membersDir).filter((e) => {
47737
+ return fs89.readdirSync(membersDir).filter((e) => {
47407
47738
  try {
47408
- return fs88.statSync(path88.join(membersDir, e)).isDirectory();
47739
+ return fs89.statSync(path88.join(membersDir, e)).isDirectory();
47409
47740
  } catch {
47410
47741
  return false;
47411
47742
  }
@@ -47421,7 +47752,7 @@ function formatSourcePrefix(cfg) {
47421
47752
  return `${p}${s}`;
47422
47753
  }
47423
47754
  function defaultSourcePrefixSyncPrompt(input2) {
47424
- return new Promise((resolve30) => {
47755
+ return new Promise((resolve31) => {
47425
47756
  const rl = readline4.createInterface({ input: process.stdin, output: process.stdout });
47426
47757
  const newLabel = formatSourcePrefix(input2.newConfig);
47427
47758
  let line;
@@ -47438,16 +47769,16 @@ Accept change? ${pc38.dim("[Y/n] ")}`;
47438
47769
  process.stdout.write(line);
47439
47770
  rl.question("", (a) => {
47440
47771
  rl.close();
47441
- resolve30(!/^n(o)?$/i.test(a.trim()));
47772
+ resolve31(!/^n(o)?$/i.test(a.trim()));
47442
47773
  });
47443
47774
  });
47444
47775
  }
47445
47776
  function defaultAtlasUserPrompt(question) {
47446
- return new Promise((resolve30) => {
47777
+ return new Promise((resolve31) => {
47447
47778
  const rl = readline4.createInterface({ input: process.stdin, output: process.stdout });
47448
47779
  rl.question(question, (a) => {
47449
47780
  rl.close();
47450
- resolve30(a);
47781
+ resolve31(a);
47451
47782
  });
47452
47783
  });
47453
47784
  }
@@ -47456,8 +47787,8 @@ async function resolveAtlasUserWithPicker(cliOverride, opts) {
47456
47787
  const ATLAS_USER_RE2 = /^[a-z0-9][a-z0-9_-]{0,38}$/;
47457
47788
  const claudeDirPathForRead = opts?._testClaudeDir ?? (process.env["OLAM_CLAUDE_DIR"] ?? path88.join(os50.homedir(), ".claude"));
47458
47789
  const atlasUserFile = path88.join(claudeDirPathForRead, ".atlas-user");
47459
- if (fs88.existsSync(atlasUserFile)) {
47460
- const existing = fs88.readFileSync(atlasUserFile, "utf-8").trim();
47790
+ if (fs89.existsSync(atlasUserFile)) {
47791
+ const existing = fs89.readFileSync(atlasUserFile, "utf-8").trim();
47461
47792
  if (existing.length > 0) {
47462
47793
  if (ATLAS_USER_RE2.test(existing)) {
47463
47794
  return existing;
@@ -47517,8 +47848,8 @@ async function resolveAtlasUserWithPicker(cliOverride, opts) {
47517
47848
  return void 0;
47518
47849
  }
47519
47850
  const claudeDirPath = opts?._testClaudeDir ?? (process.env["OLAM_CLAUDE_DIR"] ?? path88.join(os50.homedir(), ".claude"));
47520
- fs88.mkdirSync(claudeDirPath, { recursive: true });
47521
- fs88.writeFileSync(path88.join(claudeDirPath, ".atlas-user"), picked + "\n", "utf8");
47851
+ fs89.mkdirSync(claudeDirPath, { recursive: true });
47852
+ fs89.writeFileSync(path88.join(claudeDirPath, ".atlas-user"), picked + "\n", "utf8");
47522
47853
  process.stdout.write(pc38.green(`\u2713 atlas-user set to "${picked}" (written to ${path88.join(claudeDirPath, ".atlas-user")})
47523
47854
  `));
47524
47855
  return picked;
@@ -47532,13 +47863,13 @@ function listDeployed() {
47532
47863
  const entries = [];
47533
47864
  for (const bucket of ["skills", "agents", "scripts", "rules", "commands"]) {
47534
47865
  const bucketDir = path88.join(dir, bucket);
47535
- if (!fs88.existsSync(bucketDir)) continue;
47536
- for (const name of fs88.readdirSync(bucketDir)) {
47866
+ if (!fs89.existsSync(bucketDir)) continue;
47867
+ for (const name of fs89.readdirSync(bucketDir)) {
47537
47868
  const full = path88.join(bucketDir, name);
47538
47869
  try {
47539
- const stat = fs88.lstatSync(full);
47870
+ const stat = fs89.lstatSync(full);
47540
47871
  if (!stat.isSymbolicLink()) continue;
47541
- const target = fs88.readlinkSync(full);
47872
+ const target = fs89.readlinkSync(full);
47542
47873
  let sourceId;
47543
47874
  for (const [clonePath, id] of sourcePaths.entries()) {
47544
47875
  if (target.startsWith(clonePath)) {
@@ -47754,17 +48085,18 @@ function registerSkills(program2) {
47754
48085
  process.exitCode = 2;
47755
48086
  }
47756
48087
  });
48088
+ registerSkillsInstallModelRouter(skills);
47757
48089
  }
47758
48090
 
47759
48091
  // src/commands/skills-hook.ts
47760
48092
  init_skill_sources();
47761
48093
  init_output();
47762
- import * as fs89 from "node:fs";
48094
+ import * as fs90 from "node:fs";
47763
48095
  function backup(filePath) {
47764
- if (!fs89.existsSync(filePath)) return null;
48096
+ if (!fs90.existsSync(filePath)) return null;
47765
48097
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
47766
48098
  const backupPath = `${filePath}.olam-bak.${ts}`;
47767
- fs89.copyFileSync(filePath, backupPath);
48099
+ fs90.copyFileSync(filePath, backupPath);
47768
48100
  return backupPath;
47769
48101
  }
47770
48102
  function registerSkillsHook(program2) {
@@ -47812,7 +48144,7 @@ function registerSkillsHook(program2) {
47812
48144
  printInfo("olam-skills hook", `not found in ${filePath} \u2014 already uninstalled`);
47813
48145
  if (backupPath) {
47814
48146
  try {
47815
- fs89.unlinkSync(backupPath);
48147
+ fs90.unlinkSync(backupPath);
47816
48148
  } catch {
47817
48149
  }
47818
48150
  }
@@ -47999,24 +48331,24 @@ init_skill_sources();
47999
48331
  init_merge_settings();
48000
48332
  init_skill_sources();
48001
48333
  init_output();
48002
- import * as fs90 from "node:fs";
48334
+ import * as fs91 from "node:fs";
48003
48335
  import * as path89 from "node:path";
48004
48336
  var MIGRATE_FROM_TOOLBOX_COMMAND = "migrate-from-toolbox";
48005
48337
  function asMessage6(err) {
48006
48338
  return err instanceof Error ? err.message : String(err);
48007
48339
  }
48008
48340
  function isOlamSkillsHookPresent(filePath) {
48009
- if (!fs90.existsSync(filePath)) return false;
48341
+ if (!fs91.existsSync(filePath)) return false;
48010
48342
  try {
48011
- const raw = fs90.readFileSync(filePath, "utf-8");
48343
+ const raw = fs91.readFileSync(filePath, "utf-8");
48012
48344
  return raw.includes(OLAM_SKILLS_HOOK_SENTINEL);
48013
48345
  } catch {
48014
48346
  return false;
48015
48347
  }
48016
48348
  }
48017
48349
  function uninstallLegacyToolboxSessionStartHook(filePath, toolboxPath) {
48018
- if (!fs90.existsSync(filePath)) return { removed: 0 };
48019
- const raw = fs90.readFileSync(filePath, "utf-8");
48350
+ if (!fs91.existsSync(filePath)) return { removed: 0 };
48351
+ const raw = fs91.readFileSync(filePath, "utf-8");
48020
48352
  const settings = raw.trim() ? JSON.parse(raw) : {};
48021
48353
  const ss = settings?.hooks?.SessionStart;
48022
48354
  if (!Array.isArray(ss)) return { removed: 0 };
@@ -48045,7 +48377,7 @@ function uninstallLegacyToolboxSessionStartHook(filePath, toolboxPath) {
48045
48377
  if (otherStages.length === 0) delete next.hooks;
48046
48378
  else delete next.hooks.SessionStart;
48047
48379
  }
48048
- fs90.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
48380
+ fs91.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
48049
48381
  return { removed };
48050
48382
  }
48051
48383
  function registerSkillsMigrate(program2) {
@@ -48124,7 +48456,7 @@ function registerSkillsMigrate(program2) {
48124
48456
  const scope = opts.scope === "user" ? "user" : "project";
48125
48457
  const olamHookPath = scope === "user" ? settingsFile : path89.join(process.cwd(), ".claude", "settings.json");
48126
48458
  try {
48127
- fs90.mkdirSync(path89.dirname(olamHookPath), { recursive: true });
48459
+ fs91.mkdirSync(path89.dirname(olamHookPath), { recursive: true });
48128
48460
  const result = mergeHomeSettingsJson(olamHookPath, {
48129
48461
  ensureHook: {
48130
48462
  stage: OLAM_SKILLS_HOOK_STAGE,
@@ -48157,7 +48489,7 @@ function registerSkillsMigrate(program2) {
48157
48489
  // src/commands/skills-migrate-back.ts
48158
48490
  init_skill_sources();
48159
48491
  init_output();
48160
- import * as fs91 from "node:fs";
48492
+ import * as fs92 from "node:fs";
48161
48493
  import * as path90 from "node:path";
48162
48494
  var MIGRATE_BACK_TO_TOOLBOX_COMMAND = "migrate-back-to-toolbox";
48163
48495
  function asMessage7(err) {
@@ -48173,9 +48505,9 @@ function restoreSessionStartFromSnapshot(filePath, originalSessionStartHook) {
48173
48505
  return { restored: false };
48174
48506
  }
48175
48507
  let settings;
48176
- if (fs91.existsSync(filePath)) {
48508
+ if (fs92.existsSync(filePath)) {
48177
48509
  try {
48178
- const raw = fs91.readFileSync(filePath, "utf-8");
48510
+ const raw = fs92.readFileSync(filePath, "utf-8");
48179
48511
  settings = raw.trim() ? JSON.parse(raw) : {};
48180
48512
  } catch {
48181
48513
  settings = {};
@@ -48191,8 +48523,8 @@ function restoreSessionStartFromSnapshot(filePath, originalSessionStartHook) {
48191
48523
  SessionStart: originalSessionStartHook
48192
48524
  }
48193
48525
  };
48194
- fs91.mkdirSync(path90.dirname(filePath), { recursive: true });
48195
- fs91.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
48526
+ fs92.mkdirSync(path90.dirname(filePath), { recursive: true });
48527
+ fs92.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
48196
48528
  return { restored: true };
48197
48529
  }
48198
48530
  function removeOlamManagedSymlinks() {
@@ -48202,15 +48534,15 @@ function removeOlamManagedSymlinks() {
48202
48534
  let removed = 0;
48203
48535
  for (const bucket of ["skills", "agents", "scripts", "rules", "commands"]) {
48204
48536
  const dir = path90.join(claude, bucket);
48205
- if (!fs91.existsSync(dir)) continue;
48206
- for (const name of fs91.readdirSync(dir)) {
48537
+ if (!fs92.existsSync(dir)) continue;
48538
+ for (const name of fs92.readdirSync(dir)) {
48207
48539
  const linkPath = path90.join(dir, name);
48208
48540
  try {
48209
- const stat = fs91.lstatSync(linkPath);
48541
+ const stat = fs92.lstatSync(linkPath);
48210
48542
  if (!stat.isSymbolicLink()) continue;
48211
- const target = fs91.readlinkSync(linkPath);
48543
+ const target = fs92.readlinkSync(linkPath);
48212
48544
  if (olamClonePaths.some((cp) => target.startsWith(cp))) {
48213
- fs91.unlinkSync(linkPath);
48545
+ fs92.unlinkSync(linkPath);
48214
48546
  removed += 1;
48215
48547
  }
48216
48548
  } catch {
@@ -48223,18 +48555,18 @@ function restoreToolboxSymlinks(symlinks) {
48223
48555
  let restored = 0;
48224
48556
  for (const { link, target } of symlinks) {
48225
48557
  try {
48226
- fs91.mkdirSync(path90.dirname(link), { recursive: true });
48227
- if (fs91.existsSync(link) || (() => {
48558
+ fs92.mkdirSync(path90.dirname(link), { recursive: true });
48559
+ if (fs92.existsSync(link) || (() => {
48228
48560
  try {
48229
- fs91.lstatSync(link);
48561
+ fs92.lstatSync(link);
48230
48562
  return true;
48231
48563
  } catch {
48232
48564
  return false;
48233
48565
  }
48234
48566
  })()) {
48235
- fs91.unlinkSync(link);
48567
+ fs92.unlinkSync(link);
48236
48568
  }
48237
- fs91.symlinkSync(target, link);
48569
+ fs92.symlinkSync(target, link);
48238
48570
  restored += 1;
48239
48571
  } catch {
48240
48572
  }
@@ -48244,8 +48576,8 @@ function restoreToolboxSymlinks(symlinks) {
48244
48576
  function restoreAtlasUserMarker(atlasUser) {
48245
48577
  if (!atlasUser) return false;
48246
48578
  const file = path90.join(claudeDirInternal4(), ".atlas-user");
48247
- fs91.mkdirSync(path90.dirname(file), { recursive: true });
48248
- fs91.writeFileSync(file, atlasUser);
48579
+ fs92.mkdirSync(path90.dirname(file), { recursive: true });
48580
+ fs92.writeFileSync(file, atlasUser);
48249
48581
  return true;
48250
48582
  }
48251
48583
  function registerSkillsMigrateBack(program2) {
@@ -48259,7 +48591,7 @@ function registerSkillsMigrateBack(program2) {
48259
48591
  try {
48260
48592
  if (opts.snapshot) {
48261
48593
  snapshotPath = path90.resolve(opts.snapshot);
48262
- if (!fs91.existsSync(snapshotPath)) {
48594
+ if (!fs92.existsSync(snapshotPath)) {
48263
48595
  printError(`snapshot not found at ${snapshotPath}`);
48264
48596
  process.exitCode = 1;
48265
48597
  return;
@@ -48343,7 +48675,7 @@ init_meta_hooks_migration_snapshot();
48343
48675
  init_trust_audit_log();
48344
48676
  init_atlas_hook_strip();
48345
48677
  init_output();
48346
- import * as fs92 from "node:fs";
48678
+ import * as fs93 from "node:fs";
48347
48679
  import * as path91 from "node:path";
48348
48680
  import pc40 from "picocolors";
48349
48681
  var MIGRATE_HOOKS_COMMAND = "migrate-hooks";
@@ -48365,16 +48697,16 @@ function settingsHasOlamMetaSentinel(settings) {
48365
48697
  return false;
48366
48698
  }
48367
48699
  function readSettings2(filePath) {
48368
- if (!fs92.existsSync(filePath)) return null;
48369
- const raw = fs92.readFileSync(filePath, "utf-8");
48700
+ if (!fs93.existsSync(filePath)) return null;
48701
+ const raw = fs93.readFileSync(filePath, "utf-8");
48370
48702
  if (raw.trim().length === 0) return {};
48371
48703
  return JSON.parse(raw);
48372
48704
  }
48373
48705
  function writeSettings(filePath, settings) {
48374
- fs92.mkdirSync(path91.dirname(filePath), { recursive: true });
48706
+ fs93.mkdirSync(path91.dirname(filePath), { recursive: true });
48375
48707
  const tmp = `${filePath}.tmp-migrate-hooks-${process.pid}-${Date.now()}`;
48376
- fs92.writeFileSync(tmp, JSON.stringify(settings, null, 2) + "\n");
48377
- fs92.renameSync(tmp, filePath);
48708
+ fs93.writeFileSync(tmp, JSON.stringify(settings, null, 2) + "\n");
48709
+ fs93.renameSync(tmp, filePath);
48378
48710
  }
48379
48711
  function printSummary(candidates2, opts) {
48380
48712
  if (candidates2.length === 0) {
@@ -48509,7 +48841,7 @@ function registerSkillsMigrateHooksBack(program2) {
48509
48841
  // src/commands/skills-shadow-backups.ts
48510
48842
  init_skill_sources();
48511
48843
  init_output();
48512
- import * as fs93 from "node:fs";
48844
+ import * as fs94 from "node:fs";
48513
48845
  import pc41 from "picocolors";
48514
48846
  function asMessage10(err) {
48515
48847
  return err instanceof Error ? err.message : String(err);
@@ -48592,7 +48924,7 @@ function registerSkillsShadowBackups(program2) {
48592
48924
  });
48593
48925
  sb.command("restore").description("Move a shadow-backup file back to its original path").argument("<path>", "Absolute path to the .shadow-backup-<epoch> file").option("--force", "Overwrite the original path if it already exists").action((p, opts) => {
48594
48926
  try {
48595
- if (!fs93.existsSync(p)) {
48927
+ if (!fs94.existsSync(p)) {
48596
48928
  printError(`backup file not found: ${p}`);
48597
48929
  process.exitCode = 1;
48598
48930
  return;
@@ -48615,11 +48947,11 @@ function asMessage11(err) {
48615
48947
  return err instanceof Error ? err.message : String(err);
48616
48948
  }
48617
48949
  function defaultDoctorPrompt(question) {
48618
- return new Promise((resolve30) => {
48950
+ return new Promise((resolve31) => {
48619
48951
  const rl = readline5.createInterface({ input: process.stdin, output: process.stdout });
48620
48952
  rl.question(question, (a) => {
48621
48953
  rl.close();
48622
- resolve30(a);
48954
+ resolve31(a);
48623
48955
  });
48624
48956
  });
48625
48957
  }
@@ -48710,23 +49042,26 @@ function registerSkillsDoctor(program2) {
48710
49042
  });
48711
49043
  }
48712
49044
 
48713
- // src/commands/skills-10x.ts
49045
+ // src/commands/skills-100x.ts
48714
49046
  init_skill_sources();
48715
49047
  init_cli_version();
48716
49048
  init_output();
48717
49049
  import { execFileSync as execFileSync17 } from "node:child_process";
48718
- import * as fs94 from "node:fs";
49050
+ import * as fs95 from "node:fs";
48719
49051
  import * as path93 from "node:path";
48720
49052
  var CHAIN_SKILL_NAMES = [
48721
- "10x:brainstorm",
48722
- "10x:plan-hard",
48723
- "10x:review-plan",
48724
- "10x:break-plan",
48725
- "10x:commit-plan",
48726
- "10x:execute",
48727
- "10x:retro",
48728
- "10x:learn"
49053
+ "100x:brainstorm",
49054
+ "100x:plan-hard",
49055
+ "100x:review-plan",
49056
+ "100x:break-plan",
49057
+ "100x:commit-plan",
49058
+ "100x:execute",
49059
+ "100x:retro",
49060
+ "100x:learn"
48729
49061
  ];
49062
+ var PLUGIN_MARKETPLACE = "atlas-builders/atlas-toolbox";
49063
+ var PLUGIN_SPEC = "100x@atlas-one";
49064
+ var PLUGIN_SCOPES = ["user", "project", "local"];
48730
49065
  function asMessage12(err) {
48731
49066
  return err instanceof Error ? err.message : String(err);
48732
49067
  }
@@ -48739,13 +49074,13 @@ function hasBeadsCli() {
48739
49074
  }
48740
49075
  }
48741
49076
  function hasBeadsProjectInit(cwd) {
48742
- return fs94.existsSync(path93.join(cwd, ".beads"));
49077
+ return fs95.existsSync(path93.join(cwd, ".beads"));
48743
49078
  }
48744
49079
  function hasBeadsClaudeSetup() {
48745
49080
  const settingsPath = path93.join(claudeDir(), "settings.json");
48746
- if (!fs94.existsSync(settingsPath)) return false;
49081
+ if (!fs95.existsSync(settingsPath)) return false;
48747
49082
  try {
48748
- const content = fs94.readFileSync(settingsPath, "utf8");
49083
+ const content = fs95.readFileSync(settingsPath, "utf8");
48749
49084
  return /"command"\s*:\s*"bd\b/.test(content) || /"bd setup\b/.test(content);
48750
49085
  } catch {
48751
49086
  return false;
@@ -48782,6 +49117,37 @@ async function bootstrapBeads(cwd) {
48782
49117
  console.log("beads Claude hooks already installed \u2014 skipping bd setup");
48783
49118
  }
48784
49119
  }
49120
+ function normalizeScope(raw) {
49121
+ if (raw === void 0) return "user";
49122
+ if (PLUGIN_SCOPES.includes(raw)) {
49123
+ return raw;
49124
+ }
49125
+ throw new Error(
49126
+ `invalid --scope '${raw}' \u2014 expected one of: ${PLUGIN_SCOPES.join(", ")}`
49127
+ );
49128
+ }
49129
+ function addPluginMarketplace(scope) {
49130
+ console.log(
49131
+ `claude plugin marketplace add ${PLUGIN_MARKETPLACE} (scope: ${scope})`
49132
+ );
49133
+ try {
49134
+ execFileSync17(
49135
+ "claude",
49136
+ ["plugin", "marketplace", "add", PLUGIN_MARKETPLACE, "--scope", scope],
49137
+ { stdio: "inherit" }
49138
+ );
49139
+ } catch (err) {
49140
+ printWarning(
49141
+ `claude plugin marketplace add returned an error (continuing \u2014 likely already added): ${asMessage12(err)}`
49142
+ );
49143
+ }
49144
+ }
49145
+ function installPlugin(scope) {
49146
+ console.log(`claude plugin install ${PLUGIN_SPEC} (scope: ${scope})`);
49147
+ execFileSync17("claude", ["plugin", "install", PLUGIN_SPEC, "--scope", scope], {
49148
+ stdio: "inherit"
49149
+ });
49150
+ }
48785
49151
  function captureSourceShas() {
48786
49152
  return listSkillSources().map((s) => ({
48787
49153
  id: s.id,
@@ -48811,11 +49177,11 @@ function shortSha(sha) {
48811
49177
  }
48812
49178
  function listInstalledClaudeSkills() {
48813
49179
  const skillsDir = path93.join(claudeDir(), "skills");
48814
- if (!fs94.existsSync(skillsDir)) return [];
49180
+ if (!fs95.existsSync(skillsDir)) return [];
48815
49181
  try {
48816
- return fs94.readdirSync(skillsDir).filter((name) => {
49182
+ return fs95.readdirSync(skillsDir).filter((name) => {
48817
49183
  try {
48818
- const stat = fs94.lstatSync(path93.join(skillsDir, name));
49184
+ const stat = fs95.lstatSync(path93.join(skillsDir, name));
48819
49185
  return stat.isSymbolicLink() || stat.isDirectory();
48820
49186
  } catch {
48821
49187
  return false;
@@ -48828,24 +49194,64 @@ function listInstalledClaudeSkills() {
48828
49194
  function isChainSkill(name) {
48829
49195
  const lower = name.toLowerCase();
48830
49196
  return CHAIN_SKILL_NAMES.some((canonical) => {
48831
- const slug = canonical.replace(/^10x:/, "");
48832
- return lower === canonical.toLowerCase() || lower === slug || lower === `10x-${slug}`;
49197
+ const slug = canonical.replace(/^100x:/, "");
49198
+ return lower === canonical.toLowerCase() || lower === slug || lower === `100x-${slug}` || // Legacy pre-rename forms (10x:slug / 10x-slug).
49199
+ lower === `10x:${slug}` || lower === `10x-${slug}`;
48833
49200
  });
48834
49201
  }
48835
- function registerSkills10x(program2) {
48836
- const skills = program2.commands.find((c) => c.name() === "skills") ?? program2.command("skills").description("Manage skill sources and synchronization");
48837
- const tenx = skills.command("10x").description(
48838
- "Manage the /10x: planning chain skills + beads integration"
49202
+ function registerSkills100x(program2) {
49203
+ registerTopLevel100x(program2);
49204
+ registerDeprecatedSkills10xAlias(program2);
49205
+ }
49206
+ function registerTopLevel100x(program2) {
49207
+ const onex = program2.command("100x").description(
49208
+ "Install the /100x: planning chain as a native Claude Code plugin + beads integration"
48839
49209
  );
49210
+ onex.command("install").description(
49211
+ "Install the native Claude Code plugin (claude plugin marketplace add + plugin install) + auto-bootstrap beads (bd init + bd setup claude)."
49212
+ ).option("--no-beads", "Skip beads auto-bootstrap (plugin install only)").option(
49213
+ "--scope <scope>",
49214
+ "Plugin scope passed through to claude (user|project|local)",
49215
+ "user"
49216
+ ).action(async (opts) => {
49217
+ try {
49218
+ const scope = normalizeScope(opts.scope);
49219
+ console.log(
49220
+ "Installing the /100x: chain via the native Claude Code plugin..."
49221
+ );
49222
+ addPluginMarketplace(scope);
49223
+ installPlugin(scope);
49224
+ printSuccess(`Installed plugin ${PLUGIN_SPEC} (scope: ${scope})`);
49225
+ if (opts.beads !== false) {
49226
+ await bootstrapBeads(process.cwd());
49227
+ } else {
49228
+ console.log("--no-beads \u2014 skipping beads auto-bootstrap");
49229
+ }
49230
+ printSuccess("olam 100x install complete");
49231
+ } catch (err) {
49232
+ printError(`Install failed: ${asMessage12(err)}`);
49233
+ process.exitCode = 1;
49234
+ }
49235
+ });
49236
+ }
49237
+ function registerDeprecatedSkills10xAlias(program2) {
49238
+ const skills = program2.commands.find((c) => c.name() === "skills") ?? program2.command("skills").description("Manage skill sources and synchronization");
49239
+ const tenx = skills.command("10x", { hidden: true }).description(
49240
+ "DEPRECATED \u2014 use `olam 100x install`. Manage the /100x: planning chain skills via syncSkills() + beads."
49241
+ ).hook("preAction", () => {
49242
+ printWarning(
49243
+ "DEPRECATED: `olam skills 10x` \u2014 use `olam 100x install` (native Claude Code plugin) instead."
49244
+ );
49245
+ });
48840
49246
  tenx.command("install").description(
48841
- "Sync /10x: chain skills from registered sources + auto-bootstrap beads (bd init + bd setup claude). Surfaces source-SHA bumps + shadow-backups for sentinel-versioned upgrade."
49247
+ "Sync /100x: chain skills from registered sources + auto-bootstrap beads (bd init + bd setup claude). Surfaces source-SHA bumps + shadow-backups for sentinel-versioned upgrade."
48842
49248
  ).option("--no-beads", "Skip beads auto-bootstrap (chain skills only)").option(
48843
49249
  "--force",
48844
49250
  "Suppress shadow-backup warning + proceed without operator attention (shadow backups are still created by the sync engine; this flag only suppresses the surface-prominence)"
48845
49251
  ).action(async (opts) => {
48846
49252
  try {
48847
49253
  const preSync = captureSourceShas();
48848
- console.log("Syncing /10x: chain skills from registered sources...");
49254
+ console.log("Syncing /100x: chain skills from registered sources...");
48849
49255
  const summary2 = await syncSkills({});
48850
49256
  printSuccess(
48851
49257
  `Synced ${summary2.artifactCount} artifact(s) from ${summary2.sourceCount} source(s)`
@@ -48888,43 +49294,43 @@ function registerSkills10x(program2) {
48888
49294
  }
48889
49295
  });
48890
49296
  tenx.command("uninstall").description(
48891
- "Remove /10x: chain skill symlinks from ~/.claude/skills (preserves user-authored skills + non-chain skill sources)"
49297
+ "Remove /100x: chain skill symlinks from ~/.claude/skills (preserves user-authored skills + non-chain skill sources)"
48892
49298
  ).action(() => {
48893
49299
  const skillsDir = path93.join(claudeDir(), "skills");
48894
- if (!fs94.existsSync(skillsDir)) {
49300
+ if (!fs95.existsSync(skillsDir)) {
48895
49301
  printWarning("No ~/.claude/skills/ directory found; nothing to uninstall");
48896
49302
  return;
48897
49303
  }
48898
49304
  let removed = 0;
48899
- for (const name of fs94.readdirSync(skillsDir)) {
49305
+ for (const name of fs95.readdirSync(skillsDir)) {
48900
49306
  const full = path93.join(skillsDir, name);
48901
49307
  try {
48902
- const stat = fs94.lstatSync(full);
49308
+ const stat = fs95.lstatSync(full);
48903
49309
  if (!stat.isSymbolicLink()) continue;
48904
- const target = fs94.readlinkSync(full);
48905
- if (isChainSkill(name) || /\/10x[-:]/.test(target)) {
48906
- fs94.unlinkSync(full);
49310
+ const target = fs95.readlinkSync(full);
49311
+ if (isChainSkill(name) || /\/(100x|10x)[-:]/.test(target)) {
49312
+ fs95.unlinkSync(full);
48907
49313
  removed += 1;
48908
49314
  }
48909
49315
  } catch {
48910
49316
  }
48911
49317
  }
48912
- printSuccess(`Removed ${removed} /10x: chain skill symlink(s)`);
49318
+ printSuccess(`Removed ${removed} /100x: chain skill symlink(s)`);
48913
49319
  console.log("User-authored + non-chain skill sources preserved");
48914
49320
  });
48915
49321
  tenx.command("doctor").description(
48916
- "Diagnose /10x: chain skill installation + beads bootstrap state"
49322
+ "Diagnose /100x: chain skill installation + beads bootstrap state"
48917
49323
  ).action(() => {
48918
- console.log("=== /10x: chain skills + beads health ===");
49324
+ console.log("=== /100x: chain skills + beads health ===");
48919
49325
  const installed = listInstalledClaudeSkills();
48920
49326
  const chainInstalled = installed.filter(isChainSkill);
48921
49327
  console.log(
48922
- ` /10x: chain skills: ${chainInstalled.length} / ${CHAIN_SKILL_NAMES.length} installed`
49328
+ ` /100x: chain skills: ${chainInstalled.length} / ${CHAIN_SKILL_NAMES.length} installed`
48923
49329
  );
48924
49330
  for (const canonical of CHAIN_SKILL_NAMES) {
48925
- const slug = canonical.replace(/^10x:/, "");
49331
+ const slug = canonical.replace(/^100x:/, "");
48926
49332
  const found = installed.some(
48927
- (n) => n.toLowerCase() === canonical.toLowerCase() || n.toLowerCase() === slug || n.toLowerCase() === `10x-${slug}`
49333
+ (n) => n.toLowerCase() === canonical.toLowerCase() || n.toLowerCase() === slug || n.toLowerCase() === `100x-${slug}` || n.toLowerCase() === `10x:${slug}` || n.toLowerCase() === `10x-${slug}`
48928
49334
  );
48929
49335
  console.log(` ${found ? "\u2713" : "\u2717"} ${canonical}`);
48930
49336
  }
@@ -48937,11 +49343,11 @@ function registerSkills10x(program2) {
48937
49343
  const allChainPresent = chainInstalled.length === CHAIN_SKILL_NAMES.length;
48938
49344
  const allOk = allChainPresent && bdCli && bdInit && bdHooks;
48939
49345
  if (allOk) {
48940
- printSuccess("All /10x: chain skill + beads checks pass");
49346
+ printSuccess("All /100x: chain skill + beads checks pass");
48941
49347
  return;
48942
49348
  }
48943
49349
  const fixHints = [];
48944
- if (!allChainPresent) fixHints.push("olam skills 10x install");
49350
+ if (!allChainPresent) fixHints.push("olam 100x install");
48945
49351
  if (!bdCli) fixHints.push("brew install beads OR npm i -g @beads/bd");
48946
49352
  if (!bdInit) fixHints.push("bd init");
48947
49353
  if (!bdHooks) fixHints.push("bd setup claude");
@@ -48955,7 +49361,7 @@ function registerSkills10x(program2) {
48955
49361
  const olamVersion = readCliVersion();
48956
49362
  const sources = listSkillSources();
48957
49363
  console.log(`olam-cli: ${olamVersion}`);
48958
- console.log(`chain canonical: ${CHAIN_SKILL_NAMES.length} skills (/10x: chain)`);
49364
+ console.log(`chain canonical: ${CHAIN_SKILL_NAMES.length} skills (/100x: chain)`);
48959
49365
  console.log(`registered sources: ${sources.length}`);
48960
49366
  for (const s of sources) {
48961
49367
  const shortId = s.id ? s.id.slice(0, 8) : "????????";
@@ -48971,7 +49377,7 @@ function registerSkills10x(program2) {
48971
49377
 
48972
49378
  // src/commands/hermes.ts
48973
49379
  init_output();
48974
- import * as fs95 from "node:fs";
49380
+ import * as fs96 from "node:fs";
48975
49381
  import * as os51 from "node:os";
48976
49382
  import * as path94 from "node:path";
48977
49383
  import * as child_process from "node:child_process";
@@ -48986,7 +49392,7 @@ function claudeSkillsDir() {
48986
49392
  return path94.join(os51.homedir(), ".claude", "skills");
48987
49393
  }
48988
49394
  function readHermesConfig(configPath) {
48989
- const raw = fs95.readFileSync(configPath, "utf-8");
49395
+ const raw = fs96.readFileSync(configPath, "utf-8");
48990
49396
  const parsed = yamlParse2(raw);
48991
49397
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
48992
49398
  throw new Error(`${configPath} is not a YAML mapping`);
@@ -48994,13 +49400,13 @@ function readHermesConfig(configPath) {
48994
49400
  return parsed;
48995
49401
  }
48996
49402
  function writeHermesConfig(configPath, config) {
48997
- fs95.writeFileSync(configPath, yamlStringify3(config), "utf-8");
49403
+ fs96.writeFileSync(configPath, yamlStringify3(config), "utf-8");
48998
49404
  }
48999
49405
  function resolveOlamBinary() {
49000
49406
  try {
49001
49407
  const result = child_process.spawnSync("which", ["olam"], { encoding: "utf-8" });
49002
49408
  const found = result.stdout.trim();
49003
- if (found && fs95.existsSync(found)) return found;
49409
+ if (found && fs96.existsSync(found)) return found;
49004
49410
  } catch {
49005
49411
  }
49006
49412
  return process.argv[1] ?? "olam";
@@ -49013,7 +49419,7 @@ function resolveWorkspaceDir() {
49013
49419
  { encoding: "utf-8" }
49014
49420
  );
49015
49421
  const out = result.stdout.trim();
49016
- if (out && fs95.existsSync(out)) return out;
49422
+ if (out && fs96.existsSync(out)) return out;
49017
49423
  } catch {
49018
49424
  }
49019
49425
  return process.cwd();
@@ -49083,22 +49489,22 @@ function ensureTerminalBackendLocal(config, dryRun, summary2) {
49083
49489
  }
49084
49490
  function mirrorSkillSymlinks(dryRun, summary2) {
49085
49491
  const srcDir = claudeSkillsDir();
49086
- if (!fs95.existsSync(srcDir)) {
49492
+ if (!fs96.existsSync(srcDir)) {
49087
49493
  summary2.skipped.push("skills mirror (no ~/.claude/skills/ found)");
49088
49494
  return;
49089
49495
  }
49090
49496
  const destDir = hermesSkillsDir();
49091
49497
  if (!dryRun) {
49092
- fs95.mkdirSync(destDir, { recursive: true });
49498
+ fs96.mkdirSync(destDir, { recursive: true });
49093
49499
  }
49094
- const entries = fs95.readdirSync(srcDir);
49500
+ const entries = fs96.readdirSync(srcDir);
49095
49501
  let mirrored = 0;
49096
49502
  let collisions = 0;
49097
49503
  for (const entry of entries) {
49098
49504
  const srcPath = path94.join(srcDir, entry);
49099
49505
  const destPath2 = path94.join(destDir, entry);
49100
- if (fs95.existsSync(destPath2) || fs95.lstatSync(srcPath).isFile()) {
49101
- if (fs95.existsSync(destPath2)) collisions++;
49506
+ if (fs96.existsSync(destPath2) || fs96.lstatSync(srcPath).isFile()) {
49507
+ if (fs96.existsSync(destPath2)) collisions++;
49102
49508
  continue;
49103
49509
  }
49104
49510
  if (dryRun) {
@@ -49106,7 +49512,7 @@ function mirrorSkillSymlinks(dryRun, summary2) {
49106
49512
  continue;
49107
49513
  }
49108
49514
  try {
49109
- fs95.symlinkSync(srcPath, destPath2);
49515
+ fs96.symlinkSync(srcPath, destPath2);
49110
49516
  mirrored++;
49111
49517
  } catch (err) {
49112
49518
  printWarning(`skills mirror: skipping ${entry} \u2014 ${err instanceof Error ? err.message : String(err)}`);
@@ -49125,7 +49531,7 @@ async function runHermesBootstrap(opts, deps = {}) {
49125
49531
  const writeConfig2 = deps.writeConfig ?? writeHermesConfig;
49126
49532
  const mirrorSkillsFn = deps.mirrorSkills ?? mirrorSkillSymlinks;
49127
49533
  const installHookFn = deps.installHook ?? installKgFirstHookForHermes;
49128
- if (!fs95.existsSync(configPath)) {
49534
+ if (!fs96.existsSync(configPath)) {
49129
49535
  printError(`~/.hermes/config.yaml not found at ${configPath}`);
49130
49536
  printInfo(
49131
49537
  "remedy",
@@ -49242,7 +49648,7 @@ function registerStop(program2) {
49242
49648
  }
49243
49649
 
49244
49650
  // src/lib/upgrade-check.ts
49245
- import * as fs96 from "node:fs";
49651
+ import * as fs97 from "node:fs";
49246
49652
  import * as os52 from "node:os";
49247
49653
  import * as path95 from "node:path";
49248
49654
  var UPGRADE_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
@@ -49261,7 +49667,7 @@ function isNewer(latest, current) {
49261
49667
  }
49262
49668
  function readCache(cachePath) {
49263
49669
  try {
49264
- const raw = fs96.readFileSync(cachePath, "utf-8");
49670
+ const raw = fs97.readFileSync(cachePath, "utf-8");
49265
49671
  const parsed = JSON.parse(raw);
49266
49672
  if (typeof parsed === "object" && parsed !== null && typeof parsed["checkedAt"] === "number" && typeof parsed["latestVersion"] === "string") {
49267
49673
  return parsed;
@@ -49273,8 +49679,8 @@ function readCache(cachePath) {
49273
49679
  function writeCache(cachePath, data) {
49274
49680
  try {
49275
49681
  const dir = path95.dirname(cachePath);
49276
- fs96.mkdirSync(dir, { recursive: true });
49277
- fs96.writeFileSync(cachePath, JSON.stringify(data), "utf-8");
49682
+ fs97.mkdirSync(dir, { recursive: true });
49683
+ fs97.writeFileSync(cachePath, JSON.stringify(data), "utf-8");
49278
49684
  } catch {
49279
49685
  }
49280
49686
  }
@@ -49417,17 +49823,17 @@ function registerWorldUpgrade(program2) {
49417
49823
 
49418
49824
  // src/commands/mcp/serve.ts
49419
49825
  init_output();
49420
- import { existsSync as existsSync104 } from "node:fs";
49421
- import { dirname as dirname59, resolve as resolve26 } from "node:path";
49422
- import { fileURLToPath as fileURLToPath9 } from "node:url";
49423
- var here2 = dirname59(fileURLToPath9(import.meta.url));
49826
+ import { existsSync as existsSync106 } from "node:fs";
49827
+ import { dirname as dirname60, resolve as resolve27 } from "node:path";
49828
+ import { fileURLToPath as fileURLToPath10 } from "node:url";
49829
+ var here2 = dirname60(fileURLToPath10(import.meta.url));
49424
49830
  var BUNDLE_PATH_CANDIDATES = [
49425
49831
  // bundled (`dist/index.js` after bundle-cli.mjs) — sibling
49426
- resolve26(here2, "mcp-server.js"),
49832
+ resolve27(here2, "mcp-server.js"),
49427
49833
  // dev / tsc-only (`dist/commands/mcp/serve.js`) — up two levels
49428
- resolve26(here2, "..", "..", "mcp-server.js")
49834
+ resolve27(here2, "..", "..", "mcp-server.js")
49429
49835
  ];
49430
- function resolveBundlePath(candidates2 = BUNDLE_PATH_CANDIDATES, exists = existsSync104) {
49836
+ function resolveBundlePath(candidates2 = BUNDLE_PATH_CANDIDATES, exists = existsSync106) {
49431
49837
  return candidates2.find(exists) ?? null;
49432
49838
  }
49433
49839
  var MISSING_BUNDLE_REMEDY = "olam mcp server bundle missing. Searched: " + BUNDLE_PATH_CANDIDATES.join(", ") + ". For local dev, run: node packages/cli/scripts/bundle-mcp-server.mjs. A fresh `npm install -g @pleri/olam-cli@latest` should always include the bundle (see prepublishOnly in packages/cli/package.json); file an issue if it does not.";
@@ -49691,7 +50097,7 @@ function registerMcpComplete(cmd) {
49691
50097
  init_output();
49692
50098
  import * as readline6 from "node:readline";
49693
50099
  async function readTokenSilent(prompt) {
49694
- return new Promise((resolve30, reject) => {
50100
+ return new Promise((resolve31, reject) => {
49695
50101
  const rl = readline6.createInterface({
49696
50102
  input: process.stdin,
49697
50103
  output: process.stdout,
@@ -49709,7 +50115,7 @@ async function readTokenSilent(prompt) {
49709
50115
  process.stdin.removeListener("data", onData);
49710
50116
  process.stdout.write("\n");
49711
50117
  rl.close();
49712
- resolve30(token);
50118
+ resolve31(token);
49713
50119
  } else if (char === "") {
49714
50120
  if (process.stdin.isTTY) process.stdin.setRawMode(false);
49715
50121
  process.stdin.removeListener("data", onData);
@@ -49864,12 +50270,12 @@ import * as readline7 from "node:readline";
49864
50270
  import pc45 from "picocolors";
49865
50271
 
49866
50272
  // src/commands/mcp/import-discovery.ts
49867
- import * as fs97 from "node:fs";
50273
+ import * as fs98 from "node:fs";
49868
50274
  import * as os53 from "node:os";
49869
50275
  import * as path96 from "node:path";
49870
50276
  function readJsonFile(filePath) {
49871
50277
  try {
49872
- const raw = fs97.readFileSync(filePath, "utf-8");
50278
+ const raw = fs98.readFileSync(filePath, "utf-8");
49873
50279
  return JSON.parse(raw);
49874
50280
  } catch {
49875
50281
  return null;
@@ -49913,9 +50319,9 @@ function getOlamRepoPaths() {
49913
50319
  ];
49914
50320
  const paths = [];
49915
50321
  for (const configPath of configPaths) {
49916
- if (!fs97.existsSync(configPath)) continue;
50322
+ if (!fs98.existsSync(configPath)) continue;
49917
50323
  try {
49918
- const raw = fs97.readFileSync(configPath, "utf-8");
50324
+ const raw = fs98.readFileSync(configPath, "utf-8");
49919
50325
  const repoMatches = [...raw.matchAll(/path:\s*["']?([^\s"'\n]+)/g)];
49920
50326
  for (const m of repoMatches) {
49921
50327
  if (m[1]) paths.push(m[1]);
@@ -49984,7 +50390,7 @@ async function discoverMcpSources(repoPaths) {
49984
50390
  import { spawn as spawn10 } from "node:child_process";
49985
50391
  var VALIDATION_TIMEOUT_MS = 5e3;
49986
50392
  async function validateMcpEntry(entry) {
49987
- return new Promise((resolve30) => {
50393
+ return new Promise((resolve31) => {
49988
50394
  let stdout = "";
49989
50395
  let timedOut = false;
49990
50396
  let child;
@@ -49994,7 +50400,7 @@ async function validateMcpEntry(entry) {
49994
50400
  env: { ...process.env, ...entry.env ?? {} }
49995
50401
  });
49996
50402
  } catch (err) {
49997
- resolve30({
50403
+ resolve31({
49998
50404
  name: entry.name,
49999
50405
  validated: false,
50000
50406
  reason: err instanceof Error ? err.message : "spawn failed"
@@ -50011,11 +50417,11 @@ async function validateMcpEntry(entry) {
50011
50417
  child.on("close", (code) => {
50012
50418
  clearTimeout(timer);
50013
50419
  if (timedOut) {
50014
- resolve30({ name: entry.name, validated: false, reason: "timeout (5s)" });
50420
+ resolve31({ name: entry.name, validated: false, reason: "timeout (5s)" });
50015
50421
  return;
50016
50422
  }
50017
50423
  const validated = code === 0 && stdout.trim().length > 0;
50018
- resolve30({
50424
+ resolve31({
50019
50425
  name: entry.name,
50020
50426
  validated,
50021
50427
  reason: validated ? "ok" : `exit code ${code ?? "null"}`
@@ -50023,7 +50429,7 @@ async function validateMcpEntry(entry) {
50023
50429
  });
50024
50430
  child.on("error", (err) => {
50025
50431
  clearTimeout(timer);
50026
- resolve30({ name: entry.name, validated: false, reason: err.message });
50432
+ resolve31({ name: entry.name, validated: false, reason: err.message });
50027
50433
  });
50028
50434
  });
50029
50435
  }
@@ -50038,11 +50444,11 @@ async function multiSelectPicker(entries) {
50038
50444
  );
50039
50445
  });
50040
50446
  console.log("\n" + pc45.dim('Enter numbers to import (e.g. 1,2,3 or "all" or Enter to skip):'));
50041
- const answer = await new Promise((resolve30) => {
50447
+ const answer = await new Promise((resolve31) => {
50042
50448
  const rl = readline7.createInterface({ input: process.stdin, output: process.stdout });
50043
50449
  rl.question("> ", (ans) => {
50044
50450
  rl.close();
50045
- resolve30(ans.trim());
50451
+ resolve31(ans.trim());
50046
50452
  });
50047
50453
  });
50048
50454
  if (!answer || answer === "") return [];
@@ -50189,14 +50595,14 @@ init_output();
50189
50595
 
50190
50596
  // src/lib/memory-host-process-migration.ts
50191
50597
  init_paths2();
50192
- import { existsSync as existsSync106, readFileSync as readFileSync92, unlinkSync as unlinkSync23 } from "node:fs";
50598
+ import { existsSync as existsSync108, readFileSync as readFileSync94, unlinkSync as unlinkSync23 } from "node:fs";
50193
50599
  import { spawnSync as spawnSync31 } from "node:child_process";
50194
50600
  var KILL_TIMEOUT_MS = 5e3;
50195
50601
  function migrateFromHostProcess(opts = {}) {
50196
50602
  const pidPath2 = opts.pidPath ?? MEMORY_PID_PATH;
50197
50603
  const logPath = opts.logPath ?? MEMORY_LOG_PATH;
50198
- const pidfileExists = existsSync106(pidPath2);
50199
- const logExists = existsSync106(logPath);
50604
+ const pidfileExists = existsSync108(pidPath2);
50605
+ const logExists = existsSync108(logPath);
50200
50606
  if (!pidfileExists && !logExists) {
50201
50607
  return { cleaned: false, summary: "no legacy host-process state to clean" };
50202
50608
  }
@@ -50235,7 +50641,7 @@ function migrateFromHostProcess(opts = {}) {
50235
50641
  }
50236
50642
  function readPidFromFile(pidPath2) {
50237
50643
  try {
50238
- const raw = readFileSync92(pidPath2, "utf8").trim();
50644
+ const raw = readFileSync94(pidPath2, "utf8").trim();
50239
50645
  const pid = parseInt(raw, 10);
50240
50646
  if (!Number.isFinite(pid) || pid <= 0) return null;
50241
50647
  return pid;
@@ -50365,7 +50771,7 @@ function registerMemoryStop(cmd) {
50365
50771
  init_output();
50366
50772
  init_memory_secret();
50367
50773
  init_paths2();
50368
- import { existsSync as existsSync107 } from "node:fs";
50774
+ import { existsSync as existsSync109 } from "node:fs";
50369
50775
  var RESTART_CHURN_THRESHOLD = 3;
50370
50776
  async function probe(secret) {
50371
50777
  try {
@@ -50392,7 +50798,7 @@ async function collectMemoryStatus() {
50392
50798
  livez,
50393
50799
  secretSet: hasMemorySecret(),
50394
50800
  port: MEMORY_REST_PORT,
50395
- legacyPidfilePresent: existsSync107(MEMORY_PID_PATH),
50801
+ legacyPidfilePresent: existsSync109(MEMORY_PID_PATH),
50396
50802
  startedAt: runtime?.startedAt ?? null,
50397
50803
  restartCount: runtime?.restartCount ?? null,
50398
50804
  health: runtime?.health ?? "unknown"
@@ -50479,8 +50885,8 @@ async function runMemoryLogs(opts) {
50479
50885
  args.push(MEMORY_SERVICE_CONTAINER);
50480
50886
  printHeader(`olam memory logs (${opts.follow ? "follow" : `tail -n ${tailN}`})`);
50481
50887
  const child = spawn11("docker", args, { stdio: "inherit" });
50482
- return new Promise((resolve30) => {
50483
- child.on("exit", (code) => resolve30(code ?? 0));
50888
+ return new Promise((resolve31) => {
50889
+ child.on("exit", (code) => resolve31(code ?? 0));
50484
50890
  });
50485
50891
  }
50486
50892
  function registerMemoryLogs(cmd) {
@@ -50616,14 +51022,14 @@ function registerMemoryUninstall(cmd) {
50616
51022
  init_schema2();
50617
51023
  init_output();
50618
51024
  init_memory_secret();
50619
- import { existsSync as existsSync108, readFileSync as readFileSync93, writeFileSync as writeFileSync56 } from "node:fs";
50620
- import { join as join105 } from "node:path";
51025
+ import { existsSync as existsSync110, readFileSync as readFileSync95, writeFileSync as writeFileSync58 } from "node:fs";
51026
+ import { join as join106 } from "node:path";
50621
51027
  import * as readline8 from "node:readline/promises";
50622
51028
  import { parse as parseYaml9, stringify as stringifyYaml7 } from "yaml";
50623
51029
  var CONFIG_REL = ".olam/config.yaml";
50624
51030
  function locateConfig(cwd) {
50625
- const absPath = join105(cwd, CONFIG_REL);
50626
- if (!existsSync108(absPath)) {
51031
+ const absPath = join106(cwd, CONFIG_REL);
51032
+ if (!existsSync110(absPath)) {
50627
51033
  throw new Error(
50628
51034
  `No ${CONFIG_REL} at ${cwd}. Run \`olam init\` in your workspace root first.`
50629
51035
  );
@@ -50631,7 +51037,7 @@ function locateConfig(cwd) {
50631
51037
  return { absPath };
50632
51038
  }
50633
51039
  function readConfigYaml(absPath) {
50634
- const raw = readFileSync93(absPath, "utf-8");
51040
+ const raw = readFileSync95(absPath, "utf-8");
50635
51041
  const parsed = parseYaml9(raw) ?? {};
50636
51042
  if (typeof parsed !== "object" || parsed === null) {
50637
51043
  throw new Error(`${absPath} is not a YAML object`);
@@ -50640,7 +51046,7 @@ function readConfigYaml(absPath) {
50640
51046
  }
50641
51047
  function writeConfigYaml(absPath, parsed) {
50642
51048
  const out = stringifyYaml7(parsed, { aliasDuplicateObjects: false });
50643
- writeFileSync56(absPath, out, "utf-8");
51049
+ writeFileSync58(absPath, out, "utf-8");
50644
51050
  }
50645
51051
  async function defaultPromptText(question) {
50646
51052
  const rl = readline8.createInterface({ input: process.stdin, output: process.stdout });
@@ -50761,20 +51167,20 @@ init_output();
50761
51167
  init_memory_secret();
50762
51168
  init_paths2();
50763
51169
  import { spawn as spawn12 } from "node:child_process";
50764
- import { existsSync as existsSync109 } from "node:fs";
50765
- import { join as join106 } from "node:path";
51170
+ import { existsSync as existsSync111 } from "node:fs";
51171
+ import { join as join107 } from "node:path";
50766
51172
  var DEFAULT_PORT2 = 8788;
50767
51173
  function resolveMemoryServiceDir() {
50768
51174
  for (const c of MEMORY_SERVICE_CANDIDATES) {
50769
- if (existsSync109(c)) return c;
51175
+ if (existsSync111(c)) return c;
50770
51176
  }
50771
51177
  throw new Error(
50772
51178
  `Could not find packages/memory-service/. Searched: ${MEMORY_SERVICE_CANDIDATES.join(", ")}. If running from a published @pleri/olam-cli tarball, this is a packaging bug \u2014 please file an issue.`
50773
51179
  );
50774
51180
  }
50775
51181
  function resolveLocalBridgeScript(serviceDir) {
50776
- const path106 = join106(serviceDir, "scripts", "local-bridge-server.mjs");
50777
- if (!existsSync109(path106)) {
51182
+ const path106 = join107(serviceDir, "scripts", "local-bridge-server.mjs");
51183
+ if (!existsSync111(path106)) {
50778
51184
  throw new Error(
50779
51185
  `Could not find local-bridge-server.mjs at ${path106}. Verify packages/memory-service ships the scripts/ directory.`
50780
51186
  );
@@ -50822,12 +51228,12 @@ async function runBridgeServe(opts, deps = {}) {
50822
51228
  stdio: "inherit"
50823
51229
  }));
50824
51230
  const child = spawner(process.execPath, [scriptPath, ...args], env);
50825
- return new Promise((resolve30) => {
51231
+ return new Promise((resolve31) => {
50826
51232
  let resolved = false;
50827
51233
  const finish = (code) => {
50828
51234
  if (resolved) return;
50829
51235
  resolved = true;
50830
- resolve30(code);
51236
+ resolve31(code);
50831
51237
  };
50832
51238
  const forward = (signal) => () => {
50833
51239
  if (!child.killed) {
@@ -51115,38 +51521,38 @@ function registerMemoryStats(cmd) {
51115
51521
  }
51116
51522
 
51117
51523
  // src/commands/memory/install-hooks.ts
51118
- import { copyFileSync as copyFileSync12, existsSync as existsSync110, mkdirSync as mkdirSync64, readFileSync as readFileSync94, writeFileSync as writeFileSync57 } from "node:fs";
51119
- import { homedir as homedir62 } from "node:os";
51120
- import { dirname as dirname60, join as join107, resolve as resolve27 } from "node:path";
51121
- import { fileURLToPath as fileURLToPath10 } from "node:url";
51524
+ import { copyFileSync as copyFileSync12, existsSync as existsSync112, mkdirSync as mkdirSync65, readFileSync as readFileSync96, writeFileSync as writeFileSync59 } from "node:fs";
51525
+ import { homedir as homedir63 } from "node:os";
51526
+ import { dirname as dirname61, join as join108, resolve as resolve28 } from "node:path";
51527
+ import { fileURLToPath as fileURLToPath11 } from "node:url";
51122
51528
  var HOOK_BASENAMES = [
51123
51529
  "agentmemory-session-recall.js",
51124
51530
  "agentmemory-recall-trigger.mjs",
51125
51531
  "agentmemory-classify-queue.mjs"
51126
51532
  ];
51127
51533
  function defaultSourceDir() {
51128
- const here3 = dirname60(fileURLToPath10(import.meta.url));
51129
- const candidate = resolve27(here3, "..", "..", "..", "memory-service", "hooks");
51130
- if (existsSync110(candidate)) return candidate;
51131
- const srcCandidate = resolve27(here3, "..", "..", "..", "..", "memory-service", "hooks");
51132
- if (existsSync110(srcCandidate)) return srcCandidate;
51534
+ const here3 = dirname61(fileURLToPath11(import.meta.url));
51535
+ const candidate = resolve28(here3, "..", "..", "..", "memory-service", "hooks");
51536
+ if (existsSync112(candidate)) return candidate;
51537
+ const srcCandidate = resolve28(here3, "..", "..", "..", "..", "memory-service", "hooks");
51538
+ if (existsSync112(srcCandidate)) return srcCandidate;
51133
51539
  return candidate;
51134
51540
  }
51135
51541
  function installOne2(basename17, sourceDir, targetDir, opts) {
51136
- const sourcePath = join107(sourceDir, basename17);
51137
- const targetPath = join107(targetDir, basename17);
51138
- if (!existsSync110(sourcePath)) {
51542
+ const sourcePath = join108(sourceDir, basename17);
51543
+ const targetPath = join108(targetDir, basename17);
51544
+ if (!existsSync112(sourcePath)) {
51139
51545
  throw new Error(`canonical hook source missing at ${sourcePath} \u2014 olam install corrupt or sourceDir is wrong`);
51140
51546
  }
51141
- const newContent = readFileSync94(sourcePath, "utf8");
51142
- if (!existsSync110(targetPath)) {
51547
+ const newContent = readFileSync96(sourcePath, "utf8");
51548
+ if (!existsSync112(targetPath)) {
51143
51549
  if (opts.dryRun !== true) {
51144
- mkdirSync64(dirname60(targetPath), { recursive: true });
51145
- writeFileSync57(targetPath, newContent, { mode: 493 });
51550
+ mkdirSync65(dirname61(targetPath), { recursive: true });
51551
+ writeFileSync59(targetPath, newContent, { mode: 493 });
51146
51552
  }
51147
51553
  return { basename: basename17, action: "written", targetPath };
51148
51554
  }
51149
- const existing = readFileSync94(targetPath, "utf8");
51555
+ const existing = readFileSync96(targetPath, "utf8");
51150
51556
  if (existing === newContent) {
51151
51557
  return { basename: basename17, action: "unchanged", targetPath };
51152
51558
  }
@@ -51154,7 +51560,7 @@ function installOne2(basename17, sourceDir, targetDir, opts) {
51154
51560
  const backupPath = `${targetPath}.agentmemory-hook-backup-${Math.floor(Date.now() / 1e3)}`;
51155
51561
  if (opts.dryRun !== true) {
51156
51562
  copyFileSync12(targetPath, backupPath);
51157
- writeFileSync57(targetPath, newContent, { mode: 493 });
51563
+ writeFileSync59(targetPath, newContent, { mode: 493 });
51158
51564
  }
51159
51565
  return { basename: basename17, action: "force-overwritten", targetPath, backupPath };
51160
51566
  }
@@ -51169,13 +51575,13 @@ Add these hook entries to ~/.claude/settings.json:
51169
51575
  {
51170
51576
  "hooks": {
51171
51577
  "SessionStart": [
51172
- { "command": "node ${join107(targetDir, "agentmemory-session-recall.js")}" }
51578
+ { "command": "node ${join108(targetDir, "agentmemory-session-recall.js")}" }
51173
51579
  ],
51174
51580
  "PreToolUse": [
51175
- { "command": "node ${join107(targetDir, "agentmemory-recall-trigger.mjs")}" }
51581
+ { "command": "node ${join108(targetDir, "agentmemory-recall-trigger.mjs")}" }
51176
51582
  ],
51177
51583
  "PostToolUse": [
51178
- { "command": "node ${join107(targetDir, "agentmemory-classify-queue.mjs")}" }
51584
+ { "command": "node ${join108(targetDir, "agentmemory-classify-queue.mjs")}" }
51179
51585
  ]
51180
51586
  }
51181
51587
  }
@@ -51185,7 +51591,7 @@ If existing entries already point at the same paths, no edit needed.
51185
51591
  }
51186
51592
  function registerMemoryInstallHooks(parent) {
51187
51593
  parent.command("install-hooks").description("Install agentmemory hooks (PreToolUse + PostToolUse + SessionStart) to ~/.claude/scripts/hooks/").option("--force", "overwrite existing non-canonical files (backs them up to .agentmemory-hook-backup-<ts>)").option("--dry-run", "preview which hooks would be written without modifying disk").option("--target-dir <path>", "override target directory (default: ~/.claude/scripts/hooks/); for tests").option("--source-dir <path>", "override source directory (default: packages/memory-service/hooks/); for tests").action((opts) => {
51188
- const targetDir = opts.targetDir ?? join107(homedir62(), ".claude", "scripts", "hooks");
51594
+ const targetDir = opts.targetDir ?? join108(homedir63(), ".claude", "scripts", "hooks");
51189
51595
  const sourceDir = opts.sourceDir ?? defaultSourceDir();
51190
51596
  let written = 0;
51191
51597
  let unchanged = 0;
@@ -51261,7 +51667,7 @@ function registerMemory(program2) {
51261
51667
  // src/commands/kg-build.ts
51262
51668
  init_storage_paths();
51263
51669
  init_workspace_name();
51264
- import * as fs103 from "node:fs";
51670
+ import * as fs104 from "node:fs";
51265
51671
  import * as os57 from "node:os";
51266
51672
  import * as path102 from "node:path";
51267
51673
 
@@ -51355,11 +51761,11 @@ init_storage_paths();
51355
51761
  init_workspace_name();
51356
51762
  init_kg_caps();
51357
51763
  init_output();
51358
- import fs98 from "node:fs";
51359
- import { homedir as homedir63 } from "node:os";
51764
+ import fs99 from "node:fs";
51765
+ import { homedir as homedir64 } from "node:os";
51360
51766
  import path97 from "node:path";
51361
51767
  function olamHome5() {
51362
- return process.env.OLAM_HOME ?? path97.join(homedir63(), ".olam");
51768
+ return process.env.OLAM_HOME ?? path97.join(homedir64(), ".olam");
51363
51769
  }
51364
51770
  function kgRoot2() {
51365
51771
  return path97.join(olamHome5(), "kg");
@@ -51368,14 +51774,14 @@ function worldsRoot2() {
51368
51774
  return path97.join(olamHome5(), "worlds");
51369
51775
  }
51370
51776
  function dirSizeBytes2(dir) {
51371
- if (!fs98.existsSync(dir)) return 0;
51777
+ if (!fs99.existsSync(dir)) return 0;
51372
51778
  let total = 0;
51373
51779
  const stack = [dir];
51374
51780
  while (stack.length > 0) {
51375
51781
  const cur = stack.pop();
51376
51782
  let entries;
51377
51783
  try {
51378
- entries = fs98.readdirSync(cur, { withFileTypes: true });
51784
+ entries = fs99.readdirSync(cur, { withFileTypes: true });
51379
51785
  } catch {
51380
51786
  continue;
51381
51787
  }
@@ -51387,7 +51793,7 @@ function dirSizeBytes2(dir) {
51387
51793
  continue;
51388
51794
  }
51389
51795
  try {
51390
- total += fs98.statSync(full).size;
51796
+ total += fs99.statSync(full).size;
51391
51797
  } catch {
51392
51798
  }
51393
51799
  }
@@ -51402,9 +51808,9 @@ function formatBytes5(n) {
51402
51808
  }
51403
51809
  function readFreshness(workspace) {
51404
51810
  const file = path97.join(kgPristinePath(workspace), "freshness.json");
51405
- if (!fs98.existsSync(file)) return null;
51811
+ if (!fs99.existsSync(file)) return null;
51406
51812
  try {
51407
- const raw = JSON.parse(fs98.readFileSync(file, "utf-8"));
51813
+ const raw = JSON.parse(fs99.readFileSync(file, "utf-8"));
51408
51814
  if (raw && typeof raw === "object") return raw;
51409
51815
  return null;
51410
51816
  } catch {
@@ -51413,9 +51819,9 @@ function readFreshness(workspace) {
51413
51819
  }
51414
51820
  function readOverlayNodeCount(graphifyOutDir) {
51415
51821
  const graphPath = path97.join(graphifyOutDir, "graph.json");
51416
- if (!fs98.existsSync(graphPath)) return null;
51822
+ if (!fs99.existsSync(graphPath)) return null;
51417
51823
  try {
51418
- const raw = JSON.parse(fs98.readFileSync(graphPath, "utf-8"));
51824
+ const raw = JSON.parse(fs99.readFileSync(graphPath, "utf-8"));
51419
51825
  if (raw && typeof raw === "object") {
51420
51826
  const nodes = raw.nodes;
51421
51827
  if (Array.isArray(nodes)) return nodes.length;
@@ -51427,11 +51833,11 @@ function readOverlayNodeCount(graphifyOutDir) {
51427
51833
  }
51428
51834
  function listOverlays() {
51429
51835
  const root = worldsRoot2();
51430
- if (!fs98.existsSync(root)) return [];
51836
+ if (!fs99.existsSync(root)) return [];
51431
51837
  const records = [];
51432
51838
  let worldDirs;
51433
51839
  try {
51434
- worldDirs = fs98.readdirSync(root, { withFileTypes: true });
51840
+ worldDirs = fs99.readdirSync(root, { withFileTypes: true });
51435
51841
  } catch {
51436
51842
  return [];
51437
51843
  }
@@ -51441,14 +51847,14 @@ function listOverlays() {
51441
51847
  const worldDir = path97.join(root, worldId);
51442
51848
  let cloneDirs;
51443
51849
  try {
51444
- cloneDirs = fs98.readdirSync(worldDir, { withFileTypes: true });
51850
+ cloneDirs = fs99.readdirSync(worldDir, { withFileTypes: true });
51445
51851
  } catch {
51446
51852
  continue;
51447
51853
  }
51448
51854
  for (const cloneEntry of cloneDirs) {
51449
51855
  if (!cloneEntry.isDirectory()) continue;
51450
51856
  const graphifyOut = path97.join(worldDir, cloneEntry.name, "graphify-out");
51451
- if (!fs98.existsSync(graphifyOut)) continue;
51857
+ if (!fs99.existsSync(graphifyOut)) continue;
51452
51858
  records.push({
51453
51859
  world_id: worldId,
51454
51860
  clone_dir: cloneEntry.name,
@@ -51462,11 +51868,11 @@ function listOverlays() {
51462
51868
  }
51463
51869
  function listPristines(overlays) {
51464
51870
  const root = kgRoot2();
51465
- if (!fs98.existsSync(root)) return [];
51871
+ if (!fs99.existsSync(root)) return [];
51466
51872
  const records = [];
51467
51873
  let entries;
51468
51874
  try {
51469
- entries = fs98.readdirSync(root, { withFileTypes: true });
51875
+ entries = fs99.readdirSync(root, { withFileTypes: true });
51470
51876
  } catch {
51471
51877
  return [];
51472
51878
  }
@@ -51615,7 +52021,7 @@ init_storage_paths();
51615
52021
  init_workspace_name();
51616
52022
  init_output();
51617
52023
  import { spawn as spawn13 } from "node:child_process";
51618
- import fs99 from "node:fs";
52024
+ import fs100 from "node:fs";
51619
52025
  import path98 from "node:path";
51620
52026
  function pidFilePath2(workspace) {
51621
52027
  return path98.join(kgPristinePath(workspace), ".watch.pid");
@@ -51633,33 +52039,33 @@ function isPidAlive3(pid) {
51633
52039
  }
51634
52040
  function readAndClassifyPid(workspace) {
51635
52041
  const file = pidFilePath2(workspace);
51636
- if (!fs99.existsSync(file)) return { status: "no-pidfile", pid: null };
52042
+ if (!fs100.existsSync(file)) return { status: "no-pidfile", pid: null };
51637
52043
  let pid;
51638
52044
  try {
51639
- const raw = fs99.readFileSync(file, "utf-8").trim();
52045
+ const raw = fs100.readFileSync(file, "utf-8").trim();
51640
52046
  pid = Number.parseInt(raw, 10);
51641
52047
  } catch {
51642
- fs99.rmSync(file, { force: true });
52048
+ fs100.rmSync(file, { force: true });
51643
52049
  return { status: "stale-reclaimed", pid: null };
51644
52050
  }
51645
52051
  if (!Number.isInteger(pid) || pid <= 0) {
51646
- fs99.rmSync(file, { force: true });
52052
+ fs100.rmSync(file, { force: true });
51647
52053
  return { status: "stale-reclaimed", pid: null };
51648
52054
  }
51649
52055
  if (isPidAlive3(pid)) return { status: "active", pid };
51650
- fs99.rmSync(file, { force: true });
52056
+ fs100.rmSync(file, { force: true });
51651
52057
  return { status: "stale-reclaimed", pid: null };
51652
52058
  }
51653
52059
  function writePidFile2(workspace, pid) {
51654
52060
  const file = pidFilePath2(workspace);
51655
52061
  const dir = path98.dirname(file);
51656
- fs99.mkdirSync(dir, { recursive: true });
51657
- fs99.writeFileSync(file, String(pid), { encoding: "utf-8" });
52062
+ fs100.mkdirSync(dir, { recursive: true });
52063
+ fs100.writeFileSync(file, String(pid), { encoding: "utf-8" });
51658
52064
  }
51659
52065
  function removePidFile(workspace) {
51660
52066
  const file = pidFilePath2(workspace);
51661
52067
  try {
51662
- fs99.rmSync(file, { force: true });
52068
+ fs100.rmSync(file, { force: true });
51663
52069
  } catch {
51664
52070
  }
51665
52071
  }
@@ -51713,16 +52119,16 @@ async function runKgWatch(workspaceArg, opts, deps = {}) {
51713
52119
  process.on("SIGINT", () => forward("SIGINT"));
51714
52120
  process.on("SIGTERM", () => forward("SIGTERM"));
51715
52121
  }
51716
- return new Promise((resolve30) => {
52122
+ return new Promise((resolve31) => {
51717
52123
  child.on("exit", (code, signal) => {
51718
52124
  removePidFile(name);
51719
52125
  const exitCode = typeof code === "number" ? code : signal === "SIGINT" || signal === "SIGTERM" ? 0 : 1;
51720
- resolve30({ exitCode, pidWritten: true });
52126
+ resolve31({ exitCode, pidWritten: true });
51721
52127
  });
51722
52128
  child.on("error", (err) => {
51723
52129
  removePidFile(name);
51724
52130
  printError(`graphify subprocess error: ${err.message}`);
51725
- resolve30({ exitCode: 1, pidWritten: true });
52131
+ resolve31({ exitCode: 1, pidWritten: true });
51726
52132
  });
51727
52133
  });
51728
52134
  }
@@ -51986,7 +52392,7 @@ function registerKgDoctorCommand(kg) {
51986
52392
  init_merge_settings();
51987
52393
  init_hook_template2();
51988
52394
  init_output();
51989
- import * as fs100 from "node:fs";
52395
+ import * as fs101 from "node:fs";
51990
52396
  import * as path99 from "node:path";
51991
52397
  import * as os54 from "node:os";
51992
52398
  import { parse as yamlParse3, stringify as yamlStringify4 } from "yaml";
@@ -51997,10 +52403,10 @@ function settingsPathFor2(scope) {
51997
52403
  return path99.join(process.cwd(), ".claude", "settings.json");
51998
52404
  }
51999
52405
  function backup2(filePath) {
52000
- if (!fs100.existsSync(filePath)) return null;
52406
+ if (!fs101.existsSync(filePath)) return null;
52001
52407
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
52002
52408
  const backupPath = `${filePath}.olam-bak.${ts}`;
52003
- fs100.copyFileSync(filePath, backupPath);
52409
+ fs101.copyFileSync(filePath, backupPath);
52004
52410
  return backupPath;
52005
52411
  }
52006
52412
  var HERMES_HOOK_MATCHERS = ["terminal", "bash", "shell", "search_files", "grep", "ripgrep"];
@@ -52012,7 +52418,7 @@ function hermesHooksDir() {
52012
52418
  }
52013
52419
  function patchHermesConfigForHook(action) {
52014
52420
  const configPath = hermesConfigPath2();
52015
- const raw = fs100.readFileSync(configPath, "utf-8");
52421
+ const raw = fs101.readFileSync(configPath, "utf-8");
52016
52422
  const config = yamlParse3(raw);
52017
52423
  const hooks = config["hooks"] ?? {};
52018
52424
  const preToolCall = Array.isArray(hooks["pre_tool_call"]) ? hooks["pre_tool_call"] : [];
@@ -52031,7 +52437,7 @@ function patchHermesConfigForHook(action) {
52031
52437
  hooks: { ...hooks, pre_tool_call: [...preToolCall, entry] },
52032
52438
  hooks_auto_accept: true
52033
52439
  };
52034
- fs100.writeFileSync(configPath, yamlStringify4(updated2), "utf-8");
52440
+ fs101.writeFileSync(configPath, yamlStringify4(updated2), "utf-8");
52035
52441
  return "patched";
52036
52442
  }
52037
52443
  const filtered = preToolCall.filter(
@@ -52042,12 +52448,12 @@ function patchHermesConfigForHook(action) {
52042
52448
  ...config,
52043
52449
  hooks: { ...hooks, pre_tool_call: filtered }
52044
52450
  };
52045
- fs100.writeFileSync(configPath, yamlStringify4(updated), "utf-8");
52451
+ fs101.writeFileSync(configPath, yamlStringify4(updated), "utf-8");
52046
52452
  return "patched";
52047
52453
  }
52048
52454
  function doInstallForHermes() {
52049
52455
  const configPath = hermesConfigPath2();
52050
- if (!fs100.existsSync(configPath)) {
52456
+ if (!fs101.existsSync(configPath)) {
52051
52457
  printError(`~/.hermes/config.yaml not found at ${configPath}`);
52052
52458
  printInfo("remedy", "Install Hermes first, then re-run `olam kg install-hook --for hermes`");
52053
52459
  process.exitCode = 1;
@@ -52077,15 +52483,15 @@ function doUninstallForHermes() {
52077
52483
  const hooksDir = hermesHooksDir();
52078
52484
  const hookScriptPath = path99.join(hooksDir, "kg-first.sh");
52079
52485
  let scriptRemoved = false;
52080
- if (fs100.existsSync(hookScriptPath)) {
52081
- const content = fs100.readFileSync(hookScriptPath, "utf-8");
52486
+ if (fs101.existsSync(hookScriptPath)) {
52487
+ const content = fs101.readFileSync(hookScriptPath, "utf-8");
52082
52488
  if (content.includes(HERMES_KG_HOOK_SENTINEL)) {
52083
- fs100.unlinkSync(hookScriptPath);
52489
+ fs101.unlinkSync(hookScriptPath);
52084
52490
  scriptRemoved = true;
52085
52491
  }
52086
52492
  }
52087
52493
  let configPatched = false;
52088
- if (fs100.existsSync(configPath)) {
52494
+ if (fs101.existsSync(configPath)) {
52089
52495
  const result = patchHermesConfigForHook("uninstall");
52090
52496
  configPatched = result === "patched";
52091
52497
  }
@@ -52110,7 +52516,7 @@ function registerKgInstallHookCommand(kg) {
52110
52516
  const scope = opts.scope === "user" ? "user" : "project";
52111
52517
  const filePath = settingsPathFor2(scope);
52112
52518
  try {
52113
- fs100.mkdirSync(path99.dirname(filePath), { recursive: true });
52519
+ fs101.mkdirSync(path99.dirname(filePath), { recursive: true });
52114
52520
  } catch (err) {
52115
52521
  printError(`could not create ${path99.dirname(filePath)}: ${err instanceof Error ? err.message : String(err)}`);
52116
52522
  process.exitCode = 1;
@@ -52136,7 +52542,7 @@ function registerKgInstallHookCommand(kg) {
52136
52542
  printInfo("kg-service hook", `already installed at ${filePath}`);
52137
52543
  if (backupPath) {
52138
52544
  try {
52139
- fs100.unlinkSync(backupPath);
52545
+ fs101.unlinkSync(backupPath);
52140
52546
  } catch {
52141
52547
  }
52142
52548
  }
@@ -52156,7 +52562,7 @@ function registerKgInstallHookCommand(kg) {
52156
52562
  // src/commands/kg-uninstall-hook.ts
52157
52563
  init_hook_template2();
52158
52564
  init_output();
52159
- import * as fs101 from "node:fs";
52565
+ import * as fs102 from "node:fs";
52160
52566
  import * as path100 from "node:path";
52161
52567
  import * as os55 from "node:os";
52162
52568
  function settingsPathFor3(scope) {
@@ -52193,13 +52599,13 @@ function registerKgUninstallHookCommand(kg) {
52193
52599
  kg.command("uninstall-hook").description("Remove kg-service PreToolUse hook from .claude/settings.json (sentinel-matched; surgical)").option("--scope <scope>", "project (default) or user", "project").action((opts) => {
52194
52600
  const scope = opts.scope === "user" ? "user" : "project";
52195
52601
  const filePath = settingsPathFor3(scope);
52196
- if (!fs101.existsSync(filePath)) {
52602
+ if (!fs102.existsSync(filePath)) {
52197
52603
  printInfo("kg-service hook", `no settings.json at ${filePath} \u2014 nothing to remove`);
52198
52604
  return;
52199
52605
  }
52200
52606
  let settings;
52201
52607
  try {
52202
- const raw = fs101.readFileSync(filePath, "utf-8");
52608
+ const raw = fs102.readFileSync(filePath, "utf-8");
52203
52609
  settings = raw.trim() ? JSON.parse(raw) : {};
52204
52610
  } catch (err) {
52205
52611
  printError(`could not parse ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
@@ -52219,7 +52625,7 @@ function registerKgUninstallHookCommand(kg) {
52219
52625
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
52220
52626
  const backupPath = `${filePath}.olam-bak.${ts}`;
52221
52627
  try {
52222
- fs101.copyFileSync(filePath, backupPath);
52628
+ fs102.copyFileSync(filePath, backupPath);
52223
52629
  } catch {
52224
52630
  }
52225
52631
  const next = {
@@ -52238,7 +52644,7 @@ function registerKgUninstallHookCommand(kg) {
52238
52644
  }
52239
52645
  }
52240
52646
  try {
52241
- fs101.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
52647
+ fs102.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
52242
52648
  printSuccess(`kg-service hook removed from ${filePath}`);
52243
52649
  printInfo("backup", backupPath);
52244
52650
  } catch (err) {
@@ -52311,7 +52717,7 @@ function registerKgSavingsCommand(kg) {
52311
52717
 
52312
52718
  // src/commands/kg-mirror.ts
52313
52719
  init_output();
52314
- import * as fs102 from "node:fs";
52720
+ import * as fs103 from "node:fs";
52315
52721
  import * as os56 from "node:os";
52316
52722
  import * as path101 from "node:path";
52317
52723
  function readEnvOrFile(envVar, fileName) {
@@ -52319,7 +52725,7 @@ function readEnvOrFile(envVar, fileName) {
52319
52725
  if (fromEnv && fromEnv.length > 0) return fromEnv.trim();
52320
52726
  try {
52321
52727
  const file = path101.join(os56.homedir(), ".olam", fileName);
52322
- const content = fs102.readFileSync(file, "utf-8").trim();
52728
+ const content = fs103.readFileSync(file, "utf-8").trim();
52323
52729
  if (content.length > 0) return content;
52324
52730
  } catch {
52325
52731
  }
@@ -52499,6 +52905,76 @@ async function runKgMirrorClassify(question, options = {}) {
52499
52905
  printInfo("est. savings", `~${Math.round(Number(savings2) / 1e3)}k tokens`);
52500
52906
  return { exitCode: 0 };
52501
52907
  }
52908
+ async function runKgMirrorGraph(symbol, options = {}) {
52909
+ const cfg = resolveClassifier();
52910
+ if (!cfg) {
52911
+ printError(
52912
+ "kg-mirror URL/bearer not configured. Set OLAM_KG_PROXY_URL + OLAM_KG_PROXY_BEARER (or ~/.olam/kg-proxy-url + ~/.olam/kg-proxy-bearer)."
52913
+ );
52914
+ return { exitCode: 3 };
52915
+ }
52916
+ if (!options.workspace) {
52917
+ printError("graph query needs a --workspace (e.g. --workspace atlas-one).");
52918
+ return { exitCode: 2 };
52919
+ }
52920
+ const sym = (symbol ?? "").trim();
52921
+ if (!sym && !options.repo) {
52922
+ printError("provide a <symbol> to search, and/or --repo <name> to browse a repo.");
52923
+ return { exitCode: 2 };
52924
+ }
52925
+ const mode = options.relates ? "relates" : "where";
52926
+ const body = { workspace: options.workspace, symbol: sym, mode };
52927
+ if (options.repo) body.repo = options.repo;
52928
+ if (options.limit) {
52929
+ const n = Number.parseInt(options.limit, 10);
52930
+ if (Number.isFinite(n) && n > 0) body.limit = n;
52931
+ }
52932
+ let res;
52933
+ try {
52934
+ res = await fetch(`${cfg.url}/v1/graph`, {
52935
+ method: "POST",
52936
+ headers: { Authorization: `Bearer ${cfg.bearer}`, "Content-Type": "application/json" },
52937
+ body: JSON.stringify(body)
52938
+ });
52939
+ } catch (err) {
52940
+ printError(`kg-mirror unreachable: ${err instanceof Error ? err.message : String(err)}`);
52941
+ return { exitCode: 4 };
52942
+ }
52943
+ const text = await res.text();
52944
+ if (options.json) {
52945
+ process.stdout.write(text + "\n");
52946
+ return { exitCode: res.ok ? 0 : 1 };
52947
+ }
52948
+ let j;
52949
+ try {
52950
+ j = JSON.parse(text);
52951
+ } catch {
52952
+ printError(`kg-mirror returned non-JSON (HTTP ${res.status}): ${text.slice(0, 200)}`);
52953
+ return { exitCode: 1 };
52954
+ }
52955
+ if (!res.ok) {
52956
+ printError(`graph /v1/graph failed (HTTP ${res.status}): ${j.error ?? "?"}`);
52957
+ if (j.detail) printInfo("detail", String(j.detail));
52958
+ return { exitCode: 1 };
52959
+ }
52960
+ const matched = j.matched ?? [];
52961
+ printInfo("graph", `${options.workspace} \xB7 ${mode} \xB7 "${symbol}"`);
52962
+ if (matched.length === 0) {
52963
+ printInfo("matched", "no nodes match that symbol");
52964
+ }
52965
+ for (const m of matched) {
52966
+ printSuccess(`${m.label} ${m.file}:${String(m.loc ?? "").replace(/^L/, "")}`);
52967
+ }
52968
+ if (mode === "relates") {
52969
+ const relates = j.relates ?? [];
52970
+ for (const e of relates) {
52971
+ const arrow = e.direction === "out" ? "\u2192" : "\u2190";
52972
+ printInfo(String(e.relation), `${arrow} ${e.label} (${e.file})`);
52973
+ }
52974
+ }
52975
+ if (j.truncated) printInfo("note", "results truncated \u2014 pass --limit to widen");
52976
+ return { exitCode: 0 };
52977
+ }
52502
52978
  function guessGitUrl(workspace) {
52503
52979
  try {
52504
52980
  const { spawnSync: spawnSync35 } = __require("node:child_process");
@@ -52509,7 +52985,7 @@ function guessGitUrl(workspace) {
52509
52985
  path101.join(os56.homedir(), "Projects", workspace)
52510
52986
  ];
52511
52987
  for (const dir of candidates2) {
52512
- if (!fs102.existsSync(path101.join(dir, ".git"))) continue;
52988
+ if (!fs103.existsSync(path101.join(dir, ".git"))) continue;
52513
52989
  const r = spawnSync35("git", ["-C", dir, "remote", "get-url", "origin"], {
52514
52990
  encoding: "utf-8"
52515
52991
  });
@@ -52538,12 +53014,16 @@ function registerKgMirrorCommand(kg) {
52538
53014
  const r = await runKgMirrorClassify(question, opts);
52539
53015
  if (r.exitCode !== 0) process.exitCode = r.exitCode;
52540
53016
  });
53017
+ mirror.command("graph").description("Query the cross-repo graph: locate a symbol, its relationships, or browse a repo (POST /v1/graph)").argument("[symbol]", "symbol/label to look up (e.g. UserService); omit with --repo to browse a repo").requiredOption("--workspace <name>", "workspace to query (e.g. atlas-one)").option("--repo <name>", "scope to / browse a submodule by path prefix (e.g. diner-app)").option("--relates", "return relationships (calls/imports/contains) instead of just locations").option("--limit <n>", "max results (default 50)").option("--json", "emit raw JSON response").action(async (symbol, opts) => {
53018
+ const r = await runKgMirrorGraph(symbol, opts);
53019
+ if (r.exitCode !== 0) process.exitCode = r.exitCode;
53020
+ });
52541
53021
  }
52542
53022
 
52543
53023
  // src/commands/kg-build.ts
52544
53024
  function readQueueFromDisk(queuePath) {
52545
- if (!fs103.existsSync(queuePath)) return [];
52546
- const raw = fs103.readFileSync(queuePath, "utf-8");
53025
+ if (!fs104.existsSync(queuePath)) return [];
53026
+ const raw = fs104.readFileSync(queuePath, "utf-8");
52547
53027
  const entries = [];
52548
53028
  for (const line of raw.split("\n")) {
52549
53029
  const t = line.trim();
@@ -52556,9 +53036,9 @@ function readQueueFromDisk(queuePath) {
52556
53036
  return entries;
52557
53037
  }
52558
53038
  function writeQueueToDisk(queuePath, entries) {
52559
- fs103.mkdirSync(path102.dirname(queuePath), { recursive: true });
53039
+ fs104.mkdirSync(path102.dirname(queuePath), { recursive: true });
52560
53040
  const content = entries.map((e) => JSON.stringify(e)).join("\n") + (entries.length > 0 ? "\n" : "");
52561
- fs103.writeFileSync(queuePath, content, "utf-8");
53041
+ fs104.writeFileSync(queuePath, content, "utf-8");
52562
53042
  }
52563
53043
  async function runKgBuildPending(opts = {}) {
52564
53044
  const queuePath = opts.queuePath ?? (() => {
@@ -52648,7 +53128,7 @@ async function runKgBuild(workspaceArg, options = {}) {
52648
53128
  return { exitCode: 2 };
52649
53129
  }
52650
53130
  const outDir = kgPristinePath(workspace.name);
52651
- fs103.mkdirSync(outDir, { recursive: true });
53131
+ fs104.mkdirSync(outDir, { recursive: true });
52652
53132
  const human = !options.json;
52653
53133
  if (human) {
52654
53134
  printInfo("kg build", `workspace=${workspace.name} source=${workspace.sourcePath}`);
@@ -52681,7 +53161,7 @@ async function runKgBuild(workspaceArg, options = {}) {
52681
53161
  workspace: workspace.name,
52682
53162
  graphify_path: "container"
52683
53163
  };
52684
- fs103.writeFileSync(
53164
+ fs104.writeFileSync(
52685
53165
  path102.join(outDir, "freshness.json"),
52686
53166
  JSON.stringify(freshness, null, 2) + "\n",
52687
53167
  "utf-8"
@@ -52728,13 +53208,13 @@ function registerKg(program2) {
52728
53208
 
52729
53209
  // src/commands/flywheel/emit-breadcrumb.ts
52730
53210
  init_file_lock();
52731
- import { mkdirSync as mkdirSync67, appendFileSync as appendFileSync6 } from "node:fs";
52732
- import { homedir as homedir68 } from "node:os";
52733
- import { dirname as dirname64, join as join112 } from "node:path";
53211
+ import { mkdirSync as mkdirSync68, appendFileSync as appendFileSync6 } from "node:fs";
53212
+ import { homedir as homedir69 } from "node:os";
53213
+ import { dirname as dirname65, join as join113 } from "node:path";
52734
53214
  import { randomUUID as randomUUID4 } from "node:crypto";
52735
53215
  var VALID_SEVERITIES = /* @__PURE__ */ new Set(["critical", "high", "medium", "low", "info", "warn"]);
52736
53216
  var PROMPT_FEEDING_FIELDS = ["extracted_pattern", "severity", "affected_persona", "proposed_edit"];
52737
- var BREADCRUMBS_BASE = join112(homedir68(), ".local", "share", "claude", "breadcrumbs");
53217
+ var BREADCRUMBS_BASE = join113(homedir69(), ".local", "share", "claude", "breadcrumbs");
52738
53218
  var LOCK_FILENAME = ".flywheel-emit.lock";
52739
53219
  function buildRecord(opts) {
52740
53220
  const rec = {
@@ -52781,7 +53261,7 @@ function validatePromptFeeding(rec) {
52781
53261
  }
52782
53262
  function destPath(projectSlug) {
52783
53263
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
52784
- return join112(BREADCRUMBS_BASE, projectSlug, `${today}.jsonl`);
53264
+ return join113(BREADCRUMBS_BASE, projectSlug, `${today}.jsonl`);
52785
53265
  }
52786
53266
  async function emitBreadcrumb(opts) {
52787
53267
  if (!VALID_SEVERITIES.has(opts.severity)) {
@@ -52801,8 +53281,8 @@ async function emitBreadcrumb(opts) {
52801
53281
  process.exit(2);
52802
53282
  }
52803
53283
  const path106 = destPath(rec.project_slug);
52804
- const lockDir = dirname64(path106);
52805
- mkdirSync67(lockDir, { recursive: true });
53284
+ const lockDir = dirname65(path106);
53285
+ mkdirSync68(lockDir, { recursive: true });
52806
53286
  const line = JSON.stringify(rec) + "\n";
52807
53287
  await withFileLock(
52808
53288
  lockDir,
@@ -52882,7 +53362,7 @@ function registerFlywheelK5Score(parent) {
52882
53362
  }
52883
53363
 
52884
53364
  // src/commands/flywheel/k5-validate.ts
52885
- import { readFileSync as readFileSync99, statSync as statSync31 } from "node:fs";
53365
+ import { readFileSync as readFileSync101, statSync as statSync31 } from "node:fs";
52886
53366
  import { parse as parseYAML } from "yaml";
52887
53367
  var K5_DIMS = ["direction", "approach", "open_questions", "constraints", "reuse"];
52888
53368
  var MAX_PLAN_BYTES = 1048576;
@@ -52964,7 +53444,7 @@ function validatePlan(path106) {
52964
53444
  }
52965
53445
  let text;
52966
53446
  try {
52967
- text = readFileSync99(path106, "utf8");
53447
+ text = readFileSync101(path106, "utf8");
52968
53448
  } catch (err) {
52969
53449
  const m = `FAIL cannot read ${path106}: ${err instanceof Error ? err.message : "unknown"}`;
52970
53450
  return { ok: false, message: m, json: emptyJson("error", [m]) };
@@ -53088,7 +53568,7 @@ function registerFlywheelK5Validate(parent) {
53088
53568
  }
53089
53569
 
53090
53570
  // src/commands/flywheel/k10-measure.ts
53091
- import { readFileSync as readFileSync100 } from "node:fs";
53571
+ import { readFileSync as readFileSync102 } from "node:fs";
53092
53572
 
53093
53573
  // ../core/dist/lib/k10-budget.js
53094
53574
  var K10_TOKEN_CAP = 5500;
@@ -53145,7 +53625,7 @@ function registerFlywheelK10Measure(parent) {
53145
53625
  parent.command("k10-measure").description("Measure K10 token budget for upstream + optional overlay; emit PASS/REJECT verdict").requiredOption("--upstream <path>", "path to upstream file (e.g. persona prompt)").option("--overlay <path>", "path to overlay file (omit if none \u2014 PASS without enforcement)").option("--json", "emit verdict as JSON instead of human-readable").action((opts) => {
53146
53626
  let upstreamText;
53147
53627
  try {
53148
- upstreamText = readFileSync100(opts.upstream, "utf8");
53628
+ upstreamText = readFileSync102(opts.upstream, "utf8");
53149
53629
  } catch (err) {
53150
53630
  process.stderr.write(
53151
53631
  `[k10-measure-error] cannot read upstream ${opts.upstream}: ${err instanceof Error ? err.message : "unknown"}
@@ -53157,7 +53637,7 @@ function registerFlywheelK10Measure(parent) {
53157
53637
  let overlayTokens = null;
53158
53638
  if (opts.overlay !== void 0) {
53159
53639
  try {
53160
- const overlayText = readFileSync100(opts.overlay, "utf8");
53640
+ const overlayText = readFileSync102(opts.overlay, "utf8");
53161
53641
  overlayTokens = tokensFromText(overlayText);
53162
53642
  } catch (err) {
53163
53643
  process.stderr.write(
@@ -53191,13 +53671,13 @@ function registerFlywheelK10Measure(parent) {
53191
53671
  }
53192
53672
 
53193
53673
  // src/commands/flywheel/check-persona-skeleton.ts
53194
- import { existsSync as existsSync115, readFileSync as readFileSync101, statSync as statSync32 } from "node:fs";
53195
- import { homedir as homedir69 } from "node:os";
53196
- import { basename as basename14, join as join113 } from "node:path";
53674
+ import { existsSync as existsSync117, readFileSync as readFileSync103, statSync as statSync32 } from "node:fs";
53675
+ import { homedir as homedir70 } from "node:os";
53676
+ import { basename as basename14, join as join114 } from "node:path";
53197
53677
  import { parse as parseYAML2 } from "yaml";
53198
53678
  var CHARS_PER_TOKEN3 = 4;
53199
53679
  var K10_TOKEN_CAP2 = 6e3;
53200
- var AGENTS_DIR = join113(homedir69(), ".claude", "agents");
53680
+ var AGENTS_DIR = join114(homedir70(), ".claude", "agents");
53201
53681
  var REQUIRED_FRONTMATTER_KEYS = ["name", "description", "allowed-tools"];
53202
53682
  var REQUIRED_SECTIONS = [
53203
53683
  "## Role",
@@ -53237,10 +53717,10 @@ function countNamedPatterns(sectionText) {
53237
53717
  return Math.max(h3Count, bulletCount);
53238
53718
  }
53239
53719
  function checkFile(filepath) {
53240
- if (!existsSync115(filepath) || !statSync32(filepath).isFile()) {
53720
+ if (!existsSync117(filepath) || !statSync32(filepath).isFile()) {
53241
53721
  return { passed: false, failures: [`file not found: ${filepath}`], tokens: 0, mergedSkipped: false };
53242
53722
  }
53243
- const text = readFileSync101(filepath, "utf8");
53723
+ const text = readFileSync103(filepath, "utf8");
53244
53724
  const { fm, body } = parseFile(text);
53245
53725
  const failures = [];
53246
53726
  for (const key of REQUIRED_FRONTMATTER_KEYS) {
@@ -53253,8 +53733,8 @@ function checkFile(filepath) {
53253
53733
  const agentName = typeof fm.name === "string" ? fm.name : "";
53254
53734
  let mergedSkipped = false;
53255
53735
  if (!isNewAgent && agentName !== "") {
53256
- const upstreamPath = join113(AGENTS_DIR, `${agentName}.md`);
53257
- if (existsSync115(upstreamPath)) {
53736
+ const upstreamPath = join114(AGENTS_DIR, `${agentName}.md`);
53737
+ if (existsSync117(upstreamPath)) {
53258
53738
  mergedSkipped = true;
53259
53739
  }
53260
53740
  }
@@ -53306,7 +53786,7 @@ Results: ${passCount} passed, ${failCount} failed
53306
53786
  }
53307
53787
 
53308
53788
  // src/commands/flywheel/diversity-check.ts
53309
- import { readFileSync as readFileSync102 } from "node:fs";
53789
+ import { readFileSync as readFileSync104 } from "node:fs";
53310
53790
  import { basename as basename15 } from "node:path";
53311
53791
  import { globSync as globSync2 } from "node:fs";
53312
53792
 
@@ -53386,7 +53866,7 @@ function formatRedivergencePrompt(personaA, personaB, score, drifted, revisionCo
53386
53866
  ` jaccard: ${score.toFixed(3)} (threshold: ${threshold})`,
53387
53867
  ` drifted: ${driftedName}`,
53388
53868
  "",
53389
- ` Suggestion for next /10x:learn revision of ${driftedName}:`,
53869
+ ` Suggestion for next /100x:learn revision of ${driftedName}:`,
53390
53870
  ` ADD content that reinforces ${driftedName}'s historically-owned cognitive patterns.`,
53391
53871
  ` DO NOT remove shared content \u2014 removing shared boilerplate lowers Jaccard arithmetically`,
53392
53872
  ` but does not restore identity differentiation.`,
@@ -53416,7 +53896,7 @@ function registerFlywheelDiversityCheck(parent) {
53416
53896
  const personas = /* @__PURE__ */ new Map();
53417
53897
  for (const filepath of files) {
53418
53898
  try {
53419
- const body = readFileSync102(filepath, "utf8");
53899
+ const body = readFileSync104(filepath, "utf8");
53420
53900
  if (body.trim().length > 0) {
53421
53901
  personas.set(basename15(filepath, ".md"), body);
53422
53902
  }
@@ -53447,9 +53927,9 @@ ${formatRedivergencePrompt(persona_a, persona_b, score, void 0, void 0, threshol
53447
53927
  }
53448
53928
 
53449
53929
  // src/commands/flywheel/ping.ts
53450
- import { mkdirSync as mkdirSync68, writeFileSync as writeFileSync61 } from "node:fs";
53451
- import { homedir as homedir70 } from "node:os";
53452
- import { dirname as dirname65, join as join114 } from "node:path";
53930
+ import { mkdirSync as mkdirSync69, writeFileSync as writeFileSync63 } from "node:fs";
53931
+ import { homedir as homedir71 } from "node:os";
53932
+ import { dirname as dirname66, join as join115 } from "node:path";
53453
53933
  var COLD_START_BUDGET_GOOD_MS = 200;
53454
53934
  var COLD_START_BUDGET_FAIR_MS = 500;
53455
53935
  function classifyColdStart(coldStartMs) {
@@ -53465,9 +53945,9 @@ function readOlamVersion() {
53465
53945
  }
53466
53946
  }
53467
53947
  function writeBaseline(record) {
53468
- const baselinePath = join114(homedir70(), ".local", "share", "olam", "flywheel-baseline.json");
53469
- mkdirSync68(dirname65(baselinePath), { recursive: true });
53470
- writeFileSync61(baselinePath, JSON.stringify(record, null, 2) + "\n", "utf8");
53948
+ const baselinePath = join115(homedir71(), ".local", "share", "olam", "flywheel-baseline.json");
53949
+ mkdirSync69(dirname66(baselinePath), { recursive: true });
53950
+ writeFileSync63(baselinePath, JSON.stringify(record, null, 2) + "\n", "utf8");
53471
53951
  return baselinePath;
53472
53952
  }
53473
53953
  function registerFlywheelPing(parent) {
@@ -53507,16 +53987,16 @@ init_skill_sources();
53507
53987
  init_prefix_rules();
53508
53988
  import {
53509
53989
  copyFileSync as copyFileSync15,
53510
- existsSync as existsSync116,
53511
- mkdirSync as mkdirSync69,
53512
- readFileSync as readFileSync103,
53990
+ existsSync as existsSync118,
53991
+ mkdirSync as mkdirSync70,
53992
+ readFileSync as readFileSync105,
53513
53993
  readdirSync as readdirSync33,
53514
53994
  statSync as statSync33,
53515
- writeFileSync as writeFileSync62
53995
+ writeFileSync as writeFileSync64
53516
53996
  } from "node:fs";
53517
53997
  import { spawnSync as spawnSync32 } from "node:child_process";
53518
- import { homedir as homedir71 } from "node:os";
53519
- import { dirname as dirname66, join as join115, relative as relative7 } from "node:path";
53998
+ import { homedir as homedir72 } from "node:os";
53999
+ import { dirname as dirname67, join as join116, relative as relative7 } from "node:path";
53520
54000
  function escapeRegex(s) {
53521
54001
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
53522
54002
  }
@@ -53553,7 +54033,7 @@ function walkOverlayFiles(dir) {
53553
54033
  return [];
53554
54034
  }
53555
54035
  for (const entry of entries) {
53556
- const fullPath = join115(dir, entry);
54036
+ const fullPath = join116(dir, entry);
53557
54037
  let stat;
53558
54038
  try {
53559
54039
  stat = statSync33(fullPath);
@@ -53592,10 +54072,10 @@ function resolveAtlasUser2(opts) {
53592
54072
  assertValidAtlasUser(v);
53593
54073
  return v;
53594
54074
  }
53595
- const claudeDir2 = opts._testClaudeDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join115(homedir71(), ".claude");
53596
- const f = join115(claudeDir2, ".atlas-user");
53597
- if (existsSync116(f)) {
53598
- const v = readFileSync103(f, "utf-8").trim();
54075
+ const claudeDir2 = opts._testClaudeDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join116(homedir72(), ".claude");
54076
+ const f = join116(claudeDir2, ".atlas-user");
54077
+ if (existsSync118(f)) {
54078
+ const v = readFileSync105(f, "utf-8").trim();
53599
54079
  if (v.length === 0) return null;
53600
54080
  assertValidAtlasUser(v);
53601
54081
  return v;
@@ -53617,8 +54097,8 @@ function runGit2(args, cwd) {
53617
54097
  function walkPushSourceFiles(claudeDir2) {
53618
54098
  const result = [];
53619
54099
  const roots = [
53620
- { dir: join115(claudeDir2, "skills.overrides"), overlayKind: "skills" },
53621
- { dir: join115(claudeDir2, "agents.overrides"), overlayKind: "agents" }
54100
+ { dir: join116(claudeDir2, "skills.overrides"), overlayKind: "skills" },
54101
+ { dir: join116(claudeDir2, "agents.overrides"), overlayKind: "agents" }
53622
54102
  ];
53623
54103
  for (const { dir, overlayKind } of roots) {
53624
54104
  const files = walkOverlayFiles(dir);
@@ -53729,7 +54209,7 @@ function pushOverlays(opts) {
53729
54209
  Run \`olam skills atlas-user set <name>\` to configure your atlas user.`
53730
54210
  );
53731
54211
  }
53732
- const claudeDir2 = opts._testClaudeDir ?? opts.targetDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join115(homedir71(), ".claude");
54212
+ const claudeDir2 = opts._testClaudeDir ?? opts.targetDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join116(homedir72(), ".claude");
53733
54213
  const sourceFiles = walkPushSourceFiles(claudeDir2);
53734
54214
  const registeredPrefixes = (opts._testSkillSources ?? listSkillSources()).map((s) => s.prefix).filter((p) => typeof p === "string" && p.length > 0);
53735
54215
  if (registeredPrefixes.length > 0) {
@@ -53737,7 +54217,7 @@ function pushOverlays(opts) {
53737
54217
  const basename17 = relPath.split("/").pop() ?? relPath;
53738
54218
  let content;
53739
54219
  try {
53740
- content = readFileSync103(srcFile);
54220
+ content = readFileSync105(srcFile);
53741
54221
  } catch {
53742
54222
  continue;
53743
54223
  }
@@ -53776,21 +54256,21 @@ function pushOverlays(opts) {
53776
54256
  ` + preflightWarnings.map((w) => ` - ${w.split("\n")[0]}`).join("\n") + "\n"
53777
54257
  );
53778
54258
  }
53779
- const membersBase2 = join115(clonePath, "members", atlasUser);
54259
+ const membersBase2 = join116(clonePath, "members", atlasUser);
53780
54260
  let wouldCopy = 0;
53781
54261
  let wouldUnchange = 0;
53782
54262
  let wouldCreate = 0;
53783
54263
  for (const { srcFile, overlayKind, relPath } of sourceFiles) {
53784
- const targetDir = join115(membersBase2, `${overlayKind}.overrides`);
53785
- const targetFile = join115(targetDir, relPath);
54264
+ const targetDir = join116(membersBase2, `${overlayKind}.overrides`);
54265
+ const targetFile = join116(targetDir, relPath);
53786
54266
  let srcBuf;
53787
54267
  try {
53788
- srcBuf = readFileSync103(srcFile);
54268
+ srcBuf = readFileSync105(srcFile);
53789
54269
  } catch {
53790
54270
  continue;
53791
54271
  }
53792
- if (existsSync116(targetFile)) {
53793
- const dstBuf = readFileSync103(targetFile);
54272
+ if (existsSync118(targetFile)) {
54273
+ const dstBuf = readFileSync105(targetFile);
53794
54274
  if (srcBuf.equals(dstBuf)) {
53795
54275
  wouldUnchange += 1;
53796
54276
  process.stdout.write(` [skip] ${overlayKind}.overrides/${relPath} (unchanged)
@@ -53831,32 +54311,32 @@ function pushOverlays(opts) {
53831
54311
  `failed to create branch "${branchName}": ${err instanceof Error ? err.message : String(err)}`
53832
54312
  );
53833
54313
  }
53834
- const membersBase = join115(clonePath, "members", atlasUser);
54314
+ const membersBase = join116(clonePath, "members", atlasUser);
53835
54315
  let filesCopied = 0;
53836
54316
  let filesUnchanged = 0;
53837
54317
  let filesCreated = 0;
53838
54318
  try {
53839
54319
  for (const { srcFile, overlayKind, relPath } of sourceFiles) {
53840
- const targetDir = join115(membersBase, `${overlayKind}.overrides`, dirname66(relPath));
53841
- const targetFile = join115(membersBase, `${overlayKind}.overrides`, relPath);
54320
+ const targetDir = join116(membersBase, `${overlayKind}.overrides`, dirname67(relPath));
54321
+ const targetFile = join116(membersBase, `${overlayKind}.overrides`, relPath);
53842
54322
  let srcBuf;
53843
54323
  try {
53844
- srcBuf = readFileSync103(srcFile);
54324
+ srcBuf = readFileSync105(srcFile);
53845
54325
  } catch {
53846
54326
  continue;
53847
54327
  }
53848
- const targetExists = existsSync116(targetFile);
54328
+ const targetExists = existsSync118(targetFile);
53849
54329
  if (targetExists) {
53850
- const dstBuf = readFileSync103(targetFile);
54330
+ const dstBuf = readFileSync105(targetFile);
53851
54331
  if (srcBuf.equals(dstBuf)) {
53852
54332
  filesUnchanged += 1;
53853
54333
  continue;
53854
54334
  }
53855
- mkdirSync69(targetDir, { recursive: true });
54335
+ mkdirSync70(targetDir, { recursive: true });
53856
54336
  copyFileSync15(srcFile, targetFile);
53857
54337
  filesCopied += 1;
53858
54338
  } else {
53859
- mkdirSync69(targetDir, { recursive: true });
54339
+ mkdirSync70(targetDir, { recursive: true });
53860
54340
  copyFileSync15(srcFile, targetFile);
53861
54341
  filesCreated += 1;
53862
54342
  }
@@ -53924,8 +54404,8 @@ function initMember(opts) {
53924
54404
  clonePath = skillSourceClonePath(source.id);
53925
54405
  }
53926
54406
  const atlasUser = resolveAtlasUser2(opts) ?? memberName;
53927
- const memberDir = join115(clonePath, "members", memberName);
53928
- if (existsSync116(memberDir)) {
54407
+ const memberDir = join116(clonePath, "members", memberName);
54408
+ if (existsSync118(memberDir)) {
53929
54409
  throw new PushError(
53930
54410
  1,
53931
54411
  `members/${memberName}/ already exists; use --push to update; or remove manually first
@@ -53933,9 +54413,9 @@ function initMember(opts) {
53933
54413
  );
53934
54414
  }
53935
54415
  const wouldCreate = [
53936
- join115(memberDir, "skills.overrides", ".gitkeep"),
53937
- join115(memberDir, "agents.overrides", ".gitkeep"),
53938
- join115(memberDir, "README.md")
54416
+ join116(memberDir, "skills.overrides", ".gitkeep"),
54417
+ join116(memberDir, "agents.overrides", ".gitkeep"),
54418
+ join116(memberDir, "README.md")
53939
54419
  ];
53940
54420
  if (opts.dryRun === true) {
53941
54421
  const { preflightWarnings } = runPreFlight(clonePath, opts.forceCurrentBranch === true, true);
@@ -53991,12 +54471,12 @@ function initMember(opts) {
53991
54471
  );
53992
54472
  }
53993
54473
  try {
53994
- mkdirSync69(join115(memberDir, "skills.overrides"), { recursive: true });
53995
- writeFileSync62(join115(memberDir, "skills.overrides", ".gitkeep"), "");
53996
- mkdirSync69(join115(memberDir, "agents.overrides"), { recursive: true });
53997
- writeFileSync62(join115(memberDir, "agents.overrides", ".gitkeep"), "");
53998
- writeFileSync62(
53999
- join115(memberDir, "README.md"),
54474
+ mkdirSync70(join116(memberDir, "skills.overrides"), { recursive: true });
54475
+ writeFileSync64(join116(memberDir, "skills.overrides", ".gitkeep"), "");
54476
+ mkdirSync70(join116(memberDir, "agents.overrides"), { recursive: true });
54477
+ writeFileSync64(join116(memberDir, "agents.overrides", ".gitkeep"), "");
54478
+ writeFileSync64(
54479
+ join116(memberDir, "README.md"),
54000
54480
  `# Member overlays for \`${memberName}\`
54001
54481
 
54002
54482
  See docs/plans/member-overlays-sync/ for layer architecture.
@@ -54037,10 +54517,10 @@ Next steps (run in ${clonePath}):`,
54037
54517
  };
54038
54518
  }
54039
54519
  function migrateOverlays(opts = {}) {
54040
- const root = opts.targetDir ?? join115(homedir71(), ".claude");
54520
+ const root = opts.targetDir ?? join116(homedir72(), ".claude");
54041
54521
  const overrideRoots = [
54042
- join115(root, "skills.overrides"),
54043
- join115(root, "agents.overrides")
54522
+ join116(root, "skills.overrides"),
54523
+ join116(root, "agents.overrides")
54044
54524
  ];
54045
54525
  const allFiles = [];
54046
54526
  for (const overrideRoot of overrideRoots) {
@@ -54056,7 +54536,7 @@ function migrateOverlays(opts = {}) {
54056
54536
  for (const filePath of allFiles) {
54057
54537
  let original;
54058
54538
  try {
54059
- original = readFileSync103(filePath, "utf8");
54539
+ original = readFileSync105(filePath, "utf8");
54060
54540
  } catch {
54061
54541
  continue;
54062
54542
  }
@@ -54067,7 +54547,7 @@ function migrateOverlays(opts = {}) {
54067
54547
  continue;
54068
54548
  }
54069
54549
  if (opts.dryRun !== true) {
54070
- writeFileSync62(filePath, newContent, "utf8");
54550
+ writeFileSync64(filePath, newContent, "utf8");
54071
54551
  }
54072
54552
  summary2.modified += 1;
54073
54553
  summary2.totalReplacements += totalReplacements;
@@ -54159,7 +54639,7 @@ function registerFlywheelMigrateOverlays(parent) {
54159
54639
  }
54160
54640
  return;
54161
54641
  }
54162
- const root = opts.targetDir ?? join115(homedir71(), ".claude");
54642
+ const root = opts.targetDir ?? join116(homedir72(), ".claude");
54163
54643
  const summary2 = migrateOverlays(opts);
54164
54644
  if (opts.json === true) {
54165
54645
  process.stdout.write(JSON.stringify(summary2, null, 2) + "\n");
@@ -54198,9 +54678,9 @@ Per-file changes:
54198
54678
  }
54199
54679
 
54200
54680
  // src/commands/flywheel/session-start.ts
54201
- import { readFileSync as readFileSync104, statSync as statSync34 } from "node:fs";
54202
- import { homedir as homedir72 } from "node:os";
54203
- import { join as join116 } from "node:path";
54681
+ import { readFileSync as readFileSync106, statSync as statSync34 } from "node:fs";
54682
+ import { homedir as homedir73 } from "node:os";
54683
+ import { join as join117 } from "node:path";
54204
54684
  var SESSIONSTART_HOOK_SENTINEL = "olam-sessionstart-context-hook-v1";
54205
54685
  var MAX_WAKE_BRIEF_BYTES = 8 * 1024;
54206
54686
  var MAX_ACTIVE_WORLD_BYTES = 4 * 1024;
@@ -54216,7 +54696,7 @@ function tryReadCapped(path106, maxBytes) {
54216
54696
  );
54217
54697
  return null;
54218
54698
  }
54219
- return readFileSync104(path106, "utf-8");
54699
+ return readFileSync106(path106, "utf-8");
54220
54700
  } catch (err) {
54221
54701
  const code = err?.code;
54222
54702
  if (code === "ENOENT") return null;
@@ -54241,15 +54721,15 @@ function tryParseJson(raw, label) {
54241
54721
  }
54242
54722
  function buildContextBlock(olamHome6) {
54243
54723
  const config = tryParseJson(
54244
- tryReadCapped(join116(olamHome6, "config.json"), MAX_CONFIG_BYTES),
54724
+ tryReadCapped(join117(olamHome6, "config.json"), MAX_CONFIG_BYTES),
54245
54725
  "config.json"
54246
54726
  );
54247
54727
  const activeWorld = tryParseJson(
54248
- tryReadCapped(join116(olamHome6, "state", "active-world.json"), MAX_ACTIVE_WORLD_BYTES),
54728
+ tryReadCapped(join117(olamHome6, "state", "active-world.json"), MAX_ACTIVE_WORLD_BYTES),
54249
54729
  "active-world.json"
54250
54730
  );
54251
54731
  const wakeBrief = tryReadCapped(
54252
- join116(olamHome6, "state", "wake-brief.md"),
54732
+ join117(olamHome6, "state", "wake-brief.md"),
54253
54733
  MAX_WAKE_BRIEF_BYTES
54254
54734
  );
54255
54735
  const sections = [];
@@ -54301,7 +54781,7 @@ function registerFlywheelSessionStart(parent) {
54301
54781
  parent.command("session-start").description(
54302
54782
  "Emit operator-state context for the SessionStart hook (4th defense layer). Reads ~/.olam/state/* and writes the additionalContext JSON to stdout. Fail-soft: always exits 0."
54303
54783
  ).action(() => {
54304
- const olamHome6 = process.env.OLAM_HOME ?? join116(homedir72(), ".olam");
54784
+ const olamHome6 = process.env.OLAM_HOME ?? join117(homedir73(), ".olam");
54305
54785
  emitSessionStartContext(olamHome6);
54306
54786
  process.exit(0);
54307
54787
  });
@@ -54310,9 +54790,9 @@ function registerFlywheelSessionStart(parent) {
54310
54790
  // src/commands/flywheel/install-sessionstart-hook.ts
54311
54791
  init_merge_settings();
54312
54792
  init_output();
54313
- import { existsSync as existsSync117, copyFileSync as copyFileSync16, mkdirSync as mkdirSync70, readFileSync as readFileSync105, unlinkSync as unlinkSync25, writeFileSync as writeFileSync63 } from "node:fs";
54314
- import { homedir as homedir73 } from "node:os";
54315
- import { dirname as dirname67, join as join117 } from "node:path";
54793
+ import { existsSync as existsSync119, copyFileSync as copyFileSync16, mkdirSync as mkdirSync71, readFileSync as readFileSync107, unlinkSync as unlinkSync25, writeFileSync as writeFileSync65 } from "node:fs";
54794
+ import { homedir as homedir74 } from "node:os";
54795
+ import { dirname as dirname68, join as join118 } from "node:path";
54316
54796
  var SESSIONSTART_HOOK_STAGE = "SessionStart";
54317
54797
  var SESSIONSTART_HOOK_TIMEOUT_MS = 5e3;
54318
54798
  var NOOP_GUARD = "command -v olam >/dev/null 2>&1 || exit 0;";
@@ -54329,18 +54809,18 @@ function buildSessionStartHookEntry() {
54329
54809
  };
54330
54810
  }
54331
54811
  function settingsPathFor4(scope, cwd) {
54332
- if (scope === "user") return join117(homedir73(), ".claude", "settings.json");
54333
- return join117(cwd ?? process.cwd(), ".claude", "settings.json");
54812
+ if (scope === "user") return join118(homedir74(), ".claude", "settings.json");
54813
+ return join118(cwd ?? process.cwd(), ".claude", "settings.json");
54334
54814
  }
54335
54815
  function backup3(filePath) {
54336
- if (!existsSync117(filePath)) return null;
54816
+ if (!existsSync119(filePath)) return null;
54337
54817
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
54338
54818
  const backupPath = `${filePath}.olam-bak.${ts}`;
54339
54819
  copyFileSync16(filePath, backupPath);
54340
54820
  return backupPath;
54341
54821
  }
54342
54822
  function installSessionStartHook(filePath) {
54343
- mkdirSync70(dirname67(filePath), { recursive: true });
54823
+ mkdirSync71(dirname68(filePath), { recursive: true });
54344
54824
  const backupPath = backup3(filePath);
54345
54825
  const result = mergeHomeSettingsJson(filePath, {
54346
54826
  ensureHook: {
@@ -54359,8 +54839,8 @@ function installSessionStartHook(filePath) {
54359
54839
  return { status: result.status, filePath, backupPath };
54360
54840
  }
54361
54841
  function uninstallSessionStartHook(filePath) {
54362
- if (!existsSync117(filePath)) return { status: "no-settings", filePath };
54363
- const raw = readFileSync105(filePath, "utf-8");
54842
+ if (!existsSync119(filePath)) return { status: "no-settings", filePath };
54843
+ const raw = readFileSync107(filePath, "utf-8");
54364
54844
  const settings = raw.trim() ? JSON.parse(raw) : {};
54365
54845
  const matchers = settings.hooks?.SessionStart;
54366
54846
  if (!Array.isArray(matchers) || matchers.length === 0) {
@@ -54400,7 +54880,7 @@ function uninstallSessionStartHook(filePath) {
54400
54880
  delete next.hooks.SessionStart;
54401
54881
  }
54402
54882
  }
54403
- writeFileSync63(filePath, JSON.stringify(next, null, 2) + "\n");
54883
+ writeFileSync65(filePath, JSON.stringify(next, null, 2) + "\n");
54404
54884
  return { status: "removed", filePath };
54405
54885
  }
54406
54886
  function registerFlywheelInstallSessionStartHook(parent) {
@@ -54718,7 +55198,7 @@ init_manager();
54718
55198
  init_context();
54719
55199
  init_output();
54720
55200
  import { spawnSync as defaultSpawnSync } from "node:child_process";
54721
- import * as fs104 from "node:fs";
55201
+ import * as fs105 from "node:fs";
54722
55202
  import * as os58 from "node:os";
54723
55203
  import * as path103 from "node:path";
54724
55204
  function devboxContainerName(worldId) {
@@ -54738,8 +55218,8 @@ function defaultRestartContainer(name, spawn14 = defaultSpawnSync) {
54738
55218
  };
54739
55219
  }
54740
55220
  function defaultAppendAuditLog(homeDir, line) {
54741
- fs104.mkdirSync(homeDir, { recursive: true });
54742
- fs104.appendFileSync(path103.join(homeDir, "usage.log"), line.endsWith("\n") ? line : line + "\n", {
55221
+ fs105.mkdirSync(homeDir, { recursive: true });
55222
+ fs105.appendFileSync(path103.join(homeDir, "usage.log"), line.endsWith("\n") ? line : line + "\n", {
54743
55223
  encoding: "utf-8"
54744
55224
  });
54745
55225
  }
@@ -54785,18 +55265,18 @@ async function doRekey(worldId, deps) {
54785
55265
  const rotatedAt = deps.now().toISOString();
54786
55266
  const homeDir = deps.olamHomeDir();
54787
55267
  const worldDir = path103.join(homeDir, "worlds", worldId);
54788
- fs104.mkdirSync(worldDir, { recursive: true });
55268
+ fs105.mkdirSync(worldDir, { recursive: true });
54789
55269
  const credentialsPath = path103.join(worldDir, "credentials.json");
54790
55270
  const payload = {
54791
55271
  worldRoleName,
54792
55272
  password,
54793
55273
  rotatedAt
54794
55274
  };
54795
- fs104.writeFileSync(credentialsPath, JSON.stringify(payload, null, 2) + "\n", {
55275
+ fs105.writeFileSync(credentialsPath, JSON.stringify(payload, null, 2) + "\n", {
54796
55276
  encoding: "utf-8",
54797
55277
  mode: 384
54798
55278
  });
54799
- fs104.chmodSync(credentialsPath, 384);
55279
+ fs105.chmodSync(credentialsPath, 384);
54800
55280
  const restart = deps.restartContainer(devboxContainerName(worldId));
54801
55281
  deps.appendAuditLog(`${rotatedAt} ${worldId} rekey`);
54802
55282
  if (!restart.ok) {
@@ -54862,7 +55342,7 @@ function registerRekey(program2) {
54862
55342
  // src/commands/yolo.ts
54863
55343
  init_output();
54864
55344
  import * as childProcess2 from "node:child_process";
54865
- import * as fs105 from "node:fs";
55345
+ import * as fs106 from "node:fs";
54866
55346
  import * as os59 from "node:os";
54867
55347
  import * as path104 from "node:path";
54868
55348
  import pc49 from "picocolors";
@@ -54887,12 +55367,12 @@ function defaultRunner(cmd, args, opts) {
54887
55367
  };
54888
55368
  }
54889
55369
  function defaultSleeper(ms) {
54890
- return new Promise((resolve30) => setTimeout(resolve30, ms));
55370
+ return new Promise((resolve31) => setTimeout(resolve31, ms));
54891
55371
  }
54892
55372
  function detectTmuxBinary(runner = defaultRunner) {
54893
55373
  for (const p of TMUX_PROBE_PATHS) {
54894
55374
  if (TMUX_SHIM_MARKERS.some((m) => p.includes(m))) continue;
54895
- if (fs105.existsSync(p)) return p;
55375
+ if (fs106.existsSync(p)) return p;
54896
55376
  }
54897
55377
  const result = runner("which", ["tmux"]);
54898
55378
  if (result.status === 0 && result.stdout) {
@@ -54907,8 +55387,8 @@ function resolveWorktreeRoot(runner = defaultRunner, cwd = process.cwd()) {
54907
55387
  return process.env["OLAM_TMUX_YOLO_ROOT"];
54908
55388
  }
54909
55389
  const rootFile = path104.join(os59.homedir(), ".olam-tmux-yolo-root");
54910
- if (fs105.existsSync(rootFile)) {
54911
- const line = fs105.readFileSync(rootFile, "utf-8").trim();
55390
+ if (fs106.existsSync(rootFile)) {
55391
+ const line = fs106.readFileSync(rootFile, "utf-8").trim();
54912
55392
  if (line) return line;
54913
55393
  }
54914
55394
  const gitResult = runner("git", ["rev-parse", "--show-toplevel"], { cwd });
@@ -54942,7 +55422,7 @@ async function spawnYolo(opts) {
54942
55422
  );
54943
55423
  }
54944
55424
  try {
54945
- fs105.accessSync(opts.promptFile, fs105.constants.R_OK);
55425
+ fs106.accessSync(opts.promptFile, fs106.constants.R_OK);
54946
55426
  } catch {
54947
55427
  throw new Error(
54948
55428
  `Prompt file not found or not readable: ${opts.promptFile}
@@ -54958,7 +55438,7 @@ Create the file with your task description and try again.`
54958
55438
  Run: olam yolo --cleanup ${opts.name} (or use --force to bypass the merged check)`
54959
55439
  );
54960
55440
  }
54961
- if (fs105.existsSync(worktreePath)) {
55441
+ if (fs106.existsSync(worktreePath)) {
54962
55442
  throw new Error(
54963
55443
  `Worktree directory already exists: ${worktreePath}
54964
55444
  Run: olam yolo --cleanup ${opts.name} to remove it first.`
@@ -55026,7 +55506,7 @@ function listYoloWindows(opts = {}) {
55026
55506
  const worktreePath = path104.join(worktreeRoot, name);
55027
55507
  return {
55028
55508
  name,
55029
- worktreePath: fs105.existsSync(worktreePath) ? worktreePath : void 0
55509
+ worktreePath: fs106.existsSync(worktreePath) ? worktreePath : void 0
55030
55510
  };
55031
55511
  });
55032
55512
  }
@@ -55160,18 +55640,18 @@ function registerYolo(program2) {
55160
55640
  }
55161
55641
 
55162
55642
  // src/pleri-config.ts
55163
- import * as fs106 from "node:fs";
55643
+ import * as fs107 from "node:fs";
55164
55644
  import * as path105 from "node:path";
55165
55645
  function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
55166
55646
  if (process.env.PLERI_BASE_URL) {
55167
55647
  return true;
55168
55648
  }
55169
55649
  const configPath = path105.join(configDir, "config.yaml");
55170
- if (!fs106.existsSync(configPath)) {
55650
+ if (!fs107.existsSync(configPath)) {
55171
55651
  return false;
55172
55652
  }
55173
55653
  try {
55174
- const contents = fs106.readFileSync(configPath, "utf8");
55654
+ const contents = fs107.readFileSync(configPath, "utf8");
55175
55655
  return /^[^#\n]*\bpleri:/m.test(contents);
55176
55656
  } catch {
55177
55657
  return false;
@@ -55210,7 +55690,7 @@ var HELP_GROUPS = [
55210
55690
  },
55211
55691
  {
55212
55692
  title: "Skills & knowledge",
55213
- names: ["skills", "kg", "ask", "flywheel"]
55693
+ names: ["skills", "100x", "kg", "ask", "flywheel"]
55214
55694
  },
55215
55695
  {
55216
55696
  title: "Substrate & infra",
@@ -55373,7 +55853,7 @@ registerSkillsMigrateHooks(program);
55373
55853
  registerSkillsMigrateHooksBack(program);
55374
55854
  registerSkillsShadowBackups(program);
55375
55855
  registerSkillsDoctor(program);
55376
- registerSkills10x(program);
55856
+ registerSkills100x(program);
55377
55857
  registerHermes(program);
55378
55858
  void scheduleUpgradeCheck(cliVersion);
55379
55859
  await program.parseAsync();