@pleri/olam-cli 0.1.168 → 0.1.170

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 (64) hide show
  1. package/README.md +38 -0
  2. package/dist/commands/auth-status.d.ts +1 -0
  3. package/dist/commands/auth-status.d.ts.map +1 -1
  4. package/dist/commands/auth-status.js +45 -4
  5. package/dist/commands/auth-status.js.map +1 -1
  6. package/dist/commands/create.d.ts.map +1 -1
  7. package/dist/commands/create.js +26 -0
  8. package/dist/commands/create.js.map +1 -1
  9. package/dist/commands/enter.d.ts.map +1 -1
  10. package/dist/commands/enter.js +5 -0
  11. package/dist/commands/enter.js.map +1 -1
  12. package/dist/commands/resume.d.ts +63 -0
  13. package/dist/commands/resume.d.ts.map +1 -0
  14. package/dist/commands/resume.js +174 -0
  15. package/dist/commands/resume.js.map +1 -0
  16. package/dist/commands/setup.d.ts +19 -0
  17. package/dist/commands/setup.d.ts.map +1 -1
  18. package/dist/commands/setup.js +157 -19
  19. package/dist/commands/setup.js.map +1 -1
  20. package/dist/image-digests.json +8 -8
  21. package/dist/index.js +1021 -576
  22. package/dist/index.js.map +1 -1
  23. package/dist/lib/health-probes.d.ts +28 -0
  24. package/dist/lib/health-probes.d.ts.map +1 -1
  25. package/dist/lib/health-probes.js +75 -0
  26. package/dist/lib/health-probes.js.map +1 -1
  27. package/dist/lib/k8s-context-discovery.d.ts +80 -0
  28. package/dist/lib/k8s-context-discovery.d.ts.map +1 -0
  29. package/dist/lib/k8s-context-discovery.js +102 -0
  30. package/dist/lib/k8s-context-discovery.js.map +1 -0
  31. package/dist/mcp-server.js +1273 -771
  32. package/dist/spawn/home-override.d.ts +82 -0
  33. package/dist/spawn/home-override.d.ts.map +1 -0
  34. package/dist/spawn/home-override.js +107 -0
  35. package/dist/spawn/home-override.js.map +1 -0
  36. package/hermes-bundle/version.json +1 -1
  37. package/host-cp/k8s/manifests/30-configmap.yaml +5 -0
  38. package/host-cp/k8s/manifests/50-deployment.yaml +9 -2
  39. package/host-cp/k8s/manifests/auth-service/50-deployment.yaml +1 -1
  40. package/host-cp/k8s/manifests/kg-service/50-deployment.yaml +1 -1
  41. package/host-cp/k8s/manifests/mcp-auth-service/50-deployment.yaml +1 -1
  42. package/host-cp/k8s/manifests/memory-service/50-deployment.yaml +1 -1
  43. package/host-cp/lifecycle/classify.mjs +110 -0
  44. package/host-cp/lifecycle/emit.mjs +119 -0
  45. package/host-cp/lifecycle/evidence.mjs +45 -0
  46. package/host-cp/lifecycle/failure-kinds.mjs +56 -0
  47. package/host-cp/lifecycle/index.mjs +22 -0
  48. package/host-cp/lifecycle/phases.mjs +52 -0
  49. package/host-cp/observability/grafana-port-forward.sh +1 -1
  50. package/host-cp/observability/kyverno-cardinality-mutate.sh +2 -2
  51. package/host-cp/observability/loki-ingest.sh +1 -1
  52. package/host-cp/observability/ndjson-span-sink.mjs +131 -0
  53. package/host-cp/observability/prom-no-double-grafana.sh +4 -4
  54. package/host-cp/observability/redactor.mjs +72 -0
  55. package/host-cp/recovery/engine.mjs +148 -0
  56. package/host-cp/recovery/index.mjs +16 -0
  57. package/host-cp/recovery/ledger.mjs +105 -0
  58. package/host-cp/recovery/recipes.mjs +46 -0
  59. package/host-cp/recovery/scenarios.mjs +124 -0
  60. package/host-cp/recovery/step-runners.mjs +263 -0
  61. package/host-cp/src/docker-events.mjs +30 -6
  62. package/host-cp/src/pr-nanny.mjs +55 -3
  63. package/host-cp/src/server.mjs +173 -0
  64. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -492,8 +492,8 @@ var init_parseUtil = __esm({
492
492
  init_errors();
493
493
  init_en();
494
494
  makeIssue = (params) => {
495
- const { data, path: path95, errorMaps, issueData } = params;
496
- const fullPath = [...path95, ...issueData.path || []];
495
+ const { data, path: path96, errorMaps, issueData } = params;
496
+ const fullPath = [...path96, ...issueData.path || []];
497
497
  const fullIssue = {
498
498
  ...issueData,
499
499
  path: fullPath
@@ -801,11 +801,11 @@ var init_types = __esm({
801
801
  init_parseUtil();
802
802
  init_util();
803
803
  ParseInputLazyPath = class {
804
- constructor(parent, value, path95, key) {
804
+ constructor(parent, value, path96, key) {
805
805
  this._cachedPath = [];
806
806
  this.parent = parent;
807
807
  this.data = value;
808
- this._path = path95;
808
+ this._path = path96;
809
809
  this._key = key;
810
810
  }
811
811
  get path() {
@@ -4286,7 +4286,7 @@ import YAML from "yaml";
4286
4286
  function bootstrapStepCmd(entry) {
4287
4287
  return typeof entry === "string" ? entry : entry.cmd;
4288
4288
  }
4289
- function refineForbiddenKeys(value, path95, ctx, rejectSource) {
4289
+ function refineForbiddenKeys(value, path96, ctx, rejectSource) {
4290
4290
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
4291
4291
  return;
4292
4292
  }
@@ -4294,12 +4294,12 @@ function refineForbiddenKeys(value, path95, ctx, rejectSource) {
4294
4294
  if (FORBIDDEN_KEYS.has(key)) {
4295
4295
  ctx.addIssue({
4296
4296
  code: external_exports.ZodIssueCode.custom,
4297
- path: [...path95, key],
4297
+ path: [...path96, key],
4298
4298
  message: `forbidden key "${key}" (prototype-pollution surface)`
4299
4299
  });
4300
4300
  continue;
4301
4301
  }
4302
- if (rejectSource && path95.length === 0 && key === "source") {
4302
+ if (rejectSource && path96.length === 0 && key === "source") {
4303
4303
  ctx.addIssue({
4304
4304
  code: external_exports.ZodIssueCode.custom,
4305
4305
  path: ["source"],
@@ -4307,21 +4307,21 @@ function refineForbiddenKeys(value, path95, ctx, rejectSource) {
4307
4307
  });
4308
4308
  continue;
4309
4309
  }
4310
- refineForbiddenKeys(value[key], [...path95, key], ctx, false);
4310
+ refineForbiddenKeys(value[key], [...path96, key], ctx, false);
4311
4311
  }
4312
4312
  }
4313
- function rejectForbiddenKeys(value, path95, rejectSource) {
4313
+ function rejectForbiddenKeys(value, path96, rejectSource) {
4314
4314
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
4315
4315
  return;
4316
4316
  }
4317
4317
  for (const key of Object.keys(value)) {
4318
4318
  if (FORBIDDEN_KEYS.has(key)) {
4319
- throw new Error(`[manifest] ${path95}: forbidden key "${key}" (prototype-pollution surface)`);
4319
+ throw new Error(`[manifest] ${path96}: forbidden key "${key}" (prototype-pollution surface)`);
4320
4320
  }
4321
4321
  if (rejectSource && key === "source") {
4322
- throw new Error(`[manifest] ${path95}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
4322
+ throw new Error(`[manifest] ${path96}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
4323
4323
  }
4324
- rejectForbiddenKeys(value[key], `${path95}.${key}`, false);
4324
+ rejectForbiddenKeys(value[key], `${path96}.${key}`, false);
4325
4325
  }
4326
4326
  }
4327
4327
  function unknownTopLevelKeys(parsed) {
@@ -4860,7 +4860,13 @@ var init_schema2 = __esm({
4860
4860
  user: external_exports.string().min(1),
4861
4861
  key: external_exports.string().optional()
4862
4862
  });
4863
- computeProviderType = external_exports.enum(["docker", "ssh", "e2b", "cloudflare"]);
4863
+ computeProviderType = external_exports.enum([
4864
+ "docker",
4865
+ "ssh",
4866
+ "e2b",
4867
+ "cloudflare",
4868
+ "cloudflare-isolate"
4869
+ ]);
4864
4870
  stackImageSchema = external_exports.object({
4865
4871
  enabled: external_exports.boolean().optional().default(true),
4866
4872
  auto_commit: external_exports.boolean().optional().default(true),
@@ -4872,6 +4878,15 @@ var init_schema2 = __esm({
4872
4878
  }).optional(),
4873
4879
  ssh: external_exports.object({ hosts: external_exports.array(sshHostSchema).optional() }).optional(),
4874
4880
  e2b: external_exports.object({ template: external_exports.string().optional() }).optional(),
4881
+ // V8-isolate runtime tier per ADR 022. Pure isolate, no DO, no Container.
4882
+ // worker_url points at the deployed olam-worker-runner-isolate Worker.
4883
+ // Same https-or-localhost guard as the cloudflare profile — bearer token
4884
+ // in cleartext would leak the OLAM_TASK_TOKEN.
4885
+ "cloudflare-isolate": external_exports.object({
4886
+ worker_url: external_exports.string().url("worker_url must be a valid URL").refine(isSecureOrLocalhost, {
4887
+ message: "worker_url must use https:// (or http://localhost for dev)"
4888
+ }).optional()
4889
+ }).optional(),
4875
4890
  cloudflare: external_exports.object({
4876
4891
  account_id: external_exports.string().optional(),
4877
4892
  // https-only refine: bare http:// would send the operator's Pylon
@@ -5500,8 +5515,8 @@ var init_client = __esm({
5500
5515
  throw new Error(`failed to report rate-limit for ${accountId} (HTTP ${res.status})`);
5501
5516
  }
5502
5517
  }
5503
- async request(method, path95, body, attempt = 0) {
5504
- const url2 = `${this.baseUrl}${path95}`;
5518
+ async request(method, path96, body, attempt = 0) {
5519
+ const url2 = `${this.baseUrl}${path96}`;
5505
5520
  const controller = new AbortController();
5506
5521
  const timer = setTimeout(() => controller.abort(), this.timeoutMs);
5507
5522
  const headers = {};
@@ -5519,7 +5534,7 @@ var init_client = __esm({
5519
5534
  } catch (err) {
5520
5535
  if (attempt < RETRY_COUNT && isTransient(err)) {
5521
5536
  await sleep(RETRY_BACKOFF_MS * (attempt + 1));
5522
- return this.request(method, path95, body, attempt + 1);
5537
+ return this.request(method, path96, body, attempt + 1);
5523
5538
  }
5524
5539
  throw err;
5525
5540
  } finally {
@@ -7322,8 +7337,8 @@ var init_provider3 = __esm({
7322
7337
  // -----------------------------------------------------------------------
7323
7338
  // Internal fetch helper
7324
7339
  // -----------------------------------------------------------------------
7325
- async request(path95, method, body) {
7326
- const url2 = `${this.config.workerUrl}${path95}`;
7340
+ async request(path96, method, body) {
7341
+ const url2 = `${this.config.workerUrl}${path96}`;
7327
7342
  const bearer = await this.config.mintToken();
7328
7343
  const headers = {
7329
7344
  Authorization: `Bearer ${bearer}`
@@ -7884,6 +7899,46 @@ function hasImageRef(present, ref) {
7884
7899
  const variants = [`docker.io/library/${ref}`, `docker.io/${ref}`];
7885
7900
  return variants.some((v) => present.has(v));
7886
7901
  }
7902
+ function probeColimaKubernetesEnabled(opts) {
7903
+ const { platform: platform2, home } = opts;
7904
+ const colimaProfile = opts.colimaProfile ?? process.env.COLIMA_PROFILE ?? "default";
7905
+ const readFileFn = opts.readFileFn ?? ((p, enc) => readFileSync13(p, enc));
7906
+ const existsFn = opts.existsFn ?? existsSync13;
7907
+ if (platform2 !== "darwin") {
7908
+ return { ok: true, message: "colima k8s lint: not darwin, skip" };
7909
+ }
7910
+ const colimaYamlPath = path12.join(home, ".colima", colimaProfile, "colima.yaml");
7911
+ if (!existsFn(colimaYamlPath)) {
7912
+ return { ok: true, message: `colima k8s lint: ${colimaYamlPath} not found, skip` };
7913
+ }
7914
+ let yaml;
7915
+ try {
7916
+ yaml = readFileFn(colimaYamlPath, "utf8");
7917
+ } catch {
7918
+ return { ok: true, message: `colima k8s lint: could not read ${colimaYamlPath}` };
7919
+ }
7920
+ const kubernetesSection = yaml.split(/^kubernetes:/m)[1];
7921
+ if (!kubernetesSection) {
7922
+ return { ok: true, message: "colima k8s lint: no kubernetes section found" };
7923
+ }
7924
+ const sectionLines = kubernetesSection.split("\n");
7925
+ const sectionBody2 = [];
7926
+ for (const line of sectionLines) {
7927
+ if (line.length > 0 && !/^\s/.test(line)) break;
7928
+ sectionBody2.push(line);
7929
+ }
7930
+ const section = sectionBody2.join("\n");
7931
+ const enabled = /^\s+enabled:\s*true\s*$/m.test(section);
7932
+ if (!enabled) {
7933
+ return { ok: true, message: "colima k8s lint: kubernetes.enabled is not true" };
7934
+ }
7935
+ return {
7936
+ ok: true,
7937
+ warn: true,
7938
+ message: `Colima has Kubernetes mode enabled at profile '${colimaProfile}'`,
7939
+ remedy: `Colima has Kubernetes mode enabled at profile '${colimaProfile}'. k3d will attempt to coexist but may fail to start with 'context deadline exceeded' due to port conflicts. To fix: \`colima stop && colima start --kubernetes=false\`, OR re-run \`olam setup --reuse-cluster=colima\` to use Colima's existing k3s.`
7940
+ };
7941
+ }
7887
7942
  async function probeKubectl(exec = defaultDockerExec) {
7888
7943
  const r = exec("kubectl", ["version", "--client", "--output=json"]);
7889
7944
  if (r.status === 0 && r.stdout.length > 0) {
@@ -8104,7 +8159,8 @@ function rowToMetadata(row) {
8104
8159
  ...expectedServices !== void 0 ? { expectedServices } : {},
8105
8160
  ...appPortUrls !== void 0 ? { appPortUrls } : {},
8106
8161
  ...worldDbNames !== void 0 ? { worldDbNames } : {},
8107
- ...row.world_role_name ? { worldRoleName: row.world_role_name } : {}
8162
+ ...row.world_role_name ? { worldRoleName: row.world_role_name } : {},
8163
+ ...row.claude_home ? { claudeHome: row.claude_home } : {}
8108
8164
  };
8109
8165
  }
8110
8166
  var _require, _Database, SCHEMA_VERSION, CREATE_TABLE, CREATE_META, WorldRegistry;
@@ -8165,7 +8221,9 @@ CREATE TABLE IF NOT EXISTS meta (
8165
8221
  // world_db_names (SQLite has no native array; matches repos column shape).
8166
8222
  // TEXT[] would fail at DDL time (closes OQ13/OQ22 / FS-03).
8167
8223
  "world_db_names TEXT",
8168
- "world_role_name TEXT"
8224
+ "world_role_name TEXT",
8225
+ // ADR 045 — per-world Claude Code HOME path. Additive migration.
8226
+ "claude_home TEXT"
8169
8227
  ]) {
8170
8228
  try {
8171
8229
  this.db.exec(`ALTER TABLE worlds ADD COLUMN ${col}`);
@@ -8196,8 +8254,8 @@ CREATE TABLE IF NOT EXISTS meta (
8196
8254
  compute_provider, total_cost_usd, thought_count, created_at, updated_at,
8197
8255
  pr_url, pr_number, pr_repo, pr_created_at, pr_state, pr_merged_at, auto_destroy_on_merge,
8198
8256
  readiness_chain, expected_services, app_port_urls,
8199
- world_db_names, world_role_name)
8200
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(world.id, world.name, world.status, JSON.stringify(world.repos), world.branch, world.portOffset, world.workspacePath, world.computeProvider, world.totalCostUsd, world.thoughtCount, world.createdAt, world.updatedAt, world.prUrl ?? null, world.prNumber ?? null, world.prRepo ?? null, world.prCreatedAt ?? null, world.prState ?? "none", world.prMergedAt ?? null, world.autoDestroyOnMerge === false ? 0 : 1, world.readinessChain !== void 0 ? JSON.stringify(world.readinessChain) : null, world.expectedServices !== void 0 ? JSON.stringify(world.expectedServices) : null, world.appPortUrls !== void 0 ? JSON.stringify(world.appPortUrls) : null, world.worldDbNames !== void 0 ? JSON.stringify(world.worldDbNames) : null, world.worldRoleName ?? null);
8257
+ world_db_names, world_role_name, claude_home)
8258
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(world.id, world.name, world.status, JSON.stringify(world.repos), world.branch, world.portOffset, world.workspacePath, world.computeProvider, world.totalCostUsd, world.thoughtCount, world.createdAt, world.updatedAt, world.prUrl ?? null, world.prNumber ?? null, world.prRepo ?? null, world.prCreatedAt ?? null, world.prState ?? "none", world.prMergedAt ?? null, world.autoDestroyOnMerge === false ? 0 : 1, world.readinessChain !== void 0 ? JSON.stringify(world.readinessChain) : null, world.expectedServices !== void 0 ? JSON.stringify(world.expectedServices) : null, world.appPortUrls !== void 0 ? JSON.stringify(world.appPortUrls) : null, world.worldDbNames !== void 0 ? JSON.stringify(world.worldDbNames) : null, world.worldRoleName ?? null, world.claudeHome ?? null);
8201
8259
  }
8202
8260
  update(worldId, updates) {
8203
8261
  const setClauses = [];
@@ -8225,7 +8283,9 @@ CREATE TABLE IF NOT EXISTS meta (
8225
8283
  appPortUrls: "app_port_urls",
8226
8284
  // olam-hybrid-shared-postgres Phase A task A7.
8227
8285
  worldDbNames: "world_db_names",
8228
- worldRoleName: "world_role_name"
8286
+ worldRoleName: "world_role_name",
8287
+ // ADR 045 — per-world Claude Code HOME (multi-account isolation).
8288
+ claudeHome: "claude_home"
8229
8289
  };
8230
8290
  const jsonColumns = /* @__PURE__ */ new Set(["repos", "readinessChain", "expectedServices", "appPortUrls", "worldDbNames"]);
8231
8291
  for (const [key, col] of Object.entries(columnMap)) {
@@ -8922,9 +8982,9 @@ function buildRepoEnvBundle(repoName, serviceEnv, crossRepoEnv, envOverrides) {
8922
8982
  const merged = { ...serviceEnv, ...injectables };
8923
8983
  return { merged, injectables };
8924
8984
  }
8925
- function setupWorldEnv(repos, workspacePath, serviceEnv, crossRepoEnv = {}, configCtx) {
8985
+ function setupWorldEnv(repos, workspacePath, serviceEnv, crossRepoEnv = {}, configCtx, claudeHomeOverride) {
8926
8986
  try {
8927
- copyClaudeConfig(workspacePath, void 0, configCtx);
8987
+ copyClaudeConfig(workspacePath, claudeHomeOverride, configCtx);
8928
8988
  } catch {
8929
8989
  }
8930
8990
  if (configCtx) {
@@ -9124,17 +9184,17 @@ function kgRoot() {
9124
9184
  function worldsRoot() {
9125
9185
  return join17(olamHome(), "worlds");
9126
9186
  }
9127
- function assertWithinPrefix(path95, prefix, label) {
9128
- if (!path95.startsWith(prefix + "/")) {
9129
- throw new Error(`${label} escape: ${path95} not under ${prefix}/`);
9187
+ function assertWithinPrefix(path96, prefix, label) {
9188
+ if (!path96.startsWith(prefix + "/")) {
9189
+ throw new Error(`${label} escape: ${path96} not under ${prefix}/`);
9130
9190
  }
9131
9191
  }
9132
9192
  function kgPristinePath(workspace) {
9133
9193
  validateWorkspaceName(workspace);
9134
9194
  const root = kgRoot();
9135
- const path95 = resolve6(join17(root, workspace));
9136
- assertWithinPrefix(path95, root, "kgPristinePath");
9137
- return path95;
9195
+ const path96 = resolve6(join17(root, workspace));
9196
+ assertWithinPrefix(path96, root, "kgPristinePath");
9197
+ return path96;
9138
9198
  }
9139
9199
  var KG_PATHS_INTERNALS;
9140
9200
  var init_storage_paths = __esm({
@@ -9249,8 +9309,8 @@ import { execFileSync as execFileSync4 } from "node:child_process";
9249
9309
  import * as fs15 from "node:fs";
9250
9310
  import * as os9 from "node:os";
9251
9311
  import * as path17 from "node:path";
9252
- function expandHome2(p, homedir63) {
9253
- return p.replace(/^~(?=$|\/|\\)/, homedir63());
9312
+ function expandHome2(p, homedir64) {
9313
+ return p.replace(/^~(?=$|\/|\\)/, homedir64());
9254
9314
  }
9255
9315
  function sanitizeRepoFilename(name) {
9256
9316
  const sanitized = name.replace(/[^A-Za-z0-9._-]/g, "_");
@@ -9273,7 +9333,7 @@ ${stderr}`;
9273
9333
  }
9274
9334
  function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
9275
9335
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync4(cmd, args, opts));
9276
- const homedir63 = deps.homedir ?? (() => os9.homedir());
9336
+ const homedir64 = deps.homedir ?? (() => os9.homedir());
9277
9337
  const baselineDir = path17.join(workspacePath, ".olam", "baseline");
9278
9338
  try {
9279
9339
  fs15.mkdirSync(baselineDir, { recursive: true });
@@ -9289,7 +9349,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
9289
9349
  continue;
9290
9350
  const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
9291
9351
  const outPath = path17.join(baselineDir, filename);
9292
- const repoPath = expandHome2(repo.path, homedir63);
9352
+ const repoPath = expandHome2(repo.path, homedir64);
9293
9353
  if (!fs15.existsSync(repoPath)) {
9294
9354
  writeBaselineFile(outPath, `# repo: ${repo.name}
9295
9355
  # (skipped: path ${repoPath} does not exist)
@@ -9409,7 +9469,7 @@ function extractStderr(err) {
9409
9469
  }
9410
9470
  function carryUncommittedEdits(repos, workspacePath, deps = {}) {
9411
9471
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync4(cmd, args, opts));
9412
- const homedir63 = deps.homedir ?? (() => os9.homedir());
9472
+ const homedir64 = deps.homedir ?? (() => os9.homedir());
9413
9473
  const existsSync113 = deps.existsSync ?? ((p) => fs15.existsSync(p));
9414
9474
  const copyFileSync16 = deps.copyFileSync ?? ((src, dest) => fs15.copyFileSync(src, dest));
9415
9475
  const mkdirSync67 = deps.mkdirSync ?? ((dirPath, opts) => {
@@ -9419,7 +9479,7 @@ function carryUncommittedEdits(repos, workspacePath, deps = {}) {
9419
9479
  for (const repo of repos) {
9420
9480
  if (!repo.path)
9421
9481
  continue;
9422
- const repoPath = expandHome2(repo.path, homedir63);
9482
+ const repoPath = expandHome2(repo.path, homedir64);
9423
9483
  const worktreePath = path17.join(workspacePath, repo.name);
9424
9484
  if (!existsSync113(repoPath))
9425
9485
  continue;
@@ -12692,7 +12752,8 @@ ${detail}`);
12692
12752
  createdAt: now,
12693
12753
  updatedAt: now,
12694
12754
  readinessChain,
12695
- expectedServices
12755
+ expectedServices,
12756
+ ...opts.claudeHome ? { claudeHome: opts.claudeHome } : {}
12696
12757
  };
12697
12758
  const sm = new WorldStateMachine(worldId, "creating");
12698
12759
  this.registry.register(metadata);
@@ -12830,7 +12891,7 @@ ${detail}`);
12830
12891
  worlds_default: this.config.worlds_default,
12831
12892
  repos: enrichedRepos
12832
12893
  };
12833
- setupWorldEnv(enrichedRepos, workspacePath, serviceEnv, crossRepoEnv, configCtx);
12894
+ setupWorldEnv(enrichedRepos, workspacePath, serviceEnv, crossRepoEnv, configCtx, opts.claudeHome);
12834
12895
  } catch (err) {
12835
12896
  const msg = err instanceof Error ? err.message : String(err);
12836
12897
  console.warn(`[WorldManager] env setup failed: ${msg}`);
@@ -15704,10 +15765,10 @@ async function readHostCpToken2() {
15704
15765
  if (!fs26.existsSync(tp)) return null;
15705
15766
  return fs26.readFileSync(tp, "utf-8").trim();
15706
15767
  }
15707
- async function callHostCpProxy(method, worldId, path95, body) {
15768
+ async function callHostCpProxy(method, worldId, path96, body) {
15708
15769
  const token = await readHostCpToken2();
15709
15770
  if (!token) return { ok: false, status: 0, error: "no token (host CP not started)" };
15710
- const url2 = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path95}`;
15771
+ const url2 = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path96}`;
15711
15772
  try {
15712
15773
  const headers = {
15713
15774
  Authorization: `Bearer ${token}`
@@ -16174,17 +16235,75 @@ var init_registry_allowlist = __esm({
16174
16235
  }
16175
16236
  });
16176
16237
 
16238
+ // src/spawn/home-override.ts
16239
+ var home_override_exports = {};
16240
+ __export(home_override_exports, {
16241
+ CLAUDE_HOMES_BASE: () => CLAUDE_HOMES_BASE,
16242
+ HOME_ID_RE: () => HOME_ID_RE,
16243
+ SENTINEL_FILENAME: () => SENTINEL_FILENAME,
16244
+ ensureClaudeHomeDir: () => ensureClaudeHomeDir,
16245
+ resolveClaudeHome: () => resolveClaudeHome
16246
+ });
16247
+ import { mkdir, writeFile, access } from "node:fs/promises";
16248
+ import { homedir as homedir22 } from "node:os";
16249
+ import path36 from "node:path";
16250
+ function resolveClaudeHome(args) {
16251
+ const home = args.homeDir ?? homedir22();
16252
+ if (args.flag !== void 0 && args.flag.length > 0) {
16253
+ return resolveSpec(args.flag, home);
16254
+ }
16255
+ const stored = args.existingWorldConfig?.claudeHome;
16256
+ if (stored !== void 0 && stored.length > 0) {
16257
+ return resolveSpec(stored, home);
16258
+ }
16259
+ return args.envHome ?? home;
16260
+ }
16261
+ function resolveSpec(spec, home) {
16262
+ if (path36.isAbsolute(spec)) {
16263
+ return spec;
16264
+ }
16265
+ if (!HOME_ID_RE.test(spec)) {
16266
+ throw new Error(
16267
+ `--claude-home value "${spec}" must be either an absolute path or a bare id matching ${HOME_ID_RE} (alphanumeric, underscore, dash; starts with alphanumeric; max 64 chars). Rejected: relative paths, parent refs, uppercase, whitespace.`
16268
+ );
16269
+ }
16270
+ return path36.join(home, CLAUDE_HOMES_BASE, spec);
16271
+ }
16272
+ async function ensureClaudeHomeDir(targetPath) {
16273
+ await mkdir(targetPath, { recursive: true });
16274
+ const sentinelPath2 = path36.join(targetPath, SENTINEL_FILENAME);
16275
+ try {
16276
+ await access(sentinelPath2);
16277
+ return;
16278
+ } catch {
16279
+ }
16280
+ await writeFile(
16281
+ sentinelPath2,
16282
+ "# olam claude-home \u2014 managed by `olam create --claude-home`.\n# Do not delete. Re-create by running `olam create --claude-home <id>` again.\n",
16283
+ "utf-8"
16284
+ );
16285
+ }
16286
+ var CLAUDE_HOMES_BASE, SENTINEL_FILENAME, HOME_ID_RE;
16287
+ var init_home_override = __esm({
16288
+ "src/spawn/home-override.ts"() {
16289
+ "use strict";
16290
+ CLAUDE_HOMES_BASE = path36.join(".olam", "claude-homes");
16291
+ SENTINEL_FILENAME = ".olam-claude-home";
16292
+ HOME_ID_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/;
16293
+ }
16294
+ });
16295
+
16177
16296
  // ../core/dist/world/world-yaml.js
16178
16297
  import * as fs35 from "node:fs";
16179
- import * as path36 from "node:path";
16298
+ import * as path37 from "node:path";
16180
16299
  import { parse as parseYaml4, stringify as stringifyYaml4 } from "yaml";
16181
16300
  function writeWorldYaml(worldPath, data) {
16182
- const olamDir = path36.join(worldPath, ".olam");
16301
+ const olamDir = path37.join(worldPath, ".olam");
16183
16302
  fs35.mkdirSync(olamDir, { recursive: true });
16184
- fs35.writeFileSync(path36.join(olamDir, "world.yaml"), stringifyYaml4(data), "utf-8");
16303
+ fs35.writeFileSync(path37.join(olamDir, "world.yaml"), stringifyYaml4(data), "utf-8");
16185
16304
  }
16186
16305
  function readWorldYaml(worldPath) {
16187
- const yamlPath = path36.join(worldPath, ".olam", "world.yaml");
16306
+ const yamlPath = path37.join(worldPath, ".olam", "world.yaml");
16188
16307
  if (!fs35.existsSync(yamlPath))
16189
16308
  return null;
16190
16309
  try {
@@ -16313,14 +16432,14 @@ var init_checksum = __esm({
16313
16432
 
16314
16433
  // ../core/dist/skill-sources/trust-audit-log.js
16315
16434
  import * as fs52 from "node:fs";
16316
- import * as path54 from "node:path";
16435
+ import * as path55 from "node:path";
16317
16436
  import * as os28 from "node:os";
16318
16437
  function skillSourcesAuditLogPath() {
16319
16438
  const override = process.env["OLAM_SKILL_SOURCES_AUDIT_LOG_PATH"];
16320
16439
  if (override && override.length > 0)
16321
16440
  return override;
16322
- const stateDir = process.env["OLAM_STATE_DIR"] ?? path54.join(os28.homedir(), ".olam", "state");
16323
- return path54.join(stateDir, SKILL_SOURCES_AUDIT_LOG_FILENAME);
16441
+ const stateDir = process.env["OLAM_STATE_DIR"] ?? path55.join(os28.homedir(), ".olam", "state");
16442
+ return path55.join(stateDir, SKILL_SOURCES_AUDIT_LOG_FILENAME);
16324
16443
  }
16325
16444
  function appendTrustAudit(entry) {
16326
16445
  const candidate = {
@@ -16329,7 +16448,7 @@ function appendTrustAudit(entry) {
16329
16448
  };
16330
16449
  const validated = TrustAuditEntrySchema.parse(candidate);
16331
16450
  const filePath = skillSourcesAuditLogPath();
16332
- fs52.mkdirSync(path54.dirname(filePath), { recursive: true, mode: 448 });
16451
+ fs52.mkdirSync(path55.dirname(filePath), { recursive: true, mode: 448 });
16333
16452
  const fd = fs52.openSync(filePath, "a", 384);
16334
16453
  try {
16335
16454
  fs52.writeSync(fd, JSON.stringify(validated) + "\n");
@@ -16542,22 +16661,22 @@ var init_store3 = __esm({
16542
16661
  });
16543
16662
 
16544
16663
  // ../core/dist/skill-sources/clone.js
16545
- import { execFileSync as execFileSync13 } from "node:child_process";
16664
+ import { execFileSync as execFileSync14 } from "node:child_process";
16546
16665
  import * as fs53 from "node:fs";
16547
16666
  import * as os29 from "node:os";
16548
- import * as path55 from "node:path";
16667
+ import * as path56 from "node:path";
16549
16668
  function skillSourcesRootDir() {
16550
16669
  const override = process.env["OLAM_SKILL_SOURCES_DIR"];
16551
16670
  if (override && override.length > 0)
16552
16671
  return override;
16553
- return path55.join(os29.homedir(), ".olam", "state", "skill-sources");
16672
+ return path56.join(os29.homedir(), ".olam", "state", "skill-sources");
16554
16673
  }
16555
16674
  function skillSourceClonePath(id) {
16556
- return path55.join(skillSourcesRootDir(), id);
16675
+ return path56.join(skillSourcesRootDir(), id);
16557
16676
  }
16558
16677
  function runGit(args, cwd) {
16559
16678
  try {
16560
- return execFileSync13("git", args, {
16679
+ return execFileSync14("git", args, {
16561
16680
  cwd,
16562
16681
  encoding: "utf-8",
16563
16682
  stdio: ["ignore", "pipe", "pipe"]
@@ -16715,7 +16834,7 @@ var init_hook_template = __esm({
16715
16834
 
16716
16835
  // ../core/dist/world/merge-settings.js
16717
16836
  import * as fs55 from "node:fs";
16718
- import * as path56 from "node:path";
16837
+ import * as path57 from "node:path";
16719
16838
  import * as crypto8 from "node:crypto";
16720
16839
  function mergeHomeSettingsJson(filePath, options) {
16721
16840
  let settings;
@@ -16799,7 +16918,7 @@ function isHookSentinelPresent(matchers, sentinel) {
16799
16918
  return false;
16800
16919
  }
16801
16920
  function atomicWriteJson(filePath, data) {
16802
- const dir = path56.dirname(filePath);
16921
+ const dir = path57.dirname(filePath);
16803
16922
  fs55.mkdirSync(dir, { recursive: true });
16804
16923
  const rand = crypto8.randomBytes(6).toString("hex");
16805
16924
  const tmp = `${filePath}.tmp.${process.pid}.${rand}`;
@@ -16815,13 +16934,13 @@ var init_merge_settings = __esm({
16815
16934
 
16816
16935
  // ../core/dist/skill-sources/hook-install.js
16817
16936
  import * as fs56 from "node:fs";
16818
- import * as path57 from "node:path";
16937
+ import * as path58 from "node:path";
16819
16938
  import * as os30 from "node:os";
16820
16939
  function settingsPathFor(scope, cwd) {
16821
16940
  if (scope === "user") {
16822
- return path57.join(os30.homedir(), ".claude", "settings.json");
16941
+ return path58.join(os30.homedir(), ".claude", "settings.json");
16823
16942
  }
16824
- return path57.join(cwd ?? process.cwd(), ".claude", "settings.json");
16943
+ return path58.join(cwd ?? process.cwd(), ".claude", "settings.json");
16825
16944
  }
16826
16945
  function backupFile(filePath) {
16827
16946
  if (!fs56.existsSync(filePath))
@@ -16832,7 +16951,7 @@ function backupFile(filePath) {
16832
16951
  return backupPath;
16833
16952
  }
16834
16953
  function installSkillsHookToFile(filePath) {
16835
- fs56.mkdirSync(path57.dirname(filePath), { recursive: true });
16954
+ fs56.mkdirSync(path58.dirname(filePath), { recursive: true });
16836
16955
  const backupPath = backupFile(filePath);
16837
16956
  const result = mergeHomeSettingsJson(filePath, {
16838
16957
  ensureHook: {
@@ -16895,29 +17014,29 @@ var init_hook_install = __esm({
16895
17014
  // ../core/dist/skill-sources/migration-snapshot.js
16896
17015
  import * as fs57 from "node:fs";
16897
17016
  import * as os31 from "node:os";
16898
- import * as path58 from "node:path";
17017
+ import * as path59 from "node:path";
16899
17018
  function claudeDirInternal() {
16900
17019
  const override = process.env["OLAM_CLAUDE_DIR"];
16901
17020
  if (override && override.length > 0)
16902
17021
  return override;
16903
- return path58.join(os31.homedir(), ".claude");
17022
+ return path59.join(os31.homedir(), ".claude");
16904
17023
  }
16905
17024
  function migrationSnapshotsDir() {
16906
17025
  const override = process.env["OLAM_MIGRATION_SNAPSHOTS_DIR"];
16907
17026
  if (override && override.length > 0)
16908
17027
  return override;
16909
- return path58.join(os31.homedir(), ".olam", "state", "migration-snapshots");
17028
+ return path59.join(os31.homedir(), ".olam", "state", "migration-snapshots");
16910
17029
  }
16911
17030
  function listToolboxManagedSymlinks(toolboxPath) {
16912
17031
  const claude = claudeDirInternal();
16913
17032
  const out = [];
16914
17033
  const BUCKETS2 = ["skills", "agents", "scripts", "rules", "commands"];
16915
17034
  for (const bucket of BUCKETS2) {
16916
- const dir = path58.join(claude, bucket);
17035
+ const dir = path59.join(claude, bucket);
16917
17036
  if (!fs57.existsSync(dir))
16918
17037
  continue;
16919
17038
  for (const name of fs57.readdirSync(dir)) {
16920
- const link = path58.join(dir, name);
17039
+ const link = path59.join(dir, name);
16921
17040
  try {
16922
17041
  const stat = fs57.lstatSync(link);
16923
17042
  if (!stat.isSymbolicLink())
@@ -16935,12 +17054,12 @@ function listToolboxManagedSymlinks(toolboxPath) {
16935
17054
  function detectToolboxState(opts) {
16936
17055
  const claude = claudeDirInternal();
16937
17056
  const toolboxPath = opts.toolboxPath;
16938
- const namespace = opts.namespace ?? path58.basename(toolboxPath);
16939
- const atlasUserFile = path58.join(claude, ".atlas-user");
17057
+ const namespace = opts.namespace ?? path59.basename(toolboxPath);
17058
+ const atlasUserFile = path59.join(claude, ".atlas-user");
16940
17059
  const atlasUser = fs57.existsSync(atlasUserFile) ? fs57.readFileSync(atlasUserFile, "utf-8").trim() || void 0 : void 0;
16941
17060
  let subscriptionsJson;
16942
17061
  if (atlasUser) {
16943
- const sp = path58.join(toolboxPath, "members", atlasUser, "subscriptions.json");
17062
+ const sp = path59.join(toolboxPath, "members", atlasUser, "subscriptions.json");
16944
17063
  if (fs57.existsSync(sp)) {
16945
17064
  try {
16946
17065
  subscriptionsJson = JSON.parse(fs57.readFileSync(sp, "utf-8"));
@@ -16950,7 +17069,7 @@ function detectToolboxState(opts) {
16950
17069
  }
16951
17070
  const atlasManagedSymlinks = listToolboxManagedSymlinks(toolboxPath);
16952
17071
  let originalSessionStartHook;
16953
- const settingsPath = path58.join(claude, "settings.json");
17072
+ const settingsPath = path59.join(claude, "settings.json");
16954
17073
  if (fs57.existsSync(settingsPath)) {
16955
17074
  try {
16956
17075
  const settings = JSON.parse(fs57.readFileSync(settingsPath, "utf-8"));
@@ -16978,7 +17097,7 @@ function writeMigrationSnapshot(snapshot) {
16978
17097
  const dir = migrationSnapshotsDir();
16979
17098
  fs57.mkdirSync(dir, { recursive: true });
16980
17099
  const stamp = snapshot.takenAt.replace(/[:.]/g, "-");
16981
- const file = path58.join(dir, `${snapshot.namespace}-${stamp}.json`);
17100
+ const file = path59.join(dir, `${snapshot.namespace}-${stamp}.json`);
16982
17101
  fs57.writeFileSync(file, JSON.stringify(snapshot, null, 2) + "\n", { mode: 420 });
16983
17102
  return file;
16984
17103
  }
@@ -16988,7 +17107,7 @@ function readLatestMigrationSnapshot(opts = {}) {
16988
17107
  return void 0;
16989
17108
  const files = fs57.readdirSync(dir).filter((f) => f.endsWith(".json")).sort().reverse();
16990
17109
  for (const f of files) {
16991
- const full = path58.join(dir, f);
17110
+ const full = path59.join(dir, f);
16992
17111
  try {
16993
17112
  const snapshot = JSON.parse(fs57.readFileSync(full, "utf-8"));
16994
17113
  if (snapshot.schemaVersion !== MIGRATION_SNAPSHOT_SCHEMA_VERSION)
@@ -17015,11 +17134,11 @@ var init_migration_snapshot = __esm({
17015
17134
 
17016
17135
  // ../core/dist/skill-sync/artifact-resolver.js
17017
17136
  import * as fs58 from "node:fs";
17018
- import * as path59 from "node:path";
17137
+ import * as path60 from "node:path";
17019
17138
  function resolveSubscriptions(opts) {
17020
17139
  const { clonePath, atlasUser } = opts;
17021
17140
  if (atlasUser) {
17022
- const subsPath = path59.join(clonePath, "members", atlasUser, "subscriptions.json");
17141
+ const subsPath = path60.join(clonePath, "members", atlasUser, "subscriptions.json");
17023
17142
  if (fs58.existsSync(subsPath)) {
17024
17143
  try {
17025
17144
  const parsed = JSON.parse(fs58.readFileSync(subsPath, "utf-8"));
@@ -17034,7 +17153,7 @@ function resolveSubscriptions(opts) {
17034
17153
  }
17035
17154
  }
17036
17155
  }
17037
- const catsPath = path59.join(clonePath, "shared", "categories.json");
17156
+ const catsPath = path60.join(clonePath, "shared", "categories.json");
17038
17157
  if (fs58.existsSync(catsPath)) {
17039
17158
  try {
17040
17159
  const parsed = JSON.parse(fs58.readFileSync(catsPath, "utf-8"));
@@ -17048,14 +17167,14 @@ function resolveSubscriptions(opts) {
17048
17167
  } catch {
17049
17168
  }
17050
17169
  }
17051
- const sharedDir = path59.join(clonePath, "shared");
17170
+ const sharedDir = path60.join(clonePath, "shared");
17052
17171
  const cats = [];
17053
17172
  if (fs58.existsSync(sharedDir)) {
17054
17173
  for (const name of fs58.readdirSync(sharedDir)) {
17055
- const dir = path59.join(sharedDir, name);
17174
+ const dir = path60.join(sharedDir, name);
17056
17175
  if (!fs58.statSync(dir).isDirectory())
17057
17176
  continue;
17058
- if (fs58.existsSync(path59.join(dir, "skills")) || fs58.existsSync(path59.join(dir, "agents"))) {
17177
+ if (fs58.existsSync(path60.join(dir, "skills")) || fs58.existsSync(path60.join(dir, "agents"))) {
17059
17178
  cats.push(name);
17060
17179
  }
17061
17180
  }
@@ -17071,13 +17190,13 @@ function resolveSkillsDir(opts) {
17071
17190
  const { sourceId, baseDir } = opts;
17072
17191
  const out = [];
17073
17192
  for (const name of listDirSafe(baseDir)) {
17074
- const subdir = path59.join(baseDir, name);
17193
+ const subdir = path60.join(baseDir, name);
17075
17194
  if (!fs58.statSync(subdir).isDirectory())
17076
17195
  continue;
17077
- if (!fs58.existsSync(path59.join(subdir, "SKILL.md")))
17196
+ if (!fs58.existsSync(path60.join(subdir, "SKILL.md")))
17078
17197
  continue;
17079
17198
  out.push({ kind: "skill", sourceId, sourcePath: subdir, deployBasename: name });
17080
- const subagentsDir = path59.join(subdir, "references", "agents");
17199
+ const subagentsDir = path60.join(subdir, "references", "agents");
17081
17200
  if (fs58.existsSync(subagentsDir) && fs58.statSync(subagentsDir).isDirectory()) {
17082
17201
  for (const f of listDirSafe(subagentsDir)) {
17083
17202
  if (!f.endsWith(".md"))
@@ -17085,7 +17204,7 @@ function resolveSkillsDir(opts) {
17085
17204
  out.push({
17086
17205
  kind: "subagent",
17087
17206
  sourceId,
17088
- sourcePath: path59.join(subagentsDir, f),
17207
+ sourcePath: path60.join(subagentsDir, f),
17089
17208
  deployBasename: f,
17090
17209
  parentSkill: name
17091
17210
  });
@@ -17098,7 +17217,7 @@ function resolveAgentsDir(opts) {
17098
17217
  const { sourceId, baseDir } = opts;
17099
17218
  const out = [];
17100
17219
  for (const name of listDirSafe(baseDir)) {
17101
- const full = path59.join(baseDir, name);
17220
+ const full = path60.join(baseDir, name);
17102
17221
  const stat = fs58.statSync(full);
17103
17222
  if (stat.isFile() && name.endsWith(".md")) {
17104
17223
  out.push({ kind: "agent", sourceId, sourcePath: full, deployBasename: name });
@@ -17109,7 +17228,7 @@ function resolveAgentsDir(opts) {
17109
17228
  out.push({
17110
17229
  kind: "agent",
17111
17230
  sourceId,
17112
- sourcePath: path59.join(full, f),
17231
+ sourcePath: path60.join(full, f),
17113
17232
  deployBasename: `${name}-${f}`
17114
17233
  });
17115
17234
  }
@@ -17121,7 +17240,7 @@ function resolveScriptsDir(opts) {
17121
17240
  const { sourceId, baseDir } = opts;
17122
17241
  const out = [];
17123
17242
  for (const name of listDirSafe(baseDir)) {
17124
- const full = path59.join(baseDir, name);
17243
+ const full = path60.join(baseDir, name);
17125
17244
  const stat = fs58.statSync(full);
17126
17245
  if (stat.isFile() && name.endsWith(".sh")) {
17127
17246
  out.push({ kind: "script", sourceId, sourcePath: full, deployBasename: name });
@@ -17137,7 +17256,7 @@ function resolveRulesDir(opts) {
17137
17256
  for (const name of listDirSafe(baseDir)) {
17138
17257
  if (!name.endsWith(".md"))
17139
17258
  continue;
17140
- const full = path59.join(baseDir, name);
17259
+ const full = path60.join(baseDir, name);
17141
17260
  if (!fs58.statSync(full).isFile())
17142
17261
  continue;
17143
17262
  out.push({ kind: "rule", sourceId, sourcePath: full, deployBasename: name });
@@ -17150,7 +17269,7 @@ function resolveJsonDir(opts) {
17150
17269
  for (const name of listDirSafe(baseDir)) {
17151
17270
  if (!name.endsWith(".json"))
17152
17271
  continue;
17153
- const full = path59.join(baseDir, name);
17272
+ const full = path60.join(baseDir, name);
17154
17273
  if (!fs58.statSync(full).isFile())
17155
17274
  continue;
17156
17275
  out.push({ kind, sourceId, sourcePath: full, deployBasename: name });
@@ -17163,7 +17282,7 @@ function resolveOverlaysDir(opts) {
17163
17282
  for (const name of listDirSafe(baseDir)) {
17164
17283
  if (!name.endsWith(".md"))
17165
17284
  continue;
17166
- const full = path59.join(baseDir, name);
17285
+ const full = path60.join(baseDir, name);
17167
17286
  if (!fs58.statSync(full).isFile())
17168
17287
  continue;
17169
17288
  const deployBasename = name.replace(/\.md$/, "");
@@ -17182,33 +17301,33 @@ function resolveSourceArtifacts(opts) {
17182
17301
  const subscription = resolveSubscriptions({ clonePath, atlasUser });
17183
17302
  const artifacts = [];
17184
17303
  for (const cat of subscription.categories) {
17185
- const catDir = path59.join(clonePath, "shared", cat);
17304
+ const catDir = path60.join(clonePath, "shared", cat);
17186
17305
  if (!fs58.existsSync(catDir))
17187
17306
  continue;
17188
- artifacts.push(...resolveSkillsDir({ sourceId, baseDir: path59.join(catDir, "skills") }));
17189
- artifacts.push(...resolveAgentsDir({ sourceId, baseDir: path59.join(catDir, "agents") }));
17190
- artifacts.push(...resolveScriptsDir({ sourceId, baseDir: path59.join(catDir, "scripts") }));
17191
- artifacts.push(...resolveRulesDir({ sourceId, baseDir: path59.join(catDir, "rules") }));
17192
- artifacts.push(...resolveJsonDir({ sourceId, baseDir: path59.join(catDir, "hooks"), kind: "hook" }));
17193
- artifacts.push(...resolveJsonDir({ sourceId, baseDir: path59.join(catDir, "permissions"), kind: "permission" }));
17307
+ artifacts.push(...resolveSkillsDir({ sourceId, baseDir: path60.join(catDir, "skills") }));
17308
+ artifacts.push(...resolveAgentsDir({ sourceId, baseDir: path60.join(catDir, "agents") }));
17309
+ artifacts.push(...resolveScriptsDir({ sourceId, baseDir: path60.join(catDir, "scripts") }));
17310
+ artifacts.push(...resolveRulesDir({ sourceId, baseDir: path60.join(catDir, "rules") }));
17311
+ artifacts.push(...resolveJsonDir({ sourceId, baseDir: path60.join(catDir, "hooks"), kind: "hook" }));
17312
+ artifacts.push(...resolveJsonDir({ sourceId, baseDir: path60.join(catDir, "permissions"), kind: "permission" }));
17194
17313
  }
17195
17314
  if (atlasUser) {
17196
- const memberRoot = path59.join(clonePath, "members", atlasUser);
17315
+ const memberRoot = path60.join(clonePath, "members", atlasUser);
17197
17316
  if (fs58.existsSync(memberRoot)) {
17198
- artifacts.push(...resolveSkillsDir({ sourceId, baseDir: path59.join(memberRoot, "skills") }));
17199
- artifacts.push(...resolveAgentsDir({ sourceId, baseDir: path59.join(memberRoot, "agents") }));
17200
- artifacts.push(...resolveScriptsDir({ sourceId, baseDir: path59.join(memberRoot, "scripts") }));
17201
- artifacts.push(...resolveRulesDir({ sourceId, baseDir: path59.join(memberRoot, "rules") }));
17202
- artifacts.push(...resolveJsonDir({ sourceId, baseDir: path59.join(memberRoot, "hooks"), kind: "hook" }));
17203
- artifacts.push(...resolveJsonDir({ sourceId, baseDir: path59.join(memberRoot, "permissions"), kind: "permission" }));
17317
+ artifacts.push(...resolveSkillsDir({ sourceId, baseDir: path60.join(memberRoot, "skills") }));
17318
+ artifacts.push(...resolveAgentsDir({ sourceId, baseDir: path60.join(memberRoot, "agents") }));
17319
+ artifacts.push(...resolveScriptsDir({ sourceId, baseDir: path60.join(memberRoot, "scripts") }));
17320
+ artifacts.push(...resolveRulesDir({ sourceId, baseDir: path60.join(memberRoot, "rules") }));
17321
+ artifacts.push(...resolveJsonDir({ sourceId, baseDir: path60.join(memberRoot, "hooks"), kind: "hook" }));
17322
+ artifacts.push(...resolveJsonDir({ sourceId, baseDir: path60.join(memberRoot, "permissions"), kind: "permission" }));
17204
17323
  artifacts.push(...resolveOverlaysDir({
17205
17324
  sourceId,
17206
- baseDir: path59.join(memberRoot, "skills.overrides"),
17325
+ baseDir: path60.join(memberRoot, "skills.overrides"),
17207
17326
  targetKind: "skill"
17208
17327
  }));
17209
17328
  artifacts.push(...resolveOverlaysDir({
17210
17329
  sourceId,
17211
- baseDir: path59.join(memberRoot, "agents.overrides"),
17330
+ baseDir: path60.join(memberRoot, "agents.overrides"),
17212
17331
  targetKind: "agent"
17213
17332
  }));
17214
17333
  }
@@ -17275,12 +17394,12 @@ var init_shim_targets = __esm({
17275
17394
  // ../core/dist/skill-sync/symlink-deployer.js
17276
17395
  import * as fs59 from "node:fs";
17277
17396
  import * as os32 from "node:os";
17278
- import * as path60 from "node:path";
17397
+ import * as path61 from "node:path";
17279
17398
  function claudeDir() {
17280
17399
  const override = process.env["OLAM_CLAUDE_DIR"];
17281
17400
  if (override && override.length > 0)
17282
17401
  return override;
17283
- return path60.join(os32.homedir(), ".claude");
17402
+ return path61.join(os32.homedir(), ".claude");
17284
17403
  }
17285
17404
  function bucketFor(kind) {
17286
17405
  switch (kind) {
@@ -17340,13 +17459,13 @@ function detectCollisions(artifacts) {
17340
17459
  function cleanManagedSymlinks(claude, installedOlamVersion, overlayReferences, expectedAgentWinnerNames) {
17341
17460
  const shadowBackups = [];
17342
17461
  for (const bucket of BUCKETS) {
17343
- const dir = path60.join(claude, bucket);
17462
+ const dir = path61.join(claude, bucket);
17344
17463
  if (!fs59.existsSync(dir))
17345
17464
  continue;
17346
17465
  for (const name of fs59.readdirSync(dir)) {
17347
17466
  if (name === ".olam-merged")
17348
17467
  continue;
17349
- const p = path60.join(dir, name);
17468
+ const p = path61.join(dir, name);
17350
17469
  try {
17351
17470
  const stat = fs59.lstatSync(p);
17352
17471
  if (stat.isSymbolicLink()) {
@@ -17413,7 +17532,7 @@ function linkIfNeeded(target, link) {
17413
17532
  function deployArtifacts(artifacts, opts) {
17414
17533
  const claude = claudeDir();
17415
17534
  for (const bucket of BUCKETS) {
17416
- fs59.mkdirSync(path60.join(claude, bucket), { recursive: true });
17535
+ fs59.mkdirSync(path61.join(claude, bucket), { recursive: true });
17417
17536
  }
17418
17537
  const { winners, collisions } = detectCollisions(artifacts);
17419
17538
  const expectedAgentWinnerNames = new Set(winners.filter((a) => a.kind === "agent").map((a) => a.deployBasename));
@@ -17423,7 +17542,7 @@ function deployArtifacts(artifacts, opts) {
17423
17542
  const bucket = bucketFor(artifact.kind);
17424
17543
  if (!bucket)
17425
17544
  continue;
17426
- const linkPath = path60.join(claude, bucket, artifact.deployBasename);
17545
+ const linkPath = path61.join(claude, bucket, artifact.deployBasename);
17427
17546
  if (artifact.kind === "agent" && artifact.resolvedContent !== void 0) {
17428
17547
  const tmpPath = `${linkPath}.tmp-${process.pid}-${Date.now()}`;
17429
17548
  fs59.writeFileSync(tmpPath, artifact.resolvedContent);
@@ -17610,24 +17729,24 @@ var init_meta_hooks = __esm({
17610
17729
  // ../core/dist/skill-sync/settings-merger.js
17611
17730
  import * as fs62 from "node:fs";
17612
17731
  import * as os33 from "node:os";
17613
- import * as path61 from "node:path";
17732
+ import * as path62 from "node:path";
17614
17733
  function claudeSettingsPath() {
17615
17734
  const override = process.env["OLAM_CLAUDE_SETTINGS_PATH"];
17616
17735
  if (override && override.length > 0)
17617
17736
  return override;
17618
- return path61.join(claudeDirInternal2(), "settings.json");
17737
+ return path62.join(claudeDirInternal2(), "settings.json");
17619
17738
  }
17620
17739
  function claudeDirInternal2() {
17621
17740
  const override = process.env["OLAM_CLAUDE_DIR"];
17622
17741
  if (override && override.length > 0)
17623
17742
  return override;
17624
- return path61.join(os33.homedir(), ".claude");
17743
+ return path62.join(os33.homedir(), ".claude");
17625
17744
  }
17626
17745
  function settingsBackupDir() {
17627
17746
  const override = process.env["OLAM_SETTINGS_BACKUP_DIR"];
17628
17747
  if (override && override.length > 0)
17629
17748
  return override;
17630
- return path61.join(os33.homedir(), ".olam", "state", "settings-backups");
17749
+ return path62.join(os33.homedir(), ".olam", "state", "settings-backups");
17631
17750
  }
17632
17751
  function dedupeByMatcher(entries) {
17633
17752
  const map = /* @__PURE__ */ new Map();
@@ -17679,7 +17798,7 @@ function readJson(file) {
17679
17798
  function rotateBackups(backupDir) {
17680
17799
  if (!fs62.existsSync(backupDir))
17681
17800
  return;
17682
- const files = fs62.readdirSync(backupDir).filter((f) => f.endsWith(".json")).map((f) => ({ name: f, full: path61.join(backupDir, f), mtime: fs62.statSync(path61.join(backupDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
17801
+ const files = fs62.readdirSync(backupDir).filter((f) => f.endsWith(".json")).map((f) => ({ name: f, full: path62.join(backupDir, f), mtime: fs62.statSync(path62.join(backupDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
17683
17802
  for (const f of files.slice(BACKUP_RETENTION)) {
17684
17803
  try {
17685
17804
  fs62.unlinkSync(f.full);
@@ -17694,7 +17813,7 @@ function backupSettings() {
17694
17813
  const dir = settingsBackupDir();
17695
17814
  fs62.mkdirSync(dir, { recursive: true });
17696
17815
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
17697
- const dest = path61.join(dir, `settings-${stamp}.json`);
17816
+ const dest = path62.join(dir, `settings-${stamp}.json`);
17698
17817
  fs62.copyFileSync(src, dest);
17699
17818
  rotateBackups(dir);
17700
17819
  return dest;
@@ -17771,7 +17890,7 @@ function mergeSettings(input2) {
17771
17890
  ...input2.permissionFiles.length > 0 ? { allow: [...permSet] } : {}
17772
17891
  }
17773
17892
  };
17774
- fs62.mkdirSync(path61.dirname(settingsPath), { recursive: true });
17893
+ fs62.mkdirSync(path62.dirname(settingsPath), { recursive: true });
17775
17894
  const tmp = `${settingsPath}.tmp-${process.pid}`;
17776
17895
  fs62.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n", { mode: 420 });
17777
17896
  fs62.renameSync(tmp, settingsPath);
@@ -17830,15 +17949,15 @@ var init_schema5 = __esm({
17830
17949
  });
17831
17950
 
17832
17951
  // ../core/dist/skill-sync/per-project-override.js
17833
- import { execFileSync as execFileSync14 } from "node:child_process";
17952
+ import { execFileSync as execFileSync15 } from "node:child_process";
17834
17953
  import * as fs63 from "node:fs";
17835
- import * as path62 from "node:path";
17954
+ import * as path63 from "node:path";
17836
17955
  import { parse as parseYaml5 } from "yaml";
17837
17956
  function findProjectOverride(startDir) {
17838
- let dir = path62.resolve(startDir);
17839
- const root = path62.parse(dir).root;
17957
+ let dir = path63.resolve(startDir);
17958
+ const root = path63.parse(dir).root;
17840
17959
  while (true) {
17841
- const candidate = path62.join(dir, PROJECT_OVERRIDE_RELATIVE_PATH);
17960
+ const candidate = path63.join(dir, PROJECT_OVERRIDE_RELATIVE_PATH);
17842
17961
  if (fs63.existsSync(candidate) && fs63.statSync(candidate).isFile()) {
17843
17962
  const raw = fs63.readFileSync(candidate, "utf-8");
17844
17963
  let parsed;
@@ -17853,7 +17972,7 @@ function findProjectOverride(startDir) {
17853
17972
  }
17854
17973
  if (dir === root)
17855
17974
  return void 0;
17856
- dir = path62.dirname(dir);
17975
+ dir = path63.dirname(dir);
17857
17976
  }
17858
17977
  }
17859
17978
  function applyOverrideToArtifacts(artifacts, override) {
@@ -17873,7 +17992,7 @@ function applyPinToClone(opts) {
17873
17992
  if (ref.startsWith("-")) {
17874
17993
  throw new Error(`refuses ref "${ref}" \u2014 must not start with "-" (would be parsed as a git option)`);
17875
17994
  }
17876
- execFileSync14("git", ["-C", clonePath, "checkout", "-q", ref], {
17995
+ execFileSync15("git", ["-C", clonePath, "checkout", "-q", ref], {
17877
17996
  stdio: ["ignore", "ignore", "pipe"]
17878
17997
  });
17879
17998
  }
@@ -17883,7 +18002,7 @@ function restoreCloneToBranchHead(opts) {
17883
18002
  return;
17884
18003
  }
17885
18004
  try {
17886
- execFileSync14("git", ["-C", clonePath, "checkout", "-q", branch], {
18005
+ execFileSync15("git", ["-C", clonePath, "checkout", "-q", branch], {
17887
18006
  stdio: ["ignore", "ignore", "pipe"]
17888
18007
  });
17889
18008
  } catch {
@@ -17894,14 +18013,14 @@ var init_per_project_override = __esm({
17894
18013
  "../core/dist/skill-sync/per-project-override.js"() {
17895
18014
  "use strict";
17896
18015
  init_schema5();
17897
- PROJECT_OVERRIDE_RELATIVE_PATH = path62.join(".olam", "skill-overrides.yaml");
18016
+ PROJECT_OVERRIDE_RELATIVE_PATH = path63.join(".olam", "skill-overrides.yaml");
17898
18017
  }
17899
18018
  });
17900
18019
 
17901
18020
  // ../core/dist/lib/file-lock.js
17902
18021
  import * as fs64 from "node:fs";
17903
18022
  import * as os34 from "node:os";
17904
- import * as path63 from "node:path";
18023
+ import * as path64 from "node:path";
17905
18024
  function defaultIsPidAlive(pid) {
17906
18025
  try {
17907
18026
  process.kill(pid, 0);
@@ -17935,7 +18054,7 @@ function isLockStale(meta, opts) {
17935
18054
  }
17936
18055
  function tryAcquireOnce(lockPath, meta, opts) {
17937
18056
  try {
17938
- fs64.mkdirSync(path63.dirname(lockPath), { recursive: true });
18057
+ fs64.mkdirSync(path64.dirname(lockPath), { recursive: true });
17939
18058
  const fd = fs64.openSync(lockPath, "wx", 384);
17940
18059
  try {
17941
18060
  fs64.writeSync(fd, JSON.stringify(meta));
@@ -17967,7 +18086,7 @@ function tryAcquireOnce(lockPath, meta, opts) {
17967
18086
  }
17968
18087
  async function acquireFileLock(lockDir, options = {}) {
17969
18088
  const lockFilename = options.lockFilename ?? DEFAULT_LOCK_FILENAME;
17970
- const lockPath = path63.join(lockDir, lockFilename);
18089
+ const lockPath = path64.join(lockDir, lockFilename);
17971
18090
  const acquireTimeoutMs = options.acquireTimeoutMs ?? DEFAULT_ACQUIRE_TIMEOUT_MS;
17972
18091
  const staleLockMs = options.staleLockMs ?? DEFAULT_STALE_LOCK_MS;
17973
18092
  const now = options.now ?? Date.now;
@@ -18092,7 +18211,7 @@ var init_min_version_filter = __esm({
18092
18211
 
18093
18212
  // ../core/dist/skill-sync/overlay-scan.js
18094
18213
  import * as fs65 from "node:fs";
18095
- import * as path64 from "node:path";
18214
+ import * as path65 from "node:path";
18096
18215
  function scanOverlayReferences(overlayRoot, basenames, caps = DEFAULT_CAPS) {
18097
18216
  const result = /* @__PURE__ */ new Map();
18098
18217
  if (!fs65.existsSync(overlayRoot)) {
@@ -18109,7 +18228,7 @@ function scanOverlayReferences(overlayRoot, basenames, caps = DEFAULT_CAPS) {
18109
18228
  return result;
18110
18229
  }
18111
18230
  for (const subdir of OVERRIDE_SUBDIRS) {
18112
- const dir = path64.join(overlayRoot, subdir);
18231
+ const dir = path65.join(overlayRoot, subdir);
18113
18232
  if (!fs65.existsSync(dir))
18114
18233
  continue;
18115
18234
  walkMarkdown(dir, mdFiles, caps.maxFiles);
@@ -18125,8 +18244,8 @@ function scanOverlayReferences(overlayRoot, basenames, caps = DEFAULT_CAPS) {
18125
18244
  continue;
18126
18245
  throw err;
18127
18246
  }
18128
- const rel = path64.relative(overlayRootReal, realFile);
18129
- if (rel.startsWith("..") || path64.isAbsolute(rel)) {
18247
+ const rel = path65.relative(overlayRootReal, realFile);
18248
+ if (rel.startsWith("..") || path65.isAbsolute(rel)) {
18130
18249
  continue;
18131
18250
  }
18132
18251
  let content;
@@ -18144,7 +18263,7 @@ function scanOverlayReferences(overlayRoot, basenames, caps = DEFAULT_CAPS) {
18144
18263
  }
18145
18264
  throw err;
18146
18265
  }
18147
- const relpath = path64.relative(overlayRoot, filepath).split(path64.sep).join("/");
18266
+ const relpath = path65.relative(overlayRoot, filepath).split(path65.sep).join("/");
18148
18267
  for (const basename16 of basenames) {
18149
18268
  if (content.includes(basename16)) {
18150
18269
  const list = result.get(basename16) ?? [];
@@ -18168,7 +18287,7 @@ function walkMarkdown(dir, out, cap) {
18168
18287
  if (out.length >= cap) {
18169
18288
  throw new Error(`[overlay-scan] aborted: overlay tree contains > ${cap} markdown files. Check OLAM_CLAUDE_DIR / overlay paths are correctly scoped.`);
18170
18289
  }
18171
- const full = path64.join(dir, entry.name);
18290
+ const full = path65.join(dir, entry.name);
18172
18291
  if (entry.isSymbolicLink())
18173
18292
  continue;
18174
18293
  if (entry.isDirectory()) {
@@ -18195,10 +18314,10 @@ var init_overlay_scan = __esm({
18195
18314
  // ../core/dist/skill-sync/settings-json-lock.js
18196
18315
  import * as fs66 from "node:fs";
18197
18316
  import * as os35 from "node:os";
18198
- import * as path65 from "node:path";
18317
+ import * as path66 from "node:path";
18199
18318
  function defaultSettingsJsonLockPath() {
18200
- const stateDir = process.env["OLAM_STATE_DIR"] ?? path65.join(os35.homedir(), ".olam", "state");
18201
- return path65.join(stateDir, SETTINGS_JSON_LOCK_FILENAME);
18319
+ const stateDir = process.env["OLAM_STATE_DIR"] ?? path66.join(os35.homedir(), ".olam", "state");
18320
+ return path66.join(stateDir, SETTINGS_JSON_LOCK_FILENAME);
18202
18321
  }
18203
18322
  function defaultIsPidAlive2(pid) {
18204
18323
  try {
@@ -18237,7 +18356,7 @@ function isLockStale2(meta, opts) {
18237
18356
  function tryAcquireOnce2(lockPath, meta, opts) {
18238
18357
  for (let attempt = 0; attempt <= MAX_STEAL_ATTEMPTS; attempt += 1) {
18239
18358
  try {
18240
- fs66.mkdirSync(path65.dirname(lockPath), { recursive: true });
18359
+ fs66.mkdirSync(path66.dirname(lockPath), { recursive: true });
18241
18360
  const fd = fs66.openSync(lockPath, "wx", 384);
18242
18361
  try {
18243
18362
  fs66.writeSync(fd, JSON.stringify(meta));
@@ -18399,12 +18518,12 @@ var init_services_status = __esm({
18399
18518
  import * as crypto9 from "node:crypto";
18400
18519
  import * as fs67 from "node:fs";
18401
18520
  import * as os36 from "node:os";
18402
- import * as path66 from "node:path";
18521
+ import * as path67 from "node:path";
18403
18522
  function migrationSnapshotsDir2() {
18404
18523
  const override = process.env["OLAM_MIGRATION_SNAPSHOTS_DIR"];
18405
18524
  if (override && override.length > 0)
18406
18525
  return override;
18407
- return path66.join(os36.homedir(), ".olam", "state", "migration-snapshots");
18526
+ return path67.join(os36.homedir(), ".olam", "state", "migration-snapshots");
18408
18527
  }
18409
18528
  function writeMetaHooksSnapshot(originalSettings) {
18410
18529
  const snapshot = {
@@ -18418,7 +18537,7 @@ function writeMetaHooksSnapshot(originalSettings) {
18418
18537
  fs67.mkdirSync(dir, { recursive: true });
18419
18538
  const stamp = validated.takenAt.replace(/[:.]/g, "-");
18420
18539
  const rand = crypto9.randomBytes(3).toString("hex");
18421
- const file = path66.join(dir, `${META_HOOKS_SNAPSHOT_PREFIX}${stamp}-${process.pid}-${rand}.json`);
18540
+ const file = path67.join(dir, `${META_HOOKS_SNAPSHOT_PREFIX}${stamp}-${process.pid}-${rand}.json`);
18422
18541
  fs67.writeFileSync(file, JSON.stringify(validated, null, 2) + "\n", { mode: 384 });
18423
18542
  return file;
18424
18543
  }
@@ -18437,7 +18556,7 @@ function findLatestMetaHooksSnapshot() {
18437
18556
  const candidates2 = fs67.readdirSync(dir).filter((n) => n.startsWith(META_HOOKS_SNAPSHOT_PREFIX) && n.endsWith(".json")).sort().reverse();
18438
18557
  if (candidates2.length === 0)
18439
18558
  return void 0;
18440
- return path66.join(dir, candidates2[0]);
18559
+ return path67.join(dir, candidates2[0]);
18441
18560
  }
18442
18561
  function restoreSettingsFromSnapshot(snapshot, settingsPath) {
18443
18562
  if (snapshot.originalSettings === null) {
@@ -18446,7 +18565,7 @@ function restoreSettingsFromSnapshot(snapshot, settingsPath) {
18446
18565
  }
18447
18566
  return;
18448
18567
  }
18449
- fs67.mkdirSync(path66.dirname(settingsPath), { recursive: true });
18568
+ fs67.mkdirSync(path67.dirname(settingsPath), { recursive: true });
18450
18569
  const tmp = `${settingsPath}.tmp-restore-${process.pid}-${Date.now()}`;
18451
18570
  fs67.writeFileSync(tmp, JSON.stringify(snapshot.originalSettings, null, 2) + "\n");
18452
18571
  fs67.renameSync(tmp, settingsPath);
@@ -18816,17 +18935,17 @@ var init_markdown_merger = __esm({
18816
18935
 
18817
18936
  // ../core/dist/skill-sync/managed-merge.js
18818
18937
  import * as fs68 from "node:fs";
18819
- import * as path67 from "node:path";
18938
+ import * as path68 from "node:path";
18820
18939
  function materializeMergedSkill(opts) {
18821
18940
  const { sourceId, sourcePath, deployBasename, mergedContent, claudeDir: claudeDir2 } = opts;
18822
- const managedDir = path67.join(claudeDir2, ".olam-merged", sourceId, deployBasename);
18823
- const sourceRoot = path67.resolve(path67.join(claudeDir2, ".olam-merged", sourceId));
18824
- const managedResolved = path67.resolve(managedDir);
18825
- if (!(managedResolved === sourceRoot || managedResolved.startsWith(sourceRoot + path67.sep))) {
18941
+ const managedDir = path68.join(claudeDir2, ".olam-merged", sourceId, deployBasename);
18942
+ const sourceRoot = path68.resolve(path68.join(claudeDir2, ".olam-merged", sourceId));
18943
+ const managedResolved = path68.resolve(managedDir);
18944
+ if (!(managedResolved === sourceRoot || managedResolved.startsWith(sourceRoot + path68.sep))) {
18826
18945
  throw new Error(`[managed-merge] refusing to materialize: deployBasename "${deployBasename}" escapes managed root "${sourceRoot}" (resolved to "${managedResolved}")`);
18827
18946
  }
18828
18947
  fs68.mkdirSync(managedDir, { recursive: true });
18829
- const skillMdPath = path67.join(managedDir, "SKILL.md");
18948
+ const skillMdPath = path68.join(managedDir, "SKILL.md");
18830
18949
  const tmpPath = `${skillMdPath}.tmp-${process.pid}-${Date.now()}`;
18831
18950
  fs68.writeFileSync(tmpPath, mergedContent);
18832
18951
  fs68.renameSync(tmpPath, skillMdPath);
@@ -18834,9 +18953,9 @@ function materializeMergedSkill(opts) {
18834
18953
  for (const entry of baseEntries) {
18835
18954
  if (entry === "SKILL.md")
18836
18955
  continue;
18837
- const linkPath = path67.join(managedDir, entry);
18838
- const targetAbsolute = path67.join(sourcePath, entry);
18839
- const targetRelative = path67.relative(managedDir, targetAbsolute);
18956
+ const linkPath = path68.join(managedDir, entry);
18957
+ const targetAbsolute = path68.join(sourcePath, entry);
18958
+ const targetRelative = path68.relative(managedDir, targetAbsolute);
18840
18959
  try {
18841
18960
  fs68.lstatSync(linkPath);
18842
18961
  fs68.rmSync(linkPath, { recursive: true, force: true });
@@ -18850,7 +18969,7 @@ function materializeMergedSkill(opts) {
18850
18969
  if (entry === "SKILL.md")
18851
18970
  continue;
18852
18971
  if (!baseEntrySet.has(entry)) {
18853
- const stalePath = path67.join(managedDir, entry);
18972
+ const stalePath = path68.join(managedDir, entry);
18854
18973
  try {
18855
18974
  fs68.rmSync(stalePath, { recursive: true, force: true });
18856
18975
  } catch {
@@ -18860,7 +18979,7 @@ function materializeMergedSkill(opts) {
18860
18979
  return managedDir;
18861
18980
  }
18862
18981
  function cleanMergedDir(claudeDir2) {
18863
- fs68.rmSync(path67.join(claudeDir2, ".olam-merged"), { recursive: true, force: true });
18982
+ fs68.rmSync(path68.join(claudeDir2, ".olam-merged"), { recursive: true, force: true });
18864
18983
  }
18865
18984
  var init_managed_merge = __esm({
18866
18985
  "../core/dist/skill-sync/managed-merge.js"() {
@@ -18949,7 +19068,7 @@ var init_prefix_rules = __esm({
18949
19068
 
18950
19069
  // ../core/dist/skill-sync/prefix-deploy.js
18951
19070
  import * as fs69 from "node:fs";
18952
- import * as path68 from "node:path";
19071
+ import * as path69 from "node:path";
18953
19072
  function buildSourcePrefixMap(sources) {
18954
19073
  const byId = /* @__PURE__ */ new Map();
18955
19074
  const scopeById = /* @__PURE__ */ new Map();
@@ -18997,7 +19116,7 @@ function applyPrefixRewrites(baseArtifacts, sourceMap, claudeDir2, dryRun) {
18997
19116
  continue;
18998
19117
  }
18999
19118
  if (artifact.kind === "skill") {
19000
- const skillMdPath = path68.join(artifact.sourcePath, "SKILL.md");
19119
+ const skillMdPath = path69.join(artifact.sourcePath, "SKILL.md");
19001
19120
  const content = fs69.readFileSync(skillMdPath);
19002
19121
  const rewritten = rewriteFrontmatterName(content, () => renamedFrontmatterName);
19003
19122
  const managedDir = materializeMergedSkill({
@@ -19062,12 +19181,12 @@ function sourceConfigPath(clonePath) {
19062
19181
  return join76(clonePath, "shared", "source-config.yaml");
19063
19182
  }
19064
19183
  function readSourceConfig(clonePath, sourceId) {
19065
- const path95 = sourceConfigPath(clonePath);
19066
- if (!existsSync77(path95))
19184
+ const path96 = sourceConfigPath(clonePath);
19185
+ if (!existsSync77(path96))
19067
19186
  return void 0;
19068
19187
  let raw;
19069
19188
  try {
19070
- raw = readFileSync66(path95, "utf-8");
19189
+ raw = readFileSync66(path96, "utf-8");
19071
19190
  } catch (err) {
19072
19191
  emitMalformedWarning(sourceId, `read failed: ${errToMsg(err)}`);
19073
19192
  return void 0;
@@ -19148,12 +19267,12 @@ var init_resolve_source_config = __esm({
19148
19267
  // ../core/dist/skill-sync/engine.js
19149
19268
  import * as fs70 from "node:fs";
19150
19269
  import * as os37 from "node:os";
19151
- import * as path69 from "node:path";
19270
+ import * as path70 from "node:path";
19152
19271
  function resolveAtlasUser(override) {
19153
19272
  if (override)
19154
19273
  return override;
19155
- const claudeDir2 = process.env["OLAM_CLAUDE_DIR"] || path69.join(os37.homedir(), ".claude");
19156
- const f = path69.join(claudeDir2, ".atlas-user");
19274
+ const claudeDir2 = process.env["OLAM_CLAUDE_DIR"] || path70.join(os37.homedir(), ".claude");
19275
+ const f = path70.join(claudeDir2, ".atlas-user");
19157
19276
  if (fs70.existsSync(f)) {
19158
19277
  return fs70.readFileSync(f, "utf-8").trim() || void 0;
19159
19278
  }
@@ -19310,7 +19429,7 @@ async function syncSkills(opts = {}) {
19310
19429
  let baseContent;
19311
19430
  let basePath;
19312
19431
  if (overlay.targetKind === "skill") {
19313
- basePath = path69.join(base.sourcePath, "SKILL.md");
19432
+ basePath = path70.join(base.sourcePath, "SKILL.md");
19314
19433
  baseContent = fs70.readFileSync(basePath, "utf-8");
19315
19434
  } else {
19316
19435
  basePath = base.sourcePath;
@@ -19377,7 +19496,7 @@ async function syncSkills(opts = {}) {
19377
19496
  summary2.collisions = detectCollisions(baseArtifacts).collisions;
19378
19497
  return summary2;
19379
19498
  }
19380
- const claudeDirPath = process.env["OLAM_CLAUDE_DIR"] || path69.join(os37.homedir(), ".claude");
19499
+ const claudeDirPath = process.env["OLAM_CLAUDE_DIR"] || path70.join(os37.homedir(), ".claude");
19381
19500
  const overlayReferences = scanOverlayReferences(claudeDirPath, SHIM_TARGETS.map((t) => t.basename));
19382
19501
  summary2.deploy = deployArtifacts(baseArtifacts, {
19383
19502
  installedOlamVersion,
@@ -19411,10 +19530,10 @@ async function injectMetaHooksIntoSettings(opts) {
19411
19530
  } catch {
19412
19531
  try {
19413
19532
  const raw = fs70.readFileSync(settingsFile);
19414
- const bakDir = path69.join(path69.dirname(settingsFile), ".malformed-backups");
19533
+ const bakDir = path70.join(path70.dirname(settingsFile), ".malformed-backups");
19415
19534
  fs70.mkdirSync(bakDir, { recursive: true });
19416
19535
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
19417
- const bakFile = path69.join(bakDir, `settings.json.malformed.${stamp}.bak`);
19536
+ const bakFile = path70.join(bakDir, `settings.json.malformed.${stamp}.bak`);
19418
19537
  fs70.writeFileSync(bakFile, raw, { mode: 384 });
19419
19538
  snapshotError = `settings.json was malformed; original bytes preserved at ${bakFile}`;
19420
19539
  } catch (bakErr) {
@@ -19465,7 +19584,7 @@ async function injectMetaHooksIntoSettings(opts) {
19465
19584
  } catch {
19466
19585
  }
19467
19586
  }
19468
- fs70.mkdirSync(path69.dirname(settingsFile), { recursive: true });
19587
+ fs70.mkdirSync(path70.dirname(settingsFile), { recursive: true });
19469
19588
  const tmpPath = `${settingsFile}.tmp-${process.pid}-${Date.now()}`;
19470
19589
  fs70.writeFileSync(tmpPath, JSON.stringify(inject.nextSettings, null, 2) + "\n");
19471
19590
  fs70.renameSync(tmpPath, settingsFile);
@@ -19510,13 +19629,13 @@ var init_engine = __esm({
19510
19629
 
19511
19630
  // ../core/dist/skill-sync/shadow-backup-manager.js
19512
19631
  import * as fs71 from "node:fs";
19513
- import * as path70 from "node:path";
19632
+ import * as path71 from "node:path";
19514
19633
  function listShadowBackups(opts = {}) {
19515
19634
  const claude = opts.claudeDirOverride ?? claudeDir();
19516
19635
  const now = opts.now ?? Date.now();
19517
19636
  const out = [];
19518
19637
  for (const bucket of SHADOW_BACKUP_BUCKETS) {
19519
- const bucketDir = path70.join(claude, bucket);
19638
+ const bucketDir = path71.join(claude, bucket);
19520
19639
  if (!fs71.existsSync(bucketDir))
19521
19640
  continue;
19522
19641
  let entries;
@@ -19532,7 +19651,7 @@ function listShadowBackups(opts = {}) {
19532
19651
  const epochSeconds = Number.parseInt(match2[1], 10);
19533
19652
  if (!Number.isFinite(epochSeconds) || epochSeconds < 0)
19534
19653
  continue;
19535
- const full = path70.join(bucketDir, name);
19654
+ const full = path71.join(bucketDir, name);
19536
19655
  let sizeBytes = 0;
19537
19656
  try {
19538
19657
  const st = fs71.statSync(full);
@@ -19548,7 +19667,7 @@ function listShadowBackups(opts = {}) {
19548
19667
  bucket,
19549
19668
  basename: name,
19550
19669
  originalBasename,
19551
- originalPath: path70.join(bucketDir, originalBasename),
19670
+ originalPath: path71.join(bucketDir, originalBasename),
19552
19671
  epochSeconds,
19553
19672
  ageMs: now - epochSeconds * 1e3,
19554
19673
  sizeBytes
@@ -19602,17 +19721,17 @@ function pruneShadowBackups(opts) {
19602
19721
  return { deleted, skipped };
19603
19722
  }
19604
19723
  function restoreShadowBackup(opts) {
19605
- const abs = path70.resolve(opts.backupPath);
19724
+ const abs = path71.resolve(opts.backupPath);
19606
19725
  if (!fs71.existsSync(abs)) {
19607
19726
  throw new Error(`backup file not found: ${abs}`);
19608
19727
  }
19609
- const basename16 = path70.basename(abs);
19728
+ const basename16 = path71.basename(abs);
19610
19729
  const match2 = SHADOW_BACKUP_SUFFIX_RE.exec(basename16);
19611
19730
  if (!match2) {
19612
19731
  throw new Error(`not a shadow-backup file (basename "${basename16}" does not match \`.shadow-backup-<epoch>\`): ${abs}`);
19613
19732
  }
19614
19733
  const originalBasename = basename16.slice(0, basename16.length - match2[0].length);
19615
- const originalPath = path70.join(path70.dirname(abs), originalBasename);
19734
+ const originalPath = path71.join(path71.dirname(abs), originalBasename);
19616
19735
  if (fs71.existsSync(originalPath) && !opts.force) {
19617
19736
  throw new Error(`original path already occupied: ${originalPath}. Move/rename it first OR re-run with --force.`);
19618
19737
  }
@@ -19635,10 +19754,10 @@ var init_shadow_backup_manager = __esm({
19635
19754
  // ../core/dist/global-config/repos.js
19636
19755
  import * as fs72 from "node:fs";
19637
19756
  import * as os38 from "node:os";
19638
- import * as path71 from "node:path";
19757
+ import * as path72 from "node:path";
19639
19758
  function expandPath(p) {
19640
19759
  if (p === "~" || p.startsWith("~/")) {
19641
- return path71.join(os38.homedir(), p.slice(1));
19760
+ return path72.join(os38.homedir(), p.slice(1));
19642
19761
  }
19643
19762
  return p;
19644
19763
  }
@@ -19750,13 +19869,13 @@ var init_global_config = __esm({
19750
19869
 
19751
19870
  // ../core/dist/skill-sources/doctor-checks.js
19752
19871
  import * as fs73 from "node:fs";
19753
- import * as path72 from "node:path";
19872
+ import * as path73 from "node:path";
19754
19873
  import * as os39 from "node:os";
19755
19874
  function claudeDirInternal3() {
19756
19875
  const override = process.env["OLAM_CLAUDE_DIR"];
19757
19876
  if (override && override.length > 0)
19758
19877
  return override;
19759
- return path72.join(os39.homedir(), ".claude");
19878
+ return path73.join(os39.homedir(), ".claude");
19760
19879
  }
19761
19880
  function checkStateFileParse() {
19762
19881
  const filePath = globalConfigPath();
@@ -19811,11 +19930,11 @@ function checkDanglingSymlinks() {
19811
19930
  const buckets = ["commands", "agents", "skills", "scripts", "rules"];
19812
19931
  const dangling = [];
19813
19932
  for (const bucket of buckets) {
19814
- const dir = path72.join(claude, bucket);
19933
+ const dir = path73.join(claude, bucket);
19815
19934
  if (!fs73.existsSync(dir))
19816
19935
  continue;
19817
19936
  for (const name of fs73.readdirSync(dir)) {
19818
- const linkPath = path72.join(dir, name);
19937
+ const linkPath = path73.join(dir, name);
19819
19938
  try {
19820
19939
  const lst = fs73.lstatSync(linkPath);
19821
19940
  if (!lst.isSymbolicLink())
@@ -19860,7 +19979,7 @@ function checkOrphanedSnapshots() {
19860
19979
  for (const name of fs73.readdirSync(dir)) {
19861
19980
  if (!name.endsWith(".json"))
19862
19981
  continue;
19863
- const full = path72.join(dir, name);
19982
+ const full = path73.join(dir, name);
19864
19983
  try {
19865
19984
  const stat = fs73.statSync(full);
19866
19985
  if (!stat.isFile())
@@ -19998,7 +20117,7 @@ function checkMemberNameMissing() {
19998
20117
  return result;
19999
20118
  }
20000
20119
  const claudeDir2 = claudeDirInternal3();
20001
- const atlasUserPath = path72.join(claudeDir2, ".atlas-user");
20120
+ const atlasUserPath = path73.join(claudeDir2, ".atlas-user");
20002
20121
  const value = fs73.existsSync(atlasUserPath) ? fs73.readFileSync(atlasUserPath, "utf-8").trim() : "";
20003
20122
  if (value.length > 0) {
20004
20123
  result.details = [`atlas-user: ${value}`];
@@ -20007,10 +20126,10 @@ function checkMemberNameMissing() {
20007
20126
  result.healthy = false;
20008
20127
  result.issue = "atlas-toolbox source registered but ~/.claude/.atlas-user not set";
20009
20128
  const clonePath = skillSourceClonePath(atlasSource.id);
20010
- const membersDir = path72.join(clonePath, "members");
20129
+ const membersDir = path73.join(clonePath, "members");
20011
20130
  const existing = fs73.existsSync(membersDir) ? fs73.readdirSync(membersDir).filter((e) => {
20012
20131
  try {
20013
- return fs73.statSync(path72.join(membersDir, e)).isDirectory();
20132
+ return fs73.statSync(path73.join(membersDir, e)).isDirectory();
20014
20133
  } catch {
20015
20134
  return false;
20016
20135
  }
@@ -20024,7 +20143,7 @@ function checkMemberNameMissing() {
20024
20143
  }
20025
20144
  function checkMemberOverlayDrift() {
20026
20145
  const claudeDir2 = claudeDirInternal3();
20027
- const atlasUserPath = path72.join(claudeDir2, ".atlas-user");
20146
+ const atlasUserPath = path73.join(claudeDir2, ".atlas-user");
20028
20147
  const atlasUser = fs73.existsSync(atlasUserPath) ? fs73.readFileSync(atlasUserPath, "utf-8").trim() : "";
20029
20148
  if (atlasUser.length === 0) {
20030
20149
  return [];
@@ -20041,7 +20160,7 @@ function checkMemberOverlayDrift() {
20041
20160
  const clonePath = skillSourceClonePath(atlasSource.id);
20042
20161
  const results = [];
20043
20162
  for (const kind of ["skills", "agents"]) {
20044
- const localRoot = path72.join(claudeDir2, `${kind}.overrides`);
20163
+ const localRoot = path73.join(claudeDir2, `${kind}.overrides`);
20045
20164
  if (!fs73.existsSync(localRoot))
20046
20165
  continue;
20047
20166
  let entries;
@@ -20051,7 +20170,7 @@ function checkMemberOverlayDrift() {
20051
20170
  continue;
20052
20171
  }
20053
20172
  for (const entry of entries) {
20054
- const localFile = path72.join(localRoot, entry);
20173
+ const localFile = path73.join(localRoot, entry);
20055
20174
  let stat;
20056
20175
  try {
20057
20176
  stat = fs73.statSync(localFile);
@@ -20060,7 +20179,7 @@ function checkMemberOverlayDrift() {
20060
20179
  }
20061
20180
  if (!stat.isFile())
20062
20181
  continue;
20063
- const cloneFile = path72.join(clonePath, "members", atlasUser, `${kind}.overrides`, entry);
20182
+ const cloneFile = path73.join(clonePath, "members", atlasUser, `${kind}.overrides`, entry);
20064
20183
  const localSha = sha256OfPath(localFile);
20065
20184
  const cloneSha = sha256OfPath(cloneFile);
20066
20185
  if (localSha === cloneSha) {
@@ -20229,7 +20348,7 @@ var project_sweep_exports = {};
20229
20348
  __export(project_sweep_exports, {
20230
20349
  walkProjectRoot: () => walkProjectRoot
20231
20350
  });
20232
- import * as path73 from "node:path";
20351
+ import * as path74 from "node:path";
20233
20352
  import { readdirSync as readdirSync25, lstatSync as lstatSync6, statSync as statSync25, existsSync as existsSync82 } from "node:fs";
20234
20353
  function isSkipped(basename16, extra) {
20235
20354
  if (DEFAULT_SKIP.has(basename16))
@@ -20241,7 +20360,7 @@ function isSkipped(basename16, extra) {
20241
20360
  return false;
20242
20361
  }
20243
20362
  function resolveMtime(dirPath, manifestFile, fsAdapter) {
20244
- const gitHead = path73.join(dirPath, ".git", "HEAD");
20363
+ const gitHead = path74.join(dirPath, ".git", "HEAD");
20245
20364
  if (fsAdapter.existsSync(gitHead)) {
20246
20365
  try {
20247
20366
  return fsAdapter.statSync(gitHead).mtimeMs;
@@ -20255,8 +20374,8 @@ function resolveMtime(dirPath, manifestFile, fsAdapter) {
20255
20374
  }
20256
20375
  }
20257
20376
  function walk2(currentPath, depth, maxDepth, extraExclude, fsAdapter, results) {
20258
- const adbManifest = path73.join(currentPath, ".adb.yaml");
20259
- const olamManifest = path73.join(currentPath, ".olam.yaml");
20377
+ const adbManifest = path74.join(currentPath, ".adb.yaml");
20378
+ const olamManifest = path74.join(currentPath, ".olam.yaml");
20260
20379
  if (fsAdapter.existsSync(adbManifest)) {
20261
20380
  const mtime = resolveMtime(currentPath, adbManifest, fsAdapter);
20262
20381
  results.push({ path: currentPath, manifestType: "adb", mtime });
@@ -20278,7 +20397,7 @@ function walk2(currentPath, depth, maxDepth, extraExclude, fsAdapter, results) {
20278
20397
  for (const entry of entries) {
20279
20398
  if (isSkipped(entry, extraExclude))
20280
20399
  continue;
20281
- const childPath = path73.join(currentPath, entry);
20400
+ const childPath = path74.join(currentPath, entry);
20282
20401
  let stat;
20283
20402
  try {
20284
20403
  stat = fsAdapter.lstatSync(childPath);
@@ -20336,11 +20455,11 @@ __export(kg_eager_exports, {
20336
20455
  writeQueue: () => writeQueue
20337
20456
  });
20338
20457
  import * as fs74 from "node:fs";
20339
- import * as path74 from "node:path";
20458
+ import * as path75 from "node:path";
20340
20459
  import * as os40 from "node:os";
20341
20460
  function defaultQueuePath() {
20342
- const stateDir = process.env["OLAM_STATE_DIR"] ?? path74.join(os40.homedir(), ".olam", "state");
20343
- return path74.join(stateDir, "kg-pending.jsonl");
20461
+ const stateDir = process.env["OLAM_STATE_DIR"] ?? path75.join(os40.homedir(), ".olam", "state");
20462
+ return path75.join(stateDir, "kg-pending.jsonl");
20344
20463
  }
20345
20464
  function readQueue(queuePath) {
20346
20465
  if (!fs74.existsSync(queuePath))
@@ -20359,14 +20478,14 @@ function readQueue(queuePath) {
20359
20478
  return entries;
20360
20479
  }
20361
20480
  function writeQueue(queuePath, entries) {
20362
- fs74.mkdirSync(path74.dirname(queuePath), { recursive: true });
20481
+ fs74.mkdirSync(path75.dirname(queuePath), { recursive: true });
20363
20482
  const content = entries.map((e) => JSON.stringify(e)).join("\n") + (entries.length > 0 ? "\n" : "");
20364
20483
  fs74.writeFileSync(queuePath, content, "utf-8");
20365
20484
  }
20366
20485
  function appendQueue(queuePath, repos, nowMs) {
20367
20486
  if (repos.length === 0)
20368
20487
  return;
20369
- fs74.mkdirSync(path74.dirname(queuePath), { recursive: true });
20488
+ fs74.mkdirSync(path75.dirname(queuePath), { recursive: true });
20370
20489
  const lines = repos.map((r) => JSON.stringify({ path: r.path, addedAt: nowMs })).join("\n") + "\n";
20371
20490
  fs74.appendFileSync(queuePath, lines, "utf-8");
20372
20491
  }
@@ -20422,7 +20541,7 @@ __export(machine_schema_exports, {
20422
20541
  writeMachineConfig: () => writeMachineConfig
20423
20542
  });
20424
20543
  import * as fs77 from "node:fs";
20425
- import * as path78 from "node:path";
20544
+ import * as path79 from "node:path";
20426
20545
  import * as os41 from "node:os";
20427
20546
  import { parse as parseYaml7, stringify as stringifyYaml5 } from "yaml";
20428
20547
  function readMachineConfig(configPath) {
@@ -20439,7 +20558,7 @@ function readMachineConfig(configPath) {
20439
20558
  }
20440
20559
  function writeMachineConfig(config, configPath) {
20441
20560
  const p = configPath ?? DEFAULT_CONFIG_PATH;
20442
- fs77.mkdirSync(path78.dirname(p), { recursive: true });
20561
+ fs77.mkdirSync(path79.dirname(p), { recursive: true });
20443
20562
  fs77.writeFileSync(p, stringifyYaml5({ ...config }), { mode: 420 });
20444
20563
  }
20445
20564
  function initMachineConfig(opts = {}) {
@@ -20463,9 +20582,9 @@ var init_machine_schema = __esm({
20463
20582
  channel: external_exports.enum(["stable", "beta", "edge"]).default("stable"),
20464
20583
  auto_update: external_exports.boolean().default(true),
20465
20584
  telemetry: external_exports.boolean().default(true),
20466
- worlds_dir: external_exports.string().default(() => path78.join(os41.homedir(), ".olam", "worlds"))
20585
+ worlds_dir: external_exports.string().default(() => path79.join(os41.homedir(), ".olam", "worlds"))
20467
20586
  });
20468
- DEFAULT_CONFIG_PATH = path78.join(os41.homedir(), ".olam", "config.yaml");
20587
+ DEFAULT_CONFIG_PATH = path79.join(os41.homedir(), ".olam", "config.yaml");
20469
20588
  }
20470
20589
  });
20471
20590
 
@@ -20660,16 +20779,16 @@ function isValidConfig(value) {
20660
20779
  if (typeof v.install_id !== "string" || v.install_id.length === 0) return false;
20661
20780
  return true;
20662
20781
  }
20663
- function atomicWriteJSON(path95, value, stderr = process.stderr) {
20782
+ function atomicWriteJSON(path96, value, stderr = process.stderr) {
20664
20783
  ensureStateDir();
20665
- const dir = dirname3(path95);
20784
+ const dir = dirname3(path96);
20666
20785
  if (!existsSync6(dir)) {
20667
20786
  mkdirSync2(dir, { recursive: true });
20668
20787
  }
20669
- const tmp = `${path95}.tmp.${process.pid}`;
20788
+ const tmp = `${path96}.tmp.${process.pid}`;
20670
20789
  try {
20671
20790
  writeFileSync2(tmp, JSON.stringify(value, null, 2) + "\n", { encoding: "utf8" });
20672
- renameSync2(tmp, path95);
20791
+ renameSync2(tmp, path96);
20673
20792
  } catch (err) {
20674
20793
  if (existsSync6(tmp)) {
20675
20794
  try {
@@ -21030,9 +21149,9 @@ var UnknownArchetypeError = class extends Error {
21030
21149
  };
21031
21150
  var ArchetypeCycleError = class extends Error {
21032
21151
  path;
21033
- constructor(path95) {
21034
- super(`Archetype inheritance cycle detected: ${path95.join(" \u2192 ")} \u2192 ${path95[0] ?? "?"}`);
21035
- this.path = path95;
21152
+ constructor(path96) {
21153
+ super(`Archetype inheritance cycle detected: ${path96.join(" \u2192 ")} \u2192 ${path96[0] ?? "?"}`);
21154
+ this.path = path96;
21036
21155
  this.name = "ArchetypeCycleError";
21037
21156
  }
21038
21157
  };
@@ -21520,7 +21639,7 @@ function substitutePlaceholders(templateYaml, values) {
21520
21639
  function renderOneSecret(binding, templatesRoot, reuse, deps = {}, rotate = false) {
21521
21640
  const olamHome5 = deps.olamHome ?? OLAM_HOME;
21522
21641
  const readFile = deps.readFile ?? defaultReadFile;
21523
- const writeFile = deps.writeFile ?? defaultWriteFile;
21642
+ const writeFile2 = deps.writeFile ?? defaultWriteFile;
21524
21643
  const fileExists = deps.fileExists ?? defaultFileExists;
21525
21644
  const genRandomHex = deps.genRandomHex ?? defaultGenRandomHex;
21526
21645
  const runGhTokenCmd = deps.runGhTokenCmd ?? defaultRunGhTokenCmd;
@@ -21535,7 +21654,7 @@ function renderOneSecret(binding, templatesRoot, reuse, deps = {}, rotate = fals
21535
21654
  olamHome5,
21536
21655
  reuse?.keys[p.key],
21537
21656
  rotate,
21538
- { readFile, writeFile, fileExists, genRandomHex, runGhTokenCmd }
21657
+ { readFile, writeFile: writeFile2, fileExists, genRandomHex, runGhTokenCmd }
21539
21658
  );
21540
21659
  if (!resolved.ok) {
21541
21660
  missingSources.push(`${p.key}: ${resolved.reason}`);
@@ -21831,14 +21950,14 @@ function ensureSecrets() {
21831
21950
  step("1/6 \u2014 operator secrets");
21832
21951
  mkdirSync19(OLAM_HOME3, { recursive: true });
21833
21952
  for (const name of SECRET_FILES) {
21834
- const path95 = join34(OLAM_HOME3, name);
21835
- if (existsSync29(path95)) {
21953
+ const path96 = join34(OLAM_HOME3, name);
21954
+ if (existsSync29(path96)) {
21836
21955
  printInfo("skip", `~/.olam/${name} already exists`);
21837
21956
  continue;
21838
21957
  }
21839
21958
  const hex = randomBytes7(32).toString("hex");
21840
- writeFileSync15(path95, hex + "\n", { encoding: "utf8", mode: 384 });
21841
- chmodSync4(path95, 384);
21959
+ writeFileSync15(path96, hex + "\n", { encoding: "utf8", mode: 384 });
21960
+ chmodSync4(path96, 384);
21842
21961
  printSuccess(`generated ~/.olam/${name}`);
21843
21962
  }
21844
21963
  }
@@ -21961,13 +22080,13 @@ function installObservability(opts) {
21961
22080
  scriptEnv.OLAM_BUNDLE_ROOT = bundleRoot;
21962
22081
  }
21963
22082
  for (const script of OBSERVABILITY_SCRIPTS) {
21964
- const path95 = join34(observabilityDir, script);
21965
- if (!existsSync29(path95)) {
22083
+ const path96 = join34(observabilityDir, script);
22084
+ if (!existsSync29(path96)) {
21966
22085
  printWarning(`observability script missing: ${script} \u2014 skipping`);
21967
22086
  continue;
21968
22087
  }
21969
22088
  printInfo("run", script);
21970
- const result = spawnSync10("bash", [path95], {
22089
+ const result = spawnSync10("bash", [path96], {
21971
22090
  stdio: "inherit",
21972
22091
  env: scriptEnv
21973
22092
  });
@@ -22976,56 +23095,56 @@ var SECRET_LEN_BYTES = 32;
22976
23095
  function generateSecret() {
22977
23096
  return randomBytes8(SECRET_LEN_BYTES).toString("hex");
22978
23097
  }
22979
- function writeSecretAtPath(path95, value) {
22980
- mkdirSync21(dirname22(path95), { recursive: true });
22981
- const tmp = `${path95}.tmp.${process.pid}`;
23098
+ function writeSecretAtPath(path96, value) {
23099
+ mkdirSync21(dirname22(path96), { recursive: true });
23100
+ const tmp = `${path96}.tmp.${process.pid}`;
22982
23101
  writeFileSync16(tmp, value, { mode: 384 });
22983
23102
  chmodSync5(tmp, 384);
22984
- renameSync6(tmp, path95);
23103
+ renameSync6(tmp, path96);
22985
23104
  }
22986
- function readSecretAtPathOrNull(path95) {
22987
- if (!existsSync32(path95)) return null;
22988
- const mode = statSync8(path95).mode & 511;
23105
+ function readSecretAtPathOrNull(path96) {
23106
+ if (!existsSync32(path96)) return null;
23107
+ const mode = statSync8(path96).mode & 511;
22989
23108
  if (mode !== 384) {
22990
23109
  process.stderr.write(
22991
- `warn: ${path95} has mode 0${mode.toString(8)}; expected 0600. Run 'olam memory secret rotate' to regenerate.
23110
+ `warn: ${path96} has mode 0${mode.toString(8)}; expected 0600. Run 'olam memory secret rotate' to regenerate.
22992
23111
  `
22993
23112
  );
22994
23113
  }
22995
- return readFileSync25(path95, "utf8").trim();
23114
+ return readFileSync25(path96, "utf8").trim();
22996
23115
  }
22997
- function readSecretAtPath(path95) {
22998
- const v = readSecretAtPathOrNull(path95);
23116
+ function readSecretAtPath(path96) {
23117
+ const v = readSecretAtPathOrNull(path96);
22999
23118
  if (v === null) {
23000
23119
  throw new Error(
23001
- `Secret not found at ${path95}. Run 'olam memory start' to generate it.`
23120
+ `Secret not found at ${path96}. Run 'olam memory start' to generate it.`
23002
23121
  );
23003
23122
  }
23004
23123
  return v;
23005
23124
  }
23006
- function ensureMemorySecret(path95 = MEMORY_SECRET_PATH) {
23007
- const existing = readSecretAtPathOrNull(path95);
23125
+ function ensureMemorySecret(path96 = MEMORY_SECRET_PATH) {
23126
+ const existing = readSecretAtPathOrNull(path96);
23008
23127
  if (existing) return existing;
23009
23128
  const fresh = generateSecret();
23010
- writeSecretAtPath(path95, fresh);
23129
+ writeSecretAtPath(path96, fresh);
23011
23130
  return fresh;
23012
23131
  }
23013
- function readMemorySecretOrNull(path95 = MEMORY_SECRET_PATH) {
23014
- return readSecretAtPathOrNull(path95);
23132
+ function readMemorySecretOrNull(path96 = MEMORY_SECRET_PATH) {
23133
+ return readSecretAtPathOrNull(path96);
23015
23134
  }
23016
- function readMemorySecret(path95 = MEMORY_SECRET_PATH) {
23017
- return readSecretAtPath(path95);
23135
+ function readMemorySecret(path96 = MEMORY_SECRET_PATH) {
23136
+ return readSecretAtPath(path96);
23018
23137
  }
23019
- function rotateMemorySecret(path95 = MEMORY_SECRET_PATH) {
23138
+ function rotateMemorySecret(path96 = MEMORY_SECRET_PATH) {
23020
23139
  const fresh = generateSecret();
23021
- writeSecretAtPath(path95, fresh);
23140
+ writeSecretAtPath(path96, fresh);
23022
23141
  return fresh;
23023
23142
  }
23024
- function hasMemorySecret(path95 = MEMORY_SECRET_PATH) {
23025
- return existsSync32(path95);
23143
+ function hasMemorySecret(path96 = MEMORY_SECRET_PATH) {
23144
+ return existsSync32(path96);
23026
23145
  }
23027
- function writeCloudMemorySecret(value, path95 = CLOUD_MEMORY_SECRET_PATH) {
23028
- writeSecretAtPath(path95, value);
23146
+ function writeCloudMemorySecret(value, path96 = CLOUD_MEMORY_SECRET_PATH) {
23147
+ writeSecretAtPath(path96, value);
23029
23148
  }
23030
23149
 
23031
23150
  // src/commands/memory-service-container.ts
@@ -25194,9 +25313,9 @@ function formatFreshnessWarning(result, image = DEFAULT_DEVBOX_IMAGE) {
25194
25313
  "These source files have changed since the image was built; the",
25195
25314
  "changes will NOT take effect in fresh worlds until you rebuild:"
25196
25315
  ];
25197
- for (const { path: path95, mtimeMs } of result.newerSources) {
25316
+ for (const { path: path96, mtimeMs } of result.newerSources) {
25198
25317
  const when = new Date(mtimeMs).toISOString();
25199
- lines.push(` \u2022 ${path95} (modified ${when})`);
25318
+ lines.push(` \u2022 ${path96} (modified ${when})`);
25200
25319
  }
25201
25320
  lines.push("");
25202
25321
  lines.push("Rebuild with:");
@@ -25577,9 +25696,9 @@ async function readHostCpTokenForCreate() {
25577
25696
  try {
25578
25697
  const { default: fs96 } = await import("node:fs");
25579
25698
  const { default: os50 } = await import("node:os");
25580
- const { default: path95 } = await import("node:path");
25581
- const tp = path95.join(
25582
- process.env.OLAM_HOME ?? path95.join(os50.homedir(), ".olam"),
25699
+ const { default: path96 } = await import("node:path");
25700
+ const tp = path96.join(
25701
+ process.env.OLAM_HOME ?? path96.join(os50.homedir(), ".olam"),
25583
25702
  "host-cp.token"
25584
25703
  );
25585
25704
  if (!fs96.existsSync(tp)) return null;
@@ -25592,7 +25711,10 @@ function registerCreate(program2) {
25592
25711
  program2.command("create").description("Create a new development world").option("--name <name>", "World name (required unless --from-prompt is set; auto-derived in that case)").option("--repos <repos...>", "Repos to include (names from .olam/config.yaml; wins over --workspace)").option("--workspace <name>", "Named workspace from the host catalog (~/.olam/workspaces/<name>.yaml)").option("--task <task>", "Initial task to dispatch").option("--branch <branch>", "Override default branch name").option("--plan <file>", "Path to a plan file to inject").option("--no-auth", "Skip auto-injecting host credentials").option("--no-host-cp", 'Suppress the host CP "you might want to start it" hint').option("--auto-codex-review", "Spawn a parallel codex-review lane that critiques main as it works").option("--no-open", "Suppress auto-opening the Host CP UI in the browser on success").option("--rebuild-base", "Rebuild olam-devbox:latest before creating (slow)").option("--no-freshness-check", "Skip the devbox image freshness check").option("--from-prompt <prompt>", "NL prompt \u2192 infer workspace + dispatch (CLI parity for olam_create_from_prompt MCP tool)").option("--keep-after-merge", "Disable auto-destroy when the world's PR merges (useful for inspection/debugging)").option("--carry-uncommitted", "Preserve operator's uncommitted edits in the world's worktree").option(
25593
25712
  "--allow-bootstrap-failure",
25594
25713
  "Treat bootstrap step failures as warnings instead of destroying the world (dogfood escape hatch for cross-repo seed coupling)"
25595
- ).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").action(async (opts) => {
25714
+ ).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(
25715
+ "--claude-home <id-or-path>",
25716
+ "Use a per-world Claude Code HOME (multi-account isolation; see docs/decisions/045-claude-home-override.md)"
25717
+ ).action(async (opts) => {
25596
25718
  const { resolveDevboxImageOverride: resolveDevboxImageOverride2, decideAllowlist: decideAllowlist2 } = await Promise.resolve().then(() => (init_registry_allowlist(), registry_allowlist_exports));
25597
25719
  const overrideRef = resolveDevboxImageOverride2(opts.devboxImage);
25598
25720
  if (overrideRef) {
@@ -25770,6 +25892,25 @@ function registerCreate(program2) {
25770
25892
  throw err;
25771
25893
  }
25772
25894
  }
25895
+ let resolvedClaudeHome;
25896
+ if (opts.claudeHome !== void 0 && opts.claudeHome.length > 0) {
25897
+ try {
25898
+ const { resolveClaudeHome: resolveClaudeHome2, ensureClaudeHomeDir: ensureClaudeHomeDir2 } = await Promise.resolve().then(() => (init_home_override(), home_override_exports));
25899
+ const target = resolveClaudeHome2({ flag: opts.claudeHome });
25900
+ await ensureClaudeHomeDir2(target);
25901
+ resolvedClaudeHome = target;
25902
+ printInfo(
25903
+ "Claude home",
25904
+ `${target} (per-world Claude Code instance \u2014 see ADR 045)`
25905
+ );
25906
+ } catch (err) {
25907
+ printError(
25908
+ `Invalid --claude-home: ${err instanceof Error ? err.message : String(err)}`
25909
+ );
25910
+ process.exitCode = 1;
25911
+ return;
25912
+ }
25913
+ }
25773
25914
  const spinner = ora5("Creating world...").start();
25774
25915
  try {
25775
25916
  const world = await ctx.worldManager.createWorld({
@@ -25788,7 +25929,8 @@ function registerCreate(program2) {
25788
25929
  // manager, matching the manager's strict `if (!opts.carryUncommitted)`.
25789
25930
  carryUncommitted: opts.carryUncommitted === true,
25790
25931
  allowBootstrapFailure: opts.allowBootstrapFailure === true,
25791
- ...opts.runbook ? { runbookName: opts.runbook } : {}
25932
+ ...opts.runbook ? { runbookName: opts.runbook } : {},
25933
+ ...resolvedClaudeHome ? { claudeHome: resolvedClaudeHome } : {}
25792
25934
  });
25793
25935
  spinner.succeed("World created");
25794
25936
  try {
@@ -26022,8 +26164,8 @@ async function readHostCpToken3() {
26022
26164
  try {
26023
26165
  const { default: fs96 } = await import("node:fs");
26024
26166
  const { default: os50 } = await import("node:os");
26025
- const { default: path95 } = await import("node:path");
26026
- const tp = path95.join(os50.homedir(), ".olam", "host-cp.token");
26167
+ const { default: path96 } = await import("node:path");
26168
+ const tp = path96.join(os50.homedir(), ".olam", "host-cp.token");
26027
26169
  if (!fs96.existsSync(tp)) return null;
26028
26170
  const raw = fs96.readFileSync(tp, "utf-8").trim();
26029
26171
  return raw.length > 0 ? raw : null;
@@ -26240,7 +26382,7 @@ init_output();
26240
26382
  import * as fs36 from "node:fs";
26241
26383
  import * as http3 from "node:http";
26242
26384
  import * as os18 from "node:os";
26243
- import * as path37 from "node:path";
26385
+ import * as path38 from "node:path";
26244
26386
  var CLI_VERSION2 = process.env["OLAM_CLI_VERSION"] ?? "0.0.0";
26245
26387
  var HOST_CP_PORT2 = 19e3;
26246
26388
  var STATE_ENUM = [
@@ -26331,7 +26473,7 @@ async function getMachineStatus(_probe, _loadCtx, _readToken) {
26331
26473
  }
26332
26474
  } catch {
26333
26475
  }
26334
- const manifestPath2 = path37.join(os18.homedir(), ".olam", "cache", "manifest.json");
26476
+ const manifestPath2 = path38.join(os18.homedir(), ".olam", "cache", "manifest.json");
26335
26477
  let updateAvailable = null;
26336
26478
  let lastUpdateCheck = null;
26337
26479
  if (fs36.existsSync(manifestPath2)) {
@@ -26477,7 +26619,7 @@ init_context();
26477
26619
  init_output();
26478
26620
  import fs37 from "node:fs";
26479
26621
  import os19 from "node:os";
26480
- import path38 from "node:path";
26622
+ import path39 from "node:path";
26481
26623
  import { execFileSync as execFileSync9 } from "node:child_process";
26482
26624
  function registerClean(program2) {
26483
26625
  program2.command("clean").description("Reap orphan world filesystem state under ~/.olam/worlds/").option("--apply", "Actually delete the orphans (default is dry-run)", false).option(
@@ -26501,7 +26643,7 @@ async function runClean(opts) {
26501
26643
  printError(error?.message ?? "Olam is not configured. Run `olam init` first.");
26502
26644
  return 1;
26503
26645
  }
26504
- const worldsDir = path38.join(os19.homedir(), ".olam", "worlds");
26646
+ const worldsDir = path39.join(os19.homedir(), ".olam", "worlds");
26505
26647
  if (!fs37.existsSync(worldsDir)) {
26506
26648
  if (opts.json) {
26507
26649
  process.stdout.write(`${JSON.stringify({ worldsDir, entries: [] })}
@@ -26518,7 +26660,7 @@ async function runClean(opts) {
26518
26660
  const worktreeMap = collectWorktrees(worldsDir);
26519
26661
  const entries = [];
26520
26662
  for (const id of fs37.readdirSync(worldsDir).sort()) {
26521
- const fullPath = path38.join(worldsDir, id);
26663
+ const fullPath = path39.join(worldsDir, id);
26522
26664
  const stat = safeStat(fullPath);
26523
26665
  if (!stat || !stat.isDirectory()) continue;
26524
26666
  entries.push(classifyWorld({ id, fullPath, liveIds, worktreeMap }));
@@ -26584,7 +26726,7 @@ function classifyWorld(args) {
26584
26726
  if (liveIds.has(id)) {
26585
26727
  return { id, path: fullPath, bytes, category: "active", note: "in registry" };
26586
26728
  }
26587
- const worktreeChild = path38.join(fullPath, "olam");
26729
+ const worktreeChild = path39.join(fullPath, "olam");
26588
26730
  const worktreeInfo = worktreeMap.get(worktreeChild);
26589
26731
  if (worktreeInfo) {
26590
26732
  if (worktreeInfo.dirty > 0 || worktreeInfo.unpushed > 0) {
@@ -26641,8 +26783,8 @@ function reapEntry(entry) {
26641
26783
  function collectWorktrees(worldsDir) {
26642
26784
  const out = /* @__PURE__ */ new Map();
26643
26785
  for (const id of fs37.readdirSync(worldsDir)) {
26644
- const child = path38.join(worldsDir, id, "olam");
26645
- const gitMarker = path38.join(child, ".git");
26786
+ const child = path39.join(worldsDir, id, "olam");
26787
+ const gitMarker = path39.join(child, ".git");
26646
26788
  if (!fs37.existsSync(gitMarker)) continue;
26647
26789
  const gitDir = resolveGitDirForWorktree(child);
26648
26790
  if (!gitDir) continue;
@@ -26654,7 +26796,7 @@ function collectWorktrees(worldsDir) {
26654
26796
  return out;
26655
26797
  }
26656
26798
  function resolveGitDirForWorktree(worktreePath) {
26657
- const gitMarker = path38.join(worktreePath, ".git");
26799
+ const gitMarker = path39.join(worktreePath, ".git");
26658
26800
  try {
26659
26801
  const top = execFileSync9("git", ["rev-parse", "--show-toplevel"], {
26660
26802
  cwd: worktreePath,
@@ -26668,7 +26810,7 @@ function resolveGitDirForWorktree(worktreePath) {
26668
26810
  stdio: "pipe"
26669
26811
  }).trim();
26670
26812
  if (!common) return top;
26671
- return path38.dirname(path38.resolve(worktreePath, common));
26813
+ return path39.dirname(path39.resolve(worktreePath, common));
26672
26814
  } catch {
26673
26815
  return null;
26674
26816
  }
@@ -26735,7 +26877,7 @@ function computeBytes(p) {
26735
26877
  } catch {
26736
26878
  continue;
26737
26879
  }
26738
- for (const name of entries) stack.push(path38.join(cur, name));
26880
+ for (const name of entries) stack.push(path39.join(cur, name));
26739
26881
  } else {
26740
26882
  total += st.size;
26741
26883
  }
@@ -26789,7 +26931,7 @@ init_output();
26789
26931
  import { execFileSync as execFileSync10 } from "node:child_process";
26790
26932
  import * as fs38 from "node:fs";
26791
26933
  import * as os20 from "node:os";
26792
- import * as path39 from "node:path";
26934
+ import * as path40 from "node:path";
26793
26935
  import { createInterface as createInterface2 } from "node:readline/promises";
26794
26936
  import pc17 from "picocolors";
26795
26937
  var NPM_PACKAGE = "@pleri/olam-cli";
@@ -26811,7 +26953,7 @@ var realExec = (cmd, args) => {
26811
26953
  };
26812
26954
  function surveyOlam(opts = {}) {
26813
26955
  const exec = opts.exec ?? realExec;
26814
- const home = opts.olamHome ?? path39.join(os20.homedir(), ".olam");
26956
+ const home = opts.olamHome ?? path40.join(os20.homedir(), ".olam");
26815
26957
  const containers = listDocker(exec, ["ps", "-a", "--format", "{{.Names}}"]).filter(
26816
26958
  (n) => n.startsWith("olam-")
26817
26959
  );
@@ -26825,11 +26967,11 @@ function surveyOlam(opts = {}) {
26825
26967
  (n) => n.startsWith("olam-") && n !== "olam-host-cp-internal-default"
26826
26968
  );
26827
26969
  const worlds = [];
26828
- const worldsDir = path39.join(home, "worlds");
26970
+ const worldsDir = path40.join(home, "worlds");
26829
26971
  if (fs38.existsSync(worldsDir)) {
26830
26972
  for (const entry of fs38.readdirSync(worldsDir, { withFileTypes: true })) {
26831
26973
  if (!entry.isDirectory()) continue;
26832
- const wPath = path39.join(worldsDir, entry.name);
26974
+ const wPath = path40.join(worldsDir, entry.name);
26833
26975
  const bytes = dirSize(wPath);
26834
26976
  const { dirty, note } = inspectWorldGitState(wPath);
26835
26977
  worlds.push({ id: entry.name, bytes, dirty, note, path: wPath });
@@ -26838,7 +26980,7 @@ function surveyOlam(opts = {}) {
26838
26980
  const homeBytesNonWorld = fs38.existsSync(home) ? Math.max(0, dirSize(home) - worlds.reduce((acc, w) => acc + w.bytes, 0)) : 0;
26839
26981
  const npmRoot = exec("npm", ["root", "-g"]);
26840
26982
  const npmGlobalRoot = npmRoot.exitCode === 0 ? npmRoot.stdout.trim() : null;
26841
- const npmInstalled = npmGlobalRoot !== null && fs38.existsSync(path39.join(npmGlobalRoot, NPM_PACKAGE));
26983
+ const npmInstalled = npmGlobalRoot !== null && fs38.existsSync(path40.join(npmGlobalRoot, NPM_PACKAGE));
26842
26984
  return {
26843
26985
  containers,
26844
26986
  images,
@@ -26868,7 +27010,7 @@ function dirSize(p) {
26868
27010
  continue;
26869
27011
  }
26870
27012
  for (const e of entries) {
26871
- const full = path39.join(cur, e.name);
27013
+ const full = path40.join(cur, e.name);
26872
27014
  try {
26873
27015
  if (e.isDirectory()) stack.push(full);
26874
27016
  else if (e.isFile()) total += fs38.statSync(full).size;
@@ -26886,8 +27028,8 @@ function inspectWorldGitState(worldPath) {
26886
27028
  try {
26887
27029
  for (const entry of fs38.readdirSync(worldPath, { withFileTypes: true })) {
26888
27030
  if (!entry.isDirectory()) continue;
26889
- const repo = path39.join(worldPath, entry.name);
26890
- const gitDir = path39.join(repo, ".git");
27031
+ const repo = path40.join(worldPath, entry.name);
27032
+ const gitDir = path40.join(repo, ".git");
26891
27033
  if (!fs38.existsSync(gitDir)) continue;
26892
27034
  try {
26893
27035
  const status2 = execFileSync10("git", ["status", "--porcelain"], {
@@ -26981,7 +27123,7 @@ function formatBytes3(n) {
26981
27123
  }
26982
27124
  async function executeImplode(survey, opts) {
26983
27125
  const exec = opts.exec ?? realExec;
26984
- const home = opts.olamHome ?? path39.join(os20.homedir(), ".olam");
27126
+ const home = opts.olamHome ?? path40.join(os20.homedir(), ".olam");
26985
27127
  const removed = [];
26986
27128
  const skipped = [];
26987
27129
  const errors = [];
@@ -27045,7 +27187,7 @@ async function executeImplode(survey, opts) {
27045
27187
  skipped.push(`fs:~/.olam/auth-data (--keep-vault)`);
27046
27188
  continue;
27047
27189
  }
27048
- const target = path39.join(home, entry.name);
27190
+ const target = path40.join(home, entry.name);
27049
27191
  try {
27050
27192
  fs38.rmSync(target, { recursive: true, force: true });
27051
27193
  removed.push(`fs:${target}`);
@@ -27220,6 +27362,11 @@ function registerEnter(program2) {
27220
27362
  if (worldMeta) {
27221
27363
  const { checkVersionPin: checkVersionPin2 } = await Promise.resolve().then(() => (init_version_pin(), version_pin_exports));
27222
27364
  checkVersionPin2(worldId, worldMeta.workspacePath);
27365
+ if (worldMeta.claudeHome) {
27366
+ console.log(
27367
+ pc18.dim(`# claude-home: ${worldMeta.claudeHome} (per-world Claude Code instance, ADR 045)`)
27368
+ );
27369
+ }
27223
27370
  }
27224
27371
  const computeWorld = await ctx.computeProvider.getWorld(worldId);
27225
27372
  if (!computeWorld) {
@@ -27308,6 +27455,138 @@ ${pc18.dim(`Observe dispatch: docker exec -it ${containerName} tmux attach -t ol
27308
27455
  });
27309
27456
  }
27310
27457
 
27458
+ // src/commands/resume.ts
27459
+ init_context();
27460
+ init_output();
27461
+ import { execFileSync as execFileSync11 } from "node:child_process";
27462
+ function looksLikePrIdentifier(input2) {
27463
+ if (/^\d+$/.test(input2.trim())) return true;
27464
+ if (/^https?:\/\/[^\s]*\/pull\/\d+(?:[/?#].*)?$/i.test(input2.trim())) return true;
27465
+ return false;
27466
+ }
27467
+ async function runResume(input2, deps) {
27468
+ const trimmed = input2.trim();
27469
+ if (trimmed.length === 0) {
27470
+ deps.stderr("resume: argument <pr> is required (PR number, URL, or branch name).");
27471
+ return 1;
27472
+ }
27473
+ let resolved;
27474
+ try {
27475
+ resolved = await deps.resolveInput(trimmed);
27476
+ } catch (err) {
27477
+ deps.stderr(
27478
+ `resume: could not resolve "${trimmed}" via gh pr view \u2014 ` + (err instanceof Error ? err.message : String(err))
27479
+ );
27480
+ return 1;
27481
+ }
27482
+ const { branch, prNumber } = resolved;
27483
+ const worlds = deps.listWorlds();
27484
+ const matches2 = worlds.filter((w) => w.branch === branch);
27485
+ const prLabel = prNumber !== void 0 ? `PR #${prNumber}` : `branch ${branch}`;
27486
+ if (matches2.length === 0) {
27487
+ deps.stderr(
27488
+ `No active world found for ${prLabel} (branch ${branch}). Worlds visible via olam list.`
27489
+ );
27490
+ return 1;
27491
+ }
27492
+ if (matches2.length > 1) {
27493
+ deps.stderr(
27494
+ `Multiple worlds match ${prLabel} (branch ${branch}); operator decides:`
27495
+ );
27496
+ for (const w of matches2) {
27497
+ deps.stderr(` - ${w.name} (${w.id})`);
27498
+ }
27499
+ return 1;
27500
+ }
27501
+ const match2 = matches2[0];
27502
+ deps.stdout(
27503
+ `Found world ${match2.name} (${match2.id}) for ${prLabel}. Entering...`
27504
+ );
27505
+ try {
27506
+ deps.enterWorld(match2.id);
27507
+ } catch (err) {
27508
+ deps.stderr(
27509
+ `resume: olam enter ${match2.id} failed \u2014 ` + (err instanceof Error ? err.message : String(err))
27510
+ );
27511
+ return 1;
27512
+ }
27513
+ return 0;
27514
+ }
27515
+ function resolveInputViaGh(input2) {
27516
+ if (!looksLikePrIdentifier(input2)) {
27517
+ if (input2.length === 0) {
27518
+ return Promise.reject(new Error("empty branch name"));
27519
+ }
27520
+ return Promise.resolve({ branch: input2 });
27521
+ }
27522
+ let stdout;
27523
+ try {
27524
+ stdout = execFileSync11("gh", ["pr", "view", input2, "--json", "number,headRefName"], {
27525
+ encoding: "utf-8",
27526
+ stdio: ["ignore", "pipe", "pipe"],
27527
+ timeout: 1e4
27528
+ });
27529
+ } catch (err) {
27530
+ const msg = err instanceof Error ? err.message : String(err);
27531
+ return Promise.reject(new Error(`gh pr view failed: ${msg}`));
27532
+ }
27533
+ let parsed;
27534
+ try {
27535
+ parsed = JSON.parse(stdout);
27536
+ } catch (err) {
27537
+ return Promise.reject(
27538
+ new Error(`gh pr view returned non-JSON output: ${err instanceof Error ? err.message : String(err)}`)
27539
+ );
27540
+ }
27541
+ if (typeof parsed.headRefName !== "string" || parsed.headRefName.length === 0) {
27542
+ return Promise.reject(new Error("gh pr view response missing headRefName"));
27543
+ }
27544
+ const prNumber = typeof parsed.number === "number" ? parsed.number : void 0;
27545
+ return Promise.resolve({ branch: parsed.headRefName, prNumber });
27546
+ }
27547
+ function registerResume(program2) {
27548
+ program2.command("resume").description(
27549
+ "Resume a world by PR number, URL, or branch \u2014 finds the world that opened the PR and enters it."
27550
+ ).argument("<pr>", "PR number (876), PR URL, or branch name").addHelpText(
27551
+ "after",
27552
+ `
27553
+ Examples:
27554
+ $ olam resume 876
27555
+ $ olam resume https://github.com/pleri/olam/pull/876
27556
+ $ olam resume night/feat/foo
27557
+ `
27558
+ ).action(async (pr) => {
27559
+ const { ctx, error } = await loadContext();
27560
+ if (!ctx) {
27561
+ printError(error?.message ?? "Olam is not configured. Run `olam init` first.");
27562
+ process.exitCode = 1;
27563
+ return;
27564
+ }
27565
+ const code = await runResume(pr, {
27566
+ resolveInput: resolveInputViaGh,
27567
+ listWorlds: () => ctx.worldManager.listWorlds().map((w) => ({
27568
+ id: w.id,
27569
+ name: w.name,
27570
+ branch: w.branch
27571
+ })),
27572
+ enterWorld: (worldId) => {
27573
+ const entry = process.argv[1];
27574
+ if (!entry) {
27575
+ throw new Error("cannot locate CLI entry script (process.argv[1] missing)");
27576
+ }
27577
+ execFileSync11(process.execPath, [entry, "enter", worldId, "--exec"], {
27578
+ stdio: "inherit"
27579
+ });
27580
+ },
27581
+ stdout: (line) => console.log(line),
27582
+ stderr: (line) => printError(line)
27583
+ });
27584
+ if (code !== 0) {
27585
+ process.exitCode = code;
27586
+ }
27587
+ });
27588
+ }
27589
+
27311
27590
  // src/commands/crystallize.ts
27312
27591
  init_context();
27313
27592
  init_output();
@@ -27573,7 +27852,7 @@ init_host_cp();
27573
27852
  // src/lib/plans-client.ts
27574
27853
  import * as fs40 from "node:fs";
27575
27854
  import * as os21 from "node:os";
27576
- import * as path41 from "node:path";
27855
+ import * as path42 from "node:path";
27577
27856
  var PlansClientError = class extends Error {
27578
27857
  constructor(status2, message, body) {
27579
27858
  super(message);
@@ -27584,7 +27863,7 @@ var PlansClientError = class extends Error {
27584
27863
  status;
27585
27864
  body;
27586
27865
  };
27587
- var OLAM_HOME4 = path41.join(os21.homedir(), ".olam");
27866
+ var OLAM_HOME4 = path42.join(os21.homedir(), ".olam");
27588
27867
  function readFileOrNull(p) {
27589
27868
  try {
27590
27869
  return fs40.readFileSync(p, "utf8").trim();
@@ -27593,9 +27872,9 @@ function readFileOrNull(p) {
27593
27872
  }
27594
27873
  }
27595
27874
  function resolveCloudConfig() {
27596
- const cloudUrl = process.env.OLAM_CLOUD_URL ?? readFileOrNull(path41.join(OLAM_HOME4, "cloud-url"));
27875
+ const cloudUrl = process.env.OLAM_CLOUD_URL ?? readFileOrNull(path42.join(OLAM_HOME4, "cloud-url"));
27597
27876
  if (!cloudUrl) return null;
27598
- const bearer = process.env.OLAM_SHOWCASE_PASSWORD ?? readFileOrNull(path41.join(OLAM_HOME4, "showcase-password"));
27877
+ const bearer = process.env.OLAM_SHOWCASE_PASSWORD ?? readFileOrNull(path42.join(OLAM_HOME4, "showcase-password"));
27599
27878
  if (!bearer) return null;
27600
27879
  return { cloudUrl: cloudUrl.replace(/\/+$/, ""), bearer };
27601
27880
  }
@@ -27609,13 +27888,13 @@ var PlansClient = class {
27609
27888
  const credentials = Buffer.from(`operator:${this.cfg.bearer}`).toString("base64");
27610
27889
  return `Basic ${credentials}`;
27611
27890
  }
27612
- async request(path95, init) {
27891
+ async request(path96, init) {
27613
27892
  const headers = {
27614
27893
  Authorization: this.authHeader()
27615
27894
  };
27616
27895
  if (init.body) headers["content-type"] = "application/json";
27617
27896
  if (init.adminSecret) headers["X-Admin-Secret"] = init.adminSecret;
27618
- return fetch(`${this.cfg.cloudUrl}${path95}`, {
27897
+ return fetch(`${this.cfg.cloudUrl}${path96}`, {
27619
27898
  method: init.method,
27620
27899
  headers,
27621
27900
  body: init.body ? JSON.stringify(init.body) : void 0
@@ -28987,11 +29266,11 @@ var qmarksTestNoExtDot = ([$0]) => {
28987
29266
  return (f) => f.length === len && f !== "." && f !== "..";
28988
29267
  };
28989
29268
  var defaultPlatform = typeof process === "object" && process ? typeof process.env === "object" && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__ || process.platform : "posix";
28990
- var path42 = {
29269
+ var path43 = {
28991
29270
  win32: { sep: "\\" },
28992
29271
  posix: { sep: "/" }
28993
29272
  };
28994
- var sep2 = defaultPlatform === "win32" ? path42.win32.sep : path42.posix.sep;
29273
+ var sep2 = defaultPlatform === "win32" ? path43.win32.sep : path43.posix.sep;
28995
29274
  minimatch.sep = sep2;
28996
29275
  var GLOBSTAR = /* @__PURE__ */ Symbol("globstar **");
28997
29276
  minimatch.GLOBSTAR = GLOBSTAR;
@@ -30100,11 +30379,11 @@ function zodIssueToError(issue, doc, lineCounter) {
30100
30379
  suggestion: deriveSuggestion(issue)
30101
30380
  };
30102
30381
  }
30103
- function formatJsonPath(path95) {
30104
- if (path95.length === 0)
30382
+ function formatJsonPath(path96) {
30383
+ if (path96.length === 0)
30105
30384
  return "<root>";
30106
30385
  let out = "";
30107
- for (const seg of path95) {
30386
+ for (const seg of path96) {
30108
30387
  if (typeof seg === "number") {
30109
30388
  out += `[${seg}]`;
30110
30389
  } else {
@@ -30113,11 +30392,11 @@ function formatJsonPath(path95) {
30113
30392
  }
30114
30393
  return out;
30115
30394
  }
30116
- function resolveYamlLocation(path95, doc, lineCounter) {
30395
+ function resolveYamlLocation(path96, doc, lineCounter) {
30117
30396
  let bestLine = 0;
30118
30397
  let bestColumn = 0;
30119
- for (let depth = path95.length; depth >= 0; depth -= 1) {
30120
- const segment = path95.slice(0, depth);
30398
+ for (let depth = path96.length; depth >= 0; depth -= 1) {
30399
+ const segment = path96.slice(0, depth);
30121
30400
  try {
30122
30401
  const node = doc.getIn(segment, true);
30123
30402
  if (node && typeof node === "object" && "range" in node) {
@@ -30335,11 +30614,11 @@ function topoSort(nodes) {
30335
30614
  }
30336
30615
  function traceCycle(start, byId) {
30337
30616
  const seen = /* @__PURE__ */ new Set();
30338
- const path95 = [];
30617
+ const path96 = [];
30339
30618
  let current = start;
30340
30619
  while (current && !seen.has(current)) {
30341
30620
  seen.add(current);
30342
- path95.push(current);
30621
+ path96.push(current);
30343
30622
  const node = byId.get(current);
30344
30623
  const next = node?.dependsOn[0];
30345
30624
  if (next === void 0)
@@ -30347,10 +30626,10 @@ function traceCycle(start, byId) {
30347
30626
  current = next;
30348
30627
  }
30349
30628
  if (current && seen.has(current)) {
30350
- const idx = path95.indexOf(current);
30351
- return [...path95.slice(idx), current];
30629
+ const idx = path96.indexOf(current);
30630
+ return [...path96.slice(idx), current];
30352
30631
  }
30353
- return path95;
30632
+ return path96;
30354
30633
  }
30355
30634
 
30356
30635
  // ../core/dist/executor/types.js
@@ -30574,11 +30853,11 @@ async function resolveDigests(lockfile, resolver) {
30574
30853
  }
30575
30854
 
30576
30855
  // ../core/dist/worldspec/image-digest.js
30577
- import { execFileSync as execFileSync11 } from "node:child_process";
30856
+ import { execFileSync as execFileSync12 } from "node:child_process";
30578
30857
  var DOCKER_SUBPROCESS_TIMEOUT_MS = 3e4;
30579
30858
  var dockerDigestResolver = async (image, source) => {
30580
30859
  if (source === "local") {
30581
- const out = execFileSync11("docker", ["inspect", image, "--format", "{{.Id}}"], {
30860
+ const out = execFileSync12("docker", ["inspect", image, "--format", "{{.Id}}"], {
30582
30861
  encoding: "utf8",
30583
30862
  stdio: ["ignore", "pipe", "pipe"],
30584
30863
  timeout: DOCKER_SUBPROCESS_TIMEOUT_MS,
@@ -30589,7 +30868,7 @@ var dockerDigestResolver = async (image, source) => {
30589
30868
  }
30590
30869
  return out;
30591
30870
  }
30592
- const raw = execFileSync11("docker", ["buildx", "imagetools", "inspect", image], {
30871
+ const raw = execFileSync12("docker", ["buildx", "imagetools", "inspect", image], {
30593
30872
  encoding: "utf8",
30594
30873
  stdio: ["ignore", "pipe", "pipe"],
30595
30874
  timeout: DOCKER_SUBPROCESS_TIMEOUT_MS,
@@ -32250,7 +32529,7 @@ function registerWorldspec(program2) {
32250
32529
  init_output();
32251
32530
  init_host_cp();
32252
32531
  import * as fs43 from "node:fs";
32253
- import * as path45 from "node:path";
32532
+ import * as path46 from "node:path";
32254
32533
  import { spawnSync as spawnSync22 } from "node:child_process";
32255
32534
  import ora9 from "ora";
32256
32535
  import pc21 from "picocolors";
@@ -32258,9 +32537,9 @@ import pc21 from "picocolors";
32258
32537
  // src/commands/upgrade-lock.ts
32259
32538
  import * as fs41 from "node:fs";
32260
32539
  import * as os22 from "node:os";
32261
- import * as path43 from "node:path";
32540
+ import * as path44 from "node:path";
32262
32541
  import { spawnSync as spawnSync21 } from "node:child_process";
32263
- var LOCK_FILE_PATH = path43.join(os22.homedir(), ".olam", ".upgrade.lock");
32542
+ var LOCK_FILE_PATH = path44.join(os22.homedir(), ".olam", ".upgrade.lock");
32264
32543
  var STALE_LOCK_TIMEOUT_MS = 5 * 60 * 1e3;
32265
32544
  function readLockFile(lockPath) {
32266
32545
  try {
@@ -32310,7 +32589,7 @@ function isStaleLock(content, nowMs = Date.now()) {
32310
32589
  return false;
32311
32590
  }
32312
32591
  function acquireLock(lockPath = LOCK_FILE_PATH, nowMs = Date.now()) {
32313
- const dir = path43.dirname(lockPath);
32592
+ const dir = path44.dirname(lockPath);
32314
32593
  fs41.mkdirSync(dir, { recursive: true });
32315
32594
  for (let attempt = 0; attempt < 2; attempt++) {
32316
32595
  try {
@@ -32373,15 +32652,15 @@ function formatRefusalMessage(result, lockPath = LOCK_FILE_PATH) {
32373
32652
  // src/commands/upgrade-log.ts
32374
32653
  import * as fs42 from "node:fs";
32375
32654
  import * as os23 from "node:os";
32376
- import * as path44 from "node:path";
32655
+ import * as path45 from "node:path";
32377
32656
  function getUpgradeLogPath() {
32378
32657
  const home = process.env["HOME"] ?? os23.homedir();
32379
- return path44.join(home, ".olam", "upgrade.log");
32658
+ return path45.join(home, ".olam", "upgrade.log");
32380
32659
  }
32381
32660
  var UPGRADE_LOG_PATH = getUpgradeLogPath();
32382
32661
  function appendUpgradeLog(row, logPath = getUpgradeLogPath()) {
32383
32662
  try {
32384
- fs42.mkdirSync(path44.dirname(logPath), { recursive: true });
32663
+ fs42.mkdirSync(path45.dirname(logPath), { recursive: true });
32385
32664
  const line = JSON.stringify(row) + "\n";
32386
32665
  fs42.appendFileSync(logPath, line, { mode: 420 });
32387
32666
  } catch (err) {
@@ -32488,8 +32767,8 @@ init_protocol_version();
32488
32767
  init_install_root();
32489
32768
  var AUTH_HEALTH_URL2 = "http://127.0.0.1:9999/health";
32490
32769
  function isNodeModulesInSync(cwd) {
32491
- const lockPath = path45.join(cwd, "package-lock.json");
32492
- const markerPath = path45.join(cwd, "node_modules", ".package-lock.json");
32770
+ const lockPath = path46.join(cwd, "package-lock.json");
32771
+ const markerPath = path46.join(cwd, "node_modules", ".package-lock.json");
32493
32772
  if (!fs43.existsSync(lockPath) || !fs43.existsSync(markerPath)) return false;
32494
32773
  try {
32495
32774
  const lockStat = fs43.statSync(lockPath);
@@ -32509,7 +32788,7 @@ function shouldSkipInstall(opts, cwd) {
32509
32788
  return { skip: false };
32510
32789
  }
32511
32790
  function validateRepoRoot(cwd) {
32512
- const marker = path45.join(cwd, "packages/host-cp/compose.yaml");
32791
+ const marker = path46.join(cwd, "packages/host-cp/compose.yaml");
32513
32792
  if (!fs43.existsSync(marker)) {
32514
32793
  return {
32515
32794
  ok: false,
@@ -32870,7 +33149,7 @@ async function recreateAuthService() {
32870
33149
  }
32871
33150
  }
32872
33151
  function readBundleHash(cwd) {
32873
- const indexPath = path45.join(cwd, "packages/control-plane/public/index.html");
33152
+ const indexPath = path46.join(cwd, "packages/control-plane/public/index.html");
32874
33153
  if (!fs43.existsSync(indexPath)) return null;
32875
33154
  return extractBundleHash(fs43.readFileSync(indexPath, "utf-8"));
32876
33155
  }
@@ -33476,7 +33755,7 @@ ${buildResult.stderr}`);
33476
33755
  return;
33477
33756
  }
33478
33757
  const authSecret = readAuthSecret2();
33479
- const spaDir = path45.join(cwd, "packages/control-plane/app");
33758
+ const spaDir = path46.join(cwd, "packages/control-plane/app");
33480
33759
  const spaResult = runStep2(
33481
33760
  "vite build (SPA)",
33482
33761
  "npx",
@@ -34019,13 +34298,13 @@ ${pc23.dim(`world: ${worldId} sort: ${sortKey} refresh: 5s Ctrl-C to exit`)}
34019
34298
  init_output();
34020
34299
  import * as fs44 from "node:fs";
34021
34300
  import * as os24 from "node:os";
34022
- import * as path46 from "node:path";
34301
+ import * as path47 from "node:path";
34023
34302
  import YAML6 from "yaml";
34024
34303
  function olamHome3() {
34025
- return process.env.OLAM_HOME ?? path46.join(os24.homedir(), ".olam");
34304
+ return process.env.OLAM_HOME ?? path47.join(os24.homedir(), ".olam");
34026
34305
  }
34027
34306
  function keysFilePath() {
34028
- return path46.join(olamHome3(), "keys.yaml");
34307
+ return path47.join(olamHome3(), "keys.yaml");
34029
34308
  }
34030
34309
  function readKeysFile() {
34031
34310
  const filePath = keysFilePath();
@@ -34121,7 +34400,7 @@ function registerKeys(program2) {
34121
34400
  init_snapshot();
34122
34401
  init_output();
34123
34402
  import * as fs45 from "node:fs";
34124
- import * as path47 from "node:path";
34403
+ import * as path48 from "node:path";
34125
34404
  import { execSync as execSync11 } from "node:child_process";
34126
34405
  import pc24 from "picocolors";
34127
34406
 
@@ -34144,9 +34423,9 @@ function emitDeprecationWarning(subcommand) {
34144
34423
  }
34145
34424
  function bumpDeprecationCounter() {
34146
34425
  if (process.env[INTERNAL_SENTINEL_ENV] === "1") return;
34147
- const counterPath = path47.join(snapshotsDir(), ".deprecation-counter");
34426
+ const counterPath = path48.join(snapshotsDir(), ".deprecation-counter");
34148
34427
  try {
34149
- fs45.mkdirSync(path47.dirname(counterPath), { recursive: true });
34428
+ fs45.mkdirSync(path48.dirname(counterPath), { recursive: true });
34150
34429
  let current = 0;
34151
34430
  if (fs45.existsSync(counterPath)) {
34152
34431
  const raw = fs45.readFileSync(counterPath, "utf-8").trim();
@@ -34229,13 +34508,13 @@ function resolveKinds(arg) {
34229
34508
  return [];
34230
34509
  }
34231
34510
  async function captureGems(worldId, workspacePath, repo) {
34232
- const repoDir = path47.join(workspacePath, repo);
34511
+ const repoDir = path48.join(workspacePath, repo);
34233
34512
  const fingerprint = computeGemsFingerprint(repoDir);
34234
34513
  if (!fingerprint) {
34235
34514
  return { ok: false, tarPath: "", msg: "no Gemfile.lock \u2014 layer does not apply" };
34236
34515
  }
34237
34516
  const tarPath = snapshotTarPath(worldId, "gems", repo, fingerprint);
34238
- const vendorBundle = path47.join(repoDir, "vendor", "bundle");
34517
+ const vendorBundle = path48.join(repoDir, "vendor", "bundle");
34239
34518
  if (fs45.existsSync(vendorBundle)) {
34240
34519
  try {
34241
34520
  packTarball(vendorBundle, tarPath);
@@ -34272,7 +34551,7 @@ async function captureGems(worldId, workspacePath, repo) {
34272
34551
  `docker exec ${containerName} sh -c 'mkdir -p "$(dirname ${tmpTar})" && tar -czf ${tmpTar}.tmp -C ${bundlePath} . && mv ${tmpTar}.tmp ${tmpTar}'`,
34273
34552
  { stdio: "pipe", timeout: 12e4 }
34274
34553
  );
34275
- fs45.mkdirSync(path47.dirname(tarPath), { recursive: true });
34554
+ fs45.mkdirSync(path48.dirname(tarPath), { recursive: true });
34276
34555
  execSync11(`docker cp ${containerName}:${tmpTar} "${tarPath}"`, { stdio: "pipe", timeout: 12e4 });
34277
34556
  execSync11(`docker exec ${containerName} rm -f ${tmpTar}`, { stdio: "pipe" });
34278
34557
  const stat = fs45.statSync(tarPath);
@@ -34292,12 +34571,12 @@ async function captureGems(worldId, workspacePath, repo) {
34292
34571
  }
34293
34572
  }
34294
34573
  async function captureNode(worldId, workspacePath, repo) {
34295
- const repoDir = path47.join(workspacePath, repo);
34574
+ const repoDir = path48.join(workspacePath, repo);
34296
34575
  const fingerprint = computeNodeFingerprint(repoDir);
34297
34576
  if (!fingerprint) {
34298
34577
  return { ok: false, tarPath: "", msg: "no lockfile \u2014 layer does not apply" };
34299
34578
  }
34300
- const nodeModules = path47.join(repoDir, "node_modules");
34579
+ const nodeModules = path48.join(repoDir, "node_modules");
34301
34580
  if (!fs45.existsSync(nodeModules)) {
34302
34581
  return { ok: false, tarPath: "", msg: "node_modules not installed yet" };
34303
34582
  }
@@ -34321,7 +34600,7 @@ async function captureNode(worldId, workspacePath, repo) {
34321
34600
  }
34322
34601
  }
34323
34602
  async function capturePg(worldId, workspacePath, repoNames) {
34324
- const repoDirs = repoNames.map((r) => path47.join(workspacePath, r));
34603
+ const repoDirs = repoNames.map((r) => path48.join(workspacePath, r));
34325
34604
  const fingerprint = computePgFingerprint(repoDirs);
34326
34605
  if (!fingerprint) {
34327
34606
  return { ok: false, tarPath: "", msg: "no Gemfile.lock / schema.rb \u2014 layer does not apply" };
@@ -34336,9 +34615,9 @@ async function capturePg(worldId, workspacePath, repoNames) {
34336
34615
  }
34337
34616
  try {
34338
34617
  execSync11(`docker stop ${containerName}`, { stdio: "pipe", timeout: 3e4 });
34339
- fs45.mkdirSync(path47.dirname(tarPath), { recursive: true });
34618
+ fs45.mkdirSync(path48.dirname(tarPath), { recursive: true });
34340
34619
  execSync11(
34341
- `docker run --rm -v "${volumeName2}:/pgdata:ro" -v "${path47.dirname(tarPath)}:/dest" alpine sh -c 'tar -czf /dest/${path47.basename(tarPath)}.tmp -C /pgdata . && mv /dest/${path47.basename(tarPath)}.tmp /dest/${path47.basename(tarPath)}'`,
34620
+ `docker run --rm -v "${volumeName2}:/pgdata:ro" -v "${path48.dirname(tarPath)}:/dest" alpine sh -c 'tar -czf /dest/${path48.basename(tarPath)}.tmp -C /pgdata . && mv /dest/${path48.basename(tarPath)}.tmp /dest/${path48.basename(tarPath)}'`,
34342
34621
  { stdio: "pipe", timeout: 18e4 }
34343
34622
  );
34344
34623
  execSync11(`docker start ${containerName}`, { stdio: "pipe", timeout: 3e4 });
@@ -34373,7 +34652,7 @@ async function handleEvict(opts) {
34373
34652
  const allTars = [];
34374
34653
  const walk3 = (d) => {
34375
34654
  for (const entry of fs45.readdirSync(d, { withFileTypes: true })) {
34376
- const full = path47.join(d, entry.name);
34655
+ const full = path48.join(d, entry.name);
34377
34656
  if (entry.isDirectory()) {
34378
34657
  walk3(full);
34379
34658
  } else if (entry.name.endsWith(".tar.gz")) {
@@ -34472,33 +34751,33 @@ init_context();
34472
34751
  init_output();
34473
34752
  import * as fs47 from "node:fs";
34474
34753
  import * as os25 from "node:os";
34475
- import * as path49 from "node:path";
34754
+ import * as path50 from "node:path";
34476
34755
  import { spawnSync as spawnSync24 } from "node:child_process";
34477
34756
  import ora10 from "ora";
34478
34757
 
34479
34758
  // src/commands/refresh-helpers.ts
34480
34759
  import * as fs46 from "node:fs";
34481
- import * as path48 from "node:path";
34760
+ import * as path49 from "node:path";
34482
34761
  function collectCpSourceFiles(standaloneDir) {
34483
34762
  if (!fs46.existsSync(standaloneDir)) {
34484
34763
  throw new Error(`CP standalone dir not found: ${standaloneDir}`);
34485
34764
  }
34486
34765
  const entries = [];
34487
34766
  const topLevel = fs46.readdirSync(standaloneDir).filter((f) => {
34488
- const stat = fs46.statSync(path48.join(standaloneDir, f));
34767
+ const stat = fs46.statSync(path49.join(standaloneDir, f));
34489
34768
  return stat.isFile() && f.endsWith(".mjs") && !f.endsWith(".test.mjs");
34490
34769
  }).sort();
34491
34770
  for (const f of topLevel) {
34492
- entries.push({ srcPath: path48.join(standaloneDir, f), destRelPath: f });
34771
+ entries.push({ srcPath: path49.join(standaloneDir, f), destRelPath: f });
34493
34772
  }
34494
- const libDir = path48.join(standaloneDir, "lib");
34773
+ const libDir = path49.join(standaloneDir, "lib");
34495
34774
  if (fs46.existsSync(libDir) && fs46.statSync(libDir).isDirectory()) {
34496
34775
  const libFiles = fs46.readdirSync(libDir).filter((f) => {
34497
- const stat = fs46.statSync(path48.join(libDir, f));
34776
+ const stat = fs46.statSync(path49.join(libDir, f));
34498
34777
  return stat.isFile() && f.endsWith(".mjs") && !f.endsWith(".test.mjs");
34499
34778
  }).sort();
34500
34779
  for (const f of libFiles) {
34501
- entries.push({ srcPath: path48.join(libDir, f), destRelPath: `lib/${f}` });
34780
+ entries.push({ srcPath: path49.join(libDir, f), destRelPath: `lib/${f}` });
34502
34781
  }
34503
34782
  }
34504
34783
  return entries;
@@ -34557,15 +34836,15 @@ async function refreshWorld(worldId, portOffset, standaloneDir, opts) {
34557
34836
  };
34558
34837
  }
34559
34838
  const stagingDir = fs47.mkdtempSync(
34560
- path49.join(os25.tmpdir(), `olam-refresh-${worldId}-`)
34839
+ path50.join(os25.tmpdir(), `olam-refresh-${worldId}-`)
34561
34840
  );
34562
34841
  try {
34563
34842
  const hasLib = entries.some((e) => e.destRelPath.startsWith("lib/"));
34564
34843
  if (hasLib) {
34565
- fs47.mkdirSync(path49.join(stagingDir, "lib"), { recursive: true });
34844
+ fs47.mkdirSync(path50.join(stagingDir, "lib"), { recursive: true });
34566
34845
  }
34567
34846
  for (const { srcPath, destRelPath } of entries) {
34568
- fs47.copyFileSync(srcPath, path49.join(stagingDir, destRelPath));
34847
+ fs47.copyFileSync(srcPath, path50.join(stagingDir, destRelPath));
34569
34848
  }
34570
34849
  const cpResult = docker([
34571
34850
  "cp",
@@ -34617,7 +34896,7 @@ function registerRefresh(program2) {
34617
34896
  process.exitCode = 1;
34618
34897
  return;
34619
34898
  }
34620
- const standaloneDir = path49.join(
34899
+ const standaloneDir = path50.join(
34621
34900
  process.cwd(),
34622
34901
  "packages/control-plane/standalone"
34623
34902
  );
@@ -34785,8 +35064,8 @@ function registerRestart(program2) {
34785
35064
  // src/commands/diagnose.ts
34786
35065
  import * as fs48 from "node:fs";
34787
35066
  import * as os26 from "node:os";
34788
- import * as path50 from "node:path";
34789
- import { execFileSync as execFileSync12, execSync as execSync12 } from "node:child_process";
35067
+ import * as path51 from "node:path";
35068
+ import { execFileSync as execFileSync13, execSync as execSync12 } from "node:child_process";
34790
35069
  import pc25 from "picocolors";
34791
35070
 
34792
35071
  // ../core/dist/diagnose/secret-stripper.js
@@ -34820,9 +35099,9 @@ function stripSecrets(input2) {
34820
35099
  }
34821
35100
 
34822
35101
  // src/commands/diagnose.ts
34823
- var DIAGNOSTICS_DIR = path50.join(os26.homedir(), ".olam", "diagnostics");
34824
- var LOG_DIR = path50.join(os26.homedir(), ".olam", "log");
34825
- var CACHE_DIR = path50.join(os26.homedir(), ".olam", "cache");
35102
+ var DIAGNOSTICS_DIR = path51.join(os26.homedir(), ".olam", "diagnostics");
35103
+ var LOG_DIR = path51.join(os26.homedir(), ".olam", "log");
35104
+ var CACHE_DIR = path51.join(os26.homedir(), ".olam", "cache");
34826
35105
  var LOG_TAIL_LINES = 200;
34827
35106
  function safeExec(cmd) {
34828
35107
  try {
@@ -34832,12 +35111,12 @@ function safeExec(cmd) {
34832
35111
  }
34833
35112
  }
34834
35113
  function defaultZip(zipPath, files) {
34835
- execFileSync12("zip", ["-j", zipPath, ...files]);
35114
+ execFileSync13("zip", ["-j", zipPath, ...files]);
34836
35115
  }
34837
35116
  async function buildDiagnosticsZip(_exec = (cmd) => safeExec(cmd), _outDir = DIAGNOSTICS_DIR, _logDir = LOG_DIR, _zip = defaultZip) {
34838
35117
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 23);
34839
- const zipPath = path50.join(_outDir, `olam-diag-${ts}.zip`);
34840
- const tmpDir = fs48.mkdtempSync(path50.join(os26.tmpdir(), "olam-diag-"));
35118
+ const zipPath = path51.join(_outDir, `olam-diag-${ts}.zip`);
35119
+ const tmpDir = fs48.mkdtempSync(path51.join(os26.tmpdir(), "olam-diag-"));
34841
35120
  try {
34842
35121
  fs48.mkdirSync(_outDir, { recursive: true });
34843
35122
  const entries = [];
@@ -34855,7 +35134,7 @@ platform: ${platform2}
34855
35134
  `uptime: ${os26.uptime()}s`
34856
35135
  ].join("\n") + "\n";
34857
35136
  _writeEntry(tmpDir, "os-info.txt", stripSecrets(osContent), entries);
34858
- const depsFile = path50.join(CACHE_DIR, "deps.json");
35137
+ const depsFile = path51.join(CACHE_DIR, "deps.json");
34859
35138
  if (fs48.existsSync(depsFile)) {
34860
35139
  const deps = fs48.readFileSync(depsFile, "utf-8");
34861
35140
  _writeEntry(tmpDir, "deps.json", stripSecrets(deps), entries);
@@ -34874,7 +35153,7 @@ platform: ${platform2}
34874
35153
  if (authAudit) {
34875
35154
  _writeEntry(tmpDir, "audit-auth-callers.txt", stripSecrets(authAudit), entries);
34876
35155
  }
34877
- const fileArgs = entries.map((e) => path50.join(tmpDir, e));
35156
+ const fileArgs = entries.map((e) => path51.join(tmpDir, e));
34878
35157
  try {
34879
35158
  _zip(zipPath, fileArgs);
34880
35159
  } catch (err) {
@@ -34892,17 +35171,17 @@ platform: ${platform2}
34892
35171
  }
34893
35172
  }
34894
35173
  function _writeEntry(dir, name, content, entries) {
34895
- fs48.writeFileSync(path50.join(dir, name), content, { mode: 420 });
35174
+ fs48.writeFileSync(path51.join(dir, name), content, { mode: 420 });
34896
35175
  entries.push(name);
34897
35176
  }
34898
35177
  function _latestLog(logDir) {
34899
35178
  if (!fs48.existsSync(logDir)) return null;
34900
35179
  const files = fs48.readdirSync(logDir).filter((f) => f.startsWith("host-")).sort().reverse();
34901
- return files.length > 0 ? path50.join(logDir, files[0]) : null;
35180
+ return files.length > 0 ? path51.join(logDir, files[0]) : null;
34902
35181
  }
34903
35182
  async function buildTelemetryPayload() {
34904
35183
  const channel = "stable";
34905
- const manifestFile = path50.join(CACHE_DIR, "manifest.json");
35184
+ const manifestFile = path51.join(CACHE_DIR, "manifest.json");
34906
35185
  let manifestAgeHours = null;
34907
35186
  if (fs48.existsSync(manifestFile)) {
34908
35187
  const mtime = fs48.statSync(manifestFile).mtime.getTime();
@@ -35057,8 +35336,8 @@ function checkWorld(container, hostShas, dockerExec) {
35057
35336
  const m = shaLine.match(/^([a-f0-9]{64})\s+(.+)$/);
35058
35337
  if (!m) continue;
35059
35338
  const sha = m[1];
35060
- const path95 = m[2];
35061
- const filename = path95?.split("/").pop();
35339
+ const path96 = m[2];
35340
+ const filename = path96?.split("/").pop();
35062
35341
  if (!filename) continue;
35063
35342
  const mtimeSecs = parseInt(mtimeLine.trim(), 10);
35064
35343
  if (Number.isNaN(mtimeSecs) || !sha) continue;
@@ -35106,28 +35385,28 @@ function resolveRepoRootBestEffort() {
35106
35385
  init_output();
35107
35386
  import * as fs50 from "node:fs";
35108
35387
  import * as net4 from "node:net";
35109
- import * as path52 from "node:path";
35388
+ import * as path53 from "node:path";
35110
35389
  import * as os27 from "node:os";
35111
35390
 
35112
35391
  // src/commands/hermes-kg-hook.ts
35113
35392
  import * as fs49 from "node:fs";
35114
- import * as path51 from "node:path";
35393
+ import * as path52 from "node:path";
35115
35394
  import { createHash as createHash5 } from "node:crypto";
35116
35395
  import { fileURLToPath as fileURLToPath6 } from "node:url";
35117
35396
  var HERMES_KG_HOOK_SENTINEL = "OLAM_KG_HOOK";
35118
35397
  function bundleDir() {
35119
35398
  const thisFile = fileURLToPath6(import.meta.url);
35120
- return path51.resolve(path51.dirname(thisFile), "..", "..", "hermes-bundle");
35399
+ return path52.resolve(path52.dirname(thisFile), "..", "..", "hermes-bundle");
35121
35400
  }
35122
35401
  function templateContent() {
35123
- const templatePath = path51.join(bundleDir(), "kg-first.sh");
35402
+ const templatePath = path52.join(bundleDir(), "kg-first.sh");
35124
35403
  return fs49.readFileSync(templatePath);
35125
35404
  }
35126
35405
  function sha256(buf) {
35127
35406
  return createHash5("sha256").update(buf).digest("hex");
35128
35407
  }
35129
35408
  function installKgFirstHookForHermes(hooksDir, dryRun) {
35130
- const destPath2 = path51.join(hooksDir, "kg-first.sh");
35409
+ const destPath2 = path52.join(hooksDir, "kg-first.sh");
35131
35410
  const template = templateContent();
35132
35411
  if (fs49.existsSync(destPath2)) {
35133
35412
  const existing = fs49.readFileSync(destPath2);
@@ -35203,7 +35482,7 @@ async function runDoctor(opts, deps = {}) {
35203
35482
  if (isK8s) {
35204
35483
  const wrapImpl = deps.kubectlWrapImpl ?? kubectlWrap;
35205
35484
  const k8sCtx = deps.kubectlContext;
35206
- const manifestsDir = deps.manifestsDir ?? path52.join(OLAM_HOME, "k8s", "manifests");
35485
+ const manifestsDir = deps.manifestsDir ?? path53.join(OLAM_HOME, "k8s", "manifests");
35207
35486
  const readFileSyncImpl = deps.readFileSyncImpl ?? fs50.readFileSync;
35208
35487
  const sortedPeripherals = [...PERIPHERALS].sort((a, b) => a.name.localeCompare(b.name));
35209
35488
  let peripheralPosition = 14;
@@ -35340,7 +35619,7 @@ async function probeStorageClassMatch(peripherals, kubectlContext, manifestsDir,
35340
35619
  const ctxArgs = kubectlContext ? ["--context", kubectlContext] : [];
35341
35620
  const mismatches = [];
35342
35621
  for (const peripheral of peripherals) {
35343
- const pvcManifestPath = path52.join(manifestsDir, peripheral.name, "45-pvc.yaml");
35622
+ const pvcManifestPath = path53.join(manifestsDir, peripheral.name, "45-pvc.yaml");
35344
35623
  let declaredClass;
35345
35624
  try {
35346
35625
  const raw = readFileSyncImpl(pvcManifestPath, "utf8");
@@ -35453,7 +35732,7 @@ function probeNodeMemory(dockerExec, kubectlContext) {
35453
35732
  function defaultResolveHostSideProxyComposePath() {
35454
35733
  const root = resolveK8sAssetsRoot();
35455
35734
  if (root === null) return null;
35456
- const candidate = path52.join(root, "host-side", "docker-socket-proxy.compose.yaml");
35735
+ const candidate = path53.join(root, "host-side", "docker-socket-proxy.compose.yaml");
35457
35736
  return fs50.existsSync(candidate) ? candidate : null;
35458
35737
  }
35459
35738
  async function defaultDockerSocketCheck(composePath) {
@@ -35590,8 +35869,8 @@ function renderHuman(report) {
35590
35869
  }
35591
35870
  }
35592
35871
  function probeHermesIntegration(hermesDir) {
35593
- const configPath = path52.join(hermesDir, "config.yaml");
35594
- const hookPath = path52.join(hermesDir, "hooks", "kg-first.sh");
35872
+ const configPath = path53.join(hermesDir, "config.yaml");
35873
+ const hookPath = path53.join(hermesDir, "hooks", "kg-first.sh");
35595
35874
  const issues = [];
35596
35875
  if (!fs50.existsSync(configPath)) {
35597
35876
  issues.push("~/.hermes/config.yaml not found");
@@ -35632,7 +35911,7 @@ function registerDoctor(program2) {
35632
35911
  program2.command("doctor").description(
35633
35912
  "Pass/fail host-health check. Exits 0 on a healthy host (including WARN-only); 1 on any FAIL probe. Auto-detects substrate from ~/.olam/config.yaml (host.substrate) \u2014 runs 28 probes on kubernetes, 7 on docker/compose. Override with OLAM_HOST_CP_ENGINE env var."
35634
35913
  ).option("--json", "emit the report as JSON instead of a human-readable table").action(async (opts) => {
35635
- const hermesDir = path52.join(os27.homedir(), ".hermes");
35914
+ const hermesDir = path53.join(os27.homedir(), ".hermes");
35636
35915
  const r = await runDoctor(opts, {
35637
35916
  // Pass hermesHomeOverride so the probe fires when ~/.hermes/ exists.
35638
35917
  // When the dir is absent the probe is skipped; when present it WARNs
@@ -35907,7 +36186,7 @@ function registerSubstrate(program2) {
35907
36186
 
35908
36187
  // ../cli-plugin-tasks/dist/client.js
35909
36188
  import { readFileSync as readFileSync46 } from "node:fs";
35910
- import { homedir as homedir30 } from "node:os";
36189
+ import { homedir as homedir31 } from "node:os";
35911
36190
  import { join as join61 } from "node:path";
35912
36191
  var TasksClient = class {
35913
36192
  baseUrl;
@@ -35916,7 +36195,7 @@ var TasksClient = class {
35916
36195
  sessionId;
35917
36196
  constructor(opts) {
35918
36197
  this.baseUrl = (opts.hostCpUrl ?? process.env.OLAM_HOST_CP_URL ?? "http://localhost:19000").replace(/\/$/, "");
35919
- const tokenPath2 = opts.tokenPath ?? join61(homedir30(), ".olam", "host-cp.token");
36198
+ const tokenPath2 = opts.tokenPath ?? join61(homedir31(), ".olam", "host-cp.token");
35920
36199
  try {
35921
36200
  this.token = readFileSync46(tokenPath2, "utf8").trim();
35922
36201
  } catch (e) {
@@ -35925,9 +36204,9 @@ var TasksClient = class {
35925
36204
  this.olamNodeId = opts.olamNodeId;
35926
36205
  this.sessionId = opts.sessionId;
35927
36206
  }
35928
- async call(method, path95, scopes, body, query) {
36207
+ async call(method, path96, scopes, body, query) {
35929
36208
  const qs = query ? "?" + new URLSearchParams(Object.entries(query).filter(([, v]) => v !== void 0)).toString() : "";
35930
- const url2 = `${this.baseUrl}${path95}${qs}`;
36209
+ const url2 = `${this.baseUrl}${path96}${qs}`;
35931
36210
  const res = await fetch(url2, {
35932
36211
  method,
35933
36212
  headers: {
@@ -35978,8 +36257,8 @@ function parseFrontmatter2(raw) {
35978
36257
  }
35979
36258
  return { frontmatter: fm, body };
35980
36259
  }
35981
- function parseTracker(path95) {
35982
- const raw = readFileSync47(path95, "utf8");
36260
+ function parseTracker(path96) {
36261
+ const raw = readFileSync47(path96, "utf8");
35983
36262
  const { frontmatter, body } = parseFrontmatter2(raw);
35984
36263
  const lines = body.split("\n");
35985
36264
  const tasks = [];
@@ -36216,8 +36495,8 @@ function registerTasks(program2) {
36216
36495
  `);
36217
36496
  }
36218
36497
  });
36219
- tasks.command("sync-tracker <path>").description("Parse /10x:commit-plan tracker.md + upsert each task via POST /api/tasks (B2.4; dual-emit pattern, olam-side per cross-ownership decoupling)").option("--node-id <uuid>", "Olam node ID").option("--session-id <uuid>", "Session ID").option("--dry-run", "Parse + print task records; do not POST").option("--json", "Output raw JSON envelope").action(async (path95, opts) => {
36220
- const parsed = parseTracker(path95);
36498
+ tasks.command("sync-tracker <path>").description("Parse /10x:commit-plan tracker.md + upsert each task via POST /api/tasks (B2.4; dual-emit pattern, olam-side per cross-ownership decoupling)").option("--node-id <uuid>", "Olam node ID").option("--session-id <uuid>", "Session ID").option("--dry-run", "Parse + print task records; do not POST").option("--json", "Output raw JSON envelope").action(async (path96, opts) => {
36499
+ const parsed = parseTracker(path96);
36221
36500
  if (opts.dryRun) {
36222
36501
  process.stdout.write(JSON.stringify(parsed, null, 2) + "\n");
36223
36502
  return;
@@ -36371,15 +36650,76 @@ function registerCompletion(program2) {
36371
36650
  // src/commands/setup.ts
36372
36651
  init_cli_version();
36373
36652
  init_health_probes();
36374
- import { spawn as spawn7, spawnSync as spawnSync26 } from "node:child_process";
36653
+ import { spawn as spawn7, spawnSync as spawnSync27 } from "node:child_process";
36375
36654
  import { existsSync as existsSync85, readFileSync as readFileSync70 } from "node:fs";
36376
- import { homedir as homedir44 } from "node:os";
36377
- import path76 from "node:path";
36655
+ import { homedir as homedir45 } from "node:os";
36656
+ import path77 from "node:path";
36378
36657
  import { createInterface as createInterface3 } from "node:readline";
36379
36658
 
36659
+ // src/lib/k8s-context-discovery.ts
36660
+ import { spawnSync as spawnSync26 } from "node:child_process";
36661
+ var OLAM_MANAGED_CONTEXT_PREFIX = "k3d-olam-";
36662
+ function isOlamManagedContext(name) {
36663
+ return name.startsWith(OLAM_MANAGED_CONTEXT_PREFIX);
36664
+ }
36665
+ function defaultGetContexts() {
36666
+ const r = spawnSync26(
36667
+ "kubectl",
36668
+ ["config", "get-contexts", "-o", "name"],
36669
+ { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }
36670
+ );
36671
+ if (r.status !== 0 || !r.stdout) return [];
36672
+ return r.stdout.split("\n").map((l) => l.trim()).filter(Boolean);
36673
+ }
36674
+ function defaultClusterInfo(context) {
36675
+ const r = spawnSync26(
36676
+ "kubectl",
36677
+ ["--context", context, "cluster-info", "--request-timeout=3s"],
36678
+ { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }
36679
+ );
36680
+ if (r.status === 0) {
36681
+ const match2 = r.stdout.match(/running at (https?:\/\/\S+)/i);
36682
+ return { reachable: true, serverUrl: match2?.[1] };
36683
+ }
36684
+ const err = (r.stderr || "").trim().slice(0, 200);
36685
+ return { reachable: false, error: err || "cluster-info failed" };
36686
+ }
36687
+ function defaultIsIdle(context) {
36688
+ const nsResult = spawnSync26(
36689
+ "kubectl",
36690
+ ["--context", context, "get", "namespace", "olam", "--ignore-not-found", "-o", "name"],
36691
+ { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }
36692
+ );
36693
+ const nsLine = (nsResult.stdout || "").trim();
36694
+ if (!nsLine) {
36695
+ return true;
36696
+ }
36697
+ const podsResult = spawnSync26(
36698
+ "kubectl",
36699
+ ["--context", context, "get", "pods", "-n", "olam", "--no-headers"],
36700
+ { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }
36701
+ );
36702
+ const podsOut = (podsResult.stdout || "").trim();
36703
+ return !podsOut || /no resources found/i.test(podsOut);
36704
+ }
36705
+ function discoverOfferableContexts(deps = {}) {
36706
+ const getContextsFn = deps.getContexts ?? defaultGetContexts;
36707
+ const clusterInfoFn = deps.clusterInfo ?? defaultClusterInfo;
36708
+ const isIdleFn = deps.isIdle ?? defaultIsIdle;
36709
+ const allContexts = getContextsFn();
36710
+ const offerable = [];
36711
+ for (const ctx of allContexts) {
36712
+ if (isOlamManagedContext(ctx)) continue;
36713
+ const probe2 = clusterInfoFn(ctx);
36714
+ if (!probe2.reachable) continue;
36715
+ if (isIdleFn(ctx)) offerable.push(ctx);
36716
+ }
36717
+ return { offerable, allContexts };
36718
+ }
36719
+
36380
36720
  // src/lib/shell-rc.ts
36381
36721
  import { copyFileSync as copyFileSync5, existsSync as existsSync60, readFileSync as readFileSync48, renameSync as renameSync8, writeFileSync as writeFileSync29 } from "node:fs";
36382
- import path53 from "node:path";
36722
+ import path54 from "node:path";
36383
36723
  function appendIdempotent(opts) {
36384
36724
  const { rcPath, marker, contentLine, clock = () => /* @__PURE__ */ new Date() } = opts;
36385
36725
  if (!existsSync60(rcPath)) {
@@ -36402,9 +36742,9 @@ function appendIdempotent(opts) {
36402
36742
  }
36403
36743
  function resolveShellRc(home, shellEnv) {
36404
36744
  if (!shellEnv) return null;
36405
- const basename16 = path53.basename(shellEnv);
36406
- if (basename16 === "zsh") return path53.join(home, ".zshrc");
36407
- if (basename16 === "bash") return path53.join(home, ".bashrc");
36745
+ const basename16 = path54.basename(shellEnv);
36746
+ if (basename16 === "zsh") return path54.join(home, ".zshrc");
36747
+ if (basename16 === "bash") return path54.join(home, ".bashrc");
36408
36748
  return null;
36409
36749
  }
36410
36750
 
@@ -36563,8 +36903,8 @@ async function pickSkillSourcePhase(opts, deps) {
36563
36903
  }
36564
36904
 
36565
36905
  // src/commands/setup-phase-5b-project-sweep.ts
36566
- import { homedir as homedir43 } from "node:os";
36567
- import * as path75 from "node:path";
36906
+ import { homedir as homedir44 } from "node:os";
36907
+ import * as path76 from "node:path";
36568
36908
  import * as fs75 from "node:fs";
36569
36909
  async function loadWalkFn() {
36570
36910
  const m = await Promise.resolve().then(() => (init_project_sweep(), project_sweep_exports));
@@ -36583,9 +36923,9 @@ async function loadAppendTrustAuditFn() {
36583
36923
  return m.appendTrustAudit;
36584
36924
  }
36585
36925
  function deriveRepoName(repoPath, existingNames) {
36586
- const base = path75.basename(repoPath).toLowerCase().replace(/[^a-z0-9-]/g, "-");
36926
+ const base = path76.basename(repoPath).toLowerCase().replace(/[^a-z0-9-]/g, "-");
36587
36927
  if (!existingNames.has(base)) return base;
36588
- const parent = path75.basename(path75.dirname(repoPath)).toLowerCase().replace(/[^a-z0-9-]/g, "-");
36928
+ const parent = path76.basename(path76.dirname(repoPath)).toLowerCase().replace(/[^a-z0-9-]/g, "-");
36589
36929
  const composite = `${parent}-${base}`;
36590
36930
  if (!existingNames.has(composite)) return composite;
36591
36931
  let suffix = 2;
@@ -36596,8 +36936,8 @@ async function runProjectSweepPhase(opts, deps, sweepDeps = {}) {
36596
36936
  if (opts.skipProjectSweep) {
36597
36937
  return { ok: true, skipped: true, message: "skipped via --skip-project-sweep" };
36598
36938
  }
36599
- const home = deps.home ?? homedir43();
36600
- const projectsRoot = opts.projects ?? path75.join(home, "Projects");
36939
+ const home = deps.home ?? homedir44();
36940
+ const projectsRoot = opts.projects ?? path76.join(home, "Projects");
36601
36941
  const existsSyncFn = sweepDeps.existsSync ?? fs75.existsSync;
36602
36942
  if (!existsSyncFn(projectsRoot)) {
36603
36943
  return {
@@ -36771,6 +37111,67 @@ function resolveSubstrate(opts, deps) {
36771
37111
  }
36772
37112
  return "kubernetes";
36773
37113
  }
37114
+ async function phase0_5DetectExistingContext(substrate, opts, deps) {
37115
+ if (substrate !== "kubernetes") {
37116
+ return { ok: true, skipped: true, message: "no-op for docker substrate" };
37117
+ }
37118
+ if (opts.reuseCluster) {
37119
+ const name = opts.reuseCluster;
37120
+ const clusterInfoFn = deps.kubectlClusterInfo ?? defaultClusterInfo;
37121
+ const probe2 = clusterInfoFn(name);
37122
+ if (!probe2.reachable) {
37123
+ return {
37124
+ ok: false,
37125
+ message: `--reuse-cluster=${name} but context is not reachable: ${probe2.error ?? "unknown error"}`,
37126
+ remedy: `Verify the context exists (\`kubectl config get-contexts\`) and is reachable (\`kubectl --context=${name} cluster-info\`), then re-run \`olam setup --reuse-cluster=${name}\`.`,
37127
+ reuseContext: void 0
37128
+ };
37129
+ }
37130
+ return {
37131
+ ok: true,
37132
+ message: `will reuse context ${name}${probe2.serverUrl ? ` (${probe2.serverUrl})` : ""}`,
37133
+ reuseContext: name
37134
+ };
37135
+ }
37136
+ const { offerable } = discoverOfferableContexts(deps.kubeContextDeps);
37137
+ if (offerable.length === 0) {
37138
+ return {
37139
+ ok: true,
37140
+ skipped: true,
37141
+ message: "no idle reachable contexts detected; will provision k3d cluster"
37142
+ };
37143
+ }
37144
+ if (opts.yes) {
37145
+ process.stdout.write(
37146
+ ` Detected ${offerable.length} existing Kubernetes context(s): ${offerable.join(", ")}. To reuse one, pass --reuse-cluster=<name>. Provisioning k3d (--yes default).
37147
+ `
37148
+ );
37149
+ return {
37150
+ ok: true,
37151
+ skipped: true,
37152
+ message: `idle context(s) available but --yes defaults to k3d provision; use --reuse-cluster=<name> to opt in`
37153
+ };
37154
+ }
37155
+ const promptFn = deps.prompt ?? defaultPrompt;
37156
+ for (const ctx of offerable) {
37157
+ const reuse = await promptFn(
37158
+ `Detected existing Kubernetes context \`${ctx}\`. Use this cluster instead of provisioning a new k3d cluster?`,
37159
+ false
37160
+ );
37161
+ if (reuse) {
37162
+ return {
37163
+ ok: true,
37164
+ message: `operator chose to reuse context ${ctx}`,
37165
+ reuseContext: ctx
37166
+ };
37167
+ }
37168
+ }
37169
+ return {
37170
+ ok: true,
37171
+ skipped: true,
37172
+ message: "operator declined reuse; will provision k3d cluster"
37173
+ };
37174
+ }
36774
37175
  async function phase1SystemCheck(substrate, deps) {
36775
37176
  const nodeVersion = deps.nodeVersion ?? process.version;
36776
37177
  const nodeMajor = parseNodeMajor(nodeVersion);
@@ -36795,6 +37196,13 @@ async function phase1SystemCheck(substrate, deps) {
36795
37196
  remedy: `Install Node.js ${REQUIRED_NODE_MAJOR}+ LTS via nvm/fnm/asdf and re-run \`olam setup\`.`
36796
37197
  };
36797
37198
  }
37199
+ const platform2 = String(deps.osPlatform ?? process.platform);
37200
+ const home = deps.home ?? homedir45();
37201
+ const colimaLint = probeColimaKubernetesEnabled({ platform: platform2, home });
37202
+ if (colimaLint.ok && "warn" in colimaLint && colimaLint.warn === true) {
37203
+ const lintWithWarn = colimaLint;
37204
+ printWarning(` \u26A0 ${lintWithWarn.remedy}`);
37205
+ }
36798
37206
  return { ok: true, message: `kubectl on PATH; docker ready; node ${nodeVersion}` };
36799
37207
  }
36800
37208
  const dockerProbe = await probeDockerDaemon(deps.dockerExec);
@@ -36817,17 +37225,24 @@ async function phase1SystemCheck(substrate, deps) {
36817
37225
  message: `${dockerProbe.message}; ${composeProbe.message}; node ${nodeVersion}`
36818
37226
  };
36819
37227
  }
36820
- async function phase1_5InstallSubstrate(substrate, opts, deps) {
37228
+ async function phase1_5InstallSubstrate(substrate, opts, deps, reuseContext) {
36821
37229
  if (substrate === "docker") {
36822
37230
  return { ok: true, skipped: true, message: "no-op for docker substrate" };
36823
37231
  }
37232
+ if (reuseContext) {
37233
+ return {
37234
+ ok: true,
37235
+ skipped: true,
37236
+ message: `skipped k3d install (reusing context ${reuseContext})`
37237
+ };
37238
+ }
36824
37239
  const spawnFn = deps.spawnSubprocess ?? defaultSpawn;
36825
37240
  const promptFn = deps.prompt ?? defaultPrompt;
36826
37241
  const k3dProbe = await probeK3d(deps.dockerExec);
36827
37242
  if (k3dProbe.ok) {
36828
37243
  return { ok: true, message: `k3d already present: ${k3dProbe.message}` };
36829
37244
  }
36830
- const hasBrew = spawnSync26("command", ["-v", "brew"], { shell: true, stdio: "pipe" }).status === 0;
37245
+ const hasBrew = spawnSync27("command", ["-v", "brew"], { shell: true, stdio: "pipe" }).status === 0;
36831
37246
  const useBrewMsg = hasBrew ? "Homebrew" : "upstream install script";
36832
37247
  if (!opts.yes) {
36833
37248
  const confirmed = await promptFn(
@@ -36886,10 +37301,17 @@ function phaseFromProbe(probe2) {
36886
37301
  if (probe2.ok) return { ok: true, message: probe2.message };
36887
37302
  return { ok: false, message: probe2.message, remedy: probe2.remedy };
36888
37303
  }
36889
- async function phase2_5ProvisionCluster(substrate, clusterName, opts, deps) {
37304
+ async function phase2_5ProvisionCluster(substrate, clusterName, opts, deps, reuseContext) {
36890
37305
  if (substrate === "docker") {
36891
37306
  return { ok: true, skipped: true, message: "no-op for docker substrate" };
36892
37307
  }
37308
+ if (reuseContext) {
37309
+ return {
37310
+ ok: true,
37311
+ skipped: true,
37312
+ message: `skipped k3d cluster provision (reusing context ${reuseContext})`
37313
+ };
37314
+ }
36893
37315
  const spawnFn = deps.spawnSubprocess ?? defaultSpawn;
36894
37316
  const listResult = await captureSpawn("k3d", ["cluster", "list", "--output", "json"], deps.dockerExec);
36895
37317
  if (listResult.ok) {
@@ -36903,7 +37325,7 @@ async function phase2_5ProvisionCluster(substrate, clusterName, opts, deps) {
36903
37325
  }
36904
37326
  process.stdout.write(`Creating k3d cluster ${clusterName}...
36905
37327
  `);
36906
- const ghConfigBind = `${homedir44()}/.config/gh:/host/.config/gh`;
37328
+ const ghConfigBind = `${homedir45()}/.config/gh:/host/.config/gh`;
36907
37329
  const createResult = await spawnFn("k3d", [
36908
37330
  "cluster",
36909
37331
  "create",
@@ -36927,14 +37349,14 @@ async function phase2_5ProvisionCluster(substrate, clusterName, opts, deps) {
36927
37349
  }
36928
37350
  async function captureSpawn(cmd, args, dockerExec) {
36929
37351
  const exec = dockerExec ?? ((c, a) => {
36930
- const r2 = spawnSync26(c, [...a], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
37352
+ const r2 = spawnSync27(c, [...a], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
36931
37353
  return { status: r2.status, stdout: r2.stdout ?? "", stderr: r2.stderr ?? "" };
36932
37354
  });
36933
37355
  const r = exec(cmd, args);
36934
37356
  return { ok: r.status === 0, stdout: r.stdout, stderr: r.stderr };
36935
37357
  }
36936
37358
  function captureSpawnSync(cmd, args) {
36937
- const r = spawnSync26(cmd, [...args], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
37359
+ const r = spawnSync27(cmd, [...args], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
36938
37360
  return { ok: r.status === 0, stdout: r.stdout ?? "" };
36939
37361
  }
36940
37362
  function clusterExistsInList(json, clusterName) {
@@ -36963,11 +37385,11 @@ function safeReadCliVersion() {
36963
37385
  return null;
36964
37386
  }
36965
37387
  }
36966
- async function phase2_6PinKubectlContext(substrate, clusterName, deps) {
37388
+ async function phase2_6PinKubectlContext(substrate, clusterName, deps, reuseContext) {
36967
37389
  if (substrate !== "kubernetes") {
36968
37390
  return { ok: true, skipped: true, message: "no-op for docker substrate" };
36969
37391
  }
36970
- const expectedContext = `k3d-${clusterName}`;
37392
+ const expectedContext = reuseContext ?? `k3d-${clusterName}`;
36971
37393
  writeConfig({ host: { substrate: "kubernetes" } }, { configPath: deps.configPath });
36972
37394
  const result = applyKubectlContextPin([expectedContext], {
36973
37395
  configPath: deps.configPath
@@ -37004,7 +37426,7 @@ async function phase4ShellInit(opts, deps) {
37004
37426
  if (opts.skipShellInit) {
37005
37427
  return { ok: true, skipped: true, message: "skipped via --skip-shell-init" };
37006
37428
  }
37007
- const home = deps.home ?? homedir44();
37429
+ const home = deps.home ?? homedir45();
37008
37430
  const shellEnv = deps.shellEnv ?? process.env.SHELL;
37009
37431
  const rcPath = resolveShellRc(home, shellEnv);
37010
37432
  if (rcPath === null) {
@@ -37014,7 +37436,7 @@ async function phase4ShellInit(opts, deps) {
37014
37436
  message: `unsupported $SHELL (${shellEnv ?? "unset"}); add \`eval "$(olam completion <shell>)"\` to your shell rc manually`
37015
37437
  };
37016
37438
  }
37017
- const shellBasename = path76.basename(shellEnv);
37439
+ const shellBasename = path77.basename(shellEnv);
37018
37440
  const evalLine = `eval "$(olam completion ${shellBasename})"`;
37019
37441
  const result = appendIdempotent({
37020
37442
  rcPath,
@@ -37040,7 +37462,7 @@ async function phase4ShellInit(opts, deps) {
37040
37462
  async function phase5InitProject(opts, deps) {
37041
37463
  const cwd = deps.cwd ?? process.cwd();
37042
37464
  const projectRoot = findProjectRoot(cwd);
37043
- const configPath = path76.join(projectRoot, ".olam", "config.yaml");
37465
+ const configPath = path77.join(projectRoot, ".olam", "config.yaml");
37044
37466
  if (existsSync85(configPath)) {
37045
37467
  return { ok: true, message: `${configPath} present (no change)` };
37046
37468
  }
@@ -37119,7 +37541,8 @@ async function phase7Verify(opts, deps) {
37119
37541
  remedy: "Inspect doctor output above; the specific failing probe names its remedy."
37120
37542
  };
37121
37543
  }
37122
- var PHASE_TITLES_DOCKER = [
37544
+ var PHASE_TITLES = [
37545
+ "Phase 0.5: Detect existing k8s context",
37123
37546
  "Phase 1: System check",
37124
37547
  "Phase 1.5: Substrate tools install",
37125
37548
  "Phase 2: olam CLI sanity",
@@ -37157,12 +37580,32 @@ async function runSetup(opts, deps = {}) {
37157
37580
  process.stdout.write(`cluster: ${clusterName}
37158
37581
  `);
37159
37582
  }
37583
+ const results = [];
37584
+ let failureAt = null;
37585
+ const phase0_5Title = PHASE_TITLES[0];
37586
+ process.stdout.write(`
37587
+ ${phase0_5Title}
37588
+ `);
37589
+ const phase0_5Result = await phase0_5DetectExistingContext(substrate, opts, deps);
37590
+ results.push({ name: phase0_5Title, result: phase0_5Result });
37591
+ if (phase0_5Result.ok && phase0_5Result.skipped) {
37592
+ printWarning(` \u2298 ${phase0_5Result.message}`);
37593
+ } else if (phase0_5Result.ok) {
37594
+ printSuccess(` \u2713 ${phase0_5Result.message}`);
37595
+ } else {
37596
+ printError(` \u2717 ${phase0_5Result.message}`);
37597
+ if (phase0_5Result.remedy) printWarning(` remedy: ${phase0_5Result.remedy}`);
37598
+ process.stdout.write("\n");
37599
+ printError("Setup FAILED at Phase 1");
37600
+ return { phases: results, failureAt: 1, exitCode: 1 };
37601
+ }
37602
+ const reuseContext = phase0_5Result.reuseContext;
37160
37603
  const phaseFns = [
37161
37604
  () => phase1SystemCheck(substrate, deps),
37162
- () => phase1_5InstallSubstrate(substrate, opts, deps),
37605
+ () => phase1_5InstallSubstrate(substrate, opts, deps, reuseContext),
37163
37606
  () => phase2CliSanity(deps),
37164
- () => phase2_5ProvisionCluster(substrate, clusterName, opts, deps),
37165
- () => phase2_6PinKubectlContext(substrate, clusterName, deps),
37607
+ () => phase2_5ProvisionCluster(substrate, clusterName, opts, deps, reuseContext),
37608
+ () => phase2_6PinKubectlContext(substrate, clusterName, deps, reuseContext),
37166
37609
  () => phase3Bootstrap(substrate, deps),
37167
37610
  () => phase4ShellInit(opts, deps),
37168
37611
  () => phase5InitProject(opts, deps),
@@ -37171,10 +37614,8 @@ async function runSetup(opts, deps = {}) {
37171
37614
  () => phase6Auth(opts, deps),
37172
37615
  () => phase7Verify(opts, deps)
37173
37616
  ];
37174
- const results = [];
37175
- let failureAt = null;
37176
37617
  for (let i = 0; i < phaseFns.length; i += 1) {
37177
- const name = PHASE_TITLES_DOCKER[i];
37618
+ const name = PHASE_TITLES[i + 1];
37178
37619
  process.stdout.write(`
37179
37620
  ${name}
37180
37621
  `);
@@ -37187,7 +37628,7 @@ ${name}
37187
37628
  } else {
37188
37629
  printError(` \u2717 ${result.message}`);
37189
37630
  if (result.remedy) printWarning(` remedy: ${result.remedy}`);
37190
- failureAt = i + 1;
37631
+ failureAt = i + 2;
37191
37632
  break;
37192
37633
  }
37193
37634
  }
@@ -37214,6 +37655,9 @@ function registerSetup(program2) {
37214
37655
  ).option(
37215
37656
  "--cluster-name <name>",
37216
37657
  "k3d cluster name to create/use (kubernetes substrate only; default: olam-dev). Use a different name to avoid colliding with a pre-existing olam-dev cluster, to run multiple olam stacks side-by-side, or for per-run unique names in CI smoke. Must be DNS-compatible: lowercase alphanumeric, hyphens allowed in the middle."
37658
+ ).option(
37659
+ "--reuse-cluster <name>",
37660
+ "Reuse an existing kubeconfig context instead of provisioning a new k3d cluster. Pair with --substrate=kubernetes. Skips Phase 1.5 (k3d install) and Phase 2.5 (cluster provision); Phase 2.6 pins to this context. Operator owns the cluster lifecycle (teardown not handled by olam setup). Example: --reuse-cluster=colima (for Colima k8s users)."
37217
37661
  ).option("--skip-shell-init", "Skip Phase 4 (do not append to ~/.zshrc / ~/.bashrc)").option("--skip-auth", "Skip Phase 6 (do not prompt for `olam auth login`)").option("--skip-skill-source", "Skip Phase 5a (do not pick a skill source; run `olam skills source add` later)").option("--skill-source <id-or-url>", "Non-interactive Phase 5a: curated name (e.g. atlas-toolbox) or git URL").option("--skip-project-sweep", "Skip Phase 5b (do not walk projects directory for repo discovery)").option("--projects <path>", "Phase 5b: project root path to walk (default: ~/Projects)").option("--dry-run", "Phase 5b: print matches without registering or building (no side effects)").option("--exclude <glob...>", "Phase 5b: additional skip patterns for project sweep").option("--skip-kg", "Phase 5b: skip KG eager-build sub-step (sources still registered)").option(
37218
37662
  "--skip-doctor",
37219
37663
  "Skip Phase 7 final `olam doctor` verification (for CI or minimal setups)"
@@ -37412,13 +37856,13 @@ function registerSetupLinuxGate(program2) {
37412
37856
  // src/commands/update.ts
37413
37857
  import * as fs78 from "node:fs";
37414
37858
  import * as os42 from "node:os";
37415
- import * as path79 from "node:path";
37859
+ import * as path80 from "node:path";
37416
37860
  import { execSync as execSync14 } from "node:child_process";
37417
37861
  import pc28 from "picocolors";
37418
37862
 
37419
37863
  // src/lib/symlink-reconcile.ts
37420
37864
  import * as fs76 from "node:fs";
37421
- import * as path77 from "node:path";
37865
+ import * as path78 from "node:path";
37422
37866
  var realFs = {
37423
37867
  readdirSync: (p) => fs76.readdirSync(p),
37424
37868
  existsSync: (p) => fs76.existsSync(p),
@@ -37437,8 +37881,8 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir2, _fs = realFs) {
37437
37881
  _fs.mkdirSync(claudeSkillsDir2, { recursive: true });
37438
37882
  const sourceSkills = _fs.existsSync(npmSkillsDir) ? _fs.readdirSync(npmSkillsDir).filter((d) => d.startsWith("olam-")) : [];
37439
37883
  for (const skill of sourceSkills) {
37440
- const linkPath = path77.join(claudeSkillsDir2, skill);
37441
- const target = path77.join(npmSkillsDir, skill);
37884
+ const linkPath = path78.join(claudeSkillsDir2, skill);
37885
+ const target = path78.join(npmSkillsDir, skill);
37442
37886
  if (!_fs.existsSync(linkPath)) {
37443
37887
  try {
37444
37888
  _fs.symlinkSync(target, linkPath);
@@ -37451,7 +37895,7 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir2, _fs = realFs) {
37451
37895
  }
37452
37896
  const deployedEntries = _fs.existsSync(claudeSkillsDir2) ? _fs.readdirSync(claudeSkillsDir2).filter((d) => d.startsWith("olam-")) : [];
37453
37897
  for (const entry of deployedEntries) {
37454
- const linkPath = path77.join(claudeSkillsDir2, entry);
37898
+ const linkPath = path78.join(claudeSkillsDir2, entry);
37455
37899
  let isSymlink = false;
37456
37900
  try {
37457
37901
  isSymlink = _fs.lstatSync(linkPath).isSymbolicLink();
@@ -37476,9 +37920,9 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir2, _fs = realFs) {
37476
37920
 
37477
37921
  // src/commands/update.ts
37478
37922
  var PACKAGE_NAME = "@pleri/olam-cli";
37479
- var CACHE_DIR2 = path79.join(os42.homedir(), ".olam", "cache");
37480
- var LOG_DIR2 = path79.join(os42.homedir(), ".olam", "log");
37481
- var LAST_STABLE_FILE = path79.join(CACHE_DIR2, "last-stable.txt");
37923
+ var CACHE_DIR2 = path80.join(os42.homedir(), ".olam", "cache");
37924
+ var LOG_DIR2 = path80.join(os42.homedir(), ".olam", "log");
37925
+ var LAST_STABLE_FILE = path80.join(CACHE_DIR2, "last-stable.txt");
37482
37926
  function defaultExec(cmd) {
37483
37927
  try {
37484
37928
  const stdout = execSync14(cmd, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
@@ -37507,12 +37951,12 @@ function readLastStable(file = LAST_STABLE_FILE) {
37507
37951
  }
37508
37952
  }
37509
37953
  function writeLastStable(version, file = LAST_STABLE_FILE) {
37510
- fs78.mkdirSync(path79.dirname(file), { recursive: true });
37954
+ fs78.mkdirSync(path80.dirname(file), { recursive: true });
37511
37955
  fs78.writeFileSync(file, version, { mode: 420 });
37512
37956
  }
37513
37957
  function logUpdateFailure(stderr) {
37514
37958
  const ts = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
37515
- const logFile = path79.join(LOG_DIR2, `update-${ts}.log`);
37959
+ const logFile = path80.join(LOG_DIR2, `update-${ts}.log`);
37516
37960
  try {
37517
37961
  fs78.mkdirSync(LOG_DIR2, { recursive: true });
37518
37962
  fs78.appendFileSync(logFile, `[update-failure ${(/* @__PURE__ */ new Date()).toISOString()}]
@@ -37602,8 +38046,8 @@ async function doUpdate(opts, _exec = defaultExec, _reconcile = reconcileSkillSy
37602
38046
  let symlinkResult = { added: [], removed: [] };
37603
38047
  if (npmRootResult.exitCode === 0) {
37604
38048
  const npmRoot = npmRootResult.stdout.trim();
37605
- const npmSkillsDir = path79.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills");
37606
- const claudeSkillsDir2 = path79.join(os42.homedir(), ".claude", "skills");
38049
+ const npmSkillsDir = path80.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills");
38050
+ const claudeSkillsDir2 = path80.join(os42.homedir(), ".claude", "skills");
37607
38051
  const rec = _reconcile(npmSkillsDir, claudeSkillsDir2);
37608
38052
  symlinkResult = { added: rec.added, removed: rec.removed };
37609
38053
  if (!quiet && (rec.added.length > 0 || rec.removed.length > 0)) {
@@ -37649,8 +38093,8 @@ async function doRollback(_exec = defaultExec, _reconcile = reconcileSkillSymlin
37649
38093
  if (npmRootResult.exitCode === 0) {
37650
38094
  const npmRoot = npmRootResult.stdout.trim();
37651
38095
  _reconcile(
37652
- path79.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills"),
37653
- path79.join(os42.homedir(), ".claude", "skills")
38096
+ path80.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills"),
38097
+ path80.join(os42.homedir(), ".claude", "skills")
37654
38098
  );
37655
38099
  }
37656
38100
  return { action: "rolled-back", restoredVersion: prev, exitCode: 0 };
@@ -38007,7 +38451,7 @@ import pc32 from "picocolors";
38007
38451
 
38008
38452
  // src/commands/flywheel/install-shims.ts
38009
38453
  import { copyFileSync as copyFileSync9, existsSync as existsSync89, mkdirSync as mkdirSync53, readFileSync as readFileSync74, writeFileSync as writeFileSync44 } from "node:fs";
38010
- import { homedir as homedir47 } from "node:os";
38454
+ import { homedir as homedir48 } from "node:os";
38011
38455
  import { dirname as dirname48, join as join87 } from "node:path";
38012
38456
 
38013
38457
  // src/lib/shim-generator.ts
@@ -38071,7 +38515,7 @@ ${argsBlock}
38071
38515
  // src/commands/flywheel/install-shims.ts
38072
38516
  var SHIM_HEADER_MARKER = "# AUTO-GENERATED by `olam flywheel install-shims`";
38073
38517
  function refreshShims(opts = {}) {
38074
- const targetDir = opts.targetDir ?? join87(homedir47(), ".claude", "scripts");
38518
+ const targetDir = opts.targetDir ?? join87(homedir48(), ".claude", "scripts");
38075
38519
  const results = [];
38076
38520
  let written = 0;
38077
38521
  let overwritten = 0;
@@ -38132,7 +38576,7 @@ function installOne(spec, targetDir, opts) {
38132
38576
  }
38133
38577
  function registerFlywheelInstallShims(parent) {
38134
38578
  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) => {
38135
- const targetDir = opts.targetDir ?? join87(homedir47(), ".claude", "scripts");
38579
+ const targetDir = opts.targetDir ?? join87(homedir48(), ".claude", "scripts");
38136
38580
  const summary2 = refreshShims(opts);
38137
38581
  const lines = [];
38138
38582
  const dryRunSuffix = opts.dryRun === true ? " (dry-run)" : "";
@@ -38757,7 +39201,7 @@ init_skill_sources();
38757
39201
  init_output();
38758
39202
  import * as fs80 from "node:fs";
38759
39203
  import * as os43 from "node:os";
38760
- import * as path80 from "node:path";
39204
+ import * as path81 from "node:path";
38761
39205
  import * as readline3 from "node:readline";
38762
39206
  import pc33 from "picocolors";
38763
39207
 
@@ -38776,7 +39220,7 @@ import {
38776
39220
  statSync as statSync27,
38777
39221
  writeFileSync as writeFileSync45
38778
39222
  } from "node:fs";
38779
- import { homedir as homedir48 } from "node:os";
39223
+ import { homedir as homedir49 } from "node:os";
38780
39224
  import { basename as basename8, dirname as dirname49, isAbsolute as isAbsolute4, join as join88, relative as relative5, resolve as resolve21 } from "node:path";
38781
39225
 
38782
39226
  // src/commands/flywheel/sanitize-persona-output.ts
@@ -38839,7 +39283,7 @@ function registerFlywheelSanitizePersonaOutput(parent) {
38839
39283
 
38840
39284
  // src/lib/skills-apply-overlays.ts
38841
39285
  function claudeRoot(opts) {
38842
- return opts.claudeDir ?? opts.fixtureRoot ?? join88(homedir48(), ".claude");
39286
+ return opts.claudeDir ?? opts.fixtureRoot ?? join88(homedir49(), ".claude");
38843
39287
  }
38844
39288
  function ensureRealDir(p) {
38845
39289
  if (!existsSync90(p)) {
@@ -39036,12 +39480,12 @@ function asMessage4(err) {
39036
39480
  }
39037
39481
  var ATLAS_USER_PICKER_RE = /^[a-z0-9][a-z0-9_-]{0,38}$/;
39038
39482
  function listMemberNames(clonePath) {
39039
- const membersDir = path80.join(clonePath, "members");
39483
+ const membersDir = path81.join(clonePath, "members");
39040
39484
  if (!fs80.existsSync(membersDir)) return [];
39041
39485
  try {
39042
39486
  return fs80.readdirSync(membersDir).filter((e) => {
39043
39487
  try {
39044
- return fs80.statSync(path80.join(membersDir, e)).isDirectory();
39488
+ return fs80.statSync(path81.join(membersDir, e)).isDirectory();
39045
39489
  } catch {
39046
39490
  return false;
39047
39491
  }
@@ -39090,8 +39534,8 @@ function defaultAtlasUserPrompt(question) {
39090
39534
  async function resolveAtlasUserWithPicker(cliOverride, opts) {
39091
39535
  if (cliOverride !== void 0) return cliOverride;
39092
39536
  const ATLAS_USER_RE2 = /^[a-z0-9][a-z0-9_-]{0,38}$/;
39093
- const claudeDirPathForRead = opts?._testClaudeDir ?? (process.env["OLAM_CLAUDE_DIR"] ?? path80.join(os43.homedir(), ".claude"));
39094
- const atlasUserFile = path80.join(claudeDirPathForRead, ".atlas-user");
39537
+ const claudeDirPathForRead = opts?._testClaudeDir ?? (process.env["OLAM_CLAUDE_DIR"] ?? path81.join(os43.homedir(), ".claude"));
39538
+ const atlasUserFile = path81.join(claudeDirPathForRead, ".atlas-user");
39095
39539
  if (fs80.existsSync(atlasUserFile)) {
39096
39540
  const existing = fs80.readFileSync(atlasUserFile, "utf-8").trim();
39097
39541
  if (existing.length > 0) {
@@ -39152,10 +39596,10 @@ async function resolveAtlasUserWithPicker(cliOverride, opts) {
39152
39596
  );
39153
39597
  return void 0;
39154
39598
  }
39155
- const claudeDirPath = opts?._testClaudeDir ?? (process.env["OLAM_CLAUDE_DIR"] ?? path80.join(os43.homedir(), ".claude"));
39599
+ const claudeDirPath = opts?._testClaudeDir ?? (process.env["OLAM_CLAUDE_DIR"] ?? path81.join(os43.homedir(), ".claude"));
39156
39600
  fs80.mkdirSync(claudeDirPath, { recursive: true });
39157
- fs80.writeFileSync(path80.join(claudeDirPath, ".atlas-user"), picked + "\n", "utf8");
39158
- process.stdout.write(pc33.green(`\u2713 atlas-user set to "${picked}" (written to ${path80.join(claudeDirPath, ".atlas-user")})
39601
+ fs80.writeFileSync(path81.join(claudeDirPath, ".atlas-user"), picked + "\n", "utf8");
39602
+ process.stdout.write(pc33.green(`\u2713 atlas-user set to "${picked}" (written to ${path81.join(claudeDirPath, ".atlas-user")})
39159
39603
  `));
39160
39604
  return picked;
39161
39605
  }
@@ -39167,10 +39611,10 @@ function listDeployed() {
39167
39611
  );
39168
39612
  const entries = [];
39169
39613
  for (const bucket of ["skills", "agents", "scripts", "rules", "commands"]) {
39170
- const bucketDir = path80.join(dir, bucket);
39614
+ const bucketDir = path81.join(dir, bucket);
39171
39615
  if (!fs80.existsSync(bucketDir)) continue;
39172
39616
  for (const name of fs80.readdirSync(bucketDir)) {
39173
- const full = path80.join(bucketDir, name);
39617
+ const full = path81.join(bucketDir, name);
39174
39618
  try {
39175
39619
  const stat = fs80.lstatSync(full);
39176
39620
  if (!stat.isSymbolicLink()) continue;
@@ -39621,7 +40065,7 @@ init_merge_settings();
39621
40065
  init_skill_sources();
39622
40066
  init_output();
39623
40067
  import * as fs82 from "node:fs";
39624
- import * as path81 from "node:path";
40068
+ import * as path82 from "node:path";
39625
40069
  var MIGRATE_FROM_TOOLBOX_COMMAND = "migrate-from-toolbox";
39626
40070
  function asMessage6(err) {
39627
40071
  return err instanceof Error ? err.message : String(err);
@@ -39689,7 +40133,7 @@ function registerSkillsMigrate(program2) {
39689
40133
  return;
39690
40134
  }
39691
40135
  const toolboxPath = opts.path;
39692
- const namespace = opts.namespace ?? path81.basename(toolboxPath);
40136
+ const namespace = opts.namespace ?? path82.basename(toolboxPath);
39693
40137
  const sourceName = opts.sourceName ?? namespace;
39694
40138
  const snapshot = detectToolboxState({ toolboxPath, namespace });
39695
40139
  if (!snapshot) {
@@ -39743,9 +40187,9 @@ function registerSkillsMigrate(program2) {
39743
40187
  printWarning(`legacy hook removal failed: ${asMessage6(err)}; proceeding`);
39744
40188
  }
39745
40189
  const scope = opts.scope === "user" ? "user" : "project";
39746
- const olamHookPath = scope === "user" ? settingsFile : path81.join(process.cwd(), ".claude", "settings.json");
40190
+ const olamHookPath = scope === "user" ? settingsFile : path82.join(process.cwd(), ".claude", "settings.json");
39747
40191
  try {
39748
- fs82.mkdirSync(path81.dirname(olamHookPath), { recursive: true });
40192
+ fs82.mkdirSync(path82.dirname(olamHookPath), { recursive: true });
39749
40193
  const result = mergeHomeSettingsJson(olamHookPath, {
39750
40194
  ensureHook: {
39751
40195
  stage: OLAM_SKILLS_HOOK_STAGE,
@@ -39779,7 +40223,7 @@ function registerSkillsMigrate(program2) {
39779
40223
  init_skill_sources();
39780
40224
  init_output();
39781
40225
  import * as fs83 from "node:fs";
39782
- import * as path82 from "node:path";
40226
+ import * as path83 from "node:path";
39783
40227
  var MIGRATE_BACK_TO_TOOLBOX_COMMAND = "migrate-back-to-toolbox";
39784
40228
  function asMessage7(err) {
39785
40229
  return err instanceof Error ? err.message : String(err);
@@ -39787,7 +40231,7 @@ function asMessage7(err) {
39787
40231
  function claudeDirInternal4() {
39788
40232
  const override = process.env["OLAM_CLAUDE_DIR"];
39789
40233
  if (override && override.length > 0) return override;
39790
- return path82.join(process.env["HOME"] ?? "", ".claude");
40234
+ return path83.join(process.env["HOME"] ?? "", ".claude");
39791
40235
  }
39792
40236
  function restoreSessionStartFromSnapshot(filePath, originalSessionStartHook) {
39793
40237
  if (!originalSessionStartHook || originalSessionStartHook.length === 0) {
@@ -39812,7 +40256,7 @@ function restoreSessionStartFromSnapshot(filePath, originalSessionStartHook) {
39812
40256
  SessionStart: originalSessionStartHook
39813
40257
  }
39814
40258
  };
39815
- fs83.mkdirSync(path82.dirname(filePath), { recursive: true });
40259
+ fs83.mkdirSync(path83.dirname(filePath), { recursive: true });
39816
40260
  fs83.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
39817
40261
  return { restored: true };
39818
40262
  }
@@ -39822,10 +40266,10 @@ function removeOlamManagedSymlinks() {
39822
40266
  const olamClonePaths = sources.map((s) => skillSourceClonePath(s.id));
39823
40267
  let removed = 0;
39824
40268
  for (const bucket of ["skills", "agents", "scripts", "rules", "commands"]) {
39825
- const dir = path82.join(claude, bucket);
40269
+ const dir = path83.join(claude, bucket);
39826
40270
  if (!fs83.existsSync(dir)) continue;
39827
40271
  for (const name of fs83.readdirSync(dir)) {
39828
- const linkPath = path82.join(dir, name);
40272
+ const linkPath = path83.join(dir, name);
39829
40273
  try {
39830
40274
  const stat = fs83.lstatSync(linkPath);
39831
40275
  if (!stat.isSymbolicLink()) continue;
@@ -39844,7 +40288,7 @@ function restoreToolboxSymlinks(symlinks) {
39844
40288
  let restored = 0;
39845
40289
  for (const { link, target } of symlinks) {
39846
40290
  try {
39847
- fs83.mkdirSync(path82.dirname(link), { recursive: true });
40291
+ fs83.mkdirSync(path83.dirname(link), { recursive: true });
39848
40292
  if (fs83.existsSync(link) || (() => {
39849
40293
  try {
39850
40294
  fs83.lstatSync(link);
@@ -39864,8 +40308,8 @@ function restoreToolboxSymlinks(symlinks) {
39864
40308
  }
39865
40309
  function restoreAtlasUserMarker(atlasUser) {
39866
40310
  if (!atlasUser) return false;
39867
- const file = path82.join(claudeDirInternal4(), ".atlas-user");
39868
- fs83.mkdirSync(path82.dirname(file), { recursive: true });
40311
+ const file = path83.join(claudeDirInternal4(), ".atlas-user");
40312
+ fs83.mkdirSync(path83.dirname(file), { recursive: true });
39869
40313
  fs83.writeFileSync(file, atlasUser);
39870
40314
  return true;
39871
40315
  }
@@ -39879,7 +40323,7 @@ function registerSkillsMigrateBack(program2) {
39879
40323
  let snapshot;
39880
40324
  try {
39881
40325
  if (opts.snapshot) {
39882
- snapshotPath = path82.resolve(opts.snapshot);
40326
+ snapshotPath = path83.resolve(opts.snapshot);
39883
40327
  if (!fs83.existsSync(snapshotPath)) {
39884
40328
  printError(`snapshot not found at ${snapshotPath}`);
39885
40329
  process.exitCode = 1;
@@ -39887,7 +40331,7 @@ function registerSkillsMigrateBack(program2) {
39887
40331
  }
39888
40332
  snapshot = readMigrationSnapshotFromPath(snapshotPath);
39889
40333
  } else {
39890
- const filterNamespace = opts.namespace ?? (opts.path ? path82.basename(opts.path) : void 0);
40334
+ const filterNamespace = opts.namespace ?? (opts.path ? path83.basename(opts.path) : void 0);
39891
40335
  const latest = readLatestMigrationSnapshot({ namespace: filterNamespace });
39892
40336
  if (!latest) {
39893
40337
  const where = filterNamespace ? ` for namespace "${filterNamespace}"` : "";
@@ -39965,7 +40409,7 @@ init_trust_audit_log();
39965
40409
  init_atlas_hook_strip();
39966
40410
  init_output();
39967
40411
  import * as fs84 from "node:fs";
39968
- import * as path83 from "node:path";
40412
+ import * as path84 from "node:path";
39969
40413
  import pc35 from "picocolors";
39970
40414
  var MIGRATE_HOOKS_COMMAND = "migrate-hooks";
39971
40415
  function settingsHasOlamMetaSentinel(settings) {
@@ -39992,7 +40436,7 @@ function readSettings2(filePath) {
39992
40436
  return JSON.parse(raw);
39993
40437
  }
39994
40438
  function writeSettings(filePath, settings) {
39995
- fs84.mkdirSync(path83.dirname(filePath), { recursive: true });
40439
+ fs84.mkdirSync(path84.dirname(filePath), { recursive: true });
39996
40440
  const tmp = `${filePath}.tmp-migrate-hooks-${process.pid}-${Date.now()}`;
39997
40441
  fs84.writeFileSync(tmp, JSON.stringify(settings, null, 2) + "\n");
39998
40442
  fs84.renameSync(tmp, filePath);
@@ -40075,7 +40519,7 @@ function registerSkillsMigrateHooks(program2) {
40075
40519
  init_meta_hooks_migration_snapshot();
40076
40520
  init_skill_sources();
40077
40521
  init_output();
40078
- import * as path84 from "node:path";
40522
+ import * as path85 from "node:path";
40079
40523
  function asMessage9(err) {
40080
40524
  return err instanceof Error ? err.message : String(err);
40081
40525
  }
@@ -40092,16 +40536,16 @@ function registerSkillsMigrateHooksBack(program2) {
40092
40536
  return;
40093
40537
  }
40094
40538
  if (opts.snapshot) {
40095
- const resolved = path84.resolve(opts.snapshot);
40096
- const allowedDir = path84.resolve(migrationSnapshotsDir2());
40097
- if (!resolved.startsWith(allowedDir + path84.sep)) {
40539
+ const resolved = path85.resolve(opts.snapshot);
40540
+ const allowedDir = path85.resolve(migrationSnapshotsDir2());
40541
+ if (!resolved.startsWith(allowedDir + path85.sep)) {
40098
40542
  printError(
40099
40543
  `--snapshot path must be inside ${allowedDir} (got "${resolved}"). Refusing to restore from an arbitrary path \u2014 settings.json would land operator-chosen content.`
40100
40544
  );
40101
40545
  process.exitCode = 1;
40102
40546
  return;
40103
40547
  }
40104
- const basename16 = path84.basename(resolved);
40548
+ const basename16 = path85.basename(resolved);
40105
40549
  if (!basename16.startsWith(META_HOOKS_SNAPSHOT_PREFIX)) {
40106
40550
  printError(
40107
40551
  `--snapshot filename must start with "${META_HOOKS_SNAPSHOT_PREFIX}" (got "${basename16}"). Cross-namespace snapshots (atlas-toolbox-*) are not valid restore targets for olam-meta hooks.`
@@ -40335,9 +40779,9 @@ function registerSkillsDoctor(program2) {
40335
40779
  init_skill_sources();
40336
40780
  init_cli_version();
40337
40781
  init_output();
40338
- import { execFileSync as execFileSync15 } from "node:child_process";
40782
+ import { execFileSync as execFileSync16 } from "node:child_process";
40339
40783
  import * as fs86 from "node:fs";
40340
- import * as path85 from "node:path";
40784
+ import * as path86 from "node:path";
40341
40785
  var CHAIN_SKILL_NAMES = [
40342
40786
  "10x:brainstorm",
40343
40787
  "10x:plan-hard",
@@ -40353,17 +40797,17 @@ function asMessage12(err) {
40353
40797
  }
40354
40798
  function hasBeadsCli() {
40355
40799
  try {
40356
- execFileSync15("bd", ["--version"], { stdio: "ignore" });
40800
+ execFileSync16("bd", ["--version"], { stdio: "ignore" });
40357
40801
  return true;
40358
40802
  } catch {
40359
40803
  return false;
40360
40804
  }
40361
40805
  }
40362
40806
  function hasBeadsProjectInit(cwd) {
40363
- return fs86.existsSync(path85.join(cwd, ".beads"));
40807
+ return fs86.existsSync(path86.join(cwd, ".beads"));
40364
40808
  }
40365
40809
  function hasBeadsClaudeSetup() {
40366
- const settingsPath = path85.join(claudeDir(), "settings.json");
40810
+ const settingsPath = path86.join(claudeDir(), "settings.json");
40367
40811
  if (!fs86.existsSync(settingsPath)) return false;
40368
40812
  try {
40369
40813
  const content = fs86.readFileSync(settingsPath, "utf8");
@@ -40382,7 +40826,7 @@ async function bootstrapBeads(cwd) {
40382
40826
  if (!hasBeadsProjectInit(cwd)) {
40383
40827
  console.log("bd init \u2014 initializing beads in current project");
40384
40828
  try {
40385
- execFileSync15("bd", ["init", "--quiet", "--stealth"], {
40829
+ execFileSync16("bd", ["init", "--quiet", "--stealth"], {
40386
40830
  cwd,
40387
40831
  stdio: "inherit"
40388
40832
  });
@@ -40395,7 +40839,7 @@ async function bootstrapBeads(cwd) {
40395
40839
  if (!hasBeadsClaudeSetup()) {
40396
40840
  console.log("bd setup claude \u2014 installing beads Claude Code hooks");
40397
40841
  try {
40398
- execFileSync15("bd", ["setup", "claude"], { cwd, stdio: "inherit" });
40842
+ execFileSync16("bd", ["setup", "claude"], { cwd, stdio: "inherit" });
40399
40843
  } catch (err) {
40400
40844
  printWarning(`bd setup claude failed (continuing): ${asMessage12(err)}`);
40401
40845
  }
@@ -40431,12 +40875,12 @@ function shortSha(sha) {
40431
40875
  return sha.slice(0, 8);
40432
40876
  }
40433
40877
  function listInstalledClaudeSkills() {
40434
- const skillsDir = path85.join(claudeDir(), "skills");
40878
+ const skillsDir = path86.join(claudeDir(), "skills");
40435
40879
  if (!fs86.existsSync(skillsDir)) return [];
40436
40880
  try {
40437
40881
  return fs86.readdirSync(skillsDir).filter((name) => {
40438
40882
  try {
40439
- const stat = fs86.lstatSync(path85.join(skillsDir, name));
40883
+ const stat = fs86.lstatSync(path86.join(skillsDir, name));
40440
40884
  return stat.isSymbolicLink() || stat.isDirectory();
40441
40885
  } catch {
40442
40886
  return false;
@@ -40511,14 +40955,14 @@ function registerSkills10x(program2) {
40511
40955
  tenx.command("uninstall").description(
40512
40956
  "Remove /10x: chain skill symlinks from ~/.claude/skills (preserves user-authored skills + non-chain skill sources)"
40513
40957
  ).action(() => {
40514
- const skillsDir = path85.join(claudeDir(), "skills");
40958
+ const skillsDir = path86.join(claudeDir(), "skills");
40515
40959
  if (!fs86.existsSync(skillsDir)) {
40516
40960
  printWarning("No ~/.claude/skills/ directory found; nothing to uninstall");
40517
40961
  return;
40518
40962
  }
40519
40963
  let removed = 0;
40520
40964
  for (const name of fs86.readdirSync(skillsDir)) {
40521
- const full = path85.join(skillsDir, name);
40965
+ const full = path86.join(skillsDir, name);
40522
40966
  try {
40523
40967
  const stat = fs86.lstatSync(full);
40524
40968
  if (!stat.isSymbolicLink()) continue;
@@ -40594,17 +41038,17 @@ function registerSkills10x(program2) {
40594
41038
  init_output();
40595
41039
  import * as fs87 from "node:fs";
40596
41040
  import * as os44 from "node:os";
40597
- import * as path86 from "node:path";
41041
+ import * as path87 from "node:path";
40598
41042
  import * as child_process from "node:child_process";
40599
41043
  import { parse as yamlParse2, stringify as yamlStringify3 } from "yaml";
40600
41044
  function hermesConfigPath() {
40601
- return path86.join(os44.homedir(), ".hermes", "config.yaml");
41045
+ return path87.join(os44.homedir(), ".hermes", "config.yaml");
40602
41046
  }
40603
41047
  function hermesSkillsDir() {
40604
- return path86.join(os44.homedir(), ".hermes", "skills");
41048
+ return path87.join(os44.homedir(), ".hermes", "skills");
40605
41049
  }
40606
41050
  function claudeSkillsDir() {
40607
- return path86.join(os44.homedir(), ".claude", "skills");
41051
+ return path87.join(os44.homedir(), ".claude", "skills");
40608
41052
  }
40609
41053
  function readHermesConfig(configPath) {
40610
41054
  const raw = fs87.readFileSync(configPath, "utf-8");
@@ -40716,8 +41160,8 @@ function mirrorSkillSymlinks(dryRun, summary2) {
40716
41160
  let mirrored = 0;
40717
41161
  let collisions = 0;
40718
41162
  for (const entry of entries) {
40719
- const srcPath = path86.join(srcDir, entry);
40720
- const destPath2 = path86.join(destDir, entry);
41163
+ const srcPath = path87.join(srcDir, entry);
41164
+ const destPath2 = path87.join(destDir, entry);
40721
41165
  if (fs87.existsSync(destPath2) || fs87.lstatSync(srcPath).isFile()) {
40722
41166
  if (fs87.existsSync(destPath2)) collisions++;
40723
41167
  continue;
@@ -40772,7 +41216,7 @@ async function runHermesBootstrap(opts, deps = {}) {
40772
41216
  } else {
40773
41217
  summary2.skipped.push("mcp_servers.agentmemory-atlas (AGENTMEMORY_BRIDGE_URL/SECRET not set; use --bridge-url/--bridge-secret to add)");
40774
41218
  }
40775
- const hooksDir = path86.join(path86.dirname(configPath), "hooks");
41219
+ const hooksDir = path87.join(path87.dirname(configPath), "hooks");
40776
41220
  const hookResult = installHookFn(hooksDir, dryRun);
40777
41221
  switch (hookResult.status) {
40778
41222
  case "installed":
@@ -40819,7 +41263,7 @@ async function runHermesBootstrap(opts, deps = {}) {
40819
41263
  }
40820
41264
  var HOOK_MATCHERS = ["terminal", "bash", "shell", "search_files", "grep", "ripgrep"];
40821
41265
  function ensureHermesHookEntry(config, hooksDir, dryRun, summary2) {
40822
- const hookScriptPath = path86.join(hooksDir, "kg-first.sh");
41266
+ const hookScriptPath = path87.join(hooksDir, "kg-first.sh");
40823
41267
  const hooks = config["hooks"] ?? {};
40824
41268
  const preToolCall = Array.isArray(hooks["pre_tool_call"]) ? hooks["pre_tool_call"] : [];
40825
41269
  const alreadyPresent = preToolCall.some(
@@ -40957,9 +41401,9 @@ function registerMcpServe(cmd) {
40957
41401
  init_output();
40958
41402
 
40959
41403
  // src/commands/mcp/install-shared.ts
40960
- import { spawnSync as spawnSync28 } from "node:child_process";
41404
+ import { spawnSync as spawnSync29 } from "node:child_process";
40961
41405
  var DEFAULT_CLAUDE_SHELL_DEPS = {
40962
- spawn: spawnSync28,
41406
+ spawn: spawnSync29,
40963
41407
  log: (msg) => console.log(msg)
40964
41408
  };
40965
41409
  function isOnPath(deps, bin) {
@@ -41092,8 +41536,8 @@ var SECRET = process.env["OLAM_MCP_AUTH_SECRET"] ?? "";
41092
41536
  function authHeaders() {
41093
41537
  return SECRET ? { "X-Olam-Mcp-Secret": SECRET } : {};
41094
41538
  }
41095
- async function apiFetch(path95, init = {}) {
41096
- const res = await fetch(`${BASE_URL}${path95}`, {
41539
+ async function apiFetch(path96, init = {}) {
41540
+ const res = await fetch(`${BASE_URL}${path96}`, {
41097
41541
  ...init,
41098
41542
  headers: {
41099
41543
  "Content-Type": "application/json",
@@ -41355,7 +41799,7 @@ import pc40 from "picocolors";
41355
41799
  // src/commands/mcp/import-discovery.ts
41356
41800
  import * as fs88 from "node:fs";
41357
41801
  import * as os45 from "node:os";
41358
- import * as path87 from "node:path";
41802
+ import * as path88 from "node:path";
41359
41803
  function readJsonFile(filePath) {
41360
41804
  try {
41361
41805
  const raw = fs88.readFileSync(filePath, "utf-8");
@@ -41387,18 +41831,18 @@ function extractMcpServers(obj, source, sourceLabel) {
41387
41831
  }
41388
41832
  function getClaudeDesktopPath() {
41389
41833
  if (process.platform === "darwin") {
41390
- return path87.join(os45.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
41834
+ return path88.join(os45.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
41391
41835
  }
41392
41836
  if (process.platform === "win32") {
41393
- const appData = process.env["APPDATA"] ?? path87.join(os45.homedir(), "AppData", "Roaming");
41394
- return path87.join(appData, "Claude", "claude_desktop_config.json");
41837
+ const appData = process.env["APPDATA"] ?? path88.join(os45.homedir(), "AppData", "Roaming");
41838
+ return path88.join(appData, "Claude", "claude_desktop_config.json");
41395
41839
  }
41396
- return path87.join(os45.homedir(), ".config", "Claude", "claude_desktop_config.json");
41840
+ return path88.join(os45.homedir(), ".config", "Claude", "claude_desktop_config.json");
41397
41841
  }
41398
41842
  function getOlamRepoPaths() {
41399
41843
  const configPaths = [
41400
- path87.join(os45.homedir(), ".olam", "config.yaml"),
41401
- path87.join(process.cwd(), ".olam", "config.yaml")
41844
+ path88.join(os45.homedir(), ".olam", "config.yaml"),
41845
+ path88.join(process.cwd(), ".olam", "config.yaml")
41402
41846
  ];
41403
41847
  const paths = [];
41404
41848
  for (const configPath of configPaths) {
@@ -41420,7 +41864,7 @@ async function discoverMcpSources(repoPaths) {
41420
41864
  const sources = [];
41421
41865
  const sourceDefs = [
41422
41866
  {
41423
- path: path87.join(os45.homedir(), ".claude.json"),
41867
+ path: path88.join(os45.homedir(), ".claude.json"),
41424
41868
  label: "Claude Code (~/.claude.json)"
41425
41869
  },
41426
41870
  {
@@ -41428,19 +41872,19 @@ async function discoverMcpSources(repoPaths) {
41428
41872
  label: "Claude Desktop"
41429
41873
  },
41430
41874
  {
41431
- path: path87.join(os45.homedir(), ".cursor", "mcp.json"),
41875
+ path: path88.join(os45.homedir(), ".cursor", "mcp.json"),
41432
41876
  label: "Cursor (~/.cursor/mcp.json)"
41433
41877
  },
41434
41878
  {
41435
- path: path87.join(os45.homedir(), ".codeium", "windsurf", "mcp_config.json"),
41879
+ path: path88.join(os45.homedir(), ".codeium", "windsurf", "mcp_config.json"),
41436
41880
  label: "Windsurf (~/.codeium/windsurf/mcp_config.json)"
41437
41881
  }
41438
41882
  ];
41439
41883
  const resolvedRepoPaths = repoPaths ?? getOlamRepoPaths();
41440
41884
  for (const repoPath of resolvedRepoPaths) {
41441
41885
  sourceDefs.push({
41442
- path: path87.join(repoPath, ".mcp.json"),
41443
- label: `.mcp.json (${path87.basename(repoPath)})`
41886
+ path: path88.join(repoPath, ".mcp.json"),
41887
+ label: `.mcp.json (${path88.basename(repoPath)})`
41444
41888
  });
41445
41889
  }
41446
41890
  const reads = await Promise.all(
@@ -41677,13 +42121,13 @@ init_output();
41677
42121
 
41678
42122
  // src/lib/memory-host-process-migration.ts
41679
42123
  import { existsSync as existsSync101, readFileSync as readFileSync83, unlinkSync as unlinkSync23 } from "node:fs";
41680
- import { spawnSync as spawnSync29 } from "node:child_process";
42124
+ import { spawnSync as spawnSync30 } from "node:child_process";
41681
42125
 
41682
42126
  // src/commands/memory/_paths.ts
41683
- import { homedir as homedir52 } from "node:os";
42127
+ import { homedir as homedir53 } from "node:os";
41684
42128
  import { join as join95, dirname as dirname55 } from "node:path";
41685
42129
  import { fileURLToPath as fileURLToPath8 } from "node:url";
41686
- var OLAM_HOME5 = join95(homedir52(), ".olam");
42130
+ var OLAM_HOME5 = join95(homedir53(), ".olam");
41687
42131
  var MEMORY_PID_PATH = join95(OLAM_HOME5, "memory.pid");
41688
42132
  var MEMORY_LOG_PATH = join95(OLAM_HOME5, "memory-service.log");
41689
42133
  var MEMORY_DATA_DIR = join95(OLAM_HOME5, "memory-data");
@@ -41762,7 +42206,7 @@ function isProcessAlive(pid) {
41762
42206
  }
41763
42207
  }
41764
42208
  function processCommName(pid) {
41765
- const r = spawnSync29("ps", ["-p", String(pid), "-o", "comm="], { encoding: "utf-8" });
42209
+ const r = spawnSync30("ps", ["-p", String(pid), "-o", "comm="], { encoding: "utf-8" });
41766
42210
  if (r.status !== 0) return null;
41767
42211
  const comm = r.stdout.trim();
41768
42212
  return comm.split("/").pop() ?? null;
@@ -41776,7 +42220,7 @@ function terminateProcess(pid) {
41776
42220
  const deadline = Date.now() + KILL_TIMEOUT_MS;
41777
42221
  while (Date.now() < deadline) {
41778
42222
  if (!isProcessAlive(pid)) return true;
41779
- spawnSync29("sleep", ["0.1"]);
42223
+ spawnSync30("sleep", ["0.1"]);
41780
42224
  }
41781
42225
  try {
41782
42226
  process.kill(pid, "SIGKILL");
@@ -42333,13 +42777,13 @@ function resolveMemoryServiceDir() {
42333
42777
  );
42334
42778
  }
42335
42779
  function resolveLocalBridgeScript(serviceDir) {
42336
- const path95 = join97(serviceDir, "scripts", "local-bridge-server.mjs");
42337
- if (!existsSync105(path95)) {
42780
+ const path96 = join97(serviceDir, "scripts", "local-bridge-server.mjs");
42781
+ if (!existsSync105(path96)) {
42338
42782
  throw new Error(
42339
- `Could not find local-bridge-server.mjs at ${path95}. Verify packages/memory-service ships the scripts/ directory.`
42783
+ `Could not find local-bridge-server.mjs at ${path96}. Verify packages/memory-service ships the scripts/ directory.`
42340
42784
  );
42341
42785
  }
42342
- return path95;
42786
+ return path96;
42343
42787
  }
42344
42788
  function validateBridgeOpts(opts) {
42345
42789
  const local = opts.local ?? false;
@@ -42681,7 +43125,7 @@ function registerMemoryStats(cmd) {
42681
43125
 
42682
43126
  // src/commands/memory/install-hooks.ts
42683
43127
  import { copyFileSync as copyFileSync12, existsSync as existsSync106, mkdirSync as mkdirSync60, readFileSync as readFileSync85, writeFileSync as writeFileSync52 } from "node:fs";
42684
- import { homedir as homedir53 } from "node:os";
43128
+ import { homedir as homedir54 } from "node:os";
42685
43129
  import { dirname as dirname56, join as join98, resolve as resolve25 } from "node:path";
42686
43130
  import { fileURLToPath as fileURLToPath9 } from "node:url";
42687
43131
  var HOOK_BASENAMES = [
@@ -42750,7 +43194,7 @@ If existing entries already point at the same paths, no edit needed.
42750
43194
  }
42751
43195
  function registerMemoryInstallHooks(parent) {
42752
43196
  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) => {
42753
- const targetDir = opts.targetDir ?? join98(homedir53(), ".claude", "scripts", "hooks");
43197
+ const targetDir = opts.targetDir ?? join98(homedir54(), ".claude", "scripts", "hooks");
42754
43198
  const sourceDir = opts.sourceDir ?? defaultSourceDir();
42755
43199
  let written = 0;
42756
43200
  let unchanged = 0;
@@ -42830,7 +43274,7 @@ init_storage_paths();
42830
43274
  init_workspace_name();
42831
43275
  import * as fs93 from "node:fs";
42832
43276
  import * as os48 from "node:os";
42833
- import * as path92 from "node:path";
43277
+ import * as path93 from "node:path";
42834
43278
 
42835
43279
  // ../core/dist/kg/kg-service-client.js
42836
43280
  var KG_SERVICE_PORT_DEFAULT = 9997;
@@ -42841,8 +43285,8 @@ function port() {
42841
43285
  const n = Number.parseInt(env, 10);
42842
43286
  return Number.isFinite(n) && n > 0 ? n : KG_SERVICE_PORT_DEFAULT;
42843
43287
  }
42844
- function url(path95) {
42845
- return `http://127.0.0.1:${port()}${path95}`;
43288
+ function url(path96) {
43289
+ return `http://127.0.0.1:${port()}${path96}`;
42846
43290
  }
42847
43291
  function kgServiceHealthUrl() {
42848
43292
  return url("/health");
@@ -42923,16 +43367,16 @@ init_workspace_name();
42923
43367
  init_kg_caps();
42924
43368
  init_output();
42925
43369
  import fs89 from "node:fs";
42926
- import { homedir as homedir54 } from "node:os";
42927
- import path88 from "node:path";
43370
+ import { homedir as homedir55 } from "node:os";
43371
+ import path89 from "node:path";
42928
43372
  function olamHome4() {
42929
- return process.env.OLAM_HOME ?? path88.join(homedir54(), ".olam");
43373
+ return process.env.OLAM_HOME ?? path89.join(homedir55(), ".olam");
42930
43374
  }
42931
43375
  function kgRoot2() {
42932
- return path88.join(olamHome4(), "kg");
43376
+ return path89.join(olamHome4(), "kg");
42933
43377
  }
42934
43378
  function worldsRoot2() {
42935
- return path88.join(olamHome4(), "worlds");
43379
+ return path89.join(olamHome4(), "worlds");
42936
43380
  }
42937
43381
  function dirSizeBytes2(dir) {
42938
43382
  if (!fs89.existsSync(dir)) return 0;
@@ -42947,7 +43391,7 @@ function dirSizeBytes2(dir) {
42947
43391
  continue;
42948
43392
  }
42949
43393
  for (const entry of entries) {
42950
- const full = path88.join(cur, entry.name);
43394
+ const full = path89.join(cur, entry.name);
42951
43395
  if (entry.isSymbolicLink()) continue;
42952
43396
  if (entry.isDirectory()) {
42953
43397
  stack.push(full);
@@ -42968,7 +43412,7 @@ function formatBytes5(n) {
42968
43412
  return `${(n / 1024 / 1024 / 1024).toFixed(2)} GB`;
42969
43413
  }
42970
43414
  function readFreshness(workspace) {
42971
- const file = path88.join(kgPristinePath(workspace), "freshness.json");
43415
+ const file = path89.join(kgPristinePath(workspace), "freshness.json");
42972
43416
  if (!fs89.existsSync(file)) return null;
42973
43417
  try {
42974
43418
  const raw = JSON.parse(fs89.readFileSync(file, "utf-8"));
@@ -42979,7 +43423,7 @@ function readFreshness(workspace) {
42979
43423
  }
42980
43424
  }
42981
43425
  function readOverlayNodeCount(graphifyOutDir) {
42982
- const graphPath = path88.join(graphifyOutDir, "graph.json");
43426
+ const graphPath = path89.join(graphifyOutDir, "graph.json");
42983
43427
  if (!fs89.existsSync(graphPath)) return null;
42984
43428
  try {
42985
43429
  const raw = JSON.parse(fs89.readFileSync(graphPath, "utf-8"));
@@ -43005,7 +43449,7 @@ function listOverlays() {
43005
43449
  for (const worldEntry of worldDirs) {
43006
43450
  if (!worldEntry.isDirectory()) continue;
43007
43451
  const worldId = worldEntry.name;
43008
- const worldDir = path88.join(root, worldId);
43452
+ const worldDir = path89.join(root, worldId);
43009
43453
  let cloneDirs;
43010
43454
  try {
43011
43455
  cloneDirs = fs89.readdirSync(worldDir, { withFileTypes: true });
@@ -43014,7 +43458,7 @@ function listOverlays() {
43014
43458
  }
43015
43459
  for (const cloneEntry of cloneDirs) {
43016
43460
  if (!cloneEntry.isDirectory()) continue;
43017
- const graphifyOut = path88.join(worldDir, cloneEntry.name, "graphify-out");
43461
+ const graphifyOut = path89.join(worldDir, cloneEntry.name, "graphify-out");
43018
43462
  if (!fs89.existsSync(graphifyOut)) continue;
43019
43463
  records.push({
43020
43464
  world_id: worldId,
@@ -43046,7 +43490,7 @@ function listPristines(overlays) {
43046
43490
  continue;
43047
43491
  }
43048
43492
  const fresh = readFreshness(workspace);
43049
- const graphifyOut = path88.join(kgPristinePath(workspace), "graphify-out");
43493
+ const graphifyOut = path89.join(kgPristinePath(workspace), "graphify-out");
43050
43494
  const size = dirSizeBytes2(graphifyOut);
43051
43495
  const worldCount = overlays.filter((o) => o.clone_dir === workspace).length;
43052
43496
  records.push({
@@ -43183,9 +43627,9 @@ init_workspace_name();
43183
43627
  init_output();
43184
43628
  import { spawn as spawn12 } from "node:child_process";
43185
43629
  import fs90 from "node:fs";
43186
- import path89 from "node:path";
43630
+ import path90 from "node:path";
43187
43631
  function pidFilePath2(workspace) {
43188
- return path89.join(kgPristinePath(workspace), ".watch.pid");
43632
+ return path90.join(kgPristinePath(workspace), ".watch.pid");
43189
43633
  }
43190
43634
  function isPidAlive3(pid) {
43191
43635
  if (!Number.isInteger(pid) || pid <= 0) return false;
@@ -43219,7 +43663,7 @@ function readAndClassifyPid(workspace) {
43219
43663
  }
43220
43664
  function writePidFile2(workspace, pid) {
43221
43665
  const file = pidFilePath2(workspace);
43222
- const dir = path89.dirname(file);
43666
+ const dir = path90.dirname(file);
43223
43667
  fs90.mkdirSync(dir, { recursive: true });
43224
43668
  fs90.writeFileSync(file, String(pid), { encoding: "utf-8" });
43225
43669
  }
@@ -43232,7 +43676,7 @@ function removePidFile(workspace) {
43232
43676
  }
43233
43677
  async function runKgWatch(workspaceArg, opts, deps = {}) {
43234
43678
  const cwd = deps.cwd ?? opts.cwd ?? process.cwd();
43235
- const name = workspaceArg ?? path89.basename(cwd).toLowerCase();
43679
+ const name = workspaceArg ?? path90.basename(cwd).toLowerCase();
43236
43680
  try {
43237
43681
  validateWorkspaceName(name);
43238
43682
  } catch (err) {
@@ -43240,7 +43684,7 @@ async function runKgWatch(workspaceArg, opts, deps = {}) {
43240
43684
  return { exitCode: 1, pidWritten: false };
43241
43685
  }
43242
43686
  const pristinePath = kgPristinePath(name);
43243
- const graphPath = path89.join(pristinePath, "graphify-out", "graph.json");
43687
+ const graphPath = path90.join(pristinePath, "graphify-out", "graph.json");
43244
43688
  const pidState = readAndClassifyPid(name);
43245
43689
  if (pidState.status === "active") {
43246
43690
  printError(
@@ -43479,7 +43923,7 @@ function registerKgDoctorCommand(kg) {
43479
43923
  // src/commands/kg-install-hook.ts
43480
43924
  init_merge_settings();
43481
43925
  import * as fs91 from "node:fs";
43482
- import * as path90 from "node:path";
43926
+ import * as path91 from "node:path";
43483
43927
  import * as os46 from "node:os";
43484
43928
  import { parse as yamlParse3, stringify as yamlStringify4 } from "yaml";
43485
43929
 
@@ -43532,9 +43976,9 @@ function buildHookMatcherEntry(opts) {
43532
43976
  init_output();
43533
43977
  function settingsPathFor2(scope) {
43534
43978
  if (scope === "user") {
43535
- return path90.join(os46.homedir(), ".claude", "settings.json");
43979
+ return path91.join(os46.homedir(), ".claude", "settings.json");
43536
43980
  }
43537
- return path90.join(process.cwd(), ".claude", "settings.json");
43981
+ return path91.join(process.cwd(), ".claude", "settings.json");
43538
43982
  }
43539
43983
  function backup2(filePath) {
43540
43984
  if (!fs91.existsSync(filePath)) return null;
@@ -43545,10 +43989,10 @@ function backup2(filePath) {
43545
43989
  }
43546
43990
  var HERMES_HOOK_MATCHERS = ["terminal", "bash", "shell", "search_files", "grep", "ripgrep"];
43547
43991
  function hermesConfigPath2() {
43548
- return path90.join(os46.homedir(), ".hermes", "config.yaml");
43992
+ return path91.join(os46.homedir(), ".hermes", "config.yaml");
43549
43993
  }
43550
43994
  function hermesHooksDir() {
43551
- return path90.join(os46.homedir(), ".hermes", "hooks");
43995
+ return path91.join(os46.homedir(), ".hermes", "hooks");
43552
43996
  }
43553
43997
  function patchHermesConfigForHook(action) {
43554
43998
  const configPath = hermesConfigPath2();
@@ -43561,7 +44005,7 @@ function patchHermesConfigForHook(action) {
43561
44005
  (e) => typeof e["command"] === "string" && e["command"].includes(HERMES_KG_HOOK_SENTINEL)
43562
44006
  );
43563
44007
  if (alreadyPresent) return "already-present";
43564
- const hookScriptPath = path90.join(hermesHooksDir(), "kg-first.sh");
44008
+ const hookScriptPath = path91.join(hermesHooksDir(), "kg-first.sh");
43565
44009
  const entry = {
43566
44010
  matcher: HERMES_HOOK_MATCHERS.join("|"),
43567
44011
  command: `${hookScriptPath} # ${HERMES_KG_HOOK_SENTINEL}`
@@ -43615,7 +44059,7 @@ function doInstallForHermes() {
43615
44059
  function doUninstallForHermes() {
43616
44060
  const configPath = hermesConfigPath2();
43617
44061
  const hooksDir = hermesHooksDir();
43618
- const hookScriptPath = path90.join(hooksDir, "kg-first.sh");
44062
+ const hookScriptPath = path91.join(hooksDir, "kg-first.sh");
43619
44063
  let scriptRemoved = false;
43620
44064
  if (fs91.existsSync(hookScriptPath)) {
43621
44065
  const content = fs91.readFileSync(hookScriptPath, "utf-8");
@@ -43650,9 +44094,9 @@ function registerKgInstallHookCommand(kg) {
43650
44094
  const scope = opts.scope === "user" ? "user" : "project";
43651
44095
  const filePath = settingsPathFor2(scope);
43652
44096
  try {
43653
- fs91.mkdirSync(path90.dirname(filePath), { recursive: true });
44097
+ fs91.mkdirSync(path91.dirname(filePath), { recursive: true });
43654
44098
  } catch (err) {
43655
- printError(`could not create ${path90.dirname(filePath)}: ${err instanceof Error ? err.message : String(err)}`);
44099
+ printError(`could not create ${path91.dirname(filePath)}: ${err instanceof Error ? err.message : String(err)}`);
43656
44100
  process.exitCode = 1;
43657
44101
  return;
43658
44102
  }
@@ -43695,14 +44139,14 @@ function registerKgInstallHookCommand(kg) {
43695
44139
 
43696
44140
  // src/commands/kg-uninstall-hook.ts
43697
44141
  import * as fs92 from "node:fs";
43698
- import * as path91 from "node:path";
44142
+ import * as path92 from "node:path";
43699
44143
  import * as os47 from "node:os";
43700
44144
  init_output();
43701
44145
  function settingsPathFor3(scope) {
43702
44146
  if (scope === "user") {
43703
- return path91.join(os47.homedir(), ".claude", "settings.json");
44147
+ return path92.join(os47.homedir(), ".claude", "settings.json");
43704
44148
  }
43705
- return path91.join(process.cwd(), ".claude", "settings.json");
44149
+ return path92.join(process.cwd(), ".claude", "settings.json");
43706
44150
  }
43707
44151
  function dropSentinel(matchers) {
43708
44152
  let changed = false;
@@ -43864,14 +44308,14 @@ function readQueueFromDisk(queuePath) {
43864
44308
  return entries;
43865
44309
  }
43866
44310
  function writeQueueToDisk(queuePath, entries) {
43867
- fs93.mkdirSync(path92.dirname(queuePath), { recursive: true });
44311
+ fs93.mkdirSync(path93.dirname(queuePath), { recursive: true });
43868
44312
  const content = entries.map((e) => JSON.stringify(e)).join("\n") + (entries.length > 0 ? "\n" : "");
43869
44313
  fs93.writeFileSync(queuePath, content, "utf-8");
43870
44314
  }
43871
44315
  async function runKgBuildPending(opts = {}) {
43872
44316
  const queuePath = opts.queuePath ?? (() => {
43873
- const stateDir = process.env["OLAM_STATE_DIR"] ?? path92.join(os48.homedir(), ".olam", "state");
43874
- return path92.join(stateDir, "kg-pending.jsonl");
44317
+ const stateDir = process.env["OLAM_STATE_DIR"] ?? path93.join(os48.homedir(), ".olam", "state");
44318
+ return path93.join(stateDir, "kg-pending.jsonl");
43875
44319
  })();
43876
44320
  const readQueue2 = opts.readQueueFn ?? readQueueFromDisk;
43877
44321
  const writeQueue2 = opts.writeQueueFn ?? writeQueueToDisk;
@@ -43887,7 +44331,7 @@ async function runKgBuildPending(opts = {}) {
43887
44331
  const remaining = [];
43888
44332
  for (const entry of deduped) {
43889
44333
  const repoPath = entry.path;
43890
- const workspaceName = path92.basename(repoPath).toLowerCase();
44334
+ const workspaceName = path93.basename(repoPath).toLowerCase();
43891
44335
  printInfo("kg build --pending", `building ${repoPath} (workspace=${workspaceName})`);
43892
44336
  let containerPath;
43893
44337
  try {
@@ -43925,20 +44369,20 @@ async function runKgBuildPending(opts = {}) {
43925
44369
  }
43926
44370
  function resolveWorkspace(arg) {
43927
44371
  const cwd = process.cwd();
43928
- const name = arg ?? path92.basename(cwd).toLowerCase();
44372
+ const name = arg ?? path93.basename(cwd).toLowerCase();
43929
44373
  validateWorkspaceName(name);
43930
44374
  return { name, sourcePath: cwd };
43931
44375
  }
43932
44376
  function toContainerPath(hostPath) {
43933
44377
  const home = os48.homedir();
43934
- const resolved = path92.resolve(hostPath);
43935
- if (!resolved.startsWith(home + path92.sep) && resolved !== home) {
44378
+ const resolved = path93.resolve(hostPath);
44379
+ if (!resolved.startsWith(home + path93.sep) && resolved !== home) {
43936
44380
  throw new Error(
43937
44381
  `source path "${resolved}" is not under $HOME (${home}). kg-service can only build repos that live under your home dir (it bind-mounts $HOME:/host-home:ro at start). Move the repo or set OLAM_HOME if you need a different root.`
43938
44382
  );
43939
44383
  }
43940
- const rel = path92.relative(home, resolved);
43941
- return rel === "" ? "/host-home" : path92.posix.join("/host-home", rel.split(path92.sep).join("/"));
44384
+ const rel = path93.relative(home, resolved);
44385
+ return rel === "" ? "/host-home" : path93.posix.join("/host-home", rel.split(path93.sep).join("/"));
43942
44386
  }
43943
44387
  async function runKgBuild(workspaceArg, options = {}) {
43944
44388
  let workspace;
@@ -43990,11 +44434,11 @@ async function runKgBuild(workspaceArg, options = {}) {
43990
44434
  graphify_path: "container"
43991
44435
  };
43992
44436
  fs93.writeFileSync(
43993
- path92.join(outDir, "freshness.json"),
44437
+ path93.join(outDir, "freshness.json"),
43994
44438
  JSON.stringify(freshness, null, 2) + "\n",
43995
44439
  "utf-8"
43996
44440
  );
43997
- const finalOut = path92.join(outDir, "graphify-out");
44441
+ const finalOut = path93.join(outDir, "graphify-out");
43998
44442
  if (options.json) {
43999
44443
  process.stdout.write(JSON.stringify(freshness) + "\n");
44000
44444
  } else {
@@ -44036,12 +44480,12 @@ function registerKg(program2) {
44036
44480
  // src/commands/flywheel/emit-breadcrumb.ts
44037
44481
  init_file_lock();
44038
44482
  import { mkdirSync as mkdirSync63, appendFileSync as appendFileSync6 } from "node:fs";
44039
- import { homedir as homedir58 } from "node:os";
44483
+ import { homedir as homedir59 } from "node:os";
44040
44484
  import { dirname as dirname59, join as join102 } from "node:path";
44041
44485
  import { randomUUID as randomUUID4 } from "node:crypto";
44042
44486
  var VALID_SEVERITIES = /* @__PURE__ */ new Set(["critical", "high", "medium", "low", "info", "warn"]);
44043
44487
  var PROMPT_FEEDING_FIELDS = ["extracted_pattern", "severity", "affected_persona", "proposed_edit"];
44044
- var BREADCRUMBS_BASE = join102(homedir58(), ".local", "share", "claude", "breadcrumbs");
44488
+ var BREADCRUMBS_BASE = join102(homedir59(), ".local", "share", "claude", "breadcrumbs");
44045
44489
  var LOCK_FILENAME = ".flywheel-emit.lock";
44046
44490
  function buildRecord(opts) {
44047
44491
  const rec = {
@@ -44107,14 +44551,14 @@ async function emitBreadcrumb(opts) {
44107
44551
  );
44108
44552
  process.exit(2);
44109
44553
  }
44110
- const path95 = destPath(rec.project_slug);
44111
- const lockDir = dirname59(path95);
44554
+ const path96 = destPath(rec.project_slug);
44555
+ const lockDir = dirname59(path96);
44112
44556
  mkdirSync63(lockDir, { recursive: true });
44113
44557
  const line = JSON.stringify(rec) + "\n";
44114
44558
  await withFileLock(
44115
44559
  lockDir,
44116
44560
  () => {
44117
- appendFileSync6(path95, line, "utf8");
44561
+ appendFileSync6(path96, line, "utf8");
44118
44562
  },
44119
44563
  {
44120
44564
  lockFilename: LOCK_FILENAME,
@@ -44124,7 +44568,7 @@ async function emitBreadcrumb(opts) {
44124
44568
  acquireTimeoutMs: 5e3
44125
44569
  }
44126
44570
  );
44127
- process.stdout.write(`[K7-emit] ${path95}: ${rec.extracted_pattern} (${rec.severity})
44571
+ process.stdout.write(`[K7-emit] ${path96}: ${rec.extracted_pattern} (${rec.severity})
44128
44572
  `);
44129
44573
  }
44130
44574
  function registerFlywheelEmitBreadcrumb(parent) {
@@ -44247,38 +44691,38 @@ function validateK5ScoredAt(scoredAt) {
44247
44691
  }
44248
44692
  return null;
44249
44693
  }
44250
- function validatePlan(path95) {
44694
+ function validatePlan(path96) {
44251
44695
  let stat;
44252
44696
  try {
44253
- stat = statSync30(path95);
44697
+ stat = statSync30(path96);
44254
44698
  } catch (err) {
44255
- return { ok: false, message: `FAIL cannot stat ${path95}: ${err instanceof Error ? err.message : "unknown"}` };
44699
+ return { ok: false, message: `FAIL cannot stat ${path96}: ${err instanceof Error ? err.message : "unknown"}` };
44256
44700
  }
44257
44701
  if (stat.size > MAX_PLAN_BYTES) {
44258
- return { ok: false, message: `FAIL ${path95}: plan file exceeds 1MB (${stat.size} bytes); refusing to parse` };
44702
+ return { ok: false, message: `FAIL ${path96}: plan file exceeds 1MB (${stat.size} bytes); refusing to parse` };
44259
44703
  }
44260
44704
  let text;
44261
44705
  try {
44262
- text = readFileSync89(path95, "utf8");
44706
+ text = readFileSync89(path96, "utf8");
44263
44707
  } catch (err) {
44264
- return { ok: false, message: `FAIL cannot read ${path95}: ${err instanceof Error ? err.message : "unknown"}` };
44708
+ return { ok: false, message: `FAIL cannot read ${path96}: ${err instanceof Error ? err.message : "unknown"}` };
44265
44709
  }
44266
44710
  if (!text.replace(/^/, "").startsWith("---")) {
44267
- return { ok: false, message: `FAIL ${path95}: no YAML frontmatter (missing opening --- marker)` };
44711
+ return { ok: false, message: `FAIL ${path96}: no YAML frontmatter (missing opening --- marker)` };
44268
44712
  }
44269
44713
  if (!text.includes("\n---", 3)) {
44270
- return { ok: false, message: `FAIL ${path95}: frontmatter block never closed (missing closing --- marker)` };
44714
+ return { ok: false, message: `FAIL ${path96}: frontmatter block never closed (missing closing --- marker)` };
44271
44715
  }
44272
44716
  const fm = extractFrontmatter(text);
44273
44717
  if (fm === null) {
44274
- return { ok: false, message: `FAIL ${path95}: frontmatter could not be parsed as YAML` };
44718
+ return { ok: false, message: `FAIL ${path96}: frontmatter could not be parsed as YAML` };
44275
44719
  }
44276
44720
  const hasScores = "k5_scores" in fm;
44277
44721
  const hasBoost = "k5_boost" in fm;
44278
44722
  const hasComposite = "k5_composite" in fm;
44279
44723
  const hasScoredAt = "k5_scored_at" in fm;
44280
44724
  if (!hasScores && !hasBoost && !hasComposite && !hasScoredAt) {
44281
- return { ok: true, message: `PASS ${path95}: k5_scores absent (acceptable \u2014 legacy plan)` };
44725
+ return { ok: true, message: `PASS ${path96}: k5_scores absent (acceptable \u2014 legacy plan)` };
44282
44726
  }
44283
44727
  const errors = [];
44284
44728
  if (hasScores) {
@@ -44298,9 +44742,9 @@ function validatePlan(path95) {
44298
44742
  if (err !== null) errors.push(err);
44299
44743
  }
44300
44744
  if (errors.length > 0) {
44301
- return { ok: false, message: `FAIL ${path95}: ${errors.join("; ")}` };
44745
+ return { ok: false, message: `FAIL ${path96}: ${errors.join("; ")}` };
44302
44746
  }
44303
- const lines = [`PASS ${path95}: k5_scores valid`];
44747
+ const lines = [`PASS ${path96}: k5_scores valid`];
44304
44748
  if (hasScores && typeof fm.k5_scores === "object" && fm.k5_scores !== null) {
44305
44749
  const scoresObj = fm.k5_scores;
44306
44750
  const vals = [];
@@ -44445,12 +44889,12 @@ function registerFlywheelK10Measure(parent) {
44445
44889
 
44446
44890
  // src/commands/flywheel/check-persona-skeleton.ts
44447
44891
  import { existsSync as existsSync110, readFileSync as readFileSync91, statSync as statSync31 } from "node:fs";
44448
- import { homedir as homedir59 } from "node:os";
44892
+ import { homedir as homedir60 } from "node:os";
44449
44893
  import { basename as basename14, join as join103 } from "node:path";
44450
44894
  import { parse as parseYAML2 } from "yaml";
44451
44895
  var CHARS_PER_TOKEN3 = 4;
44452
44896
  var K10_TOKEN_CAP2 = 6e3;
44453
- var AGENTS_DIR = join103(homedir59(), ".claude", "agents");
44897
+ var AGENTS_DIR = join103(homedir60(), ".claude", "agents");
44454
44898
  var REQUIRED_FRONTMATTER_KEYS = ["name", "description", "allowed-tools"];
44455
44899
  var REQUIRED_SECTIONS = [
44456
44900
  "## Role",
@@ -44700,7 +45144,7 @@ ${formatRedivergencePrompt(persona_a, persona_b, score, void 0, void 0, threshol
44700
45144
 
44701
45145
  // src/commands/flywheel/ping.ts
44702
45146
  import { mkdirSync as mkdirSync64, writeFileSync as writeFileSync56 } from "node:fs";
44703
- import { homedir as homedir60 } from "node:os";
45147
+ import { homedir as homedir61 } from "node:os";
44704
45148
  import { dirname as dirname60, join as join104 } from "node:path";
44705
45149
  var COLD_START_BUDGET_GOOD_MS = 200;
44706
45150
  var COLD_START_BUDGET_FAIR_MS = 500;
@@ -44717,7 +45161,7 @@ function readOlamVersion() {
44717
45161
  }
44718
45162
  }
44719
45163
  function writeBaseline(record) {
44720
- const baselinePath = join104(homedir60(), ".local", "share", "olam", "flywheel-baseline.json");
45164
+ const baselinePath = join104(homedir61(), ".local", "share", "olam", "flywheel-baseline.json");
44721
45165
  mkdirSync64(dirname60(baselinePath), { recursive: true });
44722
45166
  writeFileSync56(baselinePath, JSON.stringify(record, null, 2) + "\n", "utf8");
44723
45167
  return baselinePath;
@@ -44766,8 +45210,8 @@ import {
44766
45210
  statSync as statSync32,
44767
45211
  writeFileSync as writeFileSync57
44768
45212
  } from "node:fs";
44769
- import { spawnSync as spawnSync30 } from "node:child_process";
44770
- import { homedir as homedir61 } from "node:os";
45213
+ import { spawnSync as spawnSync31 } from "node:child_process";
45214
+ import { homedir as homedir62 } from "node:os";
44771
45215
  import { dirname as dirname61, join as join105, relative as relative7 } from "node:path";
44772
45216
  function escapeRegex(s) {
44773
45217
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -44844,7 +45288,7 @@ function resolveAtlasUser2(opts) {
44844
45288
  assertValidAtlasUser(v);
44845
45289
  return v;
44846
45290
  }
44847
- const claudeDir2 = opts._testClaudeDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join105(homedir61(), ".claude");
45291
+ const claudeDir2 = opts._testClaudeDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join105(homedir62(), ".claude");
44848
45292
  const f = join105(claudeDir2, ".atlas-user");
44849
45293
  if (existsSync111(f)) {
44850
45294
  const v = readFileSync93(f, "utf-8").trim();
@@ -44855,7 +45299,7 @@ function resolveAtlasUser2(opts) {
44855
45299
  return null;
44856
45300
  }
44857
45301
  function runGit2(args, cwd) {
44858
- const result = spawnSync30("git", args, {
45302
+ const result = spawnSync31("git", args, {
44859
45303
  cwd,
44860
45304
  encoding: "utf-8",
44861
45305
  stdio: ["ignore", "pipe", "pipe"]
@@ -44981,7 +45425,7 @@ function pushOverlays(opts) {
44981
45425
  Run \`olam skills atlas-user set <name>\` to configure your atlas user.`
44982
45426
  );
44983
45427
  }
44984
- const claudeDir2 = opts._testClaudeDir ?? opts.targetDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join105(homedir61(), ".claude");
45428
+ const claudeDir2 = opts._testClaudeDir ?? opts.targetDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join105(homedir62(), ".claude");
44985
45429
  const sourceFiles = walkPushSourceFiles(claudeDir2);
44986
45430
  const registeredPrefixes = (opts._testSkillSources ?? listSkillSources()).map((s) => s.prefix).filter((p) => typeof p === "string" && p.length > 0);
44987
45431
  if (registeredPrefixes.length > 0) {
@@ -45289,7 +45733,7 @@ Next steps (run in ${clonePath}):`,
45289
45733
  };
45290
45734
  }
45291
45735
  function migrateOverlays(opts = {}) {
45292
- const root = opts.targetDir ?? join105(homedir61(), ".claude");
45736
+ const root = opts.targetDir ?? join105(homedir62(), ".claude");
45293
45737
  const overrideRoots = [
45294
45738
  join105(root, "skills.overrides"),
45295
45739
  join105(root, "agents.overrides")
@@ -45411,7 +45855,7 @@ function registerFlywheelMigrateOverlays(parent) {
45411
45855
  }
45412
45856
  return;
45413
45857
  }
45414
- const root = opts.targetDir ?? join105(homedir61(), ".claude");
45858
+ const root = opts.targetDir ?? join105(homedir62(), ".claude");
45415
45859
  const summary2 = migrateOverlays(opts);
45416
45860
  if (opts.json === true) {
45417
45861
  process.stdout.write(JSON.stringify(summary2, null, 2) + "\n");
@@ -45468,7 +45912,7 @@ function registerFlywheel(program2) {
45468
45912
 
45469
45913
  // src/commands/seed.ts
45470
45914
  init_output();
45471
- import { spawnSync as spawnSync31, spawn as spawnAsync2 } from "node:child_process";
45915
+ import { spawnSync as spawnSync32, spawn as spawnAsync2 } from "node:child_process";
45472
45916
  var DEFAULT_SINGLETON_CONTAINER = "olam-postgres";
45473
45917
  var DEFAULT_SINGLETON_USER = "development";
45474
45918
  function assertValidSeedName(name) {
@@ -45479,7 +45923,7 @@ function assertValidSeedName(name) {
45479
45923
  }
45480
45924
  }
45481
45925
  function singletonDocker(container, user, args, stdin) {
45482
- return spawnSync31(
45926
+ return spawnSync32(
45483
45927
  "docker",
45484
45928
  ["exec", "-i", container, "psql", "-U", user, ...args],
45485
45929
  { encoding: "utf-8", input: stdin }
@@ -45534,7 +45978,7 @@ async function handleBake(opts) {
45534
45978
  if (sources.length > 1) {
45535
45979
  throw new Error("multiple sources specified \u2014 pass exactly one of --source-container, --source-url, --source-local");
45536
45980
  }
45537
- const ping = spawnSync31("docker", ["inspect", "--format", "{{.State.Status}}", singleton], { encoding: "utf-8" });
45981
+ const ping = spawnSync32("docker", ["inspect", "--format", "{{.State.Status}}", singleton], { encoding: "utf-8" });
45538
45982
  if (ping.status !== 0 || (ping.stdout || "").trim() !== "running") {
45539
45983
  throw new Error(`singleton container "${singleton}" not running \u2014 run \`olam bootstrap\` first`);
45540
45984
  }
@@ -45717,12 +46161,12 @@ init_output();
45717
46161
  import { spawnSync as defaultSpawnSync } from "node:child_process";
45718
46162
  import * as fs94 from "node:fs";
45719
46163
  import * as os49 from "node:os";
45720
- import * as path93 from "node:path";
46164
+ import * as path94 from "node:path";
45721
46165
  function devboxContainerName(worldId) {
45722
46166
  return `olam-${worldId}-devbox`;
45723
46167
  }
45724
46168
  function olamHomeDir() {
45725
- return process.env["OLAM_HOME"] ?? path93.join(os49.homedir(), ".olam");
46169
+ return process.env["OLAM_HOME"] ?? path94.join(os49.homedir(), ".olam");
45726
46170
  }
45727
46171
  function defaultRestartContainer(name, spawn13 = defaultSpawnSync) {
45728
46172
  const r = spawn13("docker", ["restart", "--time", "30", name], {
@@ -45736,7 +46180,7 @@ function defaultRestartContainer(name, spawn13 = defaultSpawnSync) {
45736
46180
  }
45737
46181
  function defaultAppendAuditLog(homeDir, line) {
45738
46182
  fs94.mkdirSync(homeDir, { recursive: true });
45739
- fs94.appendFileSync(path93.join(homeDir, "usage.log"), line.endsWith("\n") ? line : line + "\n", {
46183
+ fs94.appendFileSync(path94.join(homeDir, "usage.log"), line.endsWith("\n") ? line : line + "\n", {
45740
46184
  encoding: "utf-8"
45741
46185
  });
45742
46186
  }
@@ -45781,9 +46225,9 @@ async function doRekey(worldId, deps) {
45781
46225
  );
45782
46226
  const rotatedAt = deps.now().toISOString();
45783
46227
  const homeDir = deps.olamHomeDir();
45784
- const worldDir = path93.join(homeDir, "worlds", worldId);
46228
+ const worldDir = path94.join(homeDir, "worlds", worldId);
45785
46229
  fs94.mkdirSync(worldDir, { recursive: true });
45786
- const credentialsPath = path93.join(worldDir, "credentials.json");
46230
+ const credentialsPath = path94.join(worldDir, "credentials.json");
45787
46231
  const payload = {
45788
46232
  worldRoleName,
45789
46233
  password,
@@ -45858,12 +46302,12 @@ function registerRekey(program2) {
45858
46302
 
45859
46303
  // src/pleri-config.ts
45860
46304
  import * as fs95 from "node:fs";
45861
- import * as path94 from "node:path";
46305
+ import * as path95 from "node:path";
45862
46306
  function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
45863
46307
  if (process.env.PLERI_BASE_URL) {
45864
46308
  return true;
45865
46309
  }
45866
- const configPath = path94.join(configDir, "config.yaml");
46310
+ const configPath = path95.join(configDir, "config.yaml");
45867
46311
  if (!fs95.existsSync(configPath)) {
45868
46312
  return false;
45869
46313
  }
@@ -45902,6 +46346,7 @@ registerDestroy(program);
45902
46346
  registerClean(program);
45903
46347
  registerImplode(program);
45904
46348
  registerEnter(program);
46349
+ registerResume(program);
45905
46350
  registerCrystallize(program, { hidden: !isPleriConfigured() });
45906
46351
  registerPr(program);
45907
46352
  registerWorkspace(program);