@pleri/olam-cli 0.1.169 → 0.1.173

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 (67) hide show
  1. package/README.md +38 -0
  2. package/dist/agent-stream/driver-runner.js +13 -0
  3. package/dist/commands/auth-status.d.ts +1 -0
  4. package/dist/commands/auth-status.d.ts.map +1 -1
  5. package/dist/commands/auth-status.js +45 -4
  6. package/dist/commands/auth-status.js.map +1 -1
  7. package/dist/commands/create.d.ts.map +1 -1
  8. package/dist/commands/create.js +26 -0
  9. package/dist/commands/create.js.map +1 -1
  10. package/dist/commands/enter.d.ts.map +1 -1
  11. package/dist/commands/enter.js +5 -0
  12. package/dist/commands/enter.js.map +1 -1
  13. package/dist/commands/resume.d.ts +63 -0
  14. package/dist/commands/resume.d.ts.map +1 -0
  15. package/dist/commands/resume.js +174 -0
  16. package/dist/commands/resume.js.map +1 -0
  17. package/dist/commands/setup.d.ts +19 -0
  18. package/dist/commands/setup.d.ts.map +1 -1
  19. package/dist/commands/setup.js +157 -19
  20. package/dist/commands/setup.js.map +1 -1
  21. package/dist/image-digests.json +8 -8
  22. package/dist/index.js +1025 -577
  23. package/dist/index.js.map +1 -1
  24. package/dist/lib/health-probes.d.ts +28 -0
  25. package/dist/lib/health-probes.d.ts.map +1 -1
  26. package/dist/lib/health-probes.js +75 -0
  27. package/dist/lib/health-probes.js.map +1 -1
  28. package/dist/lib/k8s-context-discovery.d.ts +80 -0
  29. package/dist/lib/k8s-context-discovery.d.ts.map +1 -0
  30. package/dist/lib/k8s-context-discovery.js +102 -0
  31. package/dist/lib/k8s-context-discovery.js.map +1 -0
  32. package/dist/mcp-server.js +2417 -1060
  33. package/dist/spawn/home-override.d.ts +82 -0
  34. package/dist/spawn/home-override.d.ts.map +1 -0
  35. package/dist/spawn/home-override.js +107 -0
  36. package/dist/spawn/home-override.js.map +1 -0
  37. package/hermes-bundle/version.json +1 -1
  38. package/host-cp/k8s/manifests/30-configmap.yaml +5 -0
  39. package/host-cp/k8s/manifests/50-deployment.yaml +9 -2
  40. package/host-cp/k8s/manifests/auth-service/50-deployment.yaml +1 -1
  41. package/host-cp/k8s/manifests/kg-service/50-deployment.yaml +1 -1
  42. package/host-cp/k8s/manifests/mcp-auth-service/50-deployment.yaml +1 -1
  43. package/host-cp/k8s/manifests/memory-service/50-deployment.yaml +1 -1
  44. package/host-cp/lifecycle/classify.mjs +110 -0
  45. package/host-cp/lifecycle/emit.mjs +119 -0
  46. package/host-cp/lifecycle/evidence.mjs +45 -0
  47. package/host-cp/lifecycle/failure-kinds.mjs +56 -0
  48. package/host-cp/lifecycle/index.mjs +22 -0
  49. package/host-cp/lifecycle/phases.mjs +52 -0
  50. package/host-cp/observability/grafana-port-forward.sh +1 -1
  51. package/host-cp/observability/kyverno-cardinality-mutate.sh +2 -2
  52. package/host-cp/observability/loki-ingest.sh +1 -1
  53. package/host-cp/observability/ndjson-span-sink.mjs +183 -0
  54. package/host-cp/observability/prom-no-double-grafana.sh +4 -4
  55. package/host-cp/observability/redactor.mjs +72 -0
  56. package/host-cp/recovery/engine.mjs +148 -0
  57. package/host-cp/recovery/index.mjs +16 -0
  58. package/host-cp/recovery/ledger.mjs +105 -0
  59. package/host-cp/recovery/recipes.mjs +46 -0
  60. package/host-cp/recovery/scenarios.mjs +124 -0
  61. package/host-cp/recovery/step-runners.mjs +263 -0
  62. package/host-cp/src/docker-events.mjs +30 -6
  63. package/host-cp/src/linear-sync.mjs +43 -0
  64. package/host-cp/src/plan-chat-service.mjs +129 -1
  65. package/host-cp/src/pr-nanny.mjs +55 -3
  66. package/host-cp/src/server.mjs +261 -0
  67. 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)) {
@@ -8709,6 +8769,8 @@ function stripMcpServers(mcpServers) {
8709
8769
  stripped.type = value;
8710
8770
  } else if (key === "url" && typeof value === "string") {
8711
8771
  stripped.url = value;
8772
+ } else if (key === "alwaysLoad" && typeof value === "boolean") {
8773
+ stripped.alwaysLoad = value;
8712
8774
  }
8713
8775
  }
8714
8776
  out[svc] = stripped;
@@ -8922,9 +8984,9 @@ function buildRepoEnvBundle(repoName, serviceEnv, crossRepoEnv, envOverrides) {
8922
8984
  const merged = { ...serviceEnv, ...injectables };
8923
8985
  return { merged, injectables };
8924
8986
  }
8925
- function setupWorldEnv(repos, workspacePath, serviceEnv, crossRepoEnv = {}, configCtx) {
8987
+ function setupWorldEnv(repos, workspacePath, serviceEnv, crossRepoEnv = {}, configCtx, claudeHomeOverride) {
8926
8988
  try {
8927
- copyClaudeConfig(workspacePath, void 0, configCtx);
8989
+ copyClaudeConfig(workspacePath, claudeHomeOverride, configCtx);
8928
8990
  } catch {
8929
8991
  }
8930
8992
  if (configCtx) {
@@ -9026,7 +9088,8 @@ var init_env_setup = __esm({
9026
9088
  "command",
9027
9089
  "args",
9028
9090
  "type",
9029
- "url"
9091
+ "url",
9092
+ "alwaysLoad"
9030
9093
  ]);
9031
9094
  SKIP_FILES = /* @__PURE__ */ new Set([
9032
9095
  ".credentials.json",
@@ -9124,17 +9187,17 @@ function kgRoot() {
9124
9187
  function worldsRoot() {
9125
9188
  return join17(olamHome(), "worlds");
9126
9189
  }
9127
- function assertWithinPrefix(path95, prefix, label) {
9128
- if (!path95.startsWith(prefix + "/")) {
9129
- throw new Error(`${label} escape: ${path95} not under ${prefix}/`);
9190
+ function assertWithinPrefix(path96, prefix, label) {
9191
+ if (!path96.startsWith(prefix + "/")) {
9192
+ throw new Error(`${label} escape: ${path96} not under ${prefix}/`);
9130
9193
  }
9131
9194
  }
9132
9195
  function kgPristinePath(workspace) {
9133
9196
  validateWorkspaceName(workspace);
9134
9197
  const root = kgRoot();
9135
- const path95 = resolve6(join17(root, workspace));
9136
- assertWithinPrefix(path95, root, "kgPristinePath");
9137
- return path95;
9198
+ const path96 = resolve6(join17(root, workspace));
9199
+ assertWithinPrefix(path96, root, "kgPristinePath");
9200
+ return path96;
9138
9201
  }
9139
9202
  var KG_PATHS_INTERNALS;
9140
9203
  var init_storage_paths = __esm({
@@ -9249,8 +9312,8 @@ import { execFileSync as execFileSync4 } from "node:child_process";
9249
9312
  import * as fs15 from "node:fs";
9250
9313
  import * as os9 from "node:os";
9251
9314
  import * as path17 from "node:path";
9252
- function expandHome2(p, homedir63) {
9253
- return p.replace(/^~(?=$|\/|\\)/, homedir63());
9315
+ function expandHome2(p, homedir64) {
9316
+ return p.replace(/^~(?=$|\/|\\)/, homedir64());
9254
9317
  }
9255
9318
  function sanitizeRepoFilename(name) {
9256
9319
  const sanitized = name.replace(/[^A-Za-z0-9._-]/g, "_");
@@ -9273,7 +9336,7 @@ ${stderr}`;
9273
9336
  }
9274
9337
  function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
9275
9338
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync4(cmd, args, opts));
9276
- const homedir63 = deps.homedir ?? (() => os9.homedir());
9339
+ const homedir64 = deps.homedir ?? (() => os9.homedir());
9277
9340
  const baselineDir = path17.join(workspacePath, ".olam", "baseline");
9278
9341
  try {
9279
9342
  fs15.mkdirSync(baselineDir, { recursive: true });
@@ -9289,7 +9352,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
9289
9352
  continue;
9290
9353
  const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
9291
9354
  const outPath = path17.join(baselineDir, filename);
9292
- const repoPath = expandHome2(repo.path, homedir63);
9355
+ const repoPath = expandHome2(repo.path, homedir64);
9293
9356
  if (!fs15.existsSync(repoPath)) {
9294
9357
  writeBaselineFile(outPath, `# repo: ${repo.name}
9295
9358
  # (skipped: path ${repoPath} does not exist)
@@ -9409,7 +9472,7 @@ function extractStderr(err) {
9409
9472
  }
9410
9473
  function carryUncommittedEdits(repos, workspacePath, deps = {}) {
9411
9474
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync4(cmd, args, opts));
9412
- const homedir63 = deps.homedir ?? (() => os9.homedir());
9475
+ const homedir64 = deps.homedir ?? (() => os9.homedir());
9413
9476
  const existsSync113 = deps.existsSync ?? ((p) => fs15.existsSync(p));
9414
9477
  const copyFileSync16 = deps.copyFileSync ?? ((src, dest) => fs15.copyFileSync(src, dest));
9415
9478
  const mkdirSync67 = deps.mkdirSync ?? ((dirPath, opts) => {
@@ -9419,7 +9482,7 @@ function carryUncommittedEdits(repos, workspacePath, deps = {}) {
9419
9482
  for (const repo of repos) {
9420
9483
  if (!repo.path)
9421
9484
  continue;
9422
- const repoPath = expandHome2(repo.path, homedir63);
9485
+ const repoPath = expandHome2(repo.path, homedir64);
9423
9486
  const worktreePath = path17.join(workspacePath, repo.name);
9424
9487
  if (!existsSync113(repoPath))
9425
9488
  continue;
@@ -12692,7 +12755,8 @@ ${detail}`);
12692
12755
  createdAt: now,
12693
12756
  updatedAt: now,
12694
12757
  readinessChain,
12695
- expectedServices
12758
+ expectedServices,
12759
+ ...opts.claudeHome ? { claudeHome: opts.claudeHome } : {}
12696
12760
  };
12697
12761
  const sm = new WorldStateMachine(worldId, "creating");
12698
12762
  this.registry.register(metadata);
@@ -12830,7 +12894,7 @@ ${detail}`);
12830
12894
  worlds_default: this.config.worlds_default,
12831
12895
  repos: enrichedRepos
12832
12896
  };
12833
- setupWorldEnv(enrichedRepos, workspacePath, serviceEnv, crossRepoEnv, configCtx);
12897
+ setupWorldEnv(enrichedRepos, workspacePath, serviceEnv, crossRepoEnv, configCtx, opts.claudeHome);
12834
12898
  } catch (err) {
12835
12899
  const msg = err instanceof Error ? err.message : String(err);
12836
12900
  console.warn(`[WorldManager] env setup failed: ${msg}`);
@@ -15704,10 +15768,10 @@ async function readHostCpToken2() {
15704
15768
  if (!fs26.existsSync(tp)) return null;
15705
15769
  return fs26.readFileSync(tp, "utf-8").trim();
15706
15770
  }
15707
- async function callHostCpProxy(method, worldId, path95, body) {
15771
+ async function callHostCpProxy(method, worldId, path96, body) {
15708
15772
  const token = await readHostCpToken2();
15709
15773
  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}`;
15774
+ const url2 = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path96}`;
15711
15775
  try {
15712
15776
  const headers = {
15713
15777
  Authorization: `Bearer ${token}`
@@ -16174,17 +16238,75 @@ var init_registry_allowlist = __esm({
16174
16238
  }
16175
16239
  });
16176
16240
 
16241
+ // src/spawn/home-override.ts
16242
+ var home_override_exports = {};
16243
+ __export(home_override_exports, {
16244
+ CLAUDE_HOMES_BASE: () => CLAUDE_HOMES_BASE,
16245
+ HOME_ID_RE: () => HOME_ID_RE,
16246
+ SENTINEL_FILENAME: () => SENTINEL_FILENAME,
16247
+ ensureClaudeHomeDir: () => ensureClaudeHomeDir,
16248
+ resolveClaudeHome: () => resolveClaudeHome
16249
+ });
16250
+ import { mkdir, writeFile, access } from "node:fs/promises";
16251
+ import { homedir as homedir22 } from "node:os";
16252
+ import path36 from "node:path";
16253
+ function resolveClaudeHome(args) {
16254
+ const home = args.homeDir ?? homedir22();
16255
+ if (args.flag !== void 0 && args.flag.length > 0) {
16256
+ return resolveSpec(args.flag, home);
16257
+ }
16258
+ const stored = args.existingWorldConfig?.claudeHome;
16259
+ if (stored !== void 0 && stored.length > 0) {
16260
+ return resolveSpec(stored, home);
16261
+ }
16262
+ return args.envHome ?? home;
16263
+ }
16264
+ function resolveSpec(spec, home) {
16265
+ if (path36.isAbsolute(spec)) {
16266
+ return spec;
16267
+ }
16268
+ if (!HOME_ID_RE.test(spec)) {
16269
+ throw new Error(
16270
+ `--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.`
16271
+ );
16272
+ }
16273
+ return path36.join(home, CLAUDE_HOMES_BASE, spec);
16274
+ }
16275
+ async function ensureClaudeHomeDir(targetPath) {
16276
+ await mkdir(targetPath, { recursive: true });
16277
+ const sentinelPath2 = path36.join(targetPath, SENTINEL_FILENAME);
16278
+ try {
16279
+ await access(sentinelPath2);
16280
+ return;
16281
+ } catch {
16282
+ }
16283
+ await writeFile(
16284
+ sentinelPath2,
16285
+ "# 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",
16286
+ "utf-8"
16287
+ );
16288
+ }
16289
+ var CLAUDE_HOMES_BASE, SENTINEL_FILENAME, HOME_ID_RE;
16290
+ var init_home_override = __esm({
16291
+ "src/spawn/home-override.ts"() {
16292
+ "use strict";
16293
+ CLAUDE_HOMES_BASE = path36.join(".olam", "claude-homes");
16294
+ SENTINEL_FILENAME = ".olam-claude-home";
16295
+ HOME_ID_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/;
16296
+ }
16297
+ });
16298
+
16177
16299
  // ../core/dist/world/world-yaml.js
16178
16300
  import * as fs35 from "node:fs";
16179
- import * as path36 from "node:path";
16301
+ import * as path37 from "node:path";
16180
16302
  import { parse as parseYaml4, stringify as stringifyYaml4 } from "yaml";
16181
16303
  function writeWorldYaml(worldPath, data) {
16182
- const olamDir = path36.join(worldPath, ".olam");
16304
+ const olamDir = path37.join(worldPath, ".olam");
16183
16305
  fs35.mkdirSync(olamDir, { recursive: true });
16184
- fs35.writeFileSync(path36.join(olamDir, "world.yaml"), stringifyYaml4(data), "utf-8");
16306
+ fs35.writeFileSync(path37.join(olamDir, "world.yaml"), stringifyYaml4(data), "utf-8");
16185
16307
  }
16186
16308
  function readWorldYaml(worldPath) {
16187
- const yamlPath = path36.join(worldPath, ".olam", "world.yaml");
16309
+ const yamlPath = path37.join(worldPath, ".olam", "world.yaml");
16188
16310
  if (!fs35.existsSync(yamlPath))
16189
16311
  return null;
16190
16312
  try {
@@ -16313,14 +16435,14 @@ var init_checksum = __esm({
16313
16435
 
16314
16436
  // ../core/dist/skill-sources/trust-audit-log.js
16315
16437
  import * as fs52 from "node:fs";
16316
- import * as path54 from "node:path";
16438
+ import * as path55 from "node:path";
16317
16439
  import * as os28 from "node:os";
16318
16440
  function skillSourcesAuditLogPath() {
16319
16441
  const override = process.env["OLAM_SKILL_SOURCES_AUDIT_LOG_PATH"];
16320
16442
  if (override && override.length > 0)
16321
16443
  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);
16444
+ const stateDir = process.env["OLAM_STATE_DIR"] ?? path55.join(os28.homedir(), ".olam", "state");
16445
+ return path55.join(stateDir, SKILL_SOURCES_AUDIT_LOG_FILENAME);
16324
16446
  }
16325
16447
  function appendTrustAudit(entry) {
16326
16448
  const candidate = {
@@ -16329,7 +16451,7 @@ function appendTrustAudit(entry) {
16329
16451
  };
16330
16452
  const validated = TrustAuditEntrySchema.parse(candidate);
16331
16453
  const filePath = skillSourcesAuditLogPath();
16332
- fs52.mkdirSync(path54.dirname(filePath), { recursive: true, mode: 448 });
16454
+ fs52.mkdirSync(path55.dirname(filePath), { recursive: true, mode: 448 });
16333
16455
  const fd = fs52.openSync(filePath, "a", 384);
16334
16456
  try {
16335
16457
  fs52.writeSync(fd, JSON.stringify(validated) + "\n");
@@ -16542,22 +16664,22 @@ var init_store3 = __esm({
16542
16664
  });
16543
16665
 
16544
16666
  // ../core/dist/skill-sources/clone.js
16545
- import { execFileSync as execFileSync13 } from "node:child_process";
16667
+ import { execFileSync as execFileSync14 } from "node:child_process";
16546
16668
  import * as fs53 from "node:fs";
16547
16669
  import * as os29 from "node:os";
16548
- import * as path55 from "node:path";
16670
+ import * as path56 from "node:path";
16549
16671
  function skillSourcesRootDir() {
16550
16672
  const override = process.env["OLAM_SKILL_SOURCES_DIR"];
16551
16673
  if (override && override.length > 0)
16552
16674
  return override;
16553
- return path55.join(os29.homedir(), ".olam", "state", "skill-sources");
16675
+ return path56.join(os29.homedir(), ".olam", "state", "skill-sources");
16554
16676
  }
16555
16677
  function skillSourceClonePath(id) {
16556
- return path55.join(skillSourcesRootDir(), id);
16678
+ return path56.join(skillSourcesRootDir(), id);
16557
16679
  }
16558
16680
  function runGit(args, cwd) {
16559
16681
  try {
16560
- return execFileSync13("git", args, {
16682
+ return execFileSync14("git", args, {
16561
16683
  cwd,
16562
16684
  encoding: "utf-8",
16563
16685
  stdio: ["ignore", "pipe", "pipe"]
@@ -16715,7 +16837,7 @@ var init_hook_template = __esm({
16715
16837
 
16716
16838
  // ../core/dist/world/merge-settings.js
16717
16839
  import * as fs55 from "node:fs";
16718
- import * as path56 from "node:path";
16840
+ import * as path57 from "node:path";
16719
16841
  import * as crypto8 from "node:crypto";
16720
16842
  function mergeHomeSettingsJson(filePath, options) {
16721
16843
  let settings;
@@ -16799,7 +16921,7 @@ function isHookSentinelPresent(matchers, sentinel) {
16799
16921
  return false;
16800
16922
  }
16801
16923
  function atomicWriteJson(filePath, data) {
16802
- const dir = path56.dirname(filePath);
16924
+ const dir = path57.dirname(filePath);
16803
16925
  fs55.mkdirSync(dir, { recursive: true });
16804
16926
  const rand = crypto8.randomBytes(6).toString("hex");
16805
16927
  const tmp = `${filePath}.tmp.${process.pid}.${rand}`;
@@ -16815,13 +16937,13 @@ var init_merge_settings = __esm({
16815
16937
 
16816
16938
  // ../core/dist/skill-sources/hook-install.js
16817
16939
  import * as fs56 from "node:fs";
16818
- import * as path57 from "node:path";
16940
+ import * as path58 from "node:path";
16819
16941
  import * as os30 from "node:os";
16820
16942
  function settingsPathFor(scope, cwd) {
16821
16943
  if (scope === "user") {
16822
- return path57.join(os30.homedir(), ".claude", "settings.json");
16944
+ return path58.join(os30.homedir(), ".claude", "settings.json");
16823
16945
  }
16824
- return path57.join(cwd ?? process.cwd(), ".claude", "settings.json");
16946
+ return path58.join(cwd ?? process.cwd(), ".claude", "settings.json");
16825
16947
  }
16826
16948
  function backupFile(filePath) {
16827
16949
  if (!fs56.existsSync(filePath))
@@ -16832,7 +16954,7 @@ function backupFile(filePath) {
16832
16954
  return backupPath;
16833
16955
  }
16834
16956
  function installSkillsHookToFile(filePath) {
16835
- fs56.mkdirSync(path57.dirname(filePath), { recursive: true });
16957
+ fs56.mkdirSync(path58.dirname(filePath), { recursive: true });
16836
16958
  const backupPath = backupFile(filePath);
16837
16959
  const result = mergeHomeSettingsJson(filePath, {
16838
16960
  ensureHook: {
@@ -16895,29 +17017,29 @@ var init_hook_install = __esm({
16895
17017
  // ../core/dist/skill-sources/migration-snapshot.js
16896
17018
  import * as fs57 from "node:fs";
16897
17019
  import * as os31 from "node:os";
16898
- import * as path58 from "node:path";
17020
+ import * as path59 from "node:path";
16899
17021
  function claudeDirInternal() {
16900
17022
  const override = process.env["OLAM_CLAUDE_DIR"];
16901
17023
  if (override && override.length > 0)
16902
17024
  return override;
16903
- return path58.join(os31.homedir(), ".claude");
17025
+ return path59.join(os31.homedir(), ".claude");
16904
17026
  }
16905
17027
  function migrationSnapshotsDir() {
16906
17028
  const override = process.env["OLAM_MIGRATION_SNAPSHOTS_DIR"];
16907
17029
  if (override && override.length > 0)
16908
17030
  return override;
16909
- return path58.join(os31.homedir(), ".olam", "state", "migration-snapshots");
17031
+ return path59.join(os31.homedir(), ".olam", "state", "migration-snapshots");
16910
17032
  }
16911
17033
  function listToolboxManagedSymlinks(toolboxPath) {
16912
17034
  const claude = claudeDirInternal();
16913
17035
  const out = [];
16914
17036
  const BUCKETS2 = ["skills", "agents", "scripts", "rules", "commands"];
16915
17037
  for (const bucket of BUCKETS2) {
16916
- const dir = path58.join(claude, bucket);
17038
+ const dir = path59.join(claude, bucket);
16917
17039
  if (!fs57.existsSync(dir))
16918
17040
  continue;
16919
17041
  for (const name of fs57.readdirSync(dir)) {
16920
- const link = path58.join(dir, name);
17042
+ const link = path59.join(dir, name);
16921
17043
  try {
16922
17044
  const stat = fs57.lstatSync(link);
16923
17045
  if (!stat.isSymbolicLink())
@@ -16935,12 +17057,12 @@ function listToolboxManagedSymlinks(toolboxPath) {
16935
17057
  function detectToolboxState(opts) {
16936
17058
  const claude = claudeDirInternal();
16937
17059
  const toolboxPath = opts.toolboxPath;
16938
- const namespace = opts.namespace ?? path58.basename(toolboxPath);
16939
- const atlasUserFile = path58.join(claude, ".atlas-user");
17060
+ const namespace = opts.namespace ?? path59.basename(toolboxPath);
17061
+ const atlasUserFile = path59.join(claude, ".atlas-user");
16940
17062
  const atlasUser = fs57.existsSync(atlasUserFile) ? fs57.readFileSync(atlasUserFile, "utf-8").trim() || void 0 : void 0;
16941
17063
  let subscriptionsJson;
16942
17064
  if (atlasUser) {
16943
- const sp = path58.join(toolboxPath, "members", atlasUser, "subscriptions.json");
17065
+ const sp = path59.join(toolboxPath, "members", atlasUser, "subscriptions.json");
16944
17066
  if (fs57.existsSync(sp)) {
16945
17067
  try {
16946
17068
  subscriptionsJson = JSON.parse(fs57.readFileSync(sp, "utf-8"));
@@ -16950,7 +17072,7 @@ function detectToolboxState(opts) {
16950
17072
  }
16951
17073
  const atlasManagedSymlinks = listToolboxManagedSymlinks(toolboxPath);
16952
17074
  let originalSessionStartHook;
16953
- const settingsPath = path58.join(claude, "settings.json");
17075
+ const settingsPath = path59.join(claude, "settings.json");
16954
17076
  if (fs57.existsSync(settingsPath)) {
16955
17077
  try {
16956
17078
  const settings = JSON.parse(fs57.readFileSync(settingsPath, "utf-8"));
@@ -16978,7 +17100,7 @@ function writeMigrationSnapshot(snapshot) {
16978
17100
  const dir = migrationSnapshotsDir();
16979
17101
  fs57.mkdirSync(dir, { recursive: true });
16980
17102
  const stamp = snapshot.takenAt.replace(/[:.]/g, "-");
16981
- const file = path58.join(dir, `${snapshot.namespace}-${stamp}.json`);
17103
+ const file = path59.join(dir, `${snapshot.namespace}-${stamp}.json`);
16982
17104
  fs57.writeFileSync(file, JSON.stringify(snapshot, null, 2) + "\n", { mode: 420 });
16983
17105
  return file;
16984
17106
  }
@@ -16988,7 +17110,7 @@ function readLatestMigrationSnapshot(opts = {}) {
16988
17110
  return void 0;
16989
17111
  const files = fs57.readdirSync(dir).filter((f) => f.endsWith(".json")).sort().reverse();
16990
17112
  for (const f of files) {
16991
- const full = path58.join(dir, f);
17113
+ const full = path59.join(dir, f);
16992
17114
  try {
16993
17115
  const snapshot = JSON.parse(fs57.readFileSync(full, "utf-8"));
16994
17116
  if (snapshot.schemaVersion !== MIGRATION_SNAPSHOT_SCHEMA_VERSION)
@@ -17015,11 +17137,11 @@ var init_migration_snapshot = __esm({
17015
17137
 
17016
17138
  // ../core/dist/skill-sync/artifact-resolver.js
17017
17139
  import * as fs58 from "node:fs";
17018
- import * as path59 from "node:path";
17140
+ import * as path60 from "node:path";
17019
17141
  function resolveSubscriptions(opts) {
17020
17142
  const { clonePath, atlasUser } = opts;
17021
17143
  if (atlasUser) {
17022
- const subsPath = path59.join(clonePath, "members", atlasUser, "subscriptions.json");
17144
+ const subsPath = path60.join(clonePath, "members", atlasUser, "subscriptions.json");
17023
17145
  if (fs58.existsSync(subsPath)) {
17024
17146
  try {
17025
17147
  const parsed = JSON.parse(fs58.readFileSync(subsPath, "utf-8"));
@@ -17034,7 +17156,7 @@ function resolveSubscriptions(opts) {
17034
17156
  }
17035
17157
  }
17036
17158
  }
17037
- const catsPath = path59.join(clonePath, "shared", "categories.json");
17159
+ const catsPath = path60.join(clonePath, "shared", "categories.json");
17038
17160
  if (fs58.existsSync(catsPath)) {
17039
17161
  try {
17040
17162
  const parsed = JSON.parse(fs58.readFileSync(catsPath, "utf-8"));
@@ -17048,14 +17170,14 @@ function resolveSubscriptions(opts) {
17048
17170
  } catch {
17049
17171
  }
17050
17172
  }
17051
- const sharedDir = path59.join(clonePath, "shared");
17173
+ const sharedDir = path60.join(clonePath, "shared");
17052
17174
  const cats = [];
17053
17175
  if (fs58.existsSync(sharedDir)) {
17054
17176
  for (const name of fs58.readdirSync(sharedDir)) {
17055
- const dir = path59.join(sharedDir, name);
17177
+ const dir = path60.join(sharedDir, name);
17056
17178
  if (!fs58.statSync(dir).isDirectory())
17057
17179
  continue;
17058
- if (fs58.existsSync(path59.join(dir, "skills")) || fs58.existsSync(path59.join(dir, "agents"))) {
17180
+ if (fs58.existsSync(path60.join(dir, "skills")) || fs58.existsSync(path60.join(dir, "agents"))) {
17059
17181
  cats.push(name);
17060
17182
  }
17061
17183
  }
@@ -17071,13 +17193,13 @@ function resolveSkillsDir(opts) {
17071
17193
  const { sourceId, baseDir } = opts;
17072
17194
  const out = [];
17073
17195
  for (const name of listDirSafe(baseDir)) {
17074
- const subdir = path59.join(baseDir, name);
17196
+ const subdir = path60.join(baseDir, name);
17075
17197
  if (!fs58.statSync(subdir).isDirectory())
17076
17198
  continue;
17077
- if (!fs58.existsSync(path59.join(subdir, "SKILL.md")))
17199
+ if (!fs58.existsSync(path60.join(subdir, "SKILL.md")))
17078
17200
  continue;
17079
17201
  out.push({ kind: "skill", sourceId, sourcePath: subdir, deployBasename: name });
17080
- const subagentsDir = path59.join(subdir, "references", "agents");
17202
+ const subagentsDir = path60.join(subdir, "references", "agents");
17081
17203
  if (fs58.existsSync(subagentsDir) && fs58.statSync(subagentsDir).isDirectory()) {
17082
17204
  for (const f of listDirSafe(subagentsDir)) {
17083
17205
  if (!f.endsWith(".md"))
@@ -17085,7 +17207,7 @@ function resolveSkillsDir(opts) {
17085
17207
  out.push({
17086
17208
  kind: "subagent",
17087
17209
  sourceId,
17088
- sourcePath: path59.join(subagentsDir, f),
17210
+ sourcePath: path60.join(subagentsDir, f),
17089
17211
  deployBasename: f,
17090
17212
  parentSkill: name
17091
17213
  });
@@ -17098,7 +17220,7 @@ function resolveAgentsDir(opts) {
17098
17220
  const { sourceId, baseDir } = opts;
17099
17221
  const out = [];
17100
17222
  for (const name of listDirSafe(baseDir)) {
17101
- const full = path59.join(baseDir, name);
17223
+ const full = path60.join(baseDir, name);
17102
17224
  const stat = fs58.statSync(full);
17103
17225
  if (stat.isFile() && name.endsWith(".md")) {
17104
17226
  out.push({ kind: "agent", sourceId, sourcePath: full, deployBasename: name });
@@ -17109,7 +17231,7 @@ function resolveAgentsDir(opts) {
17109
17231
  out.push({
17110
17232
  kind: "agent",
17111
17233
  sourceId,
17112
- sourcePath: path59.join(full, f),
17234
+ sourcePath: path60.join(full, f),
17113
17235
  deployBasename: `${name}-${f}`
17114
17236
  });
17115
17237
  }
@@ -17121,7 +17243,7 @@ function resolveScriptsDir(opts) {
17121
17243
  const { sourceId, baseDir } = opts;
17122
17244
  const out = [];
17123
17245
  for (const name of listDirSafe(baseDir)) {
17124
- const full = path59.join(baseDir, name);
17246
+ const full = path60.join(baseDir, name);
17125
17247
  const stat = fs58.statSync(full);
17126
17248
  if (stat.isFile() && name.endsWith(".sh")) {
17127
17249
  out.push({ kind: "script", sourceId, sourcePath: full, deployBasename: name });
@@ -17137,7 +17259,7 @@ function resolveRulesDir(opts) {
17137
17259
  for (const name of listDirSafe(baseDir)) {
17138
17260
  if (!name.endsWith(".md"))
17139
17261
  continue;
17140
- const full = path59.join(baseDir, name);
17262
+ const full = path60.join(baseDir, name);
17141
17263
  if (!fs58.statSync(full).isFile())
17142
17264
  continue;
17143
17265
  out.push({ kind: "rule", sourceId, sourcePath: full, deployBasename: name });
@@ -17150,7 +17272,7 @@ function resolveJsonDir(opts) {
17150
17272
  for (const name of listDirSafe(baseDir)) {
17151
17273
  if (!name.endsWith(".json"))
17152
17274
  continue;
17153
- const full = path59.join(baseDir, name);
17275
+ const full = path60.join(baseDir, name);
17154
17276
  if (!fs58.statSync(full).isFile())
17155
17277
  continue;
17156
17278
  out.push({ kind, sourceId, sourcePath: full, deployBasename: name });
@@ -17163,7 +17285,7 @@ function resolveOverlaysDir(opts) {
17163
17285
  for (const name of listDirSafe(baseDir)) {
17164
17286
  if (!name.endsWith(".md"))
17165
17287
  continue;
17166
- const full = path59.join(baseDir, name);
17288
+ const full = path60.join(baseDir, name);
17167
17289
  if (!fs58.statSync(full).isFile())
17168
17290
  continue;
17169
17291
  const deployBasename = name.replace(/\.md$/, "");
@@ -17182,33 +17304,33 @@ function resolveSourceArtifacts(opts) {
17182
17304
  const subscription = resolveSubscriptions({ clonePath, atlasUser });
17183
17305
  const artifacts = [];
17184
17306
  for (const cat of subscription.categories) {
17185
- const catDir = path59.join(clonePath, "shared", cat);
17307
+ const catDir = path60.join(clonePath, "shared", cat);
17186
17308
  if (!fs58.existsSync(catDir))
17187
17309
  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" }));
17310
+ artifacts.push(...resolveSkillsDir({ sourceId, baseDir: path60.join(catDir, "skills") }));
17311
+ artifacts.push(...resolveAgentsDir({ sourceId, baseDir: path60.join(catDir, "agents") }));
17312
+ artifacts.push(...resolveScriptsDir({ sourceId, baseDir: path60.join(catDir, "scripts") }));
17313
+ artifacts.push(...resolveRulesDir({ sourceId, baseDir: path60.join(catDir, "rules") }));
17314
+ artifacts.push(...resolveJsonDir({ sourceId, baseDir: path60.join(catDir, "hooks"), kind: "hook" }));
17315
+ artifacts.push(...resolveJsonDir({ sourceId, baseDir: path60.join(catDir, "permissions"), kind: "permission" }));
17194
17316
  }
17195
17317
  if (atlasUser) {
17196
- const memberRoot = path59.join(clonePath, "members", atlasUser);
17318
+ const memberRoot = path60.join(clonePath, "members", atlasUser);
17197
17319
  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" }));
17320
+ artifacts.push(...resolveSkillsDir({ sourceId, baseDir: path60.join(memberRoot, "skills") }));
17321
+ artifacts.push(...resolveAgentsDir({ sourceId, baseDir: path60.join(memberRoot, "agents") }));
17322
+ artifacts.push(...resolveScriptsDir({ sourceId, baseDir: path60.join(memberRoot, "scripts") }));
17323
+ artifacts.push(...resolveRulesDir({ sourceId, baseDir: path60.join(memberRoot, "rules") }));
17324
+ artifacts.push(...resolveJsonDir({ sourceId, baseDir: path60.join(memberRoot, "hooks"), kind: "hook" }));
17325
+ artifacts.push(...resolveJsonDir({ sourceId, baseDir: path60.join(memberRoot, "permissions"), kind: "permission" }));
17204
17326
  artifacts.push(...resolveOverlaysDir({
17205
17327
  sourceId,
17206
- baseDir: path59.join(memberRoot, "skills.overrides"),
17328
+ baseDir: path60.join(memberRoot, "skills.overrides"),
17207
17329
  targetKind: "skill"
17208
17330
  }));
17209
17331
  artifacts.push(...resolveOverlaysDir({
17210
17332
  sourceId,
17211
- baseDir: path59.join(memberRoot, "agents.overrides"),
17333
+ baseDir: path60.join(memberRoot, "agents.overrides"),
17212
17334
  targetKind: "agent"
17213
17335
  }));
17214
17336
  }
@@ -17275,12 +17397,12 @@ var init_shim_targets = __esm({
17275
17397
  // ../core/dist/skill-sync/symlink-deployer.js
17276
17398
  import * as fs59 from "node:fs";
17277
17399
  import * as os32 from "node:os";
17278
- import * as path60 from "node:path";
17400
+ import * as path61 from "node:path";
17279
17401
  function claudeDir() {
17280
17402
  const override = process.env["OLAM_CLAUDE_DIR"];
17281
17403
  if (override && override.length > 0)
17282
17404
  return override;
17283
- return path60.join(os32.homedir(), ".claude");
17405
+ return path61.join(os32.homedir(), ".claude");
17284
17406
  }
17285
17407
  function bucketFor(kind) {
17286
17408
  switch (kind) {
@@ -17340,13 +17462,13 @@ function detectCollisions(artifacts) {
17340
17462
  function cleanManagedSymlinks(claude, installedOlamVersion, overlayReferences, expectedAgentWinnerNames) {
17341
17463
  const shadowBackups = [];
17342
17464
  for (const bucket of BUCKETS) {
17343
- const dir = path60.join(claude, bucket);
17465
+ const dir = path61.join(claude, bucket);
17344
17466
  if (!fs59.existsSync(dir))
17345
17467
  continue;
17346
17468
  for (const name of fs59.readdirSync(dir)) {
17347
17469
  if (name === ".olam-merged")
17348
17470
  continue;
17349
- const p = path60.join(dir, name);
17471
+ const p = path61.join(dir, name);
17350
17472
  try {
17351
17473
  const stat = fs59.lstatSync(p);
17352
17474
  if (stat.isSymbolicLink()) {
@@ -17413,7 +17535,7 @@ function linkIfNeeded(target, link) {
17413
17535
  function deployArtifacts(artifacts, opts) {
17414
17536
  const claude = claudeDir();
17415
17537
  for (const bucket of BUCKETS) {
17416
- fs59.mkdirSync(path60.join(claude, bucket), { recursive: true });
17538
+ fs59.mkdirSync(path61.join(claude, bucket), { recursive: true });
17417
17539
  }
17418
17540
  const { winners, collisions } = detectCollisions(artifacts);
17419
17541
  const expectedAgentWinnerNames = new Set(winners.filter((a) => a.kind === "agent").map((a) => a.deployBasename));
@@ -17423,7 +17545,7 @@ function deployArtifacts(artifacts, opts) {
17423
17545
  const bucket = bucketFor(artifact.kind);
17424
17546
  if (!bucket)
17425
17547
  continue;
17426
- const linkPath = path60.join(claude, bucket, artifact.deployBasename);
17548
+ const linkPath = path61.join(claude, bucket, artifact.deployBasename);
17427
17549
  if (artifact.kind === "agent" && artifact.resolvedContent !== void 0) {
17428
17550
  const tmpPath = `${linkPath}.tmp-${process.pid}-${Date.now()}`;
17429
17551
  fs59.writeFileSync(tmpPath, artifact.resolvedContent);
@@ -17610,24 +17732,24 @@ var init_meta_hooks = __esm({
17610
17732
  // ../core/dist/skill-sync/settings-merger.js
17611
17733
  import * as fs62 from "node:fs";
17612
17734
  import * as os33 from "node:os";
17613
- import * as path61 from "node:path";
17735
+ import * as path62 from "node:path";
17614
17736
  function claudeSettingsPath() {
17615
17737
  const override = process.env["OLAM_CLAUDE_SETTINGS_PATH"];
17616
17738
  if (override && override.length > 0)
17617
17739
  return override;
17618
- return path61.join(claudeDirInternal2(), "settings.json");
17740
+ return path62.join(claudeDirInternal2(), "settings.json");
17619
17741
  }
17620
17742
  function claudeDirInternal2() {
17621
17743
  const override = process.env["OLAM_CLAUDE_DIR"];
17622
17744
  if (override && override.length > 0)
17623
17745
  return override;
17624
- return path61.join(os33.homedir(), ".claude");
17746
+ return path62.join(os33.homedir(), ".claude");
17625
17747
  }
17626
17748
  function settingsBackupDir() {
17627
17749
  const override = process.env["OLAM_SETTINGS_BACKUP_DIR"];
17628
17750
  if (override && override.length > 0)
17629
17751
  return override;
17630
- return path61.join(os33.homedir(), ".olam", "state", "settings-backups");
17752
+ return path62.join(os33.homedir(), ".olam", "state", "settings-backups");
17631
17753
  }
17632
17754
  function dedupeByMatcher(entries) {
17633
17755
  const map = /* @__PURE__ */ new Map();
@@ -17679,7 +17801,7 @@ function readJson(file) {
17679
17801
  function rotateBackups(backupDir) {
17680
17802
  if (!fs62.existsSync(backupDir))
17681
17803
  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);
17804
+ 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
17805
  for (const f of files.slice(BACKUP_RETENTION)) {
17684
17806
  try {
17685
17807
  fs62.unlinkSync(f.full);
@@ -17694,7 +17816,7 @@ function backupSettings() {
17694
17816
  const dir = settingsBackupDir();
17695
17817
  fs62.mkdirSync(dir, { recursive: true });
17696
17818
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
17697
- const dest = path61.join(dir, `settings-${stamp}.json`);
17819
+ const dest = path62.join(dir, `settings-${stamp}.json`);
17698
17820
  fs62.copyFileSync(src, dest);
17699
17821
  rotateBackups(dir);
17700
17822
  return dest;
@@ -17771,7 +17893,7 @@ function mergeSettings(input2) {
17771
17893
  ...input2.permissionFiles.length > 0 ? { allow: [...permSet] } : {}
17772
17894
  }
17773
17895
  };
17774
- fs62.mkdirSync(path61.dirname(settingsPath), { recursive: true });
17896
+ fs62.mkdirSync(path62.dirname(settingsPath), { recursive: true });
17775
17897
  const tmp = `${settingsPath}.tmp-${process.pid}`;
17776
17898
  fs62.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n", { mode: 420 });
17777
17899
  fs62.renameSync(tmp, settingsPath);
@@ -17830,15 +17952,15 @@ var init_schema5 = __esm({
17830
17952
  });
17831
17953
 
17832
17954
  // ../core/dist/skill-sync/per-project-override.js
17833
- import { execFileSync as execFileSync14 } from "node:child_process";
17955
+ import { execFileSync as execFileSync15 } from "node:child_process";
17834
17956
  import * as fs63 from "node:fs";
17835
- import * as path62 from "node:path";
17957
+ import * as path63 from "node:path";
17836
17958
  import { parse as parseYaml5 } from "yaml";
17837
17959
  function findProjectOverride(startDir) {
17838
- let dir = path62.resolve(startDir);
17839
- const root = path62.parse(dir).root;
17960
+ let dir = path63.resolve(startDir);
17961
+ const root = path63.parse(dir).root;
17840
17962
  while (true) {
17841
- const candidate = path62.join(dir, PROJECT_OVERRIDE_RELATIVE_PATH);
17963
+ const candidate = path63.join(dir, PROJECT_OVERRIDE_RELATIVE_PATH);
17842
17964
  if (fs63.existsSync(candidate) && fs63.statSync(candidate).isFile()) {
17843
17965
  const raw = fs63.readFileSync(candidate, "utf-8");
17844
17966
  let parsed;
@@ -17853,7 +17975,7 @@ function findProjectOverride(startDir) {
17853
17975
  }
17854
17976
  if (dir === root)
17855
17977
  return void 0;
17856
- dir = path62.dirname(dir);
17978
+ dir = path63.dirname(dir);
17857
17979
  }
17858
17980
  }
17859
17981
  function applyOverrideToArtifacts(artifacts, override) {
@@ -17873,7 +17995,7 @@ function applyPinToClone(opts) {
17873
17995
  if (ref.startsWith("-")) {
17874
17996
  throw new Error(`refuses ref "${ref}" \u2014 must not start with "-" (would be parsed as a git option)`);
17875
17997
  }
17876
- execFileSync14("git", ["-C", clonePath, "checkout", "-q", ref], {
17998
+ execFileSync15("git", ["-C", clonePath, "checkout", "-q", ref], {
17877
17999
  stdio: ["ignore", "ignore", "pipe"]
17878
18000
  });
17879
18001
  }
@@ -17883,7 +18005,7 @@ function restoreCloneToBranchHead(opts) {
17883
18005
  return;
17884
18006
  }
17885
18007
  try {
17886
- execFileSync14("git", ["-C", clonePath, "checkout", "-q", branch], {
18008
+ execFileSync15("git", ["-C", clonePath, "checkout", "-q", branch], {
17887
18009
  stdio: ["ignore", "ignore", "pipe"]
17888
18010
  });
17889
18011
  } catch {
@@ -17894,14 +18016,14 @@ var init_per_project_override = __esm({
17894
18016
  "../core/dist/skill-sync/per-project-override.js"() {
17895
18017
  "use strict";
17896
18018
  init_schema5();
17897
- PROJECT_OVERRIDE_RELATIVE_PATH = path62.join(".olam", "skill-overrides.yaml");
18019
+ PROJECT_OVERRIDE_RELATIVE_PATH = path63.join(".olam", "skill-overrides.yaml");
17898
18020
  }
17899
18021
  });
17900
18022
 
17901
18023
  // ../core/dist/lib/file-lock.js
17902
18024
  import * as fs64 from "node:fs";
17903
18025
  import * as os34 from "node:os";
17904
- import * as path63 from "node:path";
18026
+ import * as path64 from "node:path";
17905
18027
  function defaultIsPidAlive(pid) {
17906
18028
  try {
17907
18029
  process.kill(pid, 0);
@@ -17935,7 +18057,7 @@ function isLockStale(meta, opts) {
17935
18057
  }
17936
18058
  function tryAcquireOnce(lockPath, meta, opts) {
17937
18059
  try {
17938
- fs64.mkdirSync(path63.dirname(lockPath), { recursive: true });
18060
+ fs64.mkdirSync(path64.dirname(lockPath), { recursive: true });
17939
18061
  const fd = fs64.openSync(lockPath, "wx", 384);
17940
18062
  try {
17941
18063
  fs64.writeSync(fd, JSON.stringify(meta));
@@ -17967,7 +18089,7 @@ function tryAcquireOnce(lockPath, meta, opts) {
17967
18089
  }
17968
18090
  async function acquireFileLock(lockDir, options = {}) {
17969
18091
  const lockFilename = options.lockFilename ?? DEFAULT_LOCK_FILENAME;
17970
- const lockPath = path63.join(lockDir, lockFilename);
18092
+ const lockPath = path64.join(lockDir, lockFilename);
17971
18093
  const acquireTimeoutMs = options.acquireTimeoutMs ?? DEFAULT_ACQUIRE_TIMEOUT_MS;
17972
18094
  const staleLockMs = options.staleLockMs ?? DEFAULT_STALE_LOCK_MS;
17973
18095
  const now = options.now ?? Date.now;
@@ -18092,7 +18214,7 @@ var init_min_version_filter = __esm({
18092
18214
 
18093
18215
  // ../core/dist/skill-sync/overlay-scan.js
18094
18216
  import * as fs65 from "node:fs";
18095
- import * as path64 from "node:path";
18217
+ import * as path65 from "node:path";
18096
18218
  function scanOverlayReferences(overlayRoot, basenames, caps = DEFAULT_CAPS) {
18097
18219
  const result = /* @__PURE__ */ new Map();
18098
18220
  if (!fs65.existsSync(overlayRoot)) {
@@ -18109,7 +18231,7 @@ function scanOverlayReferences(overlayRoot, basenames, caps = DEFAULT_CAPS) {
18109
18231
  return result;
18110
18232
  }
18111
18233
  for (const subdir of OVERRIDE_SUBDIRS) {
18112
- const dir = path64.join(overlayRoot, subdir);
18234
+ const dir = path65.join(overlayRoot, subdir);
18113
18235
  if (!fs65.existsSync(dir))
18114
18236
  continue;
18115
18237
  walkMarkdown(dir, mdFiles, caps.maxFiles);
@@ -18125,8 +18247,8 @@ function scanOverlayReferences(overlayRoot, basenames, caps = DEFAULT_CAPS) {
18125
18247
  continue;
18126
18248
  throw err;
18127
18249
  }
18128
- const rel = path64.relative(overlayRootReal, realFile);
18129
- if (rel.startsWith("..") || path64.isAbsolute(rel)) {
18250
+ const rel = path65.relative(overlayRootReal, realFile);
18251
+ if (rel.startsWith("..") || path65.isAbsolute(rel)) {
18130
18252
  continue;
18131
18253
  }
18132
18254
  let content;
@@ -18144,7 +18266,7 @@ function scanOverlayReferences(overlayRoot, basenames, caps = DEFAULT_CAPS) {
18144
18266
  }
18145
18267
  throw err;
18146
18268
  }
18147
- const relpath = path64.relative(overlayRoot, filepath).split(path64.sep).join("/");
18269
+ const relpath = path65.relative(overlayRoot, filepath).split(path65.sep).join("/");
18148
18270
  for (const basename16 of basenames) {
18149
18271
  if (content.includes(basename16)) {
18150
18272
  const list = result.get(basename16) ?? [];
@@ -18168,7 +18290,7 @@ function walkMarkdown(dir, out, cap) {
18168
18290
  if (out.length >= cap) {
18169
18291
  throw new Error(`[overlay-scan] aborted: overlay tree contains > ${cap} markdown files. Check OLAM_CLAUDE_DIR / overlay paths are correctly scoped.`);
18170
18292
  }
18171
- const full = path64.join(dir, entry.name);
18293
+ const full = path65.join(dir, entry.name);
18172
18294
  if (entry.isSymbolicLink())
18173
18295
  continue;
18174
18296
  if (entry.isDirectory()) {
@@ -18195,10 +18317,10 @@ var init_overlay_scan = __esm({
18195
18317
  // ../core/dist/skill-sync/settings-json-lock.js
18196
18318
  import * as fs66 from "node:fs";
18197
18319
  import * as os35 from "node:os";
18198
- import * as path65 from "node:path";
18320
+ import * as path66 from "node:path";
18199
18321
  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);
18322
+ const stateDir = process.env["OLAM_STATE_DIR"] ?? path66.join(os35.homedir(), ".olam", "state");
18323
+ return path66.join(stateDir, SETTINGS_JSON_LOCK_FILENAME);
18202
18324
  }
18203
18325
  function defaultIsPidAlive2(pid) {
18204
18326
  try {
@@ -18237,7 +18359,7 @@ function isLockStale2(meta, opts) {
18237
18359
  function tryAcquireOnce2(lockPath, meta, opts) {
18238
18360
  for (let attempt = 0; attempt <= MAX_STEAL_ATTEMPTS; attempt += 1) {
18239
18361
  try {
18240
- fs66.mkdirSync(path65.dirname(lockPath), { recursive: true });
18362
+ fs66.mkdirSync(path66.dirname(lockPath), { recursive: true });
18241
18363
  const fd = fs66.openSync(lockPath, "wx", 384);
18242
18364
  try {
18243
18365
  fs66.writeSync(fd, JSON.stringify(meta));
@@ -18399,12 +18521,12 @@ var init_services_status = __esm({
18399
18521
  import * as crypto9 from "node:crypto";
18400
18522
  import * as fs67 from "node:fs";
18401
18523
  import * as os36 from "node:os";
18402
- import * as path66 from "node:path";
18524
+ import * as path67 from "node:path";
18403
18525
  function migrationSnapshotsDir2() {
18404
18526
  const override = process.env["OLAM_MIGRATION_SNAPSHOTS_DIR"];
18405
18527
  if (override && override.length > 0)
18406
18528
  return override;
18407
- return path66.join(os36.homedir(), ".olam", "state", "migration-snapshots");
18529
+ return path67.join(os36.homedir(), ".olam", "state", "migration-snapshots");
18408
18530
  }
18409
18531
  function writeMetaHooksSnapshot(originalSettings) {
18410
18532
  const snapshot = {
@@ -18418,7 +18540,7 @@ function writeMetaHooksSnapshot(originalSettings) {
18418
18540
  fs67.mkdirSync(dir, { recursive: true });
18419
18541
  const stamp = validated.takenAt.replace(/[:.]/g, "-");
18420
18542
  const rand = crypto9.randomBytes(3).toString("hex");
18421
- const file = path66.join(dir, `${META_HOOKS_SNAPSHOT_PREFIX}${stamp}-${process.pid}-${rand}.json`);
18543
+ const file = path67.join(dir, `${META_HOOKS_SNAPSHOT_PREFIX}${stamp}-${process.pid}-${rand}.json`);
18422
18544
  fs67.writeFileSync(file, JSON.stringify(validated, null, 2) + "\n", { mode: 384 });
18423
18545
  return file;
18424
18546
  }
@@ -18437,7 +18559,7 @@ function findLatestMetaHooksSnapshot() {
18437
18559
  const candidates2 = fs67.readdirSync(dir).filter((n) => n.startsWith(META_HOOKS_SNAPSHOT_PREFIX) && n.endsWith(".json")).sort().reverse();
18438
18560
  if (candidates2.length === 0)
18439
18561
  return void 0;
18440
- return path66.join(dir, candidates2[0]);
18562
+ return path67.join(dir, candidates2[0]);
18441
18563
  }
18442
18564
  function restoreSettingsFromSnapshot(snapshot, settingsPath) {
18443
18565
  if (snapshot.originalSettings === null) {
@@ -18446,7 +18568,7 @@ function restoreSettingsFromSnapshot(snapshot, settingsPath) {
18446
18568
  }
18447
18569
  return;
18448
18570
  }
18449
- fs67.mkdirSync(path66.dirname(settingsPath), { recursive: true });
18571
+ fs67.mkdirSync(path67.dirname(settingsPath), { recursive: true });
18450
18572
  const tmp = `${settingsPath}.tmp-restore-${process.pid}-${Date.now()}`;
18451
18573
  fs67.writeFileSync(tmp, JSON.stringify(snapshot.originalSettings, null, 2) + "\n");
18452
18574
  fs67.renameSync(tmp, settingsPath);
@@ -18816,17 +18938,17 @@ var init_markdown_merger = __esm({
18816
18938
 
18817
18939
  // ../core/dist/skill-sync/managed-merge.js
18818
18940
  import * as fs68 from "node:fs";
18819
- import * as path67 from "node:path";
18941
+ import * as path68 from "node:path";
18820
18942
  function materializeMergedSkill(opts) {
18821
18943
  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))) {
18944
+ const managedDir = path68.join(claudeDir2, ".olam-merged", sourceId, deployBasename);
18945
+ const sourceRoot = path68.resolve(path68.join(claudeDir2, ".olam-merged", sourceId));
18946
+ const managedResolved = path68.resolve(managedDir);
18947
+ if (!(managedResolved === sourceRoot || managedResolved.startsWith(sourceRoot + path68.sep))) {
18826
18948
  throw new Error(`[managed-merge] refusing to materialize: deployBasename "${deployBasename}" escapes managed root "${sourceRoot}" (resolved to "${managedResolved}")`);
18827
18949
  }
18828
18950
  fs68.mkdirSync(managedDir, { recursive: true });
18829
- const skillMdPath = path67.join(managedDir, "SKILL.md");
18951
+ const skillMdPath = path68.join(managedDir, "SKILL.md");
18830
18952
  const tmpPath = `${skillMdPath}.tmp-${process.pid}-${Date.now()}`;
18831
18953
  fs68.writeFileSync(tmpPath, mergedContent);
18832
18954
  fs68.renameSync(tmpPath, skillMdPath);
@@ -18834,9 +18956,9 @@ function materializeMergedSkill(opts) {
18834
18956
  for (const entry of baseEntries) {
18835
18957
  if (entry === "SKILL.md")
18836
18958
  continue;
18837
- const linkPath = path67.join(managedDir, entry);
18838
- const targetAbsolute = path67.join(sourcePath, entry);
18839
- const targetRelative = path67.relative(managedDir, targetAbsolute);
18959
+ const linkPath = path68.join(managedDir, entry);
18960
+ const targetAbsolute = path68.join(sourcePath, entry);
18961
+ const targetRelative = path68.relative(managedDir, targetAbsolute);
18840
18962
  try {
18841
18963
  fs68.lstatSync(linkPath);
18842
18964
  fs68.rmSync(linkPath, { recursive: true, force: true });
@@ -18850,7 +18972,7 @@ function materializeMergedSkill(opts) {
18850
18972
  if (entry === "SKILL.md")
18851
18973
  continue;
18852
18974
  if (!baseEntrySet.has(entry)) {
18853
- const stalePath = path67.join(managedDir, entry);
18975
+ const stalePath = path68.join(managedDir, entry);
18854
18976
  try {
18855
18977
  fs68.rmSync(stalePath, { recursive: true, force: true });
18856
18978
  } catch {
@@ -18860,7 +18982,7 @@ function materializeMergedSkill(opts) {
18860
18982
  return managedDir;
18861
18983
  }
18862
18984
  function cleanMergedDir(claudeDir2) {
18863
- fs68.rmSync(path67.join(claudeDir2, ".olam-merged"), { recursive: true, force: true });
18985
+ fs68.rmSync(path68.join(claudeDir2, ".olam-merged"), { recursive: true, force: true });
18864
18986
  }
18865
18987
  var init_managed_merge = __esm({
18866
18988
  "../core/dist/skill-sync/managed-merge.js"() {
@@ -18949,7 +19071,7 @@ var init_prefix_rules = __esm({
18949
19071
 
18950
19072
  // ../core/dist/skill-sync/prefix-deploy.js
18951
19073
  import * as fs69 from "node:fs";
18952
- import * as path68 from "node:path";
19074
+ import * as path69 from "node:path";
18953
19075
  function buildSourcePrefixMap(sources) {
18954
19076
  const byId = /* @__PURE__ */ new Map();
18955
19077
  const scopeById = /* @__PURE__ */ new Map();
@@ -18997,7 +19119,7 @@ function applyPrefixRewrites(baseArtifacts, sourceMap, claudeDir2, dryRun) {
18997
19119
  continue;
18998
19120
  }
18999
19121
  if (artifact.kind === "skill") {
19000
- const skillMdPath = path68.join(artifact.sourcePath, "SKILL.md");
19122
+ const skillMdPath = path69.join(artifact.sourcePath, "SKILL.md");
19001
19123
  const content = fs69.readFileSync(skillMdPath);
19002
19124
  const rewritten = rewriteFrontmatterName(content, () => renamedFrontmatterName);
19003
19125
  const managedDir = materializeMergedSkill({
@@ -19062,12 +19184,12 @@ function sourceConfigPath(clonePath) {
19062
19184
  return join76(clonePath, "shared", "source-config.yaml");
19063
19185
  }
19064
19186
  function readSourceConfig(clonePath, sourceId) {
19065
- const path95 = sourceConfigPath(clonePath);
19066
- if (!existsSync77(path95))
19187
+ const path96 = sourceConfigPath(clonePath);
19188
+ if (!existsSync77(path96))
19067
19189
  return void 0;
19068
19190
  let raw;
19069
19191
  try {
19070
- raw = readFileSync66(path95, "utf-8");
19192
+ raw = readFileSync66(path96, "utf-8");
19071
19193
  } catch (err) {
19072
19194
  emitMalformedWarning(sourceId, `read failed: ${errToMsg(err)}`);
19073
19195
  return void 0;
@@ -19148,12 +19270,12 @@ var init_resolve_source_config = __esm({
19148
19270
  // ../core/dist/skill-sync/engine.js
19149
19271
  import * as fs70 from "node:fs";
19150
19272
  import * as os37 from "node:os";
19151
- import * as path69 from "node:path";
19273
+ import * as path70 from "node:path";
19152
19274
  function resolveAtlasUser(override) {
19153
19275
  if (override)
19154
19276
  return override;
19155
- const claudeDir2 = process.env["OLAM_CLAUDE_DIR"] || path69.join(os37.homedir(), ".claude");
19156
- const f = path69.join(claudeDir2, ".atlas-user");
19277
+ const claudeDir2 = process.env["OLAM_CLAUDE_DIR"] || path70.join(os37.homedir(), ".claude");
19278
+ const f = path70.join(claudeDir2, ".atlas-user");
19157
19279
  if (fs70.existsSync(f)) {
19158
19280
  return fs70.readFileSync(f, "utf-8").trim() || void 0;
19159
19281
  }
@@ -19310,7 +19432,7 @@ async function syncSkills(opts = {}) {
19310
19432
  let baseContent;
19311
19433
  let basePath;
19312
19434
  if (overlay.targetKind === "skill") {
19313
- basePath = path69.join(base.sourcePath, "SKILL.md");
19435
+ basePath = path70.join(base.sourcePath, "SKILL.md");
19314
19436
  baseContent = fs70.readFileSync(basePath, "utf-8");
19315
19437
  } else {
19316
19438
  basePath = base.sourcePath;
@@ -19377,7 +19499,7 @@ async function syncSkills(opts = {}) {
19377
19499
  summary2.collisions = detectCollisions(baseArtifacts).collisions;
19378
19500
  return summary2;
19379
19501
  }
19380
- const claudeDirPath = process.env["OLAM_CLAUDE_DIR"] || path69.join(os37.homedir(), ".claude");
19502
+ const claudeDirPath = process.env["OLAM_CLAUDE_DIR"] || path70.join(os37.homedir(), ".claude");
19381
19503
  const overlayReferences = scanOverlayReferences(claudeDirPath, SHIM_TARGETS.map((t) => t.basename));
19382
19504
  summary2.deploy = deployArtifacts(baseArtifacts, {
19383
19505
  installedOlamVersion,
@@ -19411,10 +19533,10 @@ async function injectMetaHooksIntoSettings(opts) {
19411
19533
  } catch {
19412
19534
  try {
19413
19535
  const raw = fs70.readFileSync(settingsFile);
19414
- const bakDir = path69.join(path69.dirname(settingsFile), ".malformed-backups");
19536
+ const bakDir = path70.join(path70.dirname(settingsFile), ".malformed-backups");
19415
19537
  fs70.mkdirSync(bakDir, { recursive: true });
19416
19538
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
19417
- const bakFile = path69.join(bakDir, `settings.json.malformed.${stamp}.bak`);
19539
+ const bakFile = path70.join(bakDir, `settings.json.malformed.${stamp}.bak`);
19418
19540
  fs70.writeFileSync(bakFile, raw, { mode: 384 });
19419
19541
  snapshotError = `settings.json was malformed; original bytes preserved at ${bakFile}`;
19420
19542
  } catch (bakErr) {
@@ -19465,7 +19587,7 @@ async function injectMetaHooksIntoSettings(opts) {
19465
19587
  } catch {
19466
19588
  }
19467
19589
  }
19468
- fs70.mkdirSync(path69.dirname(settingsFile), { recursive: true });
19590
+ fs70.mkdirSync(path70.dirname(settingsFile), { recursive: true });
19469
19591
  const tmpPath = `${settingsFile}.tmp-${process.pid}-${Date.now()}`;
19470
19592
  fs70.writeFileSync(tmpPath, JSON.stringify(inject.nextSettings, null, 2) + "\n");
19471
19593
  fs70.renameSync(tmpPath, settingsFile);
@@ -19510,13 +19632,13 @@ var init_engine = __esm({
19510
19632
 
19511
19633
  // ../core/dist/skill-sync/shadow-backup-manager.js
19512
19634
  import * as fs71 from "node:fs";
19513
- import * as path70 from "node:path";
19635
+ import * as path71 from "node:path";
19514
19636
  function listShadowBackups(opts = {}) {
19515
19637
  const claude = opts.claudeDirOverride ?? claudeDir();
19516
19638
  const now = opts.now ?? Date.now();
19517
19639
  const out = [];
19518
19640
  for (const bucket of SHADOW_BACKUP_BUCKETS) {
19519
- const bucketDir = path70.join(claude, bucket);
19641
+ const bucketDir = path71.join(claude, bucket);
19520
19642
  if (!fs71.existsSync(bucketDir))
19521
19643
  continue;
19522
19644
  let entries;
@@ -19532,7 +19654,7 @@ function listShadowBackups(opts = {}) {
19532
19654
  const epochSeconds = Number.parseInt(match2[1], 10);
19533
19655
  if (!Number.isFinite(epochSeconds) || epochSeconds < 0)
19534
19656
  continue;
19535
- const full = path70.join(bucketDir, name);
19657
+ const full = path71.join(bucketDir, name);
19536
19658
  let sizeBytes = 0;
19537
19659
  try {
19538
19660
  const st = fs71.statSync(full);
@@ -19548,7 +19670,7 @@ function listShadowBackups(opts = {}) {
19548
19670
  bucket,
19549
19671
  basename: name,
19550
19672
  originalBasename,
19551
- originalPath: path70.join(bucketDir, originalBasename),
19673
+ originalPath: path71.join(bucketDir, originalBasename),
19552
19674
  epochSeconds,
19553
19675
  ageMs: now - epochSeconds * 1e3,
19554
19676
  sizeBytes
@@ -19602,17 +19724,17 @@ function pruneShadowBackups(opts) {
19602
19724
  return { deleted, skipped };
19603
19725
  }
19604
19726
  function restoreShadowBackup(opts) {
19605
- const abs = path70.resolve(opts.backupPath);
19727
+ const abs = path71.resolve(opts.backupPath);
19606
19728
  if (!fs71.existsSync(abs)) {
19607
19729
  throw new Error(`backup file not found: ${abs}`);
19608
19730
  }
19609
- const basename16 = path70.basename(abs);
19731
+ const basename16 = path71.basename(abs);
19610
19732
  const match2 = SHADOW_BACKUP_SUFFIX_RE.exec(basename16);
19611
19733
  if (!match2) {
19612
19734
  throw new Error(`not a shadow-backup file (basename "${basename16}" does not match \`.shadow-backup-<epoch>\`): ${abs}`);
19613
19735
  }
19614
19736
  const originalBasename = basename16.slice(0, basename16.length - match2[0].length);
19615
- const originalPath = path70.join(path70.dirname(abs), originalBasename);
19737
+ const originalPath = path71.join(path71.dirname(abs), originalBasename);
19616
19738
  if (fs71.existsSync(originalPath) && !opts.force) {
19617
19739
  throw new Error(`original path already occupied: ${originalPath}. Move/rename it first OR re-run with --force.`);
19618
19740
  }
@@ -19635,10 +19757,10 @@ var init_shadow_backup_manager = __esm({
19635
19757
  // ../core/dist/global-config/repos.js
19636
19758
  import * as fs72 from "node:fs";
19637
19759
  import * as os38 from "node:os";
19638
- import * as path71 from "node:path";
19760
+ import * as path72 from "node:path";
19639
19761
  function expandPath(p) {
19640
19762
  if (p === "~" || p.startsWith("~/")) {
19641
- return path71.join(os38.homedir(), p.slice(1));
19763
+ return path72.join(os38.homedir(), p.slice(1));
19642
19764
  }
19643
19765
  return p;
19644
19766
  }
@@ -19750,13 +19872,13 @@ var init_global_config = __esm({
19750
19872
 
19751
19873
  // ../core/dist/skill-sources/doctor-checks.js
19752
19874
  import * as fs73 from "node:fs";
19753
- import * as path72 from "node:path";
19875
+ import * as path73 from "node:path";
19754
19876
  import * as os39 from "node:os";
19755
19877
  function claudeDirInternal3() {
19756
19878
  const override = process.env["OLAM_CLAUDE_DIR"];
19757
19879
  if (override && override.length > 0)
19758
19880
  return override;
19759
- return path72.join(os39.homedir(), ".claude");
19881
+ return path73.join(os39.homedir(), ".claude");
19760
19882
  }
19761
19883
  function checkStateFileParse() {
19762
19884
  const filePath = globalConfigPath();
@@ -19811,11 +19933,11 @@ function checkDanglingSymlinks() {
19811
19933
  const buckets = ["commands", "agents", "skills", "scripts", "rules"];
19812
19934
  const dangling = [];
19813
19935
  for (const bucket of buckets) {
19814
- const dir = path72.join(claude, bucket);
19936
+ const dir = path73.join(claude, bucket);
19815
19937
  if (!fs73.existsSync(dir))
19816
19938
  continue;
19817
19939
  for (const name of fs73.readdirSync(dir)) {
19818
- const linkPath = path72.join(dir, name);
19940
+ const linkPath = path73.join(dir, name);
19819
19941
  try {
19820
19942
  const lst = fs73.lstatSync(linkPath);
19821
19943
  if (!lst.isSymbolicLink())
@@ -19860,7 +19982,7 @@ function checkOrphanedSnapshots() {
19860
19982
  for (const name of fs73.readdirSync(dir)) {
19861
19983
  if (!name.endsWith(".json"))
19862
19984
  continue;
19863
- const full = path72.join(dir, name);
19985
+ const full = path73.join(dir, name);
19864
19986
  try {
19865
19987
  const stat = fs73.statSync(full);
19866
19988
  if (!stat.isFile())
@@ -19998,7 +20120,7 @@ function checkMemberNameMissing() {
19998
20120
  return result;
19999
20121
  }
20000
20122
  const claudeDir2 = claudeDirInternal3();
20001
- const atlasUserPath = path72.join(claudeDir2, ".atlas-user");
20123
+ const atlasUserPath = path73.join(claudeDir2, ".atlas-user");
20002
20124
  const value = fs73.existsSync(atlasUserPath) ? fs73.readFileSync(atlasUserPath, "utf-8").trim() : "";
20003
20125
  if (value.length > 0) {
20004
20126
  result.details = [`atlas-user: ${value}`];
@@ -20007,10 +20129,10 @@ function checkMemberNameMissing() {
20007
20129
  result.healthy = false;
20008
20130
  result.issue = "atlas-toolbox source registered but ~/.claude/.atlas-user not set";
20009
20131
  const clonePath = skillSourceClonePath(atlasSource.id);
20010
- const membersDir = path72.join(clonePath, "members");
20132
+ const membersDir = path73.join(clonePath, "members");
20011
20133
  const existing = fs73.existsSync(membersDir) ? fs73.readdirSync(membersDir).filter((e) => {
20012
20134
  try {
20013
- return fs73.statSync(path72.join(membersDir, e)).isDirectory();
20135
+ return fs73.statSync(path73.join(membersDir, e)).isDirectory();
20014
20136
  } catch {
20015
20137
  return false;
20016
20138
  }
@@ -20024,7 +20146,7 @@ function checkMemberNameMissing() {
20024
20146
  }
20025
20147
  function checkMemberOverlayDrift() {
20026
20148
  const claudeDir2 = claudeDirInternal3();
20027
- const atlasUserPath = path72.join(claudeDir2, ".atlas-user");
20149
+ const atlasUserPath = path73.join(claudeDir2, ".atlas-user");
20028
20150
  const atlasUser = fs73.existsSync(atlasUserPath) ? fs73.readFileSync(atlasUserPath, "utf-8").trim() : "";
20029
20151
  if (atlasUser.length === 0) {
20030
20152
  return [];
@@ -20041,7 +20163,7 @@ function checkMemberOverlayDrift() {
20041
20163
  const clonePath = skillSourceClonePath(atlasSource.id);
20042
20164
  const results = [];
20043
20165
  for (const kind of ["skills", "agents"]) {
20044
- const localRoot = path72.join(claudeDir2, `${kind}.overrides`);
20166
+ const localRoot = path73.join(claudeDir2, `${kind}.overrides`);
20045
20167
  if (!fs73.existsSync(localRoot))
20046
20168
  continue;
20047
20169
  let entries;
@@ -20051,7 +20173,7 @@ function checkMemberOverlayDrift() {
20051
20173
  continue;
20052
20174
  }
20053
20175
  for (const entry of entries) {
20054
- const localFile = path72.join(localRoot, entry);
20176
+ const localFile = path73.join(localRoot, entry);
20055
20177
  let stat;
20056
20178
  try {
20057
20179
  stat = fs73.statSync(localFile);
@@ -20060,7 +20182,7 @@ function checkMemberOverlayDrift() {
20060
20182
  }
20061
20183
  if (!stat.isFile())
20062
20184
  continue;
20063
- const cloneFile = path72.join(clonePath, "members", atlasUser, `${kind}.overrides`, entry);
20185
+ const cloneFile = path73.join(clonePath, "members", atlasUser, `${kind}.overrides`, entry);
20064
20186
  const localSha = sha256OfPath(localFile);
20065
20187
  const cloneSha = sha256OfPath(cloneFile);
20066
20188
  if (localSha === cloneSha) {
@@ -20229,7 +20351,7 @@ var project_sweep_exports = {};
20229
20351
  __export(project_sweep_exports, {
20230
20352
  walkProjectRoot: () => walkProjectRoot
20231
20353
  });
20232
- import * as path73 from "node:path";
20354
+ import * as path74 from "node:path";
20233
20355
  import { readdirSync as readdirSync25, lstatSync as lstatSync6, statSync as statSync25, existsSync as existsSync82 } from "node:fs";
20234
20356
  function isSkipped(basename16, extra) {
20235
20357
  if (DEFAULT_SKIP.has(basename16))
@@ -20241,7 +20363,7 @@ function isSkipped(basename16, extra) {
20241
20363
  return false;
20242
20364
  }
20243
20365
  function resolveMtime(dirPath, manifestFile, fsAdapter) {
20244
- const gitHead = path73.join(dirPath, ".git", "HEAD");
20366
+ const gitHead = path74.join(dirPath, ".git", "HEAD");
20245
20367
  if (fsAdapter.existsSync(gitHead)) {
20246
20368
  try {
20247
20369
  return fsAdapter.statSync(gitHead).mtimeMs;
@@ -20255,8 +20377,8 @@ function resolveMtime(dirPath, manifestFile, fsAdapter) {
20255
20377
  }
20256
20378
  }
20257
20379
  function walk2(currentPath, depth, maxDepth, extraExclude, fsAdapter, results) {
20258
- const adbManifest = path73.join(currentPath, ".adb.yaml");
20259
- const olamManifest = path73.join(currentPath, ".olam.yaml");
20380
+ const adbManifest = path74.join(currentPath, ".adb.yaml");
20381
+ const olamManifest = path74.join(currentPath, ".olam.yaml");
20260
20382
  if (fsAdapter.existsSync(adbManifest)) {
20261
20383
  const mtime = resolveMtime(currentPath, adbManifest, fsAdapter);
20262
20384
  results.push({ path: currentPath, manifestType: "adb", mtime });
@@ -20278,7 +20400,7 @@ function walk2(currentPath, depth, maxDepth, extraExclude, fsAdapter, results) {
20278
20400
  for (const entry of entries) {
20279
20401
  if (isSkipped(entry, extraExclude))
20280
20402
  continue;
20281
- const childPath = path73.join(currentPath, entry);
20403
+ const childPath = path74.join(currentPath, entry);
20282
20404
  let stat;
20283
20405
  try {
20284
20406
  stat = fsAdapter.lstatSync(childPath);
@@ -20336,11 +20458,11 @@ __export(kg_eager_exports, {
20336
20458
  writeQueue: () => writeQueue
20337
20459
  });
20338
20460
  import * as fs74 from "node:fs";
20339
- import * as path74 from "node:path";
20461
+ import * as path75 from "node:path";
20340
20462
  import * as os40 from "node:os";
20341
20463
  function defaultQueuePath() {
20342
- const stateDir = process.env["OLAM_STATE_DIR"] ?? path74.join(os40.homedir(), ".olam", "state");
20343
- return path74.join(stateDir, "kg-pending.jsonl");
20464
+ const stateDir = process.env["OLAM_STATE_DIR"] ?? path75.join(os40.homedir(), ".olam", "state");
20465
+ return path75.join(stateDir, "kg-pending.jsonl");
20344
20466
  }
20345
20467
  function readQueue(queuePath) {
20346
20468
  if (!fs74.existsSync(queuePath))
@@ -20359,14 +20481,14 @@ function readQueue(queuePath) {
20359
20481
  return entries;
20360
20482
  }
20361
20483
  function writeQueue(queuePath, entries) {
20362
- fs74.mkdirSync(path74.dirname(queuePath), { recursive: true });
20484
+ fs74.mkdirSync(path75.dirname(queuePath), { recursive: true });
20363
20485
  const content = entries.map((e) => JSON.stringify(e)).join("\n") + (entries.length > 0 ? "\n" : "");
20364
20486
  fs74.writeFileSync(queuePath, content, "utf-8");
20365
20487
  }
20366
20488
  function appendQueue(queuePath, repos, nowMs) {
20367
20489
  if (repos.length === 0)
20368
20490
  return;
20369
- fs74.mkdirSync(path74.dirname(queuePath), { recursive: true });
20491
+ fs74.mkdirSync(path75.dirname(queuePath), { recursive: true });
20370
20492
  const lines = repos.map((r) => JSON.stringify({ path: r.path, addedAt: nowMs })).join("\n") + "\n";
20371
20493
  fs74.appendFileSync(queuePath, lines, "utf-8");
20372
20494
  }
@@ -20422,7 +20544,7 @@ __export(machine_schema_exports, {
20422
20544
  writeMachineConfig: () => writeMachineConfig
20423
20545
  });
20424
20546
  import * as fs77 from "node:fs";
20425
- import * as path78 from "node:path";
20547
+ import * as path79 from "node:path";
20426
20548
  import * as os41 from "node:os";
20427
20549
  import { parse as parseYaml7, stringify as stringifyYaml5 } from "yaml";
20428
20550
  function readMachineConfig(configPath) {
@@ -20439,7 +20561,7 @@ function readMachineConfig(configPath) {
20439
20561
  }
20440
20562
  function writeMachineConfig(config, configPath) {
20441
20563
  const p = configPath ?? DEFAULT_CONFIG_PATH;
20442
- fs77.mkdirSync(path78.dirname(p), { recursive: true });
20564
+ fs77.mkdirSync(path79.dirname(p), { recursive: true });
20443
20565
  fs77.writeFileSync(p, stringifyYaml5({ ...config }), { mode: 420 });
20444
20566
  }
20445
20567
  function initMachineConfig(opts = {}) {
@@ -20463,9 +20585,9 @@ var init_machine_schema = __esm({
20463
20585
  channel: external_exports.enum(["stable", "beta", "edge"]).default("stable"),
20464
20586
  auto_update: external_exports.boolean().default(true),
20465
20587
  telemetry: external_exports.boolean().default(true),
20466
- worlds_dir: external_exports.string().default(() => path78.join(os41.homedir(), ".olam", "worlds"))
20588
+ worlds_dir: external_exports.string().default(() => path79.join(os41.homedir(), ".olam", "worlds"))
20467
20589
  });
20468
- DEFAULT_CONFIG_PATH = path78.join(os41.homedir(), ".olam", "config.yaml");
20590
+ DEFAULT_CONFIG_PATH = path79.join(os41.homedir(), ".olam", "config.yaml");
20469
20591
  }
20470
20592
  });
20471
20593
 
@@ -20660,16 +20782,16 @@ function isValidConfig(value) {
20660
20782
  if (typeof v.install_id !== "string" || v.install_id.length === 0) return false;
20661
20783
  return true;
20662
20784
  }
20663
- function atomicWriteJSON(path95, value, stderr = process.stderr) {
20785
+ function atomicWriteJSON(path96, value, stderr = process.stderr) {
20664
20786
  ensureStateDir();
20665
- const dir = dirname3(path95);
20787
+ const dir = dirname3(path96);
20666
20788
  if (!existsSync6(dir)) {
20667
20789
  mkdirSync2(dir, { recursive: true });
20668
20790
  }
20669
- const tmp = `${path95}.tmp.${process.pid}`;
20791
+ const tmp = `${path96}.tmp.${process.pid}`;
20670
20792
  try {
20671
20793
  writeFileSync2(tmp, JSON.stringify(value, null, 2) + "\n", { encoding: "utf8" });
20672
- renameSync2(tmp, path95);
20794
+ renameSync2(tmp, path96);
20673
20795
  } catch (err) {
20674
20796
  if (existsSync6(tmp)) {
20675
20797
  try {
@@ -21030,9 +21152,9 @@ var UnknownArchetypeError = class extends Error {
21030
21152
  };
21031
21153
  var ArchetypeCycleError = class extends Error {
21032
21154
  path;
21033
- constructor(path95) {
21034
- super(`Archetype inheritance cycle detected: ${path95.join(" \u2192 ")} \u2192 ${path95[0] ?? "?"}`);
21035
- this.path = path95;
21155
+ constructor(path96) {
21156
+ super(`Archetype inheritance cycle detected: ${path96.join(" \u2192 ")} \u2192 ${path96[0] ?? "?"}`);
21157
+ this.path = path96;
21036
21158
  this.name = "ArchetypeCycleError";
21037
21159
  }
21038
21160
  };
@@ -21520,7 +21642,7 @@ function substitutePlaceholders(templateYaml, values) {
21520
21642
  function renderOneSecret(binding, templatesRoot, reuse, deps = {}, rotate = false) {
21521
21643
  const olamHome5 = deps.olamHome ?? OLAM_HOME;
21522
21644
  const readFile = deps.readFile ?? defaultReadFile;
21523
- const writeFile = deps.writeFile ?? defaultWriteFile;
21645
+ const writeFile2 = deps.writeFile ?? defaultWriteFile;
21524
21646
  const fileExists = deps.fileExists ?? defaultFileExists;
21525
21647
  const genRandomHex = deps.genRandomHex ?? defaultGenRandomHex;
21526
21648
  const runGhTokenCmd = deps.runGhTokenCmd ?? defaultRunGhTokenCmd;
@@ -21535,7 +21657,7 @@ function renderOneSecret(binding, templatesRoot, reuse, deps = {}, rotate = fals
21535
21657
  olamHome5,
21536
21658
  reuse?.keys[p.key],
21537
21659
  rotate,
21538
- { readFile, writeFile, fileExists, genRandomHex, runGhTokenCmd }
21660
+ { readFile, writeFile: writeFile2, fileExists, genRandomHex, runGhTokenCmd }
21539
21661
  );
21540
21662
  if (!resolved.ok) {
21541
21663
  missingSources.push(`${p.key}: ${resolved.reason}`);
@@ -21831,14 +21953,14 @@ function ensureSecrets() {
21831
21953
  step("1/6 \u2014 operator secrets");
21832
21954
  mkdirSync19(OLAM_HOME3, { recursive: true });
21833
21955
  for (const name of SECRET_FILES) {
21834
- const path95 = join34(OLAM_HOME3, name);
21835
- if (existsSync29(path95)) {
21956
+ const path96 = join34(OLAM_HOME3, name);
21957
+ if (existsSync29(path96)) {
21836
21958
  printInfo("skip", `~/.olam/${name} already exists`);
21837
21959
  continue;
21838
21960
  }
21839
21961
  const hex = randomBytes7(32).toString("hex");
21840
- writeFileSync15(path95, hex + "\n", { encoding: "utf8", mode: 384 });
21841
- chmodSync4(path95, 384);
21962
+ writeFileSync15(path96, hex + "\n", { encoding: "utf8", mode: 384 });
21963
+ chmodSync4(path96, 384);
21842
21964
  printSuccess(`generated ~/.olam/${name}`);
21843
21965
  }
21844
21966
  }
@@ -21961,13 +22083,13 @@ function installObservability(opts) {
21961
22083
  scriptEnv.OLAM_BUNDLE_ROOT = bundleRoot;
21962
22084
  }
21963
22085
  for (const script of OBSERVABILITY_SCRIPTS) {
21964
- const path95 = join34(observabilityDir, script);
21965
- if (!existsSync29(path95)) {
22086
+ const path96 = join34(observabilityDir, script);
22087
+ if (!existsSync29(path96)) {
21966
22088
  printWarning(`observability script missing: ${script} \u2014 skipping`);
21967
22089
  continue;
21968
22090
  }
21969
22091
  printInfo("run", script);
21970
- const result = spawnSync10("bash", [path95], {
22092
+ const result = spawnSync10("bash", [path96], {
21971
22093
  stdio: "inherit",
21972
22094
  env: scriptEnv
21973
22095
  });
@@ -22976,56 +23098,56 @@ var SECRET_LEN_BYTES = 32;
22976
23098
  function generateSecret() {
22977
23099
  return randomBytes8(SECRET_LEN_BYTES).toString("hex");
22978
23100
  }
22979
- function writeSecretAtPath(path95, value) {
22980
- mkdirSync21(dirname22(path95), { recursive: true });
22981
- const tmp = `${path95}.tmp.${process.pid}`;
23101
+ function writeSecretAtPath(path96, value) {
23102
+ mkdirSync21(dirname22(path96), { recursive: true });
23103
+ const tmp = `${path96}.tmp.${process.pid}`;
22982
23104
  writeFileSync16(tmp, value, { mode: 384 });
22983
23105
  chmodSync5(tmp, 384);
22984
- renameSync6(tmp, path95);
23106
+ renameSync6(tmp, path96);
22985
23107
  }
22986
- function readSecretAtPathOrNull(path95) {
22987
- if (!existsSync32(path95)) return null;
22988
- const mode = statSync8(path95).mode & 511;
23108
+ function readSecretAtPathOrNull(path96) {
23109
+ if (!existsSync32(path96)) return null;
23110
+ const mode = statSync8(path96).mode & 511;
22989
23111
  if (mode !== 384) {
22990
23112
  process.stderr.write(
22991
- `warn: ${path95} has mode 0${mode.toString(8)}; expected 0600. Run 'olam memory secret rotate' to regenerate.
23113
+ `warn: ${path96} has mode 0${mode.toString(8)}; expected 0600. Run 'olam memory secret rotate' to regenerate.
22992
23114
  `
22993
23115
  );
22994
23116
  }
22995
- return readFileSync25(path95, "utf8").trim();
23117
+ return readFileSync25(path96, "utf8").trim();
22996
23118
  }
22997
- function readSecretAtPath(path95) {
22998
- const v = readSecretAtPathOrNull(path95);
23119
+ function readSecretAtPath(path96) {
23120
+ const v = readSecretAtPathOrNull(path96);
22999
23121
  if (v === null) {
23000
23122
  throw new Error(
23001
- `Secret not found at ${path95}. Run 'olam memory start' to generate it.`
23123
+ `Secret not found at ${path96}. Run 'olam memory start' to generate it.`
23002
23124
  );
23003
23125
  }
23004
23126
  return v;
23005
23127
  }
23006
- function ensureMemorySecret(path95 = MEMORY_SECRET_PATH) {
23007
- const existing = readSecretAtPathOrNull(path95);
23128
+ function ensureMemorySecret(path96 = MEMORY_SECRET_PATH) {
23129
+ const existing = readSecretAtPathOrNull(path96);
23008
23130
  if (existing) return existing;
23009
23131
  const fresh = generateSecret();
23010
- writeSecretAtPath(path95, fresh);
23132
+ writeSecretAtPath(path96, fresh);
23011
23133
  return fresh;
23012
23134
  }
23013
- function readMemorySecretOrNull(path95 = MEMORY_SECRET_PATH) {
23014
- return readSecretAtPathOrNull(path95);
23135
+ function readMemorySecretOrNull(path96 = MEMORY_SECRET_PATH) {
23136
+ return readSecretAtPathOrNull(path96);
23015
23137
  }
23016
- function readMemorySecret(path95 = MEMORY_SECRET_PATH) {
23017
- return readSecretAtPath(path95);
23138
+ function readMemorySecret(path96 = MEMORY_SECRET_PATH) {
23139
+ return readSecretAtPath(path96);
23018
23140
  }
23019
- function rotateMemorySecret(path95 = MEMORY_SECRET_PATH) {
23141
+ function rotateMemorySecret(path96 = MEMORY_SECRET_PATH) {
23020
23142
  const fresh = generateSecret();
23021
- writeSecretAtPath(path95, fresh);
23143
+ writeSecretAtPath(path96, fresh);
23022
23144
  return fresh;
23023
23145
  }
23024
- function hasMemorySecret(path95 = MEMORY_SECRET_PATH) {
23025
- return existsSync32(path95);
23146
+ function hasMemorySecret(path96 = MEMORY_SECRET_PATH) {
23147
+ return existsSync32(path96);
23026
23148
  }
23027
- function writeCloudMemorySecret(value, path95 = CLOUD_MEMORY_SECRET_PATH) {
23028
- writeSecretAtPath(path95, value);
23149
+ function writeCloudMemorySecret(value, path96 = CLOUD_MEMORY_SECRET_PATH) {
23150
+ writeSecretAtPath(path96, value);
23029
23151
  }
23030
23152
 
23031
23153
  // src/commands/memory-service-container.ts
@@ -25194,9 +25316,9 @@ function formatFreshnessWarning(result, image = DEFAULT_DEVBOX_IMAGE) {
25194
25316
  "These source files have changed since the image was built; the",
25195
25317
  "changes will NOT take effect in fresh worlds until you rebuild:"
25196
25318
  ];
25197
- for (const { path: path95, mtimeMs } of result.newerSources) {
25319
+ for (const { path: path96, mtimeMs } of result.newerSources) {
25198
25320
  const when = new Date(mtimeMs).toISOString();
25199
- lines.push(` \u2022 ${path95} (modified ${when})`);
25321
+ lines.push(` \u2022 ${path96} (modified ${when})`);
25200
25322
  }
25201
25323
  lines.push("");
25202
25324
  lines.push("Rebuild with:");
@@ -25577,9 +25699,9 @@ async function readHostCpTokenForCreate() {
25577
25699
  try {
25578
25700
  const { default: fs96 } = await import("node:fs");
25579
25701
  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"),
25702
+ const { default: path96 } = await import("node:path");
25703
+ const tp = path96.join(
25704
+ process.env.OLAM_HOME ?? path96.join(os50.homedir(), ".olam"),
25583
25705
  "host-cp.token"
25584
25706
  );
25585
25707
  if (!fs96.existsSync(tp)) return null;
@@ -25592,7 +25714,10 @@ function registerCreate(program2) {
25592
25714
  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
25715
  "--allow-bootstrap-failure",
25594
25716
  "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) => {
25717
+ ).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(
25718
+ "--claude-home <id-or-path>",
25719
+ "Use a per-world Claude Code HOME (multi-account isolation; see docs/decisions/045-claude-home-override.md)"
25720
+ ).action(async (opts) => {
25596
25721
  const { resolveDevboxImageOverride: resolveDevboxImageOverride2, decideAllowlist: decideAllowlist2 } = await Promise.resolve().then(() => (init_registry_allowlist(), registry_allowlist_exports));
25597
25722
  const overrideRef = resolveDevboxImageOverride2(opts.devboxImage);
25598
25723
  if (overrideRef) {
@@ -25770,6 +25895,25 @@ function registerCreate(program2) {
25770
25895
  throw err;
25771
25896
  }
25772
25897
  }
25898
+ let resolvedClaudeHome;
25899
+ if (opts.claudeHome !== void 0 && opts.claudeHome.length > 0) {
25900
+ try {
25901
+ const { resolveClaudeHome: resolveClaudeHome2, ensureClaudeHomeDir: ensureClaudeHomeDir2 } = await Promise.resolve().then(() => (init_home_override(), home_override_exports));
25902
+ const target = resolveClaudeHome2({ flag: opts.claudeHome });
25903
+ await ensureClaudeHomeDir2(target);
25904
+ resolvedClaudeHome = target;
25905
+ printInfo(
25906
+ "Claude home",
25907
+ `${target} (per-world Claude Code instance \u2014 see ADR 045)`
25908
+ );
25909
+ } catch (err) {
25910
+ printError(
25911
+ `Invalid --claude-home: ${err instanceof Error ? err.message : String(err)}`
25912
+ );
25913
+ process.exitCode = 1;
25914
+ return;
25915
+ }
25916
+ }
25773
25917
  const spinner = ora5("Creating world...").start();
25774
25918
  try {
25775
25919
  const world = await ctx.worldManager.createWorld({
@@ -25788,7 +25932,8 @@ function registerCreate(program2) {
25788
25932
  // manager, matching the manager's strict `if (!opts.carryUncommitted)`.
25789
25933
  carryUncommitted: opts.carryUncommitted === true,
25790
25934
  allowBootstrapFailure: opts.allowBootstrapFailure === true,
25791
- ...opts.runbook ? { runbookName: opts.runbook } : {}
25935
+ ...opts.runbook ? { runbookName: opts.runbook } : {},
25936
+ ...resolvedClaudeHome ? { claudeHome: resolvedClaudeHome } : {}
25792
25937
  });
25793
25938
  spinner.succeed("World created");
25794
25939
  try {
@@ -26022,8 +26167,8 @@ async function readHostCpToken3() {
26022
26167
  try {
26023
26168
  const { default: fs96 } = await import("node:fs");
26024
26169
  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");
26170
+ const { default: path96 } = await import("node:path");
26171
+ const tp = path96.join(os50.homedir(), ".olam", "host-cp.token");
26027
26172
  if (!fs96.existsSync(tp)) return null;
26028
26173
  const raw = fs96.readFileSync(tp, "utf-8").trim();
26029
26174
  return raw.length > 0 ? raw : null;
@@ -26240,7 +26385,7 @@ init_output();
26240
26385
  import * as fs36 from "node:fs";
26241
26386
  import * as http3 from "node:http";
26242
26387
  import * as os18 from "node:os";
26243
- import * as path37 from "node:path";
26388
+ import * as path38 from "node:path";
26244
26389
  var CLI_VERSION2 = process.env["OLAM_CLI_VERSION"] ?? "0.0.0";
26245
26390
  var HOST_CP_PORT2 = 19e3;
26246
26391
  var STATE_ENUM = [
@@ -26331,7 +26476,7 @@ async function getMachineStatus(_probe, _loadCtx, _readToken) {
26331
26476
  }
26332
26477
  } catch {
26333
26478
  }
26334
- const manifestPath2 = path37.join(os18.homedir(), ".olam", "cache", "manifest.json");
26479
+ const manifestPath2 = path38.join(os18.homedir(), ".olam", "cache", "manifest.json");
26335
26480
  let updateAvailable = null;
26336
26481
  let lastUpdateCheck = null;
26337
26482
  if (fs36.existsSync(manifestPath2)) {
@@ -26477,7 +26622,7 @@ init_context();
26477
26622
  init_output();
26478
26623
  import fs37 from "node:fs";
26479
26624
  import os19 from "node:os";
26480
- import path38 from "node:path";
26625
+ import path39 from "node:path";
26481
26626
  import { execFileSync as execFileSync9 } from "node:child_process";
26482
26627
  function registerClean(program2) {
26483
26628
  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 +26646,7 @@ async function runClean(opts) {
26501
26646
  printError(error?.message ?? "Olam is not configured. Run `olam init` first.");
26502
26647
  return 1;
26503
26648
  }
26504
- const worldsDir = path38.join(os19.homedir(), ".olam", "worlds");
26649
+ const worldsDir = path39.join(os19.homedir(), ".olam", "worlds");
26505
26650
  if (!fs37.existsSync(worldsDir)) {
26506
26651
  if (opts.json) {
26507
26652
  process.stdout.write(`${JSON.stringify({ worldsDir, entries: [] })}
@@ -26518,7 +26663,7 @@ async function runClean(opts) {
26518
26663
  const worktreeMap = collectWorktrees(worldsDir);
26519
26664
  const entries = [];
26520
26665
  for (const id of fs37.readdirSync(worldsDir).sort()) {
26521
- const fullPath = path38.join(worldsDir, id);
26666
+ const fullPath = path39.join(worldsDir, id);
26522
26667
  const stat = safeStat(fullPath);
26523
26668
  if (!stat || !stat.isDirectory()) continue;
26524
26669
  entries.push(classifyWorld({ id, fullPath, liveIds, worktreeMap }));
@@ -26584,7 +26729,7 @@ function classifyWorld(args) {
26584
26729
  if (liveIds.has(id)) {
26585
26730
  return { id, path: fullPath, bytes, category: "active", note: "in registry" };
26586
26731
  }
26587
- const worktreeChild = path38.join(fullPath, "olam");
26732
+ const worktreeChild = path39.join(fullPath, "olam");
26588
26733
  const worktreeInfo = worktreeMap.get(worktreeChild);
26589
26734
  if (worktreeInfo) {
26590
26735
  if (worktreeInfo.dirty > 0 || worktreeInfo.unpushed > 0) {
@@ -26641,8 +26786,8 @@ function reapEntry(entry) {
26641
26786
  function collectWorktrees(worldsDir) {
26642
26787
  const out = /* @__PURE__ */ new Map();
26643
26788
  for (const id of fs37.readdirSync(worldsDir)) {
26644
- const child = path38.join(worldsDir, id, "olam");
26645
- const gitMarker = path38.join(child, ".git");
26789
+ const child = path39.join(worldsDir, id, "olam");
26790
+ const gitMarker = path39.join(child, ".git");
26646
26791
  if (!fs37.existsSync(gitMarker)) continue;
26647
26792
  const gitDir = resolveGitDirForWorktree(child);
26648
26793
  if (!gitDir) continue;
@@ -26654,7 +26799,7 @@ function collectWorktrees(worldsDir) {
26654
26799
  return out;
26655
26800
  }
26656
26801
  function resolveGitDirForWorktree(worktreePath) {
26657
- const gitMarker = path38.join(worktreePath, ".git");
26802
+ const gitMarker = path39.join(worktreePath, ".git");
26658
26803
  try {
26659
26804
  const top = execFileSync9("git", ["rev-parse", "--show-toplevel"], {
26660
26805
  cwd: worktreePath,
@@ -26668,7 +26813,7 @@ function resolveGitDirForWorktree(worktreePath) {
26668
26813
  stdio: "pipe"
26669
26814
  }).trim();
26670
26815
  if (!common) return top;
26671
- return path38.dirname(path38.resolve(worktreePath, common));
26816
+ return path39.dirname(path39.resolve(worktreePath, common));
26672
26817
  } catch {
26673
26818
  return null;
26674
26819
  }
@@ -26735,7 +26880,7 @@ function computeBytes(p) {
26735
26880
  } catch {
26736
26881
  continue;
26737
26882
  }
26738
- for (const name of entries) stack.push(path38.join(cur, name));
26883
+ for (const name of entries) stack.push(path39.join(cur, name));
26739
26884
  } else {
26740
26885
  total += st.size;
26741
26886
  }
@@ -26789,7 +26934,7 @@ init_output();
26789
26934
  import { execFileSync as execFileSync10 } from "node:child_process";
26790
26935
  import * as fs38 from "node:fs";
26791
26936
  import * as os20 from "node:os";
26792
- import * as path39 from "node:path";
26937
+ import * as path40 from "node:path";
26793
26938
  import { createInterface as createInterface2 } from "node:readline/promises";
26794
26939
  import pc17 from "picocolors";
26795
26940
  var NPM_PACKAGE = "@pleri/olam-cli";
@@ -26811,7 +26956,7 @@ var realExec = (cmd, args) => {
26811
26956
  };
26812
26957
  function surveyOlam(opts = {}) {
26813
26958
  const exec = opts.exec ?? realExec;
26814
- const home = opts.olamHome ?? path39.join(os20.homedir(), ".olam");
26959
+ const home = opts.olamHome ?? path40.join(os20.homedir(), ".olam");
26815
26960
  const containers = listDocker(exec, ["ps", "-a", "--format", "{{.Names}}"]).filter(
26816
26961
  (n) => n.startsWith("olam-")
26817
26962
  );
@@ -26825,11 +26970,11 @@ function surveyOlam(opts = {}) {
26825
26970
  (n) => n.startsWith("olam-") && n !== "olam-host-cp-internal-default"
26826
26971
  );
26827
26972
  const worlds = [];
26828
- const worldsDir = path39.join(home, "worlds");
26973
+ const worldsDir = path40.join(home, "worlds");
26829
26974
  if (fs38.existsSync(worldsDir)) {
26830
26975
  for (const entry of fs38.readdirSync(worldsDir, { withFileTypes: true })) {
26831
26976
  if (!entry.isDirectory()) continue;
26832
- const wPath = path39.join(worldsDir, entry.name);
26977
+ const wPath = path40.join(worldsDir, entry.name);
26833
26978
  const bytes = dirSize(wPath);
26834
26979
  const { dirty, note } = inspectWorldGitState(wPath);
26835
26980
  worlds.push({ id: entry.name, bytes, dirty, note, path: wPath });
@@ -26838,7 +26983,7 @@ function surveyOlam(opts = {}) {
26838
26983
  const homeBytesNonWorld = fs38.existsSync(home) ? Math.max(0, dirSize(home) - worlds.reduce((acc, w) => acc + w.bytes, 0)) : 0;
26839
26984
  const npmRoot = exec("npm", ["root", "-g"]);
26840
26985
  const npmGlobalRoot = npmRoot.exitCode === 0 ? npmRoot.stdout.trim() : null;
26841
- const npmInstalled = npmGlobalRoot !== null && fs38.existsSync(path39.join(npmGlobalRoot, NPM_PACKAGE));
26986
+ const npmInstalled = npmGlobalRoot !== null && fs38.existsSync(path40.join(npmGlobalRoot, NPM_PACKAGE));
26842
26987
  return {
26843
26988
  containers,
26844
26989
  images,
@@ -26868,7 +27013,7 @@ function dirSize(p) {
26868
27013
  continue;
26869
27014
  }
26870
27015
  for (const e of entries) {
26871
- const full = path39.join(cur, e.name);
27016
+ const full = path40.join(cur, e.name);
26872
27017
  try {
26873
27018
  if (e.isDirectory()) stack.push(full);
26874
27019
  else if (e.isFile()) total += fs38.statSync(full).size;
@@ -26886,8 +27031,8 @@ function inspectWorldGitState(worldPath) {
26886
27031
  try {
26887
27032
  for (const entry of fs38.readdirSync(worldPath, { withFileTypes: true })) {
26888
27033
  if (!entry.isDirectory()) continue;
26889
- const repo = path39.join(worldPath, entry.name);
26890
- const gitDir = path39.join(repo, ".git");
27034
+ const repo = path40.join(worldPath, entry.name);
27035
+ const gitDir = path40.join(repo, ".git");
26891
27036
  if (!fs38.existsSync(gitDir)) continue;
26892
27037
  try {
26893
27038
  const status2 = execFileSync10("git", ["status", "--porcelain"], {
@@ -26981,7 +27126,7 @@ function formatBytes3(n) {
26981
27126
  }
26982
27127
  async function executeImplode(survey, opts) {
26983
27128
  const exec = opts.exec ?? realExec;
26984
- const home = opts.olamHome ?? path39.join(os20.homedir(), ".olam");
27129
+ const home = opts.olamHome ?? path40.join(os20.homedir(), ".olam");
26985
27130
  const removed = [];
26986
27131
  const skipped = [];
26987
27132
  const errors = [];
@@ -27045,7 +27190,7 @@ async function executeImplode(survey, opts) {
27045
27190
  skipped.push(`fs:~/.olam/auth-data (--keep-vault)`);
27046
27191
  continue;
27047
27192
  }
27048
- const target = path39.join(home, entry.name);
27193
+ const target = path40.join(home, entry.name);
27049
27194
  try {
27050
27195
  fs38.rmSync(target, { recursive: true, force: true });
27051
27196
  removed.push(`fs:${target}`);
@@ -27220,6 +27365,11 @@ function registerEnter(program2) {
27220
27365
  if (worldMeta) {
27221
27366
  const { checkVersionPin: checkVersionPin2 } = await Promise.resolve().then(() => (init_version_pin(), version_pin_exports));
27222
27367
  checkVersionPin2(worldId, worldMeta.workspacePath);
27368
+ if (worldMeta.claudeHome) {
27369
+ console.log(
27370
+ pc18.dim(`# claude-home: ${worldMeta.claudeHome} (per-world Claude Code instance, ADR 045)`)
27371
+ );
27372
+ }
27223
27373
  }
27224
27374
  const computeWorld = await ctx.computeProvider.getWorld(worldId);
27225
27375
  if (!computeWorld) {
@@ -27308,6 +27458,138 @@ ${pc18.dim(`Observe dispatch: docker exec -it ${containerName} tmux attach -t ol
27308
27458
  });
27309
27459
  }
27310
27460
 
27461
+ // src/commands/resume.ts
27462
+ init_context();
27463
+ init_output();
27464
+ import { execFileSync as execFileSync11 } from "node:child_process";
27465
+ function looksLikePrIdentifier(input2) {
27466
+ if (/^\d+$/.test(input2.trim())) return true;
27467
+ if (/^https?:\/\/[^\s]*\/pull\/\d+(?:[/?#].*)?$/i.test(input2.trim())) return true;
27468
+ return false;
27469
+ }
27470
+ async function runResume(input2, deps) {
27471
+ const trimmed = input2.trim();
27472
+ if (trimmed.length === 0) {
27473
+ deps.stderr("resume: argument <pr> is required (PR number, URL, or branch name).");
27474
+ return 1;
27475
+ }
27476
+ let resolved;
27477
+ try {
27478
+ resolved = await deps.resolveInput(trimmed);
27479
+ } catch (err) {
27480
+ deps.stderr(
27481
+ `resume: could not resolve "${trimmed}" via gh pr view \u2014 ` + (err instanceof Error ? err.message : String(err))
27482
+ );
27483
+ return 1;
27484
+ }
27485
+ const { branch, prNumber } = resolved;
27486
+ const worlds = deps.listWorlds();
27487
+ const matches2 = worlds.filter((w) => w.branch === branch);
27488
+ const prLabel = prNumber !== void 0 ? `PR #${prNumber}` : `branch ${branch}`;
27489
+ if (matches2.length === 0) {
27490
+ deps.stderr(
27491
+ `No active world found for ${prLabel} (branch ${branch}). Worlds visible via olam list.`
27492
+ );
27493
+ return 1;
27494
+ }
27495
+ if (matches2.length > 1) {
27496
+ deps.stderr(
27497
+ `Multiple worlds match ${prLabel} (branch ${branch}); operator decides:`
27498
+ );
27499
+ for (const w of matches2) {
27500
+ deps.stderr(` - ${w.name} (${w.id})`);
27501
+ }
27502
+ return 1;
27503
+ }
27504
+ const match2 = matches2[0];
27505
+ deps.stdout(
27506
+ `Found world ${match2.name} (${match2.id}) for ${prLabel}. Entering...`
27507
+ );
27508
+ try {
27509
+ deps.enterWorld(match2.id);
27510
+ } catch (err) {
27511
+ deps.stderr(
27512
+ `resume: olam enter ${match2.id} failed \u2014 ` + (err instanceof Error ? err.message : String(err))
27513
+ );
27514
+ return 1;
27515
+ }
27516
+ return 0;
27517
+ }
27518
+ function resolveInputViaGh(input2) {
27519
+ if (!looksLikePrIdentifier(input2)) {
27520
+ if (input2.length === 0) {
27521
+ return Promise.reject(new Error("empty branch name"));
27522
+ }
27523
+ return Promise.resolve({ branch: input2 });
27524
+ }
27525
+ let stdout;
27526
+ try {
27527
+ stdout = execFileSync11("gh", ["pr", "view", input2, "--json", "number,headRefName"], {
27528
+ encoding: "utf-8",
27529
+ stdio: ["ignore", "pipe", "pipe"],
27530
+ timeout: 1e4
27531
+ });
27532
+ } catch (err) {
27533
+ const msg = err instanceof Error ? err.message : String(err);
27534
+ return Promise.reject(new Error(`gh pr view failed: ${msg}`));
27535
+ }
27536
+ let parsed;
27537
+ try {
27538
+ parsed = JSON.parse(stdout);
27539
+ } catch (err) {
27540
+ return Promise.reject(
27541
+ new Error(`gh pr view returned non-JSON output: ${err instanceof Error ? err.message : String(err)}`)
27542
+ );
27543
+ }
27544
+ if (typeof parsed.headRefName !== "string" || parsed.headRefName.length === 0) {
27545
+ return Promise.reject(new Error("gh pr view response missing headRefName"));
27546
+ }
27547
+ const prNumber = typeof parsed.number === "number" ? parsed.number : void 0;
27548
+ return Promise.resolve({ branch: parsed.headRefName, prNumber });
27549
+ }
27550
+ function registerResume(program2) {
27551
+ program2.command("resume").description(
27552
+ "Resume a world by PR number, URL, or branch \u2014 finds the world that opened the PR and enters it."
27553
+ ).argument("<pr>", "PR number (876), PR URL, or branch name").addHelpText(
27554
+ "after",
27555
+ `
27556
+ Examples:
27557
+ $ olam resume 876
27558
+ $ olam resume https://github.com/pleri/olam/pull/876
27559
+ $ olam resume night/feat/foo
27560
+ `
27561
+ ).action(async (pr) => {
27562
+ const { ctx, error } = await loadContext();
27563
+ if (!ctx) {
27564
+ printError(error?.message ?? "Olam is not configured. Run `olam init` first.");
27565
+ process.exitCode = 1;
27566
+ return;
27567
+ }
27568
+ const code = await runResume(pr, {
27569
+ resolveInput: resolveInputViaGh,
27570
+ listWorlds: () => ctx.worldManager.listWorlds().map((w) => ({
27571
+ id: w.id,
27572
+ name: w.name,
27573
+ branch: w.branch
27574
+ })),
27575
+ enterWorld: (worldId) => {
27576
+ const entry = process.argv[1];
27577
+ if (!entry) {
27578
+ throw new Error("cannot locate CLI entry script (process.argv[1] missing)");
27579
+ }
27580
+ execFileSync11(process.execPath, [entry, "enter", worldId, "--exec"], {
27581
+ stdio: "inherit"
27582
+ });
27583
+ },
27584
+ stdout: (line) => console.log(line),
27585
+ stderr: (line) => printError(line)
27586
+ });
27587
+ if (code !== 0) {
27588
+ process.exitCode = code;
27589
+ }
27590
+ });
27591
+ }
27592
+
27311
27593
  // src/commands/crystallize.ts
27312
27594
  init_context();
27313
27595
  init_output();
@@ -27573,7 +27855,7 @@ init_host_cp();
27573
27855
  // src/lib/plans-client.ts
27574
27856
  import * as fs40 from "node:fs";
27575
27857
  import * as os21 from "node:os";
27576
- import * as path41 from "node:path";
27858
+ import * as path42 from "node:path";
27577
27859
  var PlansClientError = class extends Error {
27578
27860
  constructor(status2, message, body) {
27579
27861
  super(message);
@@ -27584,7 +27866,7 @@ var PlansClientError = class extends Error {
27584
27866
  status;
27585
27867
  body;
27586
27868
  };
27587
- var OLAM_HOME4 = path41.join(os21.homedir(), ".olam");
27869
+ var OLAM_HOME4 = path42.join(os21.homedir(), ".olam");
27588
27870
  function readFileOrNull(p) {
27589
27871
  try {
27590
27872
  return fs40.readFileSync(p, "utf8").trim();
@@ -27593,9 +27875,9 @@ function readFileOrNull(p) {
27593
27875
  }
27594
27876
  }
27595
27877
  function resolveCloudConfig() {
27596
- const cloudUrl = process.env.OLAM_CLOUD_URL ?? readFileOrNull(path41.join(OLAM_HOME4, "cloud-url"));
27878
+ const cloudUrl = process.env.OLAM_CLOUD_URL ?? readFileOrNull(path42.join(OLAM_HOME4, "cloud-url"));
27597
27879
  if (!cloudUrl) return null;
27598
- const bearer = process.env.OLAM_SHOWCASE_PASSWORD ?? readFileOrNull(path41.join(OLAM_HOME4, "showcase-password"));
27880
+ const bearer = process.env.OLAM_SHOWCASE_PASSWORD ?? readFileOrNull(path42.join(OLAM_HOME4, "showcase-password"));
27599
27881
  if (!bearer) return null;
27600
27882
  return { cloudUrl: cloudUrl.replace(/\/+$/, ""), bearer };
27601
27883
  }
@@ -27609,13 +27891,13 @@ var PlansClient = class {
27609
27891
  const credentials = Buffer.from(`operator:${this.cfg.bearer}`).toString("base64");
27610
27892
  return `Basic ${credentials}`;
27611
27893
  }
27612
- async request(path95, init) {
27894
+ async request(path96, init) {
27613
27895
  const headers = {
27614
27896
  Authorization: this.authHeader()
27615
27897
  };
27616
27898
  if (init.body) headers["content-type"] = "application/json";
27617
27899
  if (init.adminSecret) headers["X-Admin-Secret"] = init.adminSecret;
27618
- return fetch(`${this.cfg.cloudUrl}${path95}`, {
27900
+ return fetch(`${this.cfg.cloudUrl}${path96}`, {
27619
27901
  method: init.method,
27620
27902
  headers,
27621
27903
  body: init.body ? JSON.stringify(init.body) : void 0
@@ -28987,11 +29269,11 @@ var qmarksTestNoExtDot = ([$0]) => {
28987
29269
  return (f) => f.length === len && f !== "." && f !== "..";
28988
29270
  };
28989
29271
  var defaultPlatform = typeof process === "object" && process ? typeof process.env === "object" && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__ || process.platform : "posix";
28990
- var path42 = {
29272
+ var path43 = {
28991
29273
  win32: { sep: "\\" },
28992
29274
  posix: { sep: "/" }
28993
29275
  };
28994
- var sep2 = defaultPlatform === "win32" ? path42.win32.sep : path42.posix.sep;
29276
+ var sep2 = defaultPlatform === "win32" ? path43.win32.sep : path43.posix.sep;
28995
29277
  minimatch.sep = sep2;
28996
29278
  var GLOBSTAR = /* @__PURE__ */ Symbol("globstar **");
28997
29279
  minimatch.GLOBSTAR = GLOBSTAR;
@@ -30100,11 +30382,11 @@ function zodIssueToError(issue, doc, lineCounter) {
30100
30382
  suggestion: deriveSuggestion(issue)
30101
30383
  };
30102
30384
  }
30103
- function formatJsonPath(path95) {
30104
- if (path95.length === 0)
30385
+ function formatJsonPath(path96) {
30386
+ if (path96.length === 0)
30105
30387
  return "<root>";
30106
30388
  let out = "";
30107
- for (const seg of path95) {
30389
+ for (const seg of path96) {
30108
30390
  if (typeof seg === "number") {
30109
30391
  out += `[${seg}]`;
30110
30392
  } else {
@@ -30113,11 +30395,11 @@ function formatJsonPath(path95) {
30113
30395
  }
30114
30396
  return out;
30115
30397
  }
30116
- function resolveYamlLocation(path95, doc, lineCounter) {
30398
+ function resolveYamlLocation(path96, doc, lineCounter) {
30117
30399
  let bestLine = 0;
30118
30400
  let bestColumn = 0;
30119
- for (let depth = path95.length; depth >= 0; depth -= 1) {
30120
- const segment = path95.slice(0, depth);
30401
+ for (let depth = path96.length; depth >= 0; depth -= 1) {
30402
+ const segment = path96.slice(0, depth);
30121
30403
  try {
30122
30404
  const node = doc.getIn(segment, true);
30123
30405
  if (node && typeof node === "object" && "range" in node) {
@@ -30335,11 +30617,11 @@ function topoSort(nodes) {
30335
30617
  }
30336
30618
  function traceCycle(start, byId) {
30337
30619
  const seen = /* @__PURE__ */ new Set();
30338
- const path95 = [];
30620
+ const path96 = [];
30339
30621
  let current = start;
30340
30622
  while (current && !seen.has(current)) {
30341
30623
  seen.add(current);
30342
- path95.push(current);
30624
+ path96.push(current);
30343
30625
  const node = byId.get(current);
30344
30626
  const next = node?.dependsOn[0];
30345
30627
  if (next === void 0)
@@ -30347,10 +30629,10 @@ function traceCycle(start, byId) {
30347
30629
  current = next;
30348
30630
  }
30349
30631
  if (current && seen.has(current)) {
30350
- const idx = path95.indexOf(current);
30351
- return [...path95.slice(idx), current];
30632
+ const idx = path96.indexOf(current);
30633
+ return [...path96.slice(idx), current];
30352
30634
  }
30353
- return path95;
30635
+ return path96;
30354
30636
  }
30355
30637
 
30356
30638
  // ../core/dist/executor/types.js
@@ -30574,11 +30856,11 @@ async function resolveDigests(lockfile, resolver) {
30574
30856
  }
30575
30857
 
30576
30858
  // ../core/dist/worldspec/image-digest.js
30577
- import { execFileSync as execFileSync11 } from "node:child_process";
30859
+ import { execFileSync as execFileSync12 } from "node:child_process";
30578
30860
  var DOCKER_SUBPROCESS_TIMEOUT_MS = 3e4;
30579
30861
  var dockerDigestResolver = async (image, source) => {
30580
30862
  if (source === "local") {
30581
- const out = execFileSync11("docker", ["inspect", image, "--format", "{{.Id}}"], {
30863
+ const out = execFileSync12("docker", ["inspect", image, "--format", "{{.Id}}"], {
30582
30864
  encoding: "utf8",
30583
30865
  stdio: ["ignore", "pipe", "pipe"],
30584
30866
  timeout: DOCKER_SUBPROCESS_TIMEOUT_MS,
@@ -30589,7 +30871,7 @@ var dockerDigestResolver = async (image, source) => {
30589
30871
  }
30590
30872
  return out;
30591
30873
  }
30592
- const raw = execFileSync11("docker", ["buildx", "imagetools", "inspect", image], {
30874
+ const raw = execFileSync12("docker", ["buildx", "imagetools", "inspect", image], {
30593
30875
  encoding: "utf8",
30594
30876
  stdio: ["ignore", "pipe", "pipe"],
30595
30877
  timeout: DOCKER_SUBPROCESS_TIMEOUT_MS,
@@ -32250,7 +32532,7 @@ function registerWorldspec(program2) {
32250
32532
  init_output();
32251
32533
  init_host_cp();
32252
32534
  import * as fs43 from "node:fs";
32253
- import * as path45 from "node:path";
32535
+ import * as path46 from "node:path";
32254
32536
  import { spawnSync as spawnSync22 } from "node:child_process";
32255
32537
  import ora9 from "ora";
32256
32538
  import pc21 from "picocolors";
@@ -32258,9 +32540,9 @@ import pc21 from "picocolors";
32258
32540
  // src/commands/upgrade-lock.ts
32259
32541
  import * as fs41 from "node:fs";
32260
32542
  import * as os22 from "node:os";
32261
- import * as path43 from "node:path";
32543
+ import * as path44 from "node:path";
32262
32544
  import { spawnSync as spawnSync21 } from "node:child_process";
32263
- var LOCK_FILE_PATH = path43.join(os22.homedir(), ".olam", ".upgrade.lock");
32545
+ var LOCK_FILE_PATH = path44.join(os22.homedir(), ".olam", ".upgrade.lock");
32264
32546
  var STALE_LOCK_TIMEOUT_MS = 5 * 60 * 1e3;
32265
32547
  function readLockFile(lockPath) {
32266
32548
  try {
@@ -32310,7 +32592,7 @@ function isStaleLock(content, nowMs = Date.now()) {
32310
32592
  return false;
32311
32593
  }
32312
32594
  function acquireLock(lockPath = LOCK_FILE_PATH, nowMs = Date.now()) {
32313
- const dir = path43.dirname(lockPath);
32595
+ const dir = path44.dirname(lockPath);
32314
32596
  fs41.mkdirSync(dir, { recursive: true });
32315
32597
  for (let attempt = 0; attempt < 2; attempt++) {
32316
32598
  try {
@@ -32373,15 +32655,15 @@ function formatRefusalMessage(result, lockPath = LOCK_FILE_PATH) {
32373
32655
  // src/commands/upgrade-log.ts
32374
32656
  import * as fs42 from "node:fs";
32375
32657
  import * as os23 from "node:os";
32376
- import * as path44 from "node:path";
32658
+ import * as path45 from "node:path";
32377
32659
  function getUpgradeLogPath() {
32378
32660
  const home = process.env["HOME"] ?? os23.homedir();
32379
- return path44.join(home, ".olam", "upgrade.log");
32661
+ return path45.join(home, ".olam", "upgrade.log");
32380
32662
  }
32381
32663
  var UPGRADE_LOG_PATH = getUpgradeLogPath();
32382
32664
  function appendUpgradeLog(row, logPath = getUpgradeLogPath()) {
32383
32665
  try {
32384
- fs42.mkdirSync(path44.dirname(logPath), { recursive: true });
32666
+ fs42.mkdirSync(path45.dirname(logPath), { recursive: true });
32385
32667
  const line = JSON.stringify(row) + "\n";
32386
32668
  fs42.appendFileSync(logPath, line, { mode: 420 });
32387
32669
  } catch (err) {
@@ -32488,8 +32770,8 @@ init_protocol_version();
32488
32770
  init_install_root();
32489
32771
  var AUTH_HEALTH_URL2 = "http://127.0.0.1:9999/health";
32490
32772
  function isNodeModulesInSync(cwd) {
32491
- const lockPath = path45.join(cwd, "package-lock.json");
32492
- const markerPath = path45.join(cwd, "node_modules", ".package-lock.json");
32773
+ const lockPath = path46.join(cwd, "package-lock.json");
32774
+ const markerPath = path46.join(cwd, "node_modules", ".package-lock.json");
32493
32775
  if (!fs43.existsSync(lockPath) || !fs43.existsSync(markerPath)) return false;
32494
32776
  try {
32495
32777
  const lockStat = fs43.statSync(lockPath);
@@ -32509,7 +32791,7 @@ function shouldSkipInstall(opts, cwd) {
32509
32791
  return { skip: false };
32510
32792
  }
32511
32793
  function validateRepoRoot(cwd) {
32512
- const marker = path45.join(cwd, "packages/host-cp/compose.yaml");
32794
+ const marker = path46.join(cwd, "packages/host-cp/compose.yaml");
32513
32795
  if (!fs43.existsSync(marker)) {
32514
32796
  return {
32515
32797
  ok: false,
@@ -32870,7 +33152,7 @@ async function recreateAuthService() {
32870
33152
  }
32871
33153
  }
32872
33154
  function readBundleHash(cwd) {
32873
- const indexPath = path45.join(cwd, "packages/control-plane/public/index.html");
33155
+ const indexPath = path46.join(cwd, "packages/control-plane/public/index.html");
32874
33156
  if (!fs43.existsSync(indexPath)) return null;
32875
33157
  return extractBundleHash(fs43.readFileSync(indexPath, "utf-8"));
32876
33158
  }
@@ -33476,7 +33758,7 @@ ${buildResult.stderr}`);
33476
33758
  return;
33477
33759
  }
33478
33760
  const authSecret = readAuthSecret2();
33479
- const spaDir = path45.join(cwd, "packages/control-plane/app");
33761
+ const spaDir = path46.join(cwd, "packages/control-plane/app");
33480
33762
  const spaResult = runStep2(
33481
33763
  "vite build (SPA)",
33482
33764
  "npx",
@@ -34019,13 +34301,13 @@ ${pc23.dim(`world: ${worldId} sort: ${sortKey} refresh: 5s Ctrl-C to exit`)}
34019
34301
  init_output();
34020
34302
  import * as fs44 from "node:fs";
34021
34303
  import * as os24 from "node:os";
34022
- import * as path46 from "node:path";
34304
+ import * as path47 from "node:path";
34023
34305
  import YAML6 from "yaml";
34024
34306
  function olamHome3() {
34025
- return process.env.OLAM_HOME ?? path46.join(os24.homedir(), ".olam");
34307
+ return process.env.OLAM_HOME ?? path47.join(os24.homedir(), ".olam");
34026
34308
  }
34027
34309
  function keysFilePath() {
34028
- return path46.join(olamHome3(), "keys.yaml");
34310
+ return path47.join(olamHome3(), "keys.yaml");
34029
34311
  }
34030
34312
  function readKeysFile() {
34031
34313
  const filePath = keysFilePath();
@@ -34121,7 +34403,7 @@ function registerKeys(program2) {
34121
34403
  init_snapshot();
34122
34404
  init_output();
34123
34405
  import * as fs45 from "node:fs";
34124
- import * as path47 from "node:path";
34406
+ import * as path48 from "node:path";
34125
34407
  import { execSync as execSync11 } from "node:child_process";
34126
34408
  import pc24 from "picocolors";
34127
34409
 
@@ -34144,9 +34426,9 @@ function emitDeprecationWarning(subcommand) {
34144
34426
  }
34145
34427
  function bumpDeprecationCounter() {
34146
34428
  if (process.env[INTERNAL_SENTINEL_ENV] === "1") return;
34147
- const counterPath = path47.join(snapshotsDir(), ".deprecation-counter");
34429
+ const counterPath = path48.join(snapshotsDir(), ".deprecation-counter");
34148
34430
  try {
34149
- fs45.mkdirSync(path47.dirname(counterPath), { recursive: true });
34431
+ fs45.mkdirSync(path48.dirname(counterPath), { recursive: true });
34150
34432
  let current = 0;
34151
34433
  if (fs45.existsSync(counterPath)) {
34152
34434
  const raw = fs45.readFileSync(counterPath, "utf-8").trim();
@@ -34229,13 +34511,13 @@ function resolveKinds(arg) {
34229
34511
  return [];
34230
34512
  }
34231
34513
  async function captureGems(worldId, workspacePath, repo) {
34232
- const repoDir = path47.join(workspacePath, repo);
34514
+ const repoDir = path48.join(workspacePath, repo);
34233
34515
  const fingerprint = computeGemsFingerprint(repoDir);
34234
34516
  if (!fingerprint) {
34235
34517
  return { ok: false, tarPath: "", msg: "no Gemfile.lock \u2014 layer does not apply" };
34236
34518
  }
34237
34519
  const tarPath = snapshotTarPath(worldId, "gems", repo, fingerprint);
34238
- const vendorBundle = path47.join(repoDir, "vendor", "bundle");
34520
+ const vendorBundle = path48.join(repoDir, "vendor", "bundle");
34239
34521
  if (fs45.existsSync(vendorBundle)) {
34240
34522
  try {
34241
34523
  packTarball(vendorBundle, tarPath);
@@ -34272,7 +34554,7 @@ async function captureGems(worldId, workspacePath, repo) {
34272
34554
  `docker exec ${containerName} sh -c 'mkdir -p "$(dirname ${tmpTar})" && tar -czf ${tmpTar}.tmp -C ${bundlePath} . && mv ${tmpTar}.tmp ${tmpTar}'`,
34273
34555
  { stdio: "pipe", timeout: 12e4 }
34274
34556
  );
34275
- fs45.mkdirSync(path47.dirname(tarPath), { recursive: true });
34557
+ fs45.mkdirSync(path48.dirname(tarPath), { recursive: true });
34276
34558
  execSync11(`docker cp ${containerName}:${tmpTar} "${tarPath}"`, { stdio: "pipe", timeout: 12e4 });
34277
34559
  execSync11(`docker exec ${containerName} rm -f ${tmpTar}`, { stdio: "pipe" });
34278
34560
  const stat = fs45.statSync(tarPath);
@@ -34292,12 +34574,12 @@ async function captureGems(worldId, workspacePath, repo) {
34292
34574
  }
34293
34575
  }
34294
34576
  async function captureNode(worldId, workspacePath, repo) {
34295
- const repoDir = path47.join(workspacePath, repo);
34577
+ const repoDir = path48.join(workspacePath, repo);
34296
34578
  const fingerprint = computeNodeFingerprint(repoDir);
34297
34579
  if (!fingerprint) {
34298
34580
  return { ok: false, tarPath: "", msg: "no lockfile \u2014 layer does not apply" };
34299
34581
  }
34300
- const nodeModules = path47.join(repoDir, "node_modules");
34582
+ const nodeModules = path48.join(repoDir, "node_modules");
34301
34583
  if (!fs45.existsSync(nodeModules)) {
34302
34584
  return { ok: false, tarPath: "", msg: "node_modules not installed yet" };
34303
34585
  }
@@ -34321,7 +34603,7 @@ async function captureNode(worldId, workspacePath, repo) {
34321
34603
  }
34322
34604
  }
34323
34605
  async function capturePg(worldId, workspacePath, repoNames) {
34324
- const repoDirs = repoNames.map((r) => path47.join(workspacePath, r));
34606
+ const repoDirs = repoNames.map((r) => path48.join(workspacePath, r));
34325
34607
  const fingerprint = computePgFingerprint(repoDirs);
34326
34608
  if (!fingerprint) {
34327
34609
  return { ok: false, tarPath: "", msg: "no Gemfile.lock / schema.rb \u2014 layer does not apply" };
@@ -34336,9 +34618,9 @@ async function capturePg(worldId, workspacePath, repoNames) {
34336
34618
  }
34337
34619
  try {
34338
34620
  execSync11(`docker stop ${containerName}`, { stdio: "pipe", timeout: 3e4 });
34339
- fs45.mkdirSync(path47.dirname(tarPath), { recursive: true });
34621
+ fs45.mkdirSync(path48.dirname(tarPath), { recursive: true });
34340
34622
  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)}'`,
34623
+ `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
34624
  { stdio: "pipe", timeout: 18e4 }
34343
34625
  );
34344
34626
  execSync11(`docker start ${containerName}`, { stdio: "pipe", timeout: 3e4 });
@@ -34373,7 +34655,7 @@ async function handleEvict(opts) {
34373
34655
  const allTars = [];
34374
34656
  const walk3 = (d) => {
34375
34657
  for (const entry of fs45.readdirSync(d, { withFileTypes: true })) {
34376
- const full = path47.join(d, entry.name);
34658
+ const full = path48.join(d, entry.name);
34377
34659
  if (entry.isDirectory()) {
34378
34660
  walk3(full);
34379
34661
  } else if (entry.name.endsWith(".tar.gz")) {
@@ -34472,33 +34754,33 @@ init_context();
34472
34754
  init_output();
34473
34755
  import * as fs47 from "node:fs";
34474
34756
  import * as os25 from "node:os";
34475
- import * as path49 from "node:path";
34757
+ import * as path50 from "node:path";
34476
34758
  import { spawnSync as spawnSync24 } from "node:child_process";
34477
34759
  import ora10 from "ora";
34478
34760
 
34479
34761
  // src/commands/refresh-helpers.ts
34480
34762
  import * as fs46 from "node:fs";
34481
- import * as path48 from "node:path";
34763
+ import * as path49 from "node:path";
34482
34764
  function collectCpSourceFiles(standaloneDir) {
34483
34765
  if (!fs46.existsSync(standaloneDir)) {
34484
34766
  throw new Error(`CP standalone dir not found: ${standaloneDir}`);
34485
34767
  }
34486
34768
  const entries = [];
34487
34769
  const topLevel = fs46.readdirSync(standaloneDir).filter((f) => {
34488
- const stat = fs46.statSync(path48.join(standaloneDir, f));
34770
+ const stat = fs46.statSync(path49.join(standaloneDir, f));
34489
34771
  return stat.isFile() && f.endsWith(".mjs") && !f.endsWith(".test.mjs");
34490
34772
  }).sort();
34491
34773
  for (const f of topLevel) {
34492
- entries.push({ srcPath: path48.join(standaloneDir, f), destRelPath: f });
34774
+ entries.push({ srcPath: path49.join(standaloneDir, f), destRelPath: f });
34493
34775
  }
34494
- const libDir = path48.join(standaloneDir, "lib");
34776
+ const libDir = path49.join(standaloneDir, "lib");
34495
34777
  if (fs46.existsSync(libDir) && fs46.statSync(libDir).isDirectory()) {
34496
34778
  const libFiles = fs46.readdirSync(libDir).filter((f) => {
34497
- const stat = fs46.statSync(path48.join(libDir, f));
34779
+ const stat = fs46.statSync(path49.join(libDir, f));
34498
34780
  return stat.isFile() && f.endsWith(".mjs") && !f.endsWith(".test.mjs");
34499
34781
  }).sort();
34500
34782
  for (const f of libFiles) {
34501
- entries.push({ srcPath: path48.join(libDir, f), destRelPath: `lib/${f}` });
34783
+ entries.push({ srcPath: path49.join(libDir, f), destRelPath: `lib/${f}` });
34502
34784
  }
34503
34785
  }
34504
34786
  return entries;
@@ -34557,15 +34839,15 @@ async function refreshWorld(worldId, portOffset, standaloneDir, opts) {
34557
34839
  };
34558
34840
  }
34559
34841
  const stagingDir = fs47.mkdtempSync(
34560
- path49.join(os25.tmpdir(), `olam-refresh-${worldId}-`)
34842
+ path50.join(os25.tmpdir(), `olam-refresh-${worldId}-`)
34561
34843
  );
34562
34844
  try {
34563
34845
  const hasLib = entries.some((e) => e.destRelPath.startsWith("lib/"));
34564
34846
  if (hasLib) {
34565
- fs47.mkdirSync(path49.join(stagingDir, "lib"), { recursive: true });
34847
+ fs47.mkdirSync(path50.join(stagingDir, "lib"), { recursive: true });
34566
34848
  }
34567
34849
  for (const { srcPath, destRelPath } of entries) {
34568
- fs47.copyFileSync(srcPath, path49.join(stagingDir, destRelPath));
34850
+ fs47.copyFileSync(srcPath, path50.join(stagingDir, destRelPath));
34569
34851
  }
34570
34852
  const cpResult = docker([
34571
34853
  "cp",
@@ -34617,7 +34899,7 @@ function registerRefresh(program2) {
34617
34899
  process.exitCode = 1;
34618
34900
  return;
34619
34901
  }
34620
- const standaloneDir = path49.join(
34902
+ const standaloneDir = path50.join(
34621
34903
  process.cwd(),
34622
34904
  "packages/control-plane/standalone"
34623
34905
  );
@@ -34785,8 +35067,8 @@ function registerRestart(program2) {
34785
35067
  // src/commands/diagnose.ts
34786
35068
  import * as fs48 from "node:fs";
34787
35069
  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";
35070
+ import * as path51 from "node:path";
35071
+ import { execFileSync as execFileSync13, execSync as execSync12 } from "node:child_process";
34790
35072
  import pc25 from "picocolors";
34791
35073
 
34792
35074
  // ../core/dist/diagnose/secret-stripper.js
@@ -34820,9 +35102,9 @@ function stripSecrets(input2) {
34820
35102
  }
34821
35103
 
34822
35104
  // 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");
35105
+ var DIAGNOSTICS_DIR = path51.join(os26.homedir(), ".olam", "diagnostics");
35106
+ var LOG_DIR = path51.join(os26.homedir(), ".olam", "log");
35107
+ var CACHE_DIR = path51.join(os26.homedir(), ".olam", "cache");
34826
35108
  var LOG_TAIL_LINES = 200;
34827
35109
  function safeExec(cmd) {
34828
35110
  try {
@@ -34832,12 +35114,12 @@ function safeExec(cmd) {
34832
35114
  }
34833
35115
  }
34834
35116
  function defaultZip(zipPath, files) {
34835
- execFileSync12("zip", ["-j", zipPath, ...files]);
35117
+ execFileSync13("zip", ["-j", zipPath, ...files]);
34836
35118
  }
34837
35119
  async function buildDiagnosticsZip(_exec = (cmd) => safeExec(cmd), _outDir = DIAGNOSTICS_DIR, _logDir = LOG_DIR, _zip = defaultZip) {
34838
35120
  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-"));
35121
+ const zipPath = path51.join(_outDir, `olam-diag-${ts}.zip`);
35122
+ const tmpDir = fs48.mkdtempSync(path51.join(os26.tmpdir(), "olam-diag-"));
34841
35123
  try {
34842
35124
  fs48.mkdirSync(_outDir, { recursive: true });
34843
35125
  const entries = [];
@@ -34855,7 +35137,7 @@ platform: ${platform2}
34855
35137
  `uptime: ${os26.uptime()}s`
34856
35138
  ].join("\n") + "\n";
34857
35139
  _writeEntry(tmpDir, "os-info.txt", stripSecrets(osContent), entries);
34858
- const depsFile = path50.join(CACHE_DIR, "deps.json");
35140
+ const depsFile = path51.join(CACHE_DIR, "deps.json");
34859
35141
  if (fs48.existsSync(depsFile)) {
34860
35142
  const deps = fs48.readFileSync(depsFile, "utf-8");
34861
35143
  _writeEntry(tmpDir, "deps.json", stripSecrets(deps), entries);
@@ -34874,7 +35156,7 @@ platform: ${platform2}
34874
35156
  if (authAudit) {
34875
35157
  _writeEntry(tmpDir, "audit-auth-callers.txt", stripSecrets(authAudit), entries);
34876
35158
  }
34877
- const fileArgs = entries.map((e) => path50.join(tmpDir, e));
35159
+ const fileArgs = entries.map((e) => path51.join(tmpDir, e));
34878
35160
  try {
34879
35161
  _zip(zipPath, fileArgs);
34880
35162
  } catch (err) {
@@ -34892,17 +35174,17 @@ platform: ${platform2}
34892
35174
  }
34893
35175
  }
34894
35176
  function _writeEntry(dir, name, content, entries) {
34895
- fs48.writeFileSync(path50.join(dir, name), content, { mode: 420 });
35177
+ fs48.writeFileSync(path51.join(dir, name), content, { mode: 420 });
34896
35178
  entries.push(name);
34897
35179
  }
34898
35180
  function _latestLog(logDir) {
34899
35181
  if (!fs48.existsSync(logDir)) return null;
34900
35182
  const files = fs48.readdirSync(logDir).filter((f) => f.startsWith("host-")).sort().reverse();
34901
- return files.length > 0 ? path50.join(logDir, files[0]) : null;
35183
+ return files.length > 0 ? path51.join(logDir, files[0]) : null;
34902
35184
  }
34903
35185
  async function buildTelemetryPayload() {
34904
35186
  const channel = "stable";
34905
- const manifestFile = path50.join(CACHE_DIR, "manifest.json");
35187
+ const manifestFile = path51.join(CACHE_DIR, "manifest.json");
34906
35188
  let manifestAgeHours = null;
34907
35189
  if (fs48.existsSync(manifestFile)) {
34908
35190
  const mtime = fs48.statSync(manifestFile).mtime.getTime();
@@ -35057,8 +35339,8 @@ function checkWorld(container, hostShas, dockerExec) {
35057
35339
  const m = shaLine.match(/^([a-f0-9]{64})\s+(.+)$/);
35058
35340
  if (!m) continue;
35059
35341
  const sha = m[1];
35060
- const path95 = m[2];
35061
- const filename = path95?.split("/").pop();
35342
+ const path96 = m[2];
35343
+ const filename = path96?.split("/").pop();
35062
35344
  if (!filename) continue;
35063
35345
  const mtimeSecs = parseInt(mtimeLine.trim(), 10);
35064
35346
  if (Number.isNaN(mtimeSecs) || !sha) continue;
@@ -35106,28 +35388,28 @@ function resolveRepoRootBestEffort() {
35106
35388
  init_output();
35107
35389
  import * as fs50 from "node:fs";
35108
35390
  import * as net4 from "node:net";
35109
- import * as path52 from "node:path";
35391
+ import * as path53 from "node:path";
35110
35392
  import * as os27 from "node:os";
35111
35393
 
35112
35394
  // src/commands/hermes-kg-hook.ts
35113
35395
  import * as fs49 from "node:fs";
35114
- import * as path51 from "node:path";
35396
+ import * as path52 from "node:path";
35115
35397
  import { createHash as createHash5 } from "node:crypto";
35116
35398
  import { fileURLToPath as fileURLToPath6 } from "node:url";
35117
35399
  var HERMES_KG_HOOK_SENTINEL = "OLAM_KG_HOOK";
35118
35400
  function bundleDir() {
35119
35401
  const thisFile = fileURLToPath6(import.meta.url);
35120
- return path51.resolve(path51.dirname(thisFile), "..", "..", "hermes-bundle");
35402
+ return path52.resolve(path52.dirname(thisFile), "..", "..", "hermes-bundle");
35121
35403
  }
35122
35404
  function templateContent() {
35123
- const templatePath = path51.join(bundleDir(), "kg-first.sh");
35405
+ const templatePath = path52.join(bundleDir(), "kg-first.sh");
35124
35406
  return fs49.readFileSync(templatePath);
35125
35407
  }
35126
35408
  function sha256(buf) {
35127
35409
  return createHash5("sha256").update(buf).digest("hex");
35128
35410
  }
35129
35411
  function installKgFirstHookForHermes(hooksDir, dryRun) {
35130
- const destPath2 = path51.join(hooksDir, "kg-first.sh");
35412
+ const destPath2 = path52.join(hooksDir, "kg-first.sh");
35131
35413
  const template = templateContent();
35132
35414
  if (fs49.existsSync(destPath2)) {
35133
35415
  const existing = fs49.readFileSync(destPath2);
@@ -35203,7 +35485,7 @@ async function runDoctor(opts, deps = {}) {
35203
35485
  if (isK8s) {
35204
35486
  const wrapImpl = deps.kubectlWrapImpl ?? kubectlWrap;
35205
35487
  const k8sCtx = deps.kubectlContext;
35206
- const manifestsDir = deps.manifestsDir ?? path52.join(OLAM_HOME, "k8s", "manifests");
35488
+ const manifestsDir = deps.manifestsDir ?? path53.join(OLAM_HOME, "k8s", "manifests");
35207
35489
  const readFileSyncImpl = deps.readFileSyncImpl ?? fs50.readFileSync;
35208
35490
  const sortedPeripherals = [...PERIPHERALS].sort((a, b) => a.name.localeCompare(b.name));
35209
35491
  let peripheralPosition = 14;
@@ -35340,7 +35622,7 @@ async function probeStorageClassMatch(peripherals, kubectlContext, manifestsDir,
35340
35622
  const ctxArgs = kubectlContext ? ["--context", kubectlContext] : [];
35341
35623
  const mismatches = [];
35342
35624
  for (const peripheral of peripherals) {
35343
- const pvcManifestPath = path52.join(manifestsDir, peripheral.name, "45-pvc.yaml");
35625
+ const pvcManifestPath = path53.join(manifestsDir, peripheral.name, "45-pvc.yaml");
35344
35626
  let declaredClass;
35345
35627
  try {
35346
35628
  const raw = readFileSyncImpl(pvcManifestPath, "utf8");
@@ -35453,7 +35735,7 @@ function probeNodeMemory(dockerExec, kubectlContext) {
35453
35735
  function defaultResolveHostSideProxyComposePath() {
35454
35736
  const root = resolveK8sAssetsRoot();
35455
35737
  if (root === null) return null;
35456
- const candidate = path52.join(root, "host-side", "docker-socket-proxy.compose.yaml");
35738
+ const candidate = path53.join(root, "host-side", "docker-socket-proxy.compose.yaml");
35457
35739
  return fs50.existsSync(candidate) ? candidate : null;
35458
35740
  }
35459
35741
  async function defaultDockerSocketCheck(composePath) {
@@ -35590,8 +35872,8 @@ function renderHuman(report) {
35590
35872
  }
35591
35873
  }
35592
35874
  function probeHermesIntegration(hermesDir) {
35593
- const configPath = path52.join(hermesDir, "config.yaml");
35594
- const hookPath = path52.join(hermesDir, "hooks", "kg-first.sh");
35875
+ const configPath = path53.join(hermesDir, "config.yaml");
35876
+ const hookPath = path53.join(hermesDir, "hooks", "kg-first.sh");
35595
35877
  const issues = [];
35596
35878
  if (!fs50.existsSync(configPath)) {
35597
35879
  issues.push("~/.hermes/config.yaml not found");
@@ -35632,7 +35914,7 @@ function registerDoctor(program2) {
35632
35914
  program2.command("doctor").description(
35633
35915
  "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
35916
  ).option("--json", "emit the report as JSON instead of a human-readable table").action(async (opts) => {
35635
- const hermesDir = path52.join(os27.homedir(), ".hermes");
35917
+ const hermesDir = path53.join(os27.homedir(), ".hermes");
35636
35918
  const r = await runDoctor(opts, {
35637
35919
  // Pass hermesHomeOverride so the probe fires when ~/.hermes/ exists.
35638
35920
  // When the dir is absent the probe is skipped; when present it WARNs
@@ -35907,7 +36189,7 @@ function registerSubstrate(program2) {
35907
36189
 
35908
36190
  // ../cli-plugin-tasks/dist/client.js
35909
36191
  import { readFileSync as readFileSync46 } from "node:fs";
35910
- import { homedir as homedir30 } from "node:os";
36192
+ import { homedir as homedir31 } from "node:os";
35911
36193
  import { join as join61 } from "node:path";
35912
36194
  var TasksClient = class {
35913
36195
  baseUrl;
@@ -35916,7 +36198,7 @@ var TasksClient = class {
35916
36198
  sessionId;
35917
36199
  constructor(opts) {
35918
36200
  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");
36201
+ const tokenPath2 = opts.tokenPath ?? join61(homedir31(), ".olam", "host-cp.token");
35920
36202
  try {
35921
36203
  this.token = readFileSync46(tokenPath2, "utf8").trim();
35922
36204
  } catch (e) {
@@ -35925,9 +36207,9 @@ var TasksClient = class {
35925
36207
  this.olamNodeId = opts.olamNodeId;
35926
36208
  this.sessionId = opts.sessionId;
35927
36209
  }
35928
- async call(method, path95, scopes, body, query) {
36210
+ async call(method, path96, scopes, body, query) {
35929
36211
  const qs = query ? "?" + new URLSearchParams(Object.entries(query).filter(([, v]) => v !== void 0)).toString() : "";
35930
- const url2 = `${this.baseUrl}${path95}${qs}`;
36212
+ const url2 = `${this.baseUrl}${path96}${qs}`;
35931
36213
  const res = await fetch(url2, {
35932
36214
  method,
35933
36215
  headers: {
@@ -35978,8 +36260,8 @@ function parseFrontmatter2(raw) {
35978
36260
  }
35979
36261
  return { frontmatter: fm, body };
35980
36262
  }
35981
- function parseTracker(path95) {
35982
- const raw = readFileSync47(path95, "utf8");
36263
+ function parseTracker(path96) {
36264
+ const raw = readFileSync47(path96, "utf8");
35983
36265
  const { frontmatter, body } = parseFrontmatter2(raw);
35984
36266
  const lines = body.split("\n");
35985
36267
  const tasks = [];
@@ -36216,8 +36498,8 @@ function registerTasks(program2) {
36216
36498
  `);
36217
36499
  }
36218
36500
  });
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);
36501
+ 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) => {
36502
+ const parsed = parseTracker(path96);
36221
36503
  if (opts.dryRun) {
36222
36504
  process.stdout.write(JSON.stringify(parsed, null, 2) + "\n");
36223
36505
  return;
@@ -36371,15 +36653,76 @@ function registerCompletion(program2) {
36371
36653
  // src/commands/setup.ts
36372
36654
  init_cli_version();
36373
36655
  init_health_probes();
36374
- import { spawn as spawn7, spawnSync as spawnSync26 } from "node:child_process";
36656
+ import { spawn as spawn7, spawnSync as spawnSync27 } from "node:child_process";
36375
36657
  import { existsSync as existsSync85, readFileSync as readFileSync70 } from "node:fs";
36376
- import { homedir as homedir44 } from "node:os";
36377
- import path76 from "node:path";
36658
+ import { homedir as homedir45 } from "node:os";
36659
+ import path77 from "node:path";
36378
36660
  import { createInterface as createInterface3 } from "node:readline";
36379
36661
 
36662
+ // src/lib/k8s-context-discovery.ts
36663
+ import { spawnSync as spawnSync26 } from "node:child_process";
36664
+ var OLAM_MANAGED_CONTEXT_PREFIX = "k3d-olam-";
36665
+ function isOlamManagedContext(name) {
36666
+ return name.startsWith(OLAM_MANAGED_CONTEXT_PREFIX);
36667
+ }
36668
+ function defaultGetContexts() {
36669
+ const r = spawnSync26(
36670
+ "kubectl",
36671
+ ["config", "get-contexts", "-o", "name"],
36672
+ { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }
36673
+ );
36674
+ if (r.status !== 0 || !r.stdout) return [];
36675
+ return r.stdout.split("\n").map((l) => l.trim()).filter(Boolean);
36676
+ }
36677
+ function defaultClusterInfo(context) {
36678
+ const r = spawnSync26(
36679
+ "kubectl",
36680
+ ["--context", context, "cluster-info", "--request-timeout=3s"],
36681
+ { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }
36682
+ );
36683
+ if (r.status === 0) {
36684
+ const match2 = r.stdout.match(/running at (https?:\/\/\S+)/i);
36685
+ return { reachable: true, serverUrl: match2?.[1] };
36686
+ }
36687
+ const err = (r.stderr || "").trim().slice(0, 200);
36688
+ return { reachable: false, error: err || "cluster-info failed" };
36689
+ }
36690
+ function defaultIsIdle(context) {
36691
+ const nsResult = spawnSync26(
36692
+ "kubectl",
36693
+ ["--context", context, "get", "namespace", "olam", "--ignore-not-found", "-o", "name"],
36694
+ { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }
36695
+ );
36696
+ const nsLine = (nsResult.stdout || "").trim();
36697
+ if (!nsLine) {
36698
+ return true;
36699
+ }
36700
+ const podsResult = spawnSync26(
36701
+ "kubectl",
36702
+ ["--context", context, "get", "pods", "-n", "olam", "--no-headers"],
36703
+ { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }
36704
+ );
36705
+ const podsOut = (podsResult.stdout || "").trim();
36706
+ return !podsOut || /no resources found/i.test(podsOut);
36707
+ }
36708
+ function discoverOfferableContexts(deps = {}) {
36709
+ const getContextsFn = deps.getContexts ?? defaultGetContexts;
36710
+ const clusterInfoFn = deps.clusterInfo ?? defaultClusterInfo;
36711
+ const isIdleFn = deps.isIdle ?? defaultIsIdle;
36712
+ const allContexts = getContextsFn();
36713
+ const offerable = [];
36714
+ for (const ctx of allContexts) {
36715
+ if (isOlamManagedContext(ctx)) continue;
36716
+ const probe2 = clusterInfoFn(ctx);
36717
+ if (!probe2.reachable) continue;
36718
+ if (isIdleFn(ctx)) offerable.push(ctx);
36719
+ }
36720
+ return { offerable, allContexts };
36721
+ }
36722
+
36380
36723
  // src/lib/shell-rc.ts
36381
36724
  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";
36725
+ import path54 from "node:path";
36383
36726
  function appendIdempotent(opts) {
36384
36727
  const { rcPath, marker, contentLine, clock = () => /* @__PURE__ */ new Date() } = opts;
36385
36728
  if (!existsSync60(rcPath)) {
@@ -36402,9 +36745,9 @@ function appendIdempotent(opts) {
36402
36745
  }
36403
36746
  function resolveShellRc(home, shellEnv) {
36404
36747
  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");
36748
+ const basename16 = path54.basename(shellEnv);
36749
+ if (basename16 === "zsh") return path54.join(home, ".zshrc");
36750
+ if (basename16 === "bash") return path54.join(home, ".bashrc");
36408
36751
  return null;
36409
36752
  }
36410
36753
 
@@ -36563,8 +36906,8 @@ async function pickSkillSourcePhase(opts, deps) {
36563
36906
  }
36564
36907
 
36565
36908
  // src/commands/setup-phase-5b-project-sweep.ts
36566
- import { homedir as homedir43 } from "node:os";
36567
- import * as path75 from "node:path";
36909
+ import { homedir as homedir44 } from "node:os";
36910
+ import * as path76 from "node:path";
36568
36911
  import * as fs75 from "node:fs";
36569
36912
  async function loadWalkFn() {
36570
36913
  const m = await Promise.resolve().then(() => (init_project_sweep(), project_sweep_exports));
@@ -36583,9 +36926,9 @@ async function loadAppendTrustAuditFn() {
36583
36926
  return m.appendTrustAudit;
36584
36927
  }
36585
36928
  function deriveRepoName(repoPath, existingNames) {
36586
- const base = path75.basename(repoPath).toLowerCase().replace(/[^a-z0-9-]/g, "-");
36929
+ const base = path76.basename(repoPath).toLowerCase().replace(/[^a-z0-9-]/g, "-");
36587
36930
  if (!existingNames.has(base)) return base;
36588
- const parent = path75.basename(path75.dirname(repoPath)).toLowerCase().replace(/[^a-z0-9-]/g, "-");
36931
+ const parent = path76.basename(path76.dirname(repoPath)).toLowerCase().replace(/[^a-z0-9-]/g, "-");
36589
36932
  const composite = `${parent}-${base}`;
36590
36933
  if (!existingNames.has(composite)) return composite;
36591
36934
  let suffix = 2;
@@ -36596,8 +36939,8 @@ async function runProjectSweepPhase(opts, deps, sweepDeps = {}) {
36596
36939
  if (opts.skipProjectSweep) {
36597
36940
  return { ok: true, skipped: true, message: "skipped via --skip-project-sweep" };
36598
36941
  }
36599
- const home = deps.home ?? homedir43();
36600
- const projectsRoot = opts.projects ?? path75.join(home, "Projects");
36942
+ const home = deps.home ?? homedir44();
36943
+ const projectsRoot = opts.projects ?? path76.join(home, "Projects");
36601
36944
  const existsSyncFn = sweepDeps.existsSync ?? fs75.existsSync;
36602
36945
  if (!existsSyncFn(projectsRoot)) {
36603
36946
  return {
@@ -36771,6 +37114,67 @@ function resolveSubstrate(opts, deps) {
36771
37114
  }
36772
37115
  return "kubernetes";
36773
37116
  }
37117
+ async function phase0_5DetectExistingContext(substrate, opts, deps) {
37118
+ if (substrate !== "kubernetes") {
37119
+ return { ok: true, skipped: true, message: "no-op for docker substrate" };
37120
+ }
37121
+ if (opts.reuseCluster) {
37122
+ const name = opts.reuseCluster;
37123
+ const clusterInfoFn = deps.kubectlClusterInfo ?? defaultClusterInfo;
37124
+ const probe2 = clusterInfoFn(name);
37125
+ if (!probe2.reachable) {
37126
+ return {
37127
+ ok: false,
37128
+ message: `--reuse-cluster=${name} but context is not reachable: ${probe2.error ?? "unknown error"}`,
37129
+ 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}\`.`,
37130
+ reuseContext: void 0
37131
+ };
37132
+ }
37133
+ return {
37134
+ ok: true,
37135
+ message: `will reuse context ${name}${probe2.serverUrl ? ` (${probe2.serverUrl})` : ""}`,
37136
+ reuseContext: name
37137
+ };
37138
+ }
37139
+ const { offerable } = discoverOfferableContexts(deps.kubeContextDeps);
37140
+ if (offerable.length === 0) {
37141
+ return {
37142
+ ok: true,
37143
+ skipped: true,
37144
+ message: "no idle reachable contexts detected; will provision k3d cluster"
37145
+ };
37146
+ }
37147
+ if (opts.yes) {
37148
+ process.stdout.write(
37149
+ ` Detected ${offerable.length} existing Kubernetes context(s): ${offerable.join(", ")}. To reuse one, pass --reuse-cluster=<name>. Provisioning k3d (--yes default).
37150
+ `
37151
+ );
37152
+ return {
37153
+ ok: true,
37154
+ skipped: true,
37155
+ message: `idle context(s) available but --yes defaults to k3d provision; use --reuse-cluster=<name> to opt in`
37156
+ };
37157
+ }
37158
+ const promptFn = deps.prompt ?? defaultPrompt;
37159
+ for (const ctx of offerable) {
37160
+ const reuse = await promptFn(
37161
+ `Detected existing Kubernetes context \`${ctx}\`. Use this cluster instead of provisioning a new k3d cluster?`,
37162
+ false
37163
+ );
37164
+ if (reuse) {
37165
+ return {
37166
+ ok: true,
37167
+ message: `operator chose to reuse context ${ctx}`,
37168
+ reuseContext: ctx
37169
+ };
37170
+ }
37171
+ }
37172
+ return {
37173
+ ok: true,
37174
+ skipped: true,
37175
+ message: "operator declined reuse; will provision k3d cluster"
37176
+ };
37177
+ }
36774
37178
  async function phase1SystemCheck(substrate, deps) {
36775
37179
  const nodeVersion = deps.nodeVersion ?? process.version;
36776
37180
  const nodeMajor = parseNodeMajor(nodeVersion);
@@ -36795,6 +37199,13 @@ async function phase1SystemCheck(substrate, deps) {
36795
37199
  remedy: `Install Node.js ${REQUIRED_NODE_MAJOR}+ LTS via nvm/fnm/asdf and re-run \`olam setup\`.`
36796
37200
  };
36797
37201
  }
37202
+ const platform2 = String(deps.osPlatform ?? process.platform);
37203
+ const home = deps.home ?? homedir45();
37204
+ const colimaLint = probeColimaKubernetesEnabled({ platform: platform2, home });
37205
+ if (colimaLint.ok && "warn" in colimaLint && colimaLint.warn === true) {
37206
+ const lintWithWarn = colimaLint;
37207
+ printWarning(` \u26A0 ${lintWithWarn.remedy}`);
37208
+ }
36798
37209
  return { ok: true, message: `kubectl on PATH; docker ready; node ${nodeVersion}` };
36799
37210
  }
36800
37211
  const dockerProbe = await probeDockerDaemon(deps.dockerExec);
@@ -36817,17 +37228,24 @@ async function phase1SystemCheck(substrate, deps) {
36817
37228
  message: `${dockerProbe.message}; ${composeProbe.message}; node ${nodeVersion}`
36818
37229
  };
36819
37230
  }
36820
- async function phase1_5InstallSubstrate(substrate, opts, deps) {
37231
+ async function phase1_5InstallSubstrate(substrate, opts, deps, reuseContext) {
36821
37232
  if (substrate === "docker") {
36822
37233
  return { ok: true, skipped: true, message: "no-op for docker substrate" };
36823
37234
  }
37235
+ if (reuseContext) {
37236
+ return {
37237
+ ok: true,
37238
+ skipped: true,
37239
+ message: `skipped k3d install (reusing context ${reuseContext})`
37240
+ };
37241
+ }
36824
37242
  const spawnFn = deps.spawnSubprocess ?? defaultSpawn;
36825
37243
  const promptFn = deps.prompt ?? defaultPrompt;
36826
37244
  const k3dProbe = await probeK3d(deps.dockerExec);
36827
37245
  if (k3dProbe.ok) {
36828
37246
  return { ok: true, message: `k3d already present: ${k3dProbe.message}` };
36829
37247
  }
36830
- const hasBrew = spawnSync26("command", ["-v", "brew"], { shell: true, stdio: "pipe" }).status === 0;
37248
+ const hasBrew = spawnSync27("command", ["-v", "brew"], { shell: true, stdio: "pipe" }).status === 0;
36831
37249
  const useBrewMsg = hasBrew ? "Homebrew" : "upstream install script";
36832
37250
  if (!opts.yes) {
36833
37251
  const confirmed = await promptFn(
@@ -36886,10 +37304,17 @@ function phaseFromProbe(probe2) {
36886
37304
  if (probe2.ok) return { ok: true, message: probe2.message };
36887
37305
  return { ok: false, message: probe2.message, remedy: probe2.remedy };
36888
37306
  }
36889
- async function phase2_5ProvisionCluster(substrate, clusterName, opts, deps) {
37307
+ async function phase2_5ProvisionCluster(substrate, clusterName, opts, deps, reuseContext) {
36890
37308
  if (substrate === "docker") {
36891
37309
  return { ok: true, skipped: true, message: "no-op for docker substrate" };
36892
37310
  }
37311
+ if (reuseContext) {
37312
+ return {
37313
+ ok: true,
37314
+ skipped: true,
37315
+ message: `skipped k3d cluster provision (reusing context ${reuseContext})`
37316
+ };
37317
+ }
36893
37318
  const spawnFn = deps.spawnSubprocess ?? defaultSpawn;
36894
37319
  const listResult = await captureSpawn("k3d", ["cluster", "list", "--output", "json"], deps.dockerExec);
36895
37320
  if (listResult.ok) {
@@ -36903,7 +37328,7 @@ async function phase2_5ProvisionCluster(substrate, clusterName, opts, deps) {
36903
37328
  }
36904
37329
  process.stdout.write(`Creating k3d cluster ${clusterName}...
36905
37330
  `);
36906
- const ghConfigBind = `${homedir44()}/.config/gh:/host/.config/gh`;
37331
+ const ghConfigBind = `${homedir45()}/.config/gh:/host/.config/gh`;
36907
37332
  const createResult = await spawnFn("k3d", [
36908
37333
  "cluster",
36909
37334
  "create",
@@ -36927,14 +37352,14 @@ async function phase2_5ProvisionCluster(substrate, clusterName, opts, deps) {
36927
37352
  }
36928
37353
  async function captureSpawn(cmd, args, dockerExec) {
36929
37354
  const exec = dockerExec ?? ((c, a) => {
36930
- const r2 = spawnSync26(c, [...a], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
37355
+ const r2 = spawnSync27(c, [...a], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
36931
37356
  return { status: r2.status, stdout: r2.stdout ?? "", stderr: r2.stderr ?? "" };
36932
37357
  });
36933
37358
  const r = exec(cmd, args);
36934
37359
  return { ok: r.status === 0, stdout: r.stdout, stderr: r.stderr };
36935
37360
  }
36936
37361
  function captureSpawnSync(cmd, args) {
36937
- const r = spawnSync26(cmd, [...args], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
37362
+ const r = spawnSync27(cmd, [...args], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
36938
37363
  return { ok: r.status === 0, stdout: r.stdout ?? "" };
36939
37364
  }
36940
37365
  function clusterExistsInList(json, clusterName) {
@@ -36963,11 +37388,11 @@ function safeReadCliVersion() {
36963
37388
  return null;
36964
37389
  }
36965
37390
  }
36966
- async function phase2_6PinKubectlContext(substrate, clusterName, deps) {
37391
+ async function phase2_6PinKubectlContext(substrate, clusterName, deps, reuseContext) {
36967
37392
  if (substrate !== "kubernetes") {
36968
37393
  return { ok: true, skipped: true, message: "no-op for docker substrate" };
36969
37394
  }
36970
- const expectedContext = `k3d-${clusterName}`;
37395
+ const expectedContext = reuseContext ?? `k3d-${clusterName}`;
36971
37396
  writeConfig({ host: { substrate: "kubernetes" } }, { configPath: deps.configPath });
36972
37397
  const result = applyKubectlContextPin([expectedContext], {
36973
37398
  configPath: deps.configPath
@@ -37004,7 +37429,7 @@ async function phase4ShellInit(opts, deps) {
37004
37429
  if (opts.skipShellInit) {
37005
37430
  return { ok: true, skipped: true, message: "skipped via --skip-shell-init" };
37006
37431
  }
37007
- const home = deps.home ?? homedir44();
37432
+ const home = deps.home ?? homedir45();
37008
37433
  const shellEnv = deps.shellEnv ?? process.env.SHELL;
37009
37434
  const rcPath = resolveShellRc(home, shellEnv);
37010
37435
  if (rcPath === null) {
@@ -37014,7 +37439,7 @@ async function phase4ShellInit(opts, deps) {
37014
37439
  message: `unsupported $SHELL (${shellEnv ?? "unset"}); add \`eval "$(olam completion <shell>)"\` to your shell rc manually`
37015
37440
  };
37016
37441
  }
37017
- const shellBasename = path76.basename(shellEnv);
37442
+ const shellBasename = path77.basename(shellEnv);
37018
37443
  const evalLine = `eval "$(olam completion ${shellBasename})"`;
37019
37444
  const result = appendIdempotent({
37020
37445
  rcPath,
@@ -37040,7 +37465,7 @@ async function phase4ShellInit(opts, deps) {
37040
37465
  async function phase5InitProject(opts, deps) {
37041
37466
  const cwd = deps.cwd ?? process.cwd();
37042
37467
  const projectRoot = findProjectRoot(cwd);
37043
- const configPath = path76.join(projectRoot, ".olam", "config.yaml");
37468
+ const configPath = path77.join(projectRoot, ".olam", "config.yaml");
37044
37469
  if (existsSync85(configPath)) {
37045
37470
  return { ok: true, message: `${configPath} present (no change)` };
37046
37471
  }
@@ -37119,7 +37544,8 @@ async function phase7Verify(opts, deps) {
37119
37544
  remedy: "Inspect doctor output above; the specific failing probe names its remedy."
37120
37545
  };
37121
37546
  }
37122
- var PHASE_TITLES_DOCKER = [
37547
+ var PHASE_TITLES = [
37548
+ "Phase 0.5: Detect existing k8s context",
37123
37549
  "Phase 1: System check",
37124
37550
  "Phase 1.5: Substrate tools install",
37125
37551
  "Phase 2: olam CLI sanity",
@@ -37157,12 +37583,32 @@ async function runSetup(opts, deps = {}) {
37157
37583
  process.stdout.write(`cluster: ${clusterName}
37158
37584
  `);
37159
37585
  }
37586
+ const results = [];
37587
+ let failureAt = null;
37588
+ const phase0_5Title = PHASE_TITLES[0];
37589
+ process.stdout.write(`
37590
+ ${phase0_5Title}
37591
+ `);
37592
+ const phase0_5Result = await phase0_5DetectExistingContext(substrate, opts, deps);
37593
+ results.push({ name: phase0_5Title, result: phase0_5Result });
37594
+ if (phase0_5Result.ok && phase0_5Result.skipped) {
37595
+ printWarning(` \u2298 ${phase0_5Result.message}`);
37596
+ } else if (phase0_5Result.ok) {
37597
+ printSuccess(` \u2713 ${phase0_5Result.message}`);
37598
+ } else {
37599
+ printError(` \u2717 ${phase0_5Result.message}`);
37600
+ if (phase0_5Result.remedy) printWarning(` remedy: ${phase0_5Result.remedy}`);
37601
+ process.stdout.write("\n");
37602
+ printError("Setup FAILED at Phase 1");
37603
+ return { phases: results, failureAt: 1, exitCode: 1 };
37604
+ }
37605
+ const reuseContext = phase0_5Result.reuseContext;
37160
37606
  const phaseFns = [
37161
37607
  () => phase1SystemCheck(substrate, deps),
37162
- () => phase1_5InstallSubstrate(substrate, opts, deps),
37608
+ () => phase1_5InstallSubstrate(substrate, opts, deps, reuseContext),
37163
37609
  () => phase2CliSanity(deps),
37164
- () => phase2_5ProvisionCluster(substrate, clusterName, opts, deps),
37165
- () => phase2_6PinKubectlContext(substrate, clusterName, deps),
37610
+ () => phase2_5ProvisionCluster(substrate, clusterName, opts, deps, reuseContext),
37611
+ () => phase2_6PinKubectlContext(substrate, clusterName, deps, reuseContext),
37166
37612
  () => phase3Bootstrap(substrate, deps),
37167
37613
  () => phase4ShellInit(opts, deps),
37168
37614
  () => phase5InitProject(opts, deps),
@@ -37171,10 +37617,8 @@ async function runSetup(opts, deps = {}) {
37171
37617
  () => phase6Auth(opts, deps),
37172
37618
  () => phase7Verify(opts, deps)
37173
37619
  ];
37174
- const results = [];
37175
- let failureAt = null;
37176
37620
  for (let i = 0; i < phaseFns.length; i += 1) {
37177
- const name = PHASE_TITLES_DOCKER[i];
37621
+ const name = PHASE_TITLES[i + 1];
37178
37622
  process.stdout.write(`
37179
37623
  ${name}
37180
37624
  `);
@@ -37187,7 +37631,7 @@ ${name}
37187
37631
  } else {
37188
37632
  printError(` \u2717 ${result.message}`);
37189
37633
  if (result.remedy) printWarning(` remedy: ${result.remedy}`);
37190
- failureAt = i + 1;
37634
+ failureAt = i + 2;
37191
37635
  break;
37192
37636
  }
37193
37637
  }
@@ -37214,6 +37658,9 @@ function registerSetup(program2) {
37214
37658
  ).option(
37215
37659
  "--cluster-name <name>",
37216
37660
  "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."
37661
+ ).option(
37662
+ "--reuse-cluster <name>",
37663
+ "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
37664
  ).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
37665
  "--skip-doctor",
37219
37666
  "Skip Phase 7 final `olam doctor` verification (for CI or minimal setups)"
@@ -37412,13 +37859,13 @@ function registerSetupLinuxGate(program2) {
37412
37859
  // src/commands/update.ts
37413
37860
  import * as fs78 from "node:fs";
37414
37861
  import * as os42 from "node:os";
37415
- import * as path79 from "node:path";
37862
+ import * as path80 from "node:path";
37416
37863
  import { execSync as execSync14 } from "node:child_process";
37417
37864
  import pc28 from "picocolors";
37418
37865
 
37419
37866
  // src/lib/symlink-reconcile.ts
37420
37867
  import * as fs76 from "node:fs";
37421
- import * as path77 from "node:path";
37868
+ import * as path78 from "node:path";
37422
37869
  var realFs = {
37423
37870
  readdirSync: (p) => fs76.readdirSync(p),
37424
37871
  existsSync: (p) => fs76.existsSync(p),
@@ -37437,8 +37884,8 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir2, _fs = realFs) {
37437
37884
  _fs.mkdirSync(claudeSkillsDir2, { recursive: true });
37438
37885
  const sourceSkills = _fs.existsSync(npmSkillsDir) ? _fs.readdirSync(npmSkillsDir).filter((d) => d.startsWith("olam-")) : [];
37439
37886
  for (const skill of sourceSkills) {
37440
- const linkPath = path77.join(claudeSkillsDir2, skill);
37441
- const target = path77.join(npmSkillsDir, skill);
37887
+ const linkPath = path78.join(claudeSkillsDir2, skill);
37888
+ const target = path78.join(npmSkillsDir, skill);
37442
37889
  if (!_fs.existsSync(linkPath)) {
37443
37890
  try {
37444
37891
  _fs.symlinkSync(target, linkPath);
@@ -37451,7 +37898,7 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir2, _fs = realFs) {
37451
37898
  }
37452
37899
  const deployedEntries = _fs.existsSync(claudeSkillsDir2) ? _fs.readdirSync(claudeSkillsDir2).filter((d) => d.startsWith("olam-")) : [];
37453
37900
  for (const entry of deployedEntries) {
37454
- const linkPath = path77.join(claudeSkillsDir2, entry);
37901
+ const linkPath = path78.join(claudeSkillsDir2, entry);
37455
37902
  let isSymlink = false;
37456
37903
  try {
37457
37904
  isSymlink = _fs.lstatSync(linkPath).isSymbolicLink();
@@ -37476,9 +37923,9 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir2, _fs = realFs) {
37476
37923
 
37477
37924
  // src/commands/update.ts
37478
37925
  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");
37926
+ var CACHE_DIR2 = path80.join(os42.homedir(), ".olam", "cache");
37927
+ var LOG_DIR2 = path80.join(os42.homedir(), ".olam", "log");
37928
+ var LAST_STABLE_FILE = path80.join(CACHE_DIR2, "last-stable.txt");
37482
37929
  function defaultExec(cmd) {
37483
37930
  try {
37484
37931
  const stdout = execSync14(cmd, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
@@ -37507,12 +37954,12 @@ function readLastStable(file = LAST_STABLE_FILE) {
37507
37954
  }
37508
37955
  }
37509
37956
  function writeLastStable(version, file = LAST_STABLE_FILE) {
37510
- fs78.mkdirSync(path79.dirname(file), { recursive: true });
37957
+ fs78.mkdirSync(path80.dirname(file), { recursive: true });
37511
37958
  fs78.writeFileSync(file, version, { mode: 420 });
37512
37959
  }
37513
37960
  function logUpdateFailure(stderr) {
37514
37961
  const ts = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
37515
- const logFile = path79.join(LOG_DIR2, `update-${ts}.log`);
37962
+ const logFile = path80.join(LOG_DIR2, `update-${ts}.log`);
37516
37963
  try {
37517
37964
  fs78.mkdirSync(LOG_DIR2, { recursive: true });
37518
37965
  fs78.appendFileSync(logFile, `[update-failure ${(/* @__PURE__ */ new Date()).toISOString()}]
@@ -37602,8 +38049,8 @@ async function doUpdate(opts, _exec = defaultExec, _reconcile = reconcileSkillSy
37602
38049
  let symlinkResult = { added: [], removed: [] };
37603
38050
  if (npmRootResult.exitCode === 0) {
37604
38051
  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");
38052
+ const npmSkillsDir = path80.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills");
38053
+ const claudeSkillsDir2 = path80.join(os42.homedir(), ".claude", "skills");
37607
38054
  const rec = _reconcile(npmSkillsDir, claudeSkillsDir2);
37608
38055
  symlinkResult = { added: rec.added, removed: rec.removed };
37609
38056
  if (!quiet && (rec.added.length > 0 || rec.removed.length > 0)) {
@@ -37649,8 +38096,8 @@ async function doRollback(_exec = defaultExec, _reconcile = reconcileSkillSymlin
37649
38096
  if (npmRootResult.exitCode === 0) {
37650
38097
  const npmRoot = npmRootResult.stdout.trim();
37651
38098
  _reconcile(
37652
- path79.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills"),
37653
- path79.join(os42.homedir(), ".claude", "skills")
38099
+ path80.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills"),
38100
+ path80.join(os42.homedir(), ".claude", "skills")
37654
38101
  );
37655
38102
  }
37656
38103
  return { action: "rolled-back", restoredVersion: prev, exitCode: 0 };
@@ -38007,7 +38454,7 @@ import pc32 from "picocolors";
38007
38454
 
38008
38455
  // src/commands/flywheel/install-shims.ts
38009
38456
  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";
38457
+ import { homedir as homedir48 } from "node:os";
38011
38458
  import { dirname as dirname48, join as join87 } from "node:path";
38012
38459
 
38013
38460
  // src/lib/shim-generator.ts
@@ -38071,7 +38518,7 @@ ${argsBlock}
38071
38518
  // src/commands/flywheel/install-shims.ts
38072
38519
  var SHIM_HEADER_MARKER = "# AUTO-GENERATED by `olam flywheel install-shims`";
38073
38520
  function refreshShims(opts = {}) {
38074
- const targetDir = opts.targetDir ?? join87(homedir47(), ".claude", "scripts");
38521
+ const targetDir = opts.targetDir ?? join87(homedir48(), ".claude", "scripts");
38075
38522
  const results = [];
38076
38523
  let written = 0;
38077
38524
  let overwritten = 0;
@@ -38132,7 +38579,7 @@ function installOne(spec, targetDir, opts) {
38132
38579
  }
38133
38580
  function registerFlywheelInstallShims(parent) {
38134
38581
  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");
38582
+ const targetDir = opts.targetDir ?? join87(homedir48(), ".claude", "scripts");
38136
38583
  const summary2 = refreshShims(opts);
38137
38584
  const lines = [];
38138
38585
  const dryRunSuffix = opts.dryRun === true ? " (dry-run)" : "";
@@ -38757,7 +39204,7 @@ init_skill_sources();
38757
39204
  init_output();
38758
39205
  import * as fs80 from "node:fs";
38759
39206
  import * as os43 from "node:os";
38760
- import * as path80 from "node:path";
39207
+ import * as path81 from "node:path";
38761
39208
  import * as readline3 from "node:readline";
38762
39209
  import pc33 from "picocolors";
38763
39210
 
@@ -38776,7 +39223,7 @@ import {
38776
39223
  statSync as statSync27,
38777
39224
  writeFileSync as writeFileSync45
38778
39225
  } from "node:fs";
38779
- import { homedir as homedir48 } from "node:os";
39226
+ import { homedir as homedir49 } from "node:os";
38780
39227
  import { basename as basename8, dirname as dirname49, isAbsolute as isAbsolute4, join as join88, relative as relative5, resolve as resolve21 } from "node:path";
38781
39228
 
38782
39229
  // src/commands/flywheel/sanitize-persona-output.ts
@@ -38839,7 +39286,7 @@ function registerFlywheelSanitizePersonaOutput(parent) {
38839
39286
 
38840
39287
  // src/lib/skills-apply-overlays.ts
38841
39288
  function claudeRoot(opts) {
38842
- return opts.claudeDir ?? opts.fixtureRoot ?? join88(homedir48(), ".claude");
39289
+ return opts.claudeDir ?? opts.fixtureRoot ?? join88(homedir49(), ".claude");
38843
39290
  }
38844
39291
  function ensureRealDir(p) {
38845
39292
  if (!existsSync90(p)) {
@@ -39036,12 +39483,12 @@ function asMessage4(err) {
39036
39483
  }
39037
39484
  var ATLAS_USER_PICKER_RE = /^[a-z0-9][a-z0-9_-]{0,38}$/;
39038
39485
  function listMemberNames(clonePath) {
39039
- const membersDir = path80.join(clonePath, "members");
39486
+ const membersDir = path81.join(clonePath, "members");
39040
39487
  if (!fs80.existsSync(membersDir)) return [];
39041
39488
  try {
39042
39489
  return fs80.readdirSync(membersDir).filter((e) => {
39043
39490
  try {
39044
- return fs80.statSync(path80.join(membersDir, e)).isDirectory();
39491
+ return fs80.statSync(path81.join(membersDir, e)).isDirectory();
39045
39492
  } catch {
39046
39493
  return false;
39047
39494
  }
@@ -39090,8 +39537,8 @@ function defaultAtlasUserPrompt(question) {
39090
39537
  async function resolveAtlasUserWithPicker(cliOverride, opts) {
39091
39538
  if (cliOverride !== void 0) return cliOverride;
39092
39539
  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");
39540
+ const claudeDirPathForRead = opts?._testClaudeDir ?? (process.env["OLAM_CLAUDE_DIR"] ?? path81.join(os43.homedir(), ".claude"));
39541
+ const atlasUserFile = path81.join(claudeDirPathForRead, ".atlas-user");
39095
39542
  if (fs80.existsSync(atlasUserFile)) {
39096
39543
  const existing = fs80.readFileSync(atlasUserFile, "utf-8").trim();
39097
39544
  if (existing.length > 0) {
@@ -39152,10 +39599,10 @@ async function resolveAtlasUserWithPicker(cliOverride, opts) {
39152
39599
  );
39153
39600
  return void 0;
39154
39601
  }
39155
- const claudeDirPath = opts?._testClaudeDir ?? (process.env["OLAM_CLAUDE_DIR"] ?? path80.join(os43.homedir(), ".claude"));
39602
+ const claudeDirPath = opts?._testClaudeDir ?? (process.env["OLAM_CLAUDE_DIR"] ?? path81.join(os43.homedir(), ".claude"));
39156
39603
  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")})
39604
+ fs80.writeFileSync(path81.join(claudeDirPath, ".atlas-user"), picked + "\n", "utf8");
39605
+ process.stdout.write(pc33.green(`\u2713 atlas-user set to "${picked}" (written to ${path81.join(claudeDirPath, ".atlas-user")})
39159
39606
  `));
39160
39607
  return picked;
39161
39608
  }
@@ -39167,10 +39614,10 @@ function listDeployed() {
39167
39614
  );
39168
39615
  const entries = [];
39169
39616
  for (const bucket of ["skills", "agents", "scripts", "rules", "commands"]) {
39170
- const bucketDir = path80.join(dir, bucket);
39617
+ const bucketDir = path81.join(dir, bucket);
39171
39618
  if (!fs80.existsSync(bucketDir)) continue;
39172
39619
  for (const name of fs80.readdirSync(bucketDir)) {
39173
- const full = path80.join(bucketDir, name);
39620
+ const full = path81.join(bucketDir, name);
39174
39621
  try {
39175
39622
  const stat = fs80.lstatSync(full);
39176
39623
  if (!stat.isSymbolicLink()) continue;
@@ -39621,7 +40068,7 @@ init_merge_settings();
39621
40068
  init_skill_sources();
39622
40069
  init_output();
39623
40070
  import * as fs82 from "node:fs";
39624
- import * as path81 from "node:path";
40071
+ import * as path82 from "node:path";
39625
40072
  var MIGRATE_FROM_TOOLBOX_COMMAND = "migrate-from-toolbox";
39626
40073
  function asMessage6(err) {
39627
40074
  return err instanceof Error ? err.message : String(err);
@@ -39689,7 +40136,7 @@ function registerSkillsMigrate(program2) {
39689
40136
  return;
39690
40137
  }
39691
40138
  const toolboxPath = opts.path;
39692
- const namespace = opts.namespace ?? path81.basename(toolboxPath);
40139
+ const namespace = opts.namespace ?? path82.basename(toolboxPath);
39693
40140
  const sourceName = opts.sourceName ?? namespace;
39694
40141
  const snapshot = detectToolboxState({ toolboxPath, namespace });
39695
40142
  if (!snapshot) {
@@ -39743,9 +40190,9 @@ function registerSkillsMigrate(program2) {
39743
40190
  printWarning(`legacy hook removal failed: ${asMessage6(err)}; proceeding`);
39744
40191
  }
39745
40192
  const scope = opts.scope === "user" ? "user" : "project";
39746
- const olamHookPath = scope === "user" ? settingsFile : path81.join(process.cwd(), ".claude", "settings.json");
40193
+ const olamHookPath = scope === "user" ? settingsFile : path82.join(process.cwd(), ".claude", "settings.json");
39747
40194
  try {
39748
- fs82.mkdirSync(path81.dirname(olamHookPath), { recursive: true });
40195
+ fs82.mkdirSync(path82.dirname(olamHookPath), { recursive: true });
39749
40196
  const result = mergeHomeSettingsJson(olamHookPath, {
39750
40197
  ensureHook: {
39751
40198
  stage: OLAM_SKILLS_HOOK_STAGE,
@@ -39779,7 +40226,7 @@ function registerSkillsMigrate(program2) {
39779
40226
  init_skill_sources();
39780
40227
  init_output();
39781
40228
  import * as fs83 from "node:fs";
39782
- import * as path82 from "node:path";
40229
+ import * as path83 from "node:path";
39783
40230
  var MIGRATE_BACK_TO_TOOLBOX_COMMAND = "migrate-back-to-toolbox";
39784
40231
  function asMessage7(err) {
39785
40232
  return err instanceof Error ? err.message : String(err);
@@ -39787,7 +40234,7 @@ function asMessage7(err) {
39787
40234
  function claudeDirInternal4() {
39788
40235
  const override = process.env["OLAM_CLAUDE_DIR"];
39789
40236
  if (override && override.length > 0) return override;
39790
- return path82.join(process.env["HOME"] ?? "", ".claude");
40237
+ return path83.join(process.env["HOME"] ?? "", ".claude");
39791
40238
  }
39792
40239
  function restoreSessionStartFromSnapshot(filePath, originalSessionStartHook) {
39793
40240
  if (!originalSessionStartHook || originalSessionStartHook.length === 0) {
@@ -39812,7 +40259,7 @@ function restoreSessionStartFromSnapshot(filePath, originalSessionStartHook) {
39812
40259
  SessionStart: originalSessionStartHook
39813
40260
  }
39814
40261
  };
39815
- fs83.mkdirSync(path82.dirname(filePath), { recursive: true });
40262
+ fs83.mkdirSync(path83.dirname(filePath), { recursive: true });
39816
40263
  fs83.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
39817
40264
  return { restored: true };
39818
40265
  }
@@ -39822,10 +40269,10 @@ function removeOlamManagedSymlinks() {
39822
40269
  const olamClonePaths = sources.map((s) => skillSourceClonePath(s.id));
39823
40270
  let removed = 0;
39824
40271
  for (const bucket of ["skills", "agents", "scripts", "rules", "commands"]) {
39825
- const dir = path82.join(claude, bucket);
40272
+ const dir = path83.join(claude, bucket);
39826
40273
  if (!fs83.existsSync(dir)) continue;
39827
40274
  for (const name of fs83.readdirSync(dir)) {
39828
- const linkPath = path82.join(dir, name);
40275
+ const linkPath = path83.join(dir, name);
39829
40276
  try {
39830
40277
  const stat = fs83.lstatSync(linkPath);
39831
40278
  if (!stat.isSymbolicLink()) continue;
@@ -39844,7 +40291,7 @@ function restoreToolboxSymlinks(symlinks) {
39844
40291
  let restored = 0;
39845
40292
  for (const { link, target } of symlinks) {
39846
40293
  try {
39847
- fs83.mkdirSync(path82.dirname(link), { recursive: true });
40294
+ fs83.mkdirSync(path83.dirname(link), { recursive: true });
39848
40295
  if (fs83.existsSync(link) || (() => {
39849
40296
  try {
39850
40297
  fs83.lstatSync(link);
@@ -39864,8 +40311,8 @@ function restoreToolboxSymlinks(symlinks) {
39864
40311
  }
39865
40312
  function restoreAtlasUserMarker(atlasUser) {
39866
40313
  if (!atlasUser) return false;
39867
- const file = path82.join(claudeDirInternal4(), ".atlas-user");
39868
- fs83.mkdirSync(path82.dirname(file), { recursive: true });
40314
+ const file = path83.join(claudeDirInternal4(), ".atlas-user");
40315
+ fs83.mkdirSync(path83.dirname(file), { recursive: true });
39869
40316
  fs83.writeFileSync(file, atlasUser);
39870
40317
  return true;
39871
40318
  }
@@ -39879,7 +40326,7 @@ function registerSkillsMigrateBack(program2) {
39879
40326
  let snapshot;
39880
40327
  try {
39881
40328
  if (opts.snapshot) {
39882
- snapshotPath = path82.resolve(opts.snapshot);
40329
+ snapshotPath = path83.resolve(opts.snapshot);
39883
40330
  if (!fs83.existsSync(snapshotPath)) {
39884
40331
  printError(`snapshot not found at ${snapshotPath}`);
39885
40332
  process.exitCode = 1;
@@ -39887,7 +40334,7 @@ function registerSkillsMigrateBack(program2) {
39887
40334
  }
39888
40335
  snapshot = readMigrationSnapshotFromPath(snapshotPath);
39889
40336
  } else {
39890
- const filterNamespace = opts.namespace ?? (opts.path ? path82.basename(opts.path) : void 0);
40337
+ const filterNamespace = opts.namespace ?? (opts.path ? path83.basename(opts.path) : void 0);
39891
40338
  const latest = readLatestMigrationSnapshot({ namespace: filterNamespace });
39892
40339
  if (!latest) {
39893
40340
  const where = filterNamespace ? ` for namespace "${filterNamespace}"` : "";
@@ -39965,7 +40412,7 @@ init_trust_audit_log();
39965
40412
  init_atlas_hook_strip();
39966
40413
  init_output();
39967
40414
  import * as fs84 from "node:fs";
39968
- import * as path83 from "node:path";
40415
+ import * as path84 from "node:path";
39969
40416
  import pc35 from "picocolors";
39970
40417
  var MIGRATE_HOOKS_COMMAND = "migrate-hooks";
39971
40418
  function settingsHasOlamMetaSentinel(settings) {
@@ -39992,7 +40439,7 @@ function readSettings2(filePath) {
39992
40439
  return JSON.parse(raw);
39993
40440
  }
39994
40441
  function writeSettings(filePath, settings) {
39995
- fs84.mkdirSync(path83.dirname(filePath), { recursive: true });
40442
+ fs84.mkdirSync(path84.dirname(filePath), { recursive: true });
39996
40443
  const tmp = `${filePath}.tmp-migrate-hooks-${process.pid}-${Date.now()}`;
39997
40444
  fs84.writeFileSync(tmp, JSON.stringify(settings, null, 2) + "\n");
39998
40445
  fs84.renameSync(tmp, filePath);
@@ -40075,7 +40522,7 @@ function registerSkillsMigrateHooks(program2) {
40075
40522
  init_meta_hooks_migration_snapshot();
40076
40523
  init_skill_sources();
40077
40524
  init_output();
40078
- import * as path84 from "node:path";
40525
+ import * as path85 from "node:path";
40079
40526
  function asMessage9(err) {
40080
40527
  return err instanceof Error ? err.message : String(err);
40081
40528
  }
@@ -40092,16 +40539,16 @@ function registerSkillsMigrateHooksBack(program2) {
40092
40539
  return;
40093
40540
  }
40094
40541
  if (opts.snapshot) {
40095
- const resolved = path84.resolve(opts.snapshot);
40096
- const allowedDir = path84.resolve(migrationSnapshotsDir2());
40097
- if (!resolved.startsWith(allowedDir + path84.sep)) {
40542
+ const resolved = path85.resolve(opts.snapshot);
40543
+ const allowedDir = path85.resolve(migrationSnapshotsDir2());
40544
+ if (!resolved.startsWith(allowedDir + path85.sep)) {
40098
40545
  printError(
40099
40546
  `--snapshot path must be inside ${allowedDir} (got "${resolved}"). Refusing to restore from an arbitrary path \u2014 settings.json would land operator-chosen content.`
40100
40547
  );
40101
40548
  process.exitCode = 1;
40102
40549
  return;
40103
40550
  }
40104
- const basename16 = path84.basename(resolved);
40551
+ const basename16 = path85.basename(resolved);
40105
40552
  if (!basename16.startsWith(META_HOOKS_SNAPSHOT_PREFIX)) {
40106
40553
  printError(
40107
40554
  `--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 +40782,9 @@ function registerSkillsDoctor(program2) {
40335
40782
  init_skill_sources();
40336
40783
  init_cli_version();
40337
40784
  init_output();
40338
- import { execFileSync as execFileSync15 } from "node:child_process";
40785
+ import { execFileSync as execFileSync16 } from "node:child_process";
40339
40786
  import * as fs86 from "node:fs";
40340
- import * as path85 from "node:path";
40787
+ import * as path86 from "node:path";
40341
40788
  var CHAIN_SKILL_NAMES = [
40342
40789
  "10x:brainstorm",
40343
40790
  "10x:plan-hard",
@@ -40353,17 +40800,17 @@ function asMessage12(err) {
40353
40800
  }
40354
40801
  function hasBeadsCli() {
40355
40802
  try {
40356
- execFileSync15("bd", ["--version"], { stdio: "ignore" });
40803
+ execFileSync16("bd", ["--version"], { stdio: "ignore" });
40357
40804
  return true;
40358
40805
  } catch {
40359
40806
  return false;
40360
40807
  }
40361
40808
  }
40362
40809
  function hasBeadsProjectInit(cwd) {
40363
- return fs86.existsSync(path85.join(cwd, ".beads"));
40810
+ return fs86.existsSync(path86.join(cwd, ".beads"));
40364
40811
  }
40365
40812
  function hasBeadsClaudeSetup() {
40366
- const settingsPath = path85.join(claudeDir(), "settings.json");
40813
+ const settingsPath = path86.join(claudeDir(), "settings.json");
40367
40814
  if (!fs86.existsSync(settingsPath)) return false;
40368
40815
  try {
40369
40816
  const content = fs86.readFileSync(settingsPath, "utf8");
@@ -40382,7 +40829,7 @@ async function bootstrapBeads(cwd) {
40382
40829
  if (!hasBeadsProjectInit(cwd)) {
40383
40830
  console.log("bd init \u2014 initializing beads in current project");
40384
40831
  try {
40385
- execFileSync15("bd", ["init", "--quiet", "--stealth"], {
40832
+ execFileSync16("bd", ["init", "--quiet", "--stealth"], {
40386
40833
  cwd,
40387
40834
  stdio: "inherit"
40388
40835
  });
@@ -40395,7 +40842,7 @@ async function bootstrapBeads(cwd) {
40395
40842
  if (!hasBeadsClaudeSetup()) {
40396
40843
  console.log("bd setup claude \u2014 installing beads Claude Code hooks");
40397
40844
  try {
40398
- execFileSync15("bd", ["setup", "claude"], { cwd, stdio: "inherit" });
40845
+ execFileSync16("bd", ["setup", "claude"], { cwd, stdio: "inherit" });
40399
40846
  } catch (err) {
40400
40847
  printWarning(`bd setup claude failed (continuing): ${asMessage12(err)}`);
40401
40848
  }
@@ -40431,12 +40878,12 @@ function shortSha(sha) {
40431
40878
  return sha.slice(0, 8);
40432
40879
  }
40433
40880
  function listInstalledClaudeSkills() {
40434
- const skillsDir = path85.join(claudeDir(), "skills");
40881
+ const skillsDir = path86.join(claudeDir(), "skills");
40435
40882
  if (!fs86.existsSync(skillsDir)) return [];
40436
40883
  try {
40437
40884
  return fs86.readdirSync(skillsDir).filter((name) => {
40438
40885
  try {
40439
- const stat = fs86.lstatSync(path85.join(skillsDir, name));
40886
+ const stat = fs86.lstatSync(path86.join(skillsDir, name));
40440
40887
  return stat.isSymbolicLink() || stat.isDirectory();
40441
40888
  } catch {
40442
40889
  return false;
@@ -40511,14 +40958,14 @@ function registerSkills10x(program2) {
40511
40958
  tenx.command("uninstall").description(
40512
40959
  "Remove /10x: chain skill symlinks from ~/.claude/skills (preserves user-authored skills + non-chain skill sources)"
40513
40960
  ).action(() => {
40514
- const skillsDir = path85.join(claudeDir(), "skills");
40961
+ const skillsDir = path86.join(claudeDir(), "skills");
40515
40962
  if (!fs86.existsSync(skillsDir)) {
40516
40963
  printWarning("No ~/.claude/skills/ directory found; nothing to uninstall");
40517
40964
  return;
40518
40965
  }
40519
40966
  let removed = 0;
40520
40967
  for (const name of fs86.readdirSync(skillsDir)) {
40521
- const full = path85.join(skillsDir, name);
40968
+ const full = path86.join(skillsDir, name);
40522
40969
  try {
40523
40970
  const stat = fs86.lstatSync(full);
40524
40971
  if (!stat.isSymbolicLink()) continue;
@@ -40594,17 +41041,17 @@ function registerSkills10x(program2) {
40594
41041
  init_output();
40595
41042
  import * as fs87 from "node:fs";
40596
41043
  import * as os44 from "node:os";
40597
- import * as path86 from "node:path";
41044
+ import * as path87 from "node:path";
40598
41045
  import * as child_process from "node:child_process";
40599
41046
  import { parse as yamlParse2, stringify as yamlStringify3 } from "yaml";
40600
41047
  function hermesConfigPath() {
40601
- return path86.join(os44.homedir(), ".hermes", "config.yaml");
41048
+ return path87.join(os44.homedir(), ".hermes", "config.yaml");
40602
41049
  }
40603
41050
  function hermesSkillsDir() {
40604
- return path86.join(os44.homedir(), ".hermes", "skills");
41051
+ return path87.join(os44.homedir(), ".hermes", "skills");
40605
41052
  }
40606
41053
  function claudeSkillsDir() {
40607
- return path86.join(os44.homedir(), ".claude", "skills");
41054
+ return path87.join(os44.homedir(), ".claude", "skills");
40608
41055
  }
40609
41056
  function readHermesConfig(configPath) {
40610
41057
  const raw = fs87.readFileSync(configPath, "utf-8");
@@ -40716,8 +41163,8 @@ function mirrorSkillSymlinks(dryRun, summary2) {
40716
41163
  let mirrored = 0;
40717
41164
  let collisions = 0;
40718
41165
  for (const entry of entries) {
40719
- const srcPath = path86.join(srcDir, entry);
40720
- const destPath2 = path86.join(destDir, entry);
41166
+ const srcPath = path87.join(srcDir, entry);
41167
+ const destPath2 = path87.join(destDir, entry);
40721
41168
  if (fs87.existsSync(destPath2) || fs87.lstatSync(srcPath).isFile()) {
40722
41169
  if (fs87.existsSync(destPath2)) collisions++;
40723
41170
  continue;
@@ -40772,7 +41219,7 @@ async function runHermesBootstrap(opts, deps = {}) {
40772
41219
  } else {
40773
41220
  summary2.skipped.push("mcp_servers.agentmemory-atlas (AGENTMEMORY_BRIDGE_URL/SECRET not set; use --bridge-url/--bridge-secret to add)");
40774
41221
  }
40775
- const hooksDir = path86.join(path86.dirname(configPath), "hooks");
41222
+ const hooksDir = path87.join(path87.dirname(configPath), "hooks");
40776
41223
  const hookResult = installHookFn(hooksDir, dryRun);
40777
41224
  switch (hookResult.status) {
40778
41225
  case "installed":
@@ -40819,7 +41266,7 @@ async function runHermesBootstrap(opts, deps = {}) {
40819
41266
  }
40820
41267
  var HOOK_MATCHERS = ["terminal", "bash", "shell", "search_files", "grep", "ripgrep"];
40821
41268
  function ensureHermesHookEntry(config, hooksDir, dryRun, summary2) {
40822
- const hookScriptPath = path86.join(hooksDir, "kg-first.sh");
41269
+ const hookScriptPath = path87.join(hooksDir, "kg-first.sh");
40823
41270
  const hooks = config["hooks"] ?? {};
40824
41271
  const preToolCall = Array.isArray(hooks["pre_tool_call"]) ? hooks["pre_tool_call"] : [];
40825
41272
  const alreadyPresent = preToolCall.some(
@@ -40957,9 +41404,9 @@ function registerMcpServe(cmd) {
40957
41404
  init_output();
40958
41405
 
40959
41406
  // src/commands/mcp/install-shared.ts
40960
- import { spawnSync as spawnSync28 } from "node:child_process";
41407
+ import { spawnSync as spawnSync29 } from "node:child_process";
40961
41408
  var DEFAULT_CLAUDE_SHELL_DEPS = {
40962
- spawn: spawnSync28,
41409
+ spawn: spawnSync29,
40963
41410
  log: (msg) => console.log(msg)
40964
41411
  };
40965
41412
  function isOnPath(deps, bin) {
@@ -41092,8 +41539,8 @@ var SECRET = process.env["OLAM_MCP_AUTH_SECRET"] ?? "";
41092
41539
  function authHeaders() {
41093
41540
  return SECRET ? { "X-Olam-Mcp-Secret": SECRET } : {};
41094
41541
  }
41095
- async function apiFetch(path95, init = {}) {
41096
- const res = await fetch(`${BASE_URL}${path95}`, {
41542
+ async function apiFetch(path96, init = {}) {
41543
+ const res = await fetch(`${BASE_URL}${path96}`, {
41097
41544
  ...init,
41098
41545
  headers: {
41099
41546
  "Content-Type": "application/json",
@@ -41355,7 +41802,7 @@ import pc40 from "picocolors";
41355
41802
  // src/commands/mcp/import-discovery.ts
41356
41803
  import * as fs88 from "node:fs";
41357
41804
  import * as os45 from "node:os";
41358
- import * as path87 from "node:path";
41805
+ import * as path88 from "node:path";
41359
41806
  function readJsonFile(filePath) {
41360
41807
  try {
41361
41808
  const raw = fs88.readFileSync(filePath, "utf-8");
@@ -41387,18 +41834,18 @@ function extractMcpServers(obj, source, sourceLabel) {
41387
41834
  }
41388
41835
  function getClaudeDesktopPath() {
41389
41836
  if (process.platform === "darwin") {
41390
- return path87.join(os45.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
41837
+ return path88.join(os45.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
41391
41838
  }
41392
41839
  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");
41840
+ const appData = process.env["APPDATA"] ?? path88.join(os45.homedir(), "AppData", "Roaming");
41841
+ return path88.join(appData, "Claude", "claude_desktop_config.json");
41395
41842
  }
41396
- return path87.join(os45.homedir(), ".config", "Claude", "claude_desktop_config.json");
41843
+ return path88.join(os45.homedir(), ".config", "Claude", "claude_desktop_config.json");
41397
41844
  }
41398
41845
  function getOlamRepoPaths() {
41399
41846
  const configPaths = [
41400
- path87.join(os45.homedir(), ".olam", "config.yaml"),
41401
- path87.join(process.cwd(), ".olam", "config.yaml")
41847
+ path88.join(os45.homedir(), ".olam", "config.yaml"),
41848
+ path88.join(process.cwd(), ".olam", "config.yaml")
41402
41849
  ];
41403
41850
  const paths = [];
41404
41851
  for (const configPath of configPaths) {
@@ -41420,7 +41867,7 @@ async function discoverMcpSources(repoPaths) {
41420
41867
  const sources = [];
41421
41868
  const sourceDefs = [
41422
41869
  {
41423
- path: path87.join(os45.homedir(), ".claude.json"),
41870
+ path: path88.join(os45.homedir(), ".claude.json"),
41424
41871
  label: "Claude Code (~/.claude.json)"
41425
41872
  },
41426
41873
  {
@@ -41428,19 +41875,19 @@ async function discoverMcpSources(repoPaths) {
41428
41875
  label: "Claude Desktop"
41429
41876
  },
41430
41877
  {
41431
- path: path87.join(os45.homedir(), ".cursor", "mcp.json"),
41878
+ path: path88.join(os45.homedir(), ".cursor", "mcp.json"),
41432
41879
  label: "Cursor (~/.cursor/mcp.json)"
41433
41880
  },
41434
41881
  {
41435
- path: path87.join(os45.homedir(), ".codeium", "windsurf", "mcp_config.json"),
41882
+ path: path88.join(os45.homedir(), ".codeium", "windsurf", "mcp_config.json"),
41436
41883
  label: "Windsurf (~/.codeium/windsurf/mcp_config.json)"
41437
41884
  }
41438
41885
  ];
41439
41886
  const resolvedRepoPaths = repoPaths ?? getOlamRepoPaths();
41440
41887
  for (const repoPath of resolvedRepoPaths) {
41441
41888
  sourceDefs.push({
41442
- path: path87.join(repoPath, ".mcp.json"),
41443
- label: `.mcp.json (${path87.basename(repoPath)})`
41889
+ path: path88.join(repoPath, ".mcp.json"),
41890
+ label: `.mcp.json (${path88.basename(repoPath)})`
41444
41891
  });
41445
41892
  }
41446
41893
  const reads = await Promise.all(
@@ -41677,13 +42124,13 @@ init_output();
41677
42124
 
41678
42125
  // src/lib/memory-host-process-migration.ts
41679
42126
  import { existsSync as existsSync101, readFileSync as readFileSync83, unlinkSync as unlinkSync23 } from "node:fs";
41680
- import { spawnSync as spawnSync29 } from "node:child_process";
42127
+ import { spawnSync as spawnSync30 } from "node:child_process";
41681
42128
 
41682
42129
  // src/commands/memory/_paths.ts
41683
- import { homedir as homedir52 } from "node:os";
42130
+ import { homedir as homedir53 } from "node:os";
41684
42131
  import { join as join95, dirname as dirname55 } from "node:path";
41685
42132
  import { fileURLToPath as fileURLToPath8 } from "node:url";
41686
- var OLAM_HOME5 = join95(homedir52(), ".olam");
42133
+ var OLAM_HOME5 = join95(homedir53(), ".olam");
41687
42134
  var MEMORY_PID_PATH = join95(OLAM_HOME5, "memory.pid");
41688
42135
  var MEMORY_LOG_PATH = join95(OLAM_HOME5, "memory-service.log");
41689
42136
  var MEMORY_DATA_DIR = join95(OLAM_HOME5, "memory-data");
@@ -41762,7 +42209,7 @@ function isProcessAlive(pid) {
41762
42209
  }
41763
42210
  }
41764
42211
  function processCommName(pid) {
41765
- const r = spawnSync29("ps", ["-p", String(pid), "-o", "comm="], { encoding: "utf-8" });
42212
+ const r = spawnSync30("ps", ["-p", String(pid), "-o", "comm="], { encoding: "utf-8" });
41766
42213
  if (r.status !== 0) return null;
41767
42214
  const comm = r.stdout.trim();
41768
42215
  return comm.split("/").pop() ?? null;
@@ -41776,7 +42223,7 @@ function terminateProcess(pid) {
41776
42223
  const deadline = Date.now() + KILL_TIMEOUT_MS;
41777
42224
  while (Date.now() < deadline) {
41778
42225
  if (!isProcessAlive(pid)) return true;
41779
- spawnSync29("sleep", ["0.1"]);
42226
+ spawnSync30("sleep", ["0.1"]);
41780
42227
  }
41781
42228
  try {
41782
42229
  process.kill(pid, "SIGKILL");
@@ -42333,13 +42780,13 @@ function resolveMemoryServiceDir() {
42333
42780
  );
42334
42781
  }
42335
42782
  function resolveLocalBridgeScript(serviceDir) {
42336
- const path95 = join97(serviceDir, "scripts", "local-bridge-server.mjs");
42337
- if (!existsSync105(path95)) {
42783
+ const path96 = join97(serviceDir, "scripts", "local-bridge-server.mjs");
42784
+ if (!existsSync105(path96)) {
42338
42785
  throw new Error(
42339
- `Could not find local-bridge-server.mjs at ${path95}. Verify packages/memory-service ships the scripts/ directory.`
42786
+ `Could not find local-bridge-server.mjs at ${path96}. Verify packages/memory-service ships the scripts/ directory.`
42340
42787
  );
42341
42788
  }
42342
- return path95;
42789
+ return path96;
42343
42790
  }
42344
42791
  function validateBridgeOpts(opts) {
42345
42792
  const local = opts.local ?? false;
@@ -42681,7 +43128,7 @@ function registerMemoryStats(cmd) {
42681
43128
 
42682
43129
  // src/commands/memory/install-hooks.ts
42683
43130
  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";
43131
+ import { homedir as homedir54 } from "node:os";
42685
43132
  import { dirname as dirname56, join as join98, resolve as resolve25 } from "node:path";
42686
43133
  import { fileURLToPath as fileURLToPath9 } from "node:url";
42687
43134
  var HOOK_BASENAMES = [
@@ -42750,7 +43197,7 @@ If existing entries already point at the same paths, no edit needed.
42750
43197
  }
42751
43198
  function registerMemoryInstallHooks(parent) {
42752
43199
  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");
43200
+ const targetDir = opts.targetDir ?? join98(homedir54(), ".claude", "scripts", "hooks");
42754
43201
  const sourceDir = opts.sourceDir ?? defaultSourceDir();
42755
43202
  let written = 0;
42756
43203
  let unchanged = 0;
@@ -42830,7 +43277,7 @@ init_storage_paths();
42830
43277
  init_workspace_name();
42831
43278
  import * as fs93 from "node:fs";
42832
43279
  import * as os48 from "node:os";
42833
- import * as path92 from "node:path";
43280
+ import * as path93 from "node:path";
42834
43281
 
42835
43282
  // ../core/dist/kg/kg-service-client.js
42836
43283
  var KG_SERVICE_PORT_DEFAULT = 9997;
@@ -42841,8 +43288,8 @@ function port() {
42841
43288
  const n = Number.parseInt(env, 10);
42842
43289
  return Number.isFinite(n) && n > 0 ? n : KG_SERVICE_PORT_DEFAULT;
42843
43290
  }
42844
- function url(path95) {
42845
- return `http://127.0.0.1:${port()}${path95}`;
43291
+ function url(path96) {
43292
+ return `http://127.0.0.1:${port()}${path96}`;
42846
43293
  }
42847
43294
  function kgServiceHealthUrl() {
42848
43295
  return url("/health");
@@ -42923,16 +43370,16 @@ init_workspace_name();
42923
43370
  init_kg_caps();
42924
43371
  init_output();
42925
43372
  import fs89 from "node:fs";
42926
- import { homedir as homedir54 } from "node:os";
42927
- import path88 from "node:path";
43373
+ import { homedir as homedir55 } from "node:os";
43374
+ import path89 from "node:path";
42928
43375
  function olamHome4() {
42929
- return process.env.OLAM_HOME ?? path88.join(homedir54(), ".olam");
43376
+ return process.env.OLAM_HOME ?? path89.join(homedir55(), ".olam");
42930
43377
  }
42931
43378
  function kgRoot2() {
42932
- return path88.join(olamHome4(), "kg");
43379
+ return path89.join(olamHome4(), "kg");
42933
43380
  }
42934
43381
  function worldsRoot2() {
42935
- return path88.join(olamHome4(), "worlds");
43382
+ return path89.join(olamHome4(), "worlds");
42936
43383
  }
42937
43384
  function dirSizeBytes2(dir) {
42938
43385
  if (!fs89.existsSync(dir)) return 0;
@@ -42947,7 +43394,7 @@ function dirSizeBytes2(dir) {
42947
43394
  continue;
42948
43395
  }
42949
43396
  for (const entry of entries) {
42950
- const full = path88.join(cur, entry.name);
43397
+ const full = path89.join(cur, entry.name);
42951
43398
  if (entry.isSymbolicLink()) continue;
42952
43399
  if (entry.isDirectory()) {
42953
43400
  stack.push(full);
@@ -42968,7 +43415,7 @@ function formatBytes5(n) {
42968
43415
  return `${(n / 1024 / 1024 / 1024).toFixed(2)} GB`;
42969
43416
  }
42970
43417
  function readFreshness(workspace) {
42971
- const file = path88.join(kgPristinePath(workspace), "freshness.json");
43418
+ const file = path89.join(kgPristinePath(workspace), "freshness.json");
42972
43419
  if (!fs89.existsSync(file)) return null;
42973
43420
  try {
42974
43421
  const raw = JSON.parse(fs89.readFileSync(file, "utf-8"));
@@ -42979,7 +43426,7 @@ function readFreshness(workspace) {
42979
43426
  }
42980
43427
  }
42981
43428
  function readOverlayNodeCount(graphifyOutDir) {
42982
- const graphPath = path88.join(graphifyOutDir, "graph.json");
43429
+ const graphPath = path89.join(graphifyOutDir, "graph.json");
42983
43430
  if (!fs89.existsSync(graphPath)) return null;
42984
43431
  try {
42985
43432
  const raw = JSON.parse(fs89.readFileSync(graphPath, "utf-8"));
@@ -43005,7 +43452,7 @@ function listOverlays() {
43005
43452
  for (const worldEntry of worldDirs) {
43006
43453
  if (!worldEntry.isDirectory()) continue;
43007
43454
  const worldId = worldEntry.name;
43008
- const worldDir = path88.join(root, worldId);
43455
+ const worldDir = path89.join(root, worldId);
43009
43456
  let cloneDirs;
43010
43457
  try {
43011
43458
  cloneDirs = fs89.readdirSync(worldDir, { withFileTypes: true });
@@ -43014,7 +43461,7 @@ function listOverlays() {
43014
43461
  }
43015
43462
  for (const cloneEntry of cloneDirs) {
43016
43463
  if (!cloneEntry.isDirectory()) continue;
43017
- const graphifyOut = path88.join(worldDir, cloneEntry.name, "graphify-out");
43464
+ const graphifyOut = path89.join(worldDir, cloneEntry.name, "graphify-out");
43018
43465
  if (!fs89.existsSync(graphifyOut)) continue;
43019
43466
  records.push({
43020
43467
  world_id: worldId,
@@ -43046,7 +43493,7 @@ function listPristines(overlays) {
43046
43493
  continue;
43047
43494
  }
43048
43495
  const fresh = readFreshness(workspace);
43049
- const graphifyOut = path88.join(kgPristinePath(workspace), "graphify-out");
43496
+ const graphifyOut = path89.join(kgPristinePath(workspace), "graphify-out");
43050
43497
  const size = dirSizeBytes2(graphifyOut);
43051
43498
  const worldCount = overlays.filter((o) => o.clone_dir === workspace).length;
43052
43499
  records.push({
@@ -43183,9 +43630,9 @@ init_workspace_name();
43183
43630
  init_output();
43184
43631
  import { spawn as spawn12 } from "node:child_process";
43185
43632
  import fs90 from "node:fs";
43186
- import path89 from "node:path";
43633
+ import path90 from "node:path";
43187
43634
  function pidFilePath2(workspace) {
43188
- return path89.join(kgPristinePath(workspace), ".watch.pid");
43635
+ return path90.join(kgPristinePath(workspace), ".watch.pid");
43189
43636
  }
43190
43637
  function isPidAlive3(pid) {
43191
43638
  if (!Number.isInteger(pid) || pid <= 0) return false;
@@ -43219,7 +43666,7 @@ function readAndClassifyPid(workspace) {
43219
43666
  }
43220
43667
  function writePidFile2(workspace, pid) {
43221
43668
  const file = pidFilePath2(workspace);
43222
- const dir = path89.dirname(file);
43669
+ const dir = path90.dirname(file);
43223
43670
  fs90.mkdirSync(dir, { recursive: true });
43224
43671
  fs90.writeFileSync(file, String(pid), { encoding: "utf-8" });
43225
43672
  }
@@ -43232,7 +43679,7 @@ function removePidFile(workspace) {
43232
43679
  }
43233
43680
  async function runKgWatch(workspaceArg, opts, deps = {}) {
43234
43681
  const cwd = deps.cwd ?? opts.cwd ?? process.cwd();
43235
- const name = workspaceArg ?? path89.basename(cwd).toLowerCase();
43682
+ const name = workspaceArg ?? path90.basename(cwd).toLowerCase();
43236
43683
  try {
43237
43684
  validateWorkspaceName(name);
43238
43685
  } catch (err) {
@@ -43240,7 +43687,7 @@ async function runKgWatch(workspaceArg, opts, deps = {}) {
43240
43687
  return { exitCode: 1, pidWritten: false };
43241
43688
  }
43242
43689
  const pristinePath = kgPristinePath(name);
43243
- const graphPath = path89.join(pristinePath, "graphify-out", "graph.json");
43690
+ const graphPath = path90.join(pristinePath, "graphify-out", "graph.json");
43244
43691
  const pidState = readAndClassifyPid(name);
43245
43692
  if (pidState.status === "active") {
43246
43693
  printError(
@@ -43479,7 +43926,7 @@ function registerKgDoctorCommand(kg) {
43479
43926
  // src/commands/kg-install-hook.ts
43480
43927
  init_merge_settings();
43481
43928
  import * as fs91 from "node:fs";
43482
- import * as path90 from "node:path";
43929
+ import * as path91 from "node:path";
43483
43930
  import * as os46 from "node:os";
43484
43931
  import { parse as yamlParse3, stringify as yamlStringify4 } from "yaml";
43485
43932
 
@@ -43532,9 +43979,9 @@ function buildHookMatcherEntry(opts) {
43532
43979
  init_output();
43533
43980
  function settingsPathFor2(scope) {
43534
43981
  if (scope === "user") {
43535
- return path90.join(os46.homedir(), ".claude", "settings.json");
43982
+ return path91.join(os46.homedir(), ".claude", "settings.json");
43536
43983
  }
43537
- return path90.join(process.cwd(), ".claude", "settings.json");
43984
+ return path91.join(process.cwd(), ".claude", "settings.json");
43538
43985
  }
43539
43986
  function backup2(filePath) {
43540
43987
  if (!fs91.existsSync(filePath)) return null;
@@ -43545,10 +43992,10 @@ function backup2(filePath) {
43545
43992
  }
43546
43993
  var HERMES_HOOK_MATCHERS = ["terminal", "bash", "shell", "search_files", "grep", "ripgrep"];
43547
43994
  function hermesConfigPath2() {
43548
- return path90.join(os46.homedir(), ".hermes", "config.yaml");
43995
+ return path91.join(os46.homedir(), ".hermes", "config.yaml");
43549
43996
  }
43550
43997
  function hermesHooksDir() {
43551
- return path90.join(os46.homedir(), ".hermes", "hooks");
43998
+ return path91.join(os46.homedir(), ".hermes", "hooks");
43552
43999
  }
43553
44000
  function patchHermesConfigForHook(action) {
43554
44001
  const configPath = hermesConfigPath2();
@@ -43561,7 +44008,7 @@ function patchHermesConfigForHook(action) {
43561
44008
  (e) => typeof e["command"] === "string" && e["command"].includes(HERMES_KG_HOOK_SENTINEL)
43562
44009
  );
43563
44010
  if (alreadyPresent) return "already-present";
43564
- const hookScriptPath = path90.join(hermesHooksDir(), "kg-first.sh");
44011
+ const hookScriptPath = path91.join(hermesHooksDir(), "kg-first.sh");
43565
44012
  const entry = {
43566
44013
  matcher: HERMES_HOOK_MATCHERS.join("|"),
43567
44014
  command: `${hookScriptPath} # ${HERMES_KG_HOOK_SENTINEL}`
@@ -43615,7 +44062,7 @@ function doInstallForHermes() {
43615
44062
  function doUninstallForHermes() {
43616
44063
  const configPath = hermesConfigPath2();
43617
44064
  const hooksDir = hermesHooksDir();
43618
- const hookScriptPath = path90.join(hooksDir, "kg-first.sh");
44065
+ const hookScriptPath = path91.join(hooksDir, "kg-first.sh");
43619
44066
  let scriptRemoved = false;
43620
44067
  if (fs91.existsSync(hookScriptPath)) {
43621
44068
  const content = fs91.readFileSync(hookScriptPath, "utf-8");
@@ -43650,9 +44097,9 @@ function registerKgInstallHookCommand(kg) {
43650
44097
  const scope = opts.scope === "user" ? "user" : "project";
43651
44098
  const filePath = settingsPathFor2(scope);
43652
44099
  try {
43653
- fs91.mkdirSync(path90.dirname(filePath), { recursive: true });
44100
+ fs91.mkdirSync(path91.dirname(filePath), { recursive: true });
43654
44101
  } catch (err) {
43655
- printError(`could not create ${path90.dirname(filePath)}: ${err instanceof Error ? err.message : String(err)}`);
44102
+ printError(`could not create ${path91.dirname(filePath)}: ${err instanceof Error ? err.message : String(err)}`);
43656
44103
  process.exitCode = 1;
43657
44104
  return;
43658
44105
  }
@@ -43695,14 +44142,14 @@ function registerKgInstallHookCommand(kg) {
43695
44142
 
43696
44143
  // src/commands/kg-uninstall-hook.ts
43697
44144
  import * as fs92 from "node:fs";
43698
- import * as path91 from "node:path";
44145
+ import * as path92 from "node:path";
43699
44146
  import * as os47 from "node:os";
43700
44147
  init_output();
43701
44148
  function settingsPathFor3(scope) {
43702
44149
  if (scope === "user") {
43703
- return path91.join(os47.homedir(), ".claude", "settings.json");
44150
+ return path92.join(os47.homedir(), ".claude", "settings.json");
43704
44151
  }
43705
- return path91.join(process.cwd(), ".claude", "settings.json");
44152
+ return path92.join(process.cwd(), ".claude", "settings.json");
43706
44153
  }
43707
44154
  function dropSentinel(matchers) {
43708
44155
  let changed = false;
@@ -43864,14 +44311,14 @@ function readQueueFromDisk(queuePath) {
43864
44311
  return entries;
43865
44312
  }
43866
44313
  function writeQueueToDisk(queuePath, entries) {
43867
- fs93.mkdirSync(path92.dirname(queuePath), { recursive: true });
44314
+ fs93.mkdirSync(path93.dirname(queuePath), { recursive: true });
43868
44315
  const content = entries.map((e) => JSON.stringify(e)).join("\n") + (entries.length > 0 ? "\n" : "");
43869
44316
  fs93.writeFileSync(queuePath, content, "utf-8");
43870
44317
  }
43871
44318
  async function runKgBuildPending(opts = {}) {
43872
44319
  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");
44320
+ const stateDir = process.env["OLAM_STATE_DIR"] ?? path93.join(os48.homedir(), ".olam", "state");
44321
+ return path93.join(stateDir, "kg-pending.jsonl");
43875
44322
  })();
43876
44323
  const readQueue2 = opts.readQueueFn ?? readQueueFromDisk;
43877
44324
  const writeQueue2 = opts.writeQueueFn ?? writeQueueToDisk;
@@ -43887,7 +44334,7 @@ async function runKgBuildPending(opts = {}) {
43887
44334
  const remaining = [];
43888
44335
  for (const entry of deduped) {
43889
44336
  const repoPath = entry.path;
43890
- const workspaceName = path92.basename(repoPath).toLowerCase();
44337
+ const workspaceName = path93.basename(repoPath).toLowerCase();
43891
44338
  printInfo("kg build --pending", `building ${repoPath} (workspace=${workspaceName})`);
43892
44339
  let containerPath;
43893
44340
  try {
@@ -43925,20 +44372,20 @@ async function runKgBuildPending(opts = {}) {
43925
44372
  }
43926
44373
  function resolveWorkspace(arg) {
43927
44374
  const cwd = process.cwd();
43928
- const name = arg ?? path92.basename(cwd).toLowerCase();
44375
+ const name = arg ?? path93.basename(cwd).toLowerCase();
43929
44376
  validateWorkspaceName(name);
43930
44377
  return { name, sourcePath: cwd };
43931
44378
  }
43932
44379
  function toContainerPath(hostPath) {
43933
44380
  const home = os48.homedir();
43934
- const resolved = path92.resolve(hostPath);
43935
- if (!resolved.startsWith(home + path92.sep) && resolved !== home) {
44381
+ const resolved = path93.resolve(hostPath);
44382
+ if (!resolved.startsWith(home + path93.sep) && resolved !== home) {
43936
44383
  throw new Error(
43937
44384
  `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
44385
  );
43939
44386
  }
43940
- const rel = path92.relative(home, resolved);
43941
- return rel === "" ? "/host-home" : path92.posix.join("/host-home", rel.split(path92.sep).join("/"));
44387
+ const rel = path93.relative(home, resolved);
44388
+ return rel === "" ? "/host-home" : path93.posix.join("/host-home", rel.split(path93.sep).join("/"));
43942
44389
  }
43943
44390
  async function runKgBuild(workspaceArg, options = {}) {
43944
44391
  let workspace;
@@ -43990,11 +44437,11 @@ async function runKgBuild(workspaceArg, options = {}) {
43990
44437
  graphify_path: "container"
43991
44438
  };
43992
44439
  fs93.writeFileSync(
43993
- path92.join(outDir, "freshness.json"),
44440
+ path93.join(outDir, "freshness.json"),
43994
44441
  JSON.stringify(freshness, null, 2) + "\n",
43995
44442
  "utf-8"
43996
44443
  );
43997
- const finalOut = path92.join(outDir, "graphify-out");
44444
+ const finalOut = path93.join(outDir, "graphify-out");
43998
44445
  if (options.json) {
43999
44446
  process.stdout.write(JSON.stringify(freshness) + "\n");
44000
44447
  } else {
@@ -44036,12 +44483,12 @@ function registerKg(program2) {
44036
44483
  // src/commands/flywheel/emit-breadcrumb.ts
44037
44484
  init_file_lock();
44038
44485
  import { mkdirSync as mkdirSync63, appendFileSync as appendFileSync6 } from "node:fs";
44039
- import { homedir as homedir58 } from "node:os";
44486
+ import { homedir as homedir59 } from "node:os";
44040
44487
  import { dirname as dirname59, join as join102 } from "node:path";
44041
44488
  import { randomUUID as randomUUID4 } from "node:crypto";
44042
44489
  var VALID_SEVERITIES = /* @__PURE__ */ new Set(["critical", "high", "medium", "low", "info", "warn"]);
44043
44490
  var PROMPT_FEEDING_FIELDS = ["extracted_pattern", "severity", "affected_persona", "proposed_edit"];
44044
- var BREADCRUMBS_BASE = join102(homedir58(), ".local", "share", "claude", "breadcrumbs");
44491
+ var BREADCRUMBS_BASE = join102(homedir59(), ".local", "share", "claude", "breadcrumbs");
44045
44492
  var LOCK_FILENAME = ".flywheel-emit.lock";
44046
44493
  function buildRecord(opts) {
44047
44494
  const rec = {
@@ -44107,14 +44554,14 @@ async function emitBreadcrumb(opts) {
44107
44554
  );
44108
44555
  process.exit(2);
44109
44556
  }
44110
- const path95 = destPath(rec.project_slug);
44111
- const lockDir = dirname59(path95);
44557
+ const path96 = destPath(rec.project_slug);
44558
+ const lockDir = dirname59(path96);
44112
44559
  mkdirSync63(lockDir, { recursive: true });
44113
44560
  const line = JSON.stringify(rec) + "\n";
44114
44561
  await withFileLock(
44115
44562
  lockDir,
44116
44563
  () => {
44117
- appendFileSync6(path95, line, "utf8");
44564
+ appendFileSync6(path96, line, "utf8");
44118
44565
  },
44119
44566
  {
44120
44567
  lockFilename: LOCK_FILENAME,
@@ -44124,7 +44571,7 @@ async function emitBreadcrumb(opts) {
44124
44571
  acquireTimeoutMs: 5e3
44125
44572
  }
44126
44573
  );
44127
- process.stdout.write(`[K7-emit] ${path95}: ${rec.extracted_pattern} (${rec.severity})
44574
+ process.stdout.write(`[K7-emit] ${path96}: ${rec.extracted_pattern} (${rec.severity})
44128
44575
  `);
44129
44576
  }
44130
44577
  function registerFlywheelEmitBreadcrumb(parent) {
@@ -44247,38 +44694,38 @@ function validateK5ScoredAt(scoredAt) {
44247
44694
  }
44248
44695
  return null;
44249
44696
  }
44250
- function validatePlan(path95) {
44697
+ function validatePlan(path96) {
44251
44698
  let stat;
44252
44699
  try {
44253
- stat = statSync30(path95);
44700
+ stat = statSync30(path96);
44254
44701
  } catch (err) {
44255
- return { ok: false, message: `FAIL cannot stat ${path95}: ${err instanceof Error ? err.message : "unknown"}` };
44702
+ return { ok: false, message: `FAIL cannot stat ${path96}: ${err instanceof Error ? err.message : "unknown"}` };
44256
44703
  }
44257
44704
  if (stat.size > MAX_PLAN_BYTES) {
44258
- return { ok: false, message: `FAIL ${path95}: plan file exceeds 1MB (${stat.size} bytes); refusing to parse` };
44705
+ return { ok: false, message: `FAIL ${path96}: plan file exceeds 1MB (${stat.size} bytes); refusing to parse` };
44259
44706
  }
44260
44707
  let text;
44261
44708
  try {
44262
- text = readFileSync89(path95, "utf8");
44709
+ text = readFileSync89(path96, "utf8");
44263
44710
  } catch (err) {
44264
- return { ok: false, message: `FAIL cannot read ${path95}: ${err instanceof Error ? err.message : "unknown"}` };
44711
+ return { ok: false, message: `FAIL cannot read ${path96}: ${err instanceof Error ? err.message : "unknown"}` };
44265
44712
  }
44266
44713
  if (!text.replace(/^/, "").startsWith("---")) {
44267
- return { ok: false, message: `FAIL ${path95}: no YAML frontmatter (missing opening --- marker)` };
44714
+ return { ok: false, message: `FAIL ${path96}: no YAML frontmatter (missing opening --- marker)` };
44268
44715
  }
44269
44716
  if (!text.includes("\n---", 3)) {
44270
- return { ok: false, message: `FAIL ${path95}: frontmatter block never closed (missing closing --- marker)` };
44717
+ return { ok: false, message: `FAIL ${path96}: frontmatter block never closed (missing closing --- marker)` };
44271
44718
  }
44272
44719
  const fm = extractFrontmatter(text);
44273
44720
  if (fm === null) {
44274
- return { ok: false, message: `FAIL ${path95}: frontmatter could not be parsed as YAML` };
44721
+ return { ok: false, message: `FAIL ${path96}: frontmatter could not be parsed as YAML` };
44275
44722
  }
44276
44723
  const hasScores = "k5_scores" in fm;
44277
44724
  const hasBoost = "k5_boost" in fm;
44278
44725
  const hasComposite = "k5_composite" in fm;
44279
44726
  const hasScoredAt = "k5_scored_at" in fm;
44280
44727
  if (!hasScores && !hasBoost && !hasComposite && !hasScoredAt) {
44281
- return { ok: true, message: `PASS ${path95}: k5_scores absent (acceptable \u2014 legacy plan)` };
44728
+ return { ok: true, message: `PASS ${path96}: k5_scores absent (acceptable \u2014 legacy plan)` };
44282
44729
  }
44283
44730
  const errors = [];
44284
44731
  if (hasScores) {
@@ -44298,9 +44745,9 @@ function validatePlan(path95) {
44298
44745
  if (err !== null) errors.push(err);
44299
44746
  }
44300
44747
  if (errors.length > 0) {
44301
- return { ok: false, message: `FAIL ${path95}: ${errors.join("; ")}` };
44748
+ return { ok: false, message: `FAIL ${path96}: ${errors.join("; ")}` };
44302
44749
  }
44303
- const lines = [`PASS ${path95}: k5_scores valid`];
44750
+ const lines = [`PASS ${path96}: k5_scores valid`];
44304
44751
  if (hasScores && typeof fm.k5_scores === "object" && fm.k5_scores !== null) {
44305
44752
  const scoresObj = fm.k5_scores;
44306
44753
  const vals = [];
@@ -44445,12 +44892,12 @@ function registerFlywheelK10Measure(parent) {
44445
44892
 
44446
44893
  // src/commands/flywheel/check-persona-skeleton.ts
44447
44894
  import { existsSync as existsSync110, readFileSync as readFileSync91, statSync as statSync31 } from "node:fs";
44448
- import { homedir as homedir59 } from "node:os";
44895
+ import { homedir as homedir60 } from "node:os";
44449
44896
  import { basename as basename14, join as join103 } from "node:path";
44450
44897
  import { parse as parseYAML2 } from "yaml";
44451
44898
  var CHARS_PER_TOKEN3 = 4;
44452
44899
  var K10_TOKEN_CAP2 = 6e3;
44453
- var AGENTS_DIR = join103(homedir59(), ".claude", "agents");
44900
+ var AGENTS_DIR = join103(homedir60(), ".claude", "agents");
44454
44901
  var REQUIRED_FRONTMATTER_KEYS = ["name", "description", "allowed-tools"];
44455
44902
  var REQUIRED_SECTIONS = [
44456
44903
  "## Role",
@@ -44700,7 +45147,7 @@ ${formatRedivergencePrompt(persona_a, persona_b, score, void 0, void 0, threshol
44700
45147
 
44701
45148
  // src/commands/flywheel/ping.ts
44702
45149
  import { mkdirSync as mkdirSync64, writeFileSync as writeFileSync56 } from "node:fs";
44703
- import { homedir as homedir60 } from "node:os";
45150
+ import { homedir as homedir61 } from "node:os";
44704
45151
  import { dirname as dirname60, join as join104 } from "node:path";
44705
45152
  var COLD_START_BUDGET_GOOD_MS = 200;
44706
45153
  var COLD_START_BUDGET_FAIR_MS = 500;
@@ -44717,7 +45164,7 @@ function readOlamVersion() {
44717
45164
  }
44718
45165
  }
44719
45166
  function writeBaseline(record) {
44720
- const baselinePath = join104(homedir60(), ".local", "share", "olam", "flywheel-baseline.json");
45167
+ const baselinePath = join104(homedir61(), ".local", "share", "olam", "flywheel-baseline.json");
44721
45168
  mkdirSync64(dirname60(baselinePath), { recursive: true });
44722
45169
  writeFileSync56(baselinePath, JSON.stringify(record, null, 2) + "\n", "utf8");
44723
45170
  return baselinePath;
@@ -44766,8 +45213,8 @@ import {
44766
45213
  statSync as statSync32,
44767
45214
  writeFileSync as writeFileSync57
44768
45215
  } from "node:fs";
44769
- import { spawnSync as spawnSync30 } from "node:child_process";
44770
- import { homedir as homedir61 } from "node:os";
45216
+ import { spawnSync as spawnSync31 } from "node:child_process";
45217
+ import { homedir as homedir62 } from "node:os";
44771
45218
  import { dirname as dirname61, join as join105, relative as relative7 } from "node:path";
44772
45219
  function escapeRegex(s) {
44773
45220
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -44844,7 +45291,7 @@ function resolveAtlasUser2(opts) {
44844
45291
  assertValidAtlasUser(v);
44845
45292
  return v;
44846
45293
  }
44847
- const claudeDir2 = opts._testClaudeDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join105(homedir61(), ".claude");
45294
+ const claudeDir2 = opts._testClaudeDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join105(homedir62(), ".claude");
44848
45295
  const f = join105(claudeDir2, ".atlas-user");
44849
45296
  if (existsSync111(f)) {
44850
45297
  const v = readFileSync93(f, "utf-8").trim();
@@ -44855,7 +45302,7 @@ function resolveAtlasUser2(opts) {
44855
45302
  return null;
44856
45303
  }
44857
45304
  function runGit2(args, cwd) {
44858
- const result = spawnSync30("git", args, {
45305
+ const result = spawnSync31("git", args, {
44859
45306
  cwd,
44860
45307
  encoding: "utf-8",
44861
45308
  stdio: ["ignore", "pipe", "pipe"]
@@ -44981,7 +45428,7 @@ function pushOverlays(opts) {
44981
45428
  Run \`olam skills atlas-user set <name>\` to configure your atlas user.`
44982
45429
  );
44983
45430
  }
44984
- const claudeDir2 = opts._testClaudeDir ?? opts.targetDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join105(homedir61(), ".claude");
45431
+ const claudeDir2 = opts._testClaudeDir ?? opts.targetDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join105(homedir62(), ".claude");
44985
45432
  const sourceFiles = walkPushSourceFiles(claudeDir2);
44986
45433
  const registeredPrefixes = (opts._testSkillSources ?? listSkillSources()).map((s) => s.prefix).filter((p) => typeof p === "string" && p.length > 0);
44987
45434
  if (registeredPrefixes.length > 0) {
@@ -45289,7 +45736,7 @@ Next steps (run in ${clonePath}):`,
45289
45736
  };
45290
45737
  }
45291
45738
  function migrateOverlays(opts = {}) {
45292
- const root = opts.targetDir ?? join105(homedir61(), ".claude");
45739
+ const root = opts.targetDir ?? join105(homedir62(), ".claude");
45293
45740
  const overrideRoots = [
45294
45741
  join105(root, "skills.overrides"),
45295
45742
  join105(root, "agents.overrides")
@@ -45411,7 +45858,7 @@ function registerFlywheelMigrateOverlays(parent) {
45411
45858
  }
45412
45859
  return;
45413
45860
  }
45414
- const root = opts.targetDir ?? join105(homedir61(), ".claude");
45861
+ const root = opts.targetDir ?? join105(homedir62(), ".claude");
45415
45862
  const summary2 = migrateOverlays(opts);
45416
45863
  if (opts.json === true) {
45417
45864
  process.stdout.write(JSON.stringify(summary2, null, 2) + "\n");
@@ -45468,7 +45915,7 @@ function registerFlywheel(program2) {
45468
45915
 
45469
45916
  // src/commands/seed.ts
45470
45917
  init_output();
45471
- import { spawnSync as spawnSync31, spawn as spawnAsync2 } from "node:child_process";
45918
+ import { spawnSync as spawnSync32, spawn as spawnAsync2 } from "node:child_process";
45472
45919
  var DEFAULT_SINGLETON_CONTAINER = "olam-postgres";
45473
45920
  var DEFAULT_SINGLETON_USER = "development";
45474
45921
  function assertValidSeedName(name) {
@@ -45479,7 +45926,7 @@ function assertValidSeedName(name) {
45479
45926
  }
45480
45927
  }
45481
45928
  function singletonDocker(container, user, args, stdin) {
45482
- return spawnSync31(
45929
+ return spawnSync32(
45483
45930
  "docker",
45484
45931
  ["exec", "-i", container, "psql", "-U", user, ...args],
45485
45932
  { encoding: "utf-8", input: stdin }
@@ -45534,7 +45981,7 @@ async function handleBake(opts) {
45534
45981
  if (sources.length > 1) {
45535
45982
  throw new Error("multiple sources specified \u2014 pass exactly one of --source-container, --source-url, --source-local");
45536
45983
  }
45537
- const ping = spawnSync31("docker", ["inspect", "--format", "{{.State.Status}}", singleton], { encoding: "utf-8" });
45984
+ const ping = spawnSync32("docker", ["inspect", "--format", "{{.State.Status}}", singleton], { encoding: "utf-8" });
45538
45985
  if (ping.status !== 0 || (ping.stdout || "").trim() !== "running") {
45539
45986
  throw new Error(`singleton container "${singleton}" not running \u2014 run \`olam bootstrap\` first`);
45540
45987
  }
@@ -45717,12 +46164,12 @@ init_output();
45717
46164
  import { spawnSync as defaultSpawnSync } from "node:child_process";
45718
46165
  import * as fs94 from "node:fs";
45719
46166
  import * as os49 from "node:os";
45720
- import * as path93 from "node:path";
46167
+ import * as path94 from "node:path";
45721
46168
  function devboxContainerName(worldId) {
45722
46169
  return `olam-${worldId}-devbox`;
45723
46170
  }
45724
46171
  function olamHomeDir() {
45725
- return process.env["OLAM_HOME"] ?? path93.join(os49.homedir(), ".olam");
46172
+ return process.env["OLAM_HOME"] ?? path94.join(os49.homedir(), ".olam");
45726
46173
  }
45727
46174
  function defaultRestartContainer(name, spawn13 = defaultSpawnSync) {
45728
46175
  const r = spawn13("docker", ["restart", "--time", "30", name], {
@@ -45736,7 +46183,7 @@ function defaultRestartContainer(name, spawn13 = defaultSpawnSync) {
45736
46183
  }
45737
46184
  function defaultAppendAuditLog(homeDir, line) {
45738
46185
  fs94.mkdirSync(homeDir, { recursive: true });
45739
- fs94.appendFileSync(path93.join(homeDir, "usage.log"), line.endsWith("\n") ? line : line + "\n", {
46186
+ fs94.appendFileSync(path94.join(homeDir, "usage.log"), line.endsWith("\n") ? line : line + "\n", {
45740
46187
  encoding: "utf-8"
45741
46188
  });
45742
46189
  }
@@ -45781,9 +46228,9 @@ async function doRekey(worldId, deps) {
45781
46228
  );
45782
46229
  const rotatedAt = deps.now().toISOString();
45783
46230
  const homeDir = deps.olamHomeDir();
45784
- const worldDir = path93.join(homeDir, "worlds", worldId);
46231
+ const worldDir = path94.join(homeDir, "worlds", worldId);
45785
46232
  fs94.mkdirSync(worldDir, { recursive: true });
45786
- const credentialsPath = path93.join(worldDir, "credentials.json");
46233
+ const credentialsPath = path94.join(worldDir, "credentials.json");
45787
46234
  const payload = {
45788
46235
  worldRoleName,
45789
46236
  password,
@@ -45858,12 +46305,12 @@ function registerRekey(program2) {
45858
46305
 
45859
46306
  // src/pleri-config.ts
45860
46307
  import * as fs95 from "node:fs";
45861
- import * as path94 from "node:path";
46308
+ import * as path95 from "node:path";
45862
46309
  function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
45863
46310
  if (process.env.PLERI_BASE_URL) {
45864
46311
  return true;
45865
46312
  }
45866
- const configPath = path94.join(configDir, "config.yaml");
46313
+ const configPath = path95.join(configDir, "config.yaml");
45867
46314
  if (!fs95.existsSync(configPath)) {
45868
46315
  return false;
45869
46316
  }
@@ -45902,6 +46349,7 @@ registerDestroy(program);
45902
46349
  registerClean(program);
45903
46350
  registerImplode(program);
45904
46351
  registerEnter(program);
46352
+ registerResume(program);
45905
46353
  registerCrystallize(program, { hidden: !isPleriConfigured() });
45906
46354
  registerPr(program);
45907
46355
  registerWorkspace(program);