@pleri/olam-cli 0.1.161 → 0.1.166

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 (54) hide show
  1. package/README.md +4 -4
  2. package/dist/agent-stream/agent-sdk-to-chunks.js +20 -2
  3. package/dist/commands/bootstrap.d.ts.map +1 -1
  4. package/dist/commands/bootstrap.js +35 -11
  5. package/dist/commands/bootstrap.js.map +1 -1
  6. package/dist/commands/flywheel/migrate-overlays.d.ts +1 -0
  7. package/dist/commands/flywheel/migrate-overlays.d.ts.map +1 -1
  8. package/dist/commands/flywheel/migrate-overlays.js +29 -3
  9. package/dist/commands/flywheel/migrate-overlays.js.map +1 -1
  10. package/dist/commands/skills-source.d.ts.map +1 -1
  11. package/dist/commands/skills-source.js +57 -2
  12. package/dist/commands/skills-source.js.map +1 -1
  13. package/dist/commands/skills.d.ts.map +1 -1
  14. package/dist/commands/skills.js +14 -0
  15. package/dist/commands/skills.js.map +1 -1
  16. package/dist/image-digests.json +7 -7
  17. package/dist/index.js +996 -618
  18. package/dist/lib/bootstrap-kubernetes.d.ts.map +1 -1
  19. package/dist/lib/bootstrap-kubernetes.js +93 -13
  20. package/dist/lib/bootstrap-kubernetes.js.map +1 -1
  21. package/dist/mcp-server.js +568 -368
  22. package/hermes-bundle/version.json +1 -1
  23. package/host-cp/k8s/manifests/50-deployment.yaml +1 -1
  24. package/host-cp/k8s/manifests/auth-service/50-deployment.yaml +1 -1
  25. package/host-cp/k8s/manifests/kg-service/50-deployment.yaml +1 -1
  26. package/host-cp/k8s/manifests/mcp-auth-service/50-deployment.yaml +1 -1
  27. package/host-cp/k8s/manifests/memory-service/50-deployment.yaml +1 -1
  28. package/host-cp/observability/grafana-port-forward.sh +12 -2
  29. package/host-cp/observability/kyverno-cardinality-mutate.sh +12 -2
  30. package/host-cp/observability/loki-ingest.sh +12 -2
  31. package/host-cp/observability/prom-no-double-grafana.sh +15 -5
  32. package/host-cp/peripheral-services/helm-values/grafana-values.yaml +159 -0
  33. package/host-cp/peripheral-services/helm-values/kube-prom-stack-values.yaml +229 -0
  34. package/host-cp/peripheral-services/helm-values/kyverno-values.yaml +85 -0
  35. package/host-cp/peripheral-services/helm-values/loki-values.yaml +166 -0
  36. package/host-cp/peripheral-services/helm-values/promtail-staging.yaml +92 -0
  37. package/host-cp/peripheral-services/helm-values/promtail-values.yaml +102 -0
  38. package/host-cp/peripheral-services/helm-values/traefik-values.yaml +73 -0
  39. package/host-cp/peripheral-services/manifests/20-namespace.yaml +6 -0
  40. package/host-cp/peripheral-services/manifests/24-deploy-kg-service.yaml +245 -0
  41. package/host-cp/peripheral-services/manifests/30-traefik-ingressroute-host-cp.yaml +22 -0
  42. package/host-cp/peripheral-services/manifests/40-traefik-ingressroute-kg.yaml +29 -0
  43. package/host-cp/peripheral-services/manifests/50-traefik-ingressroute-agent-memory.yaml +29 -0
  44. package/host-cp/peripheral-services/manifests/60-networkpolicy-ingress.yaml +80 -0
  45. package/host-cp/peripheral-services/manifests/65-networkpolicy-loki-prom-deny.yaml +67 -0
  46. package/host-cp/peripheral-services/manifests/80-grafana-dashboard-configmap.yaml +1349 -0
  47. package/host-cp/peripheral-services/manifests/90-prom-alert-cardinality.yaml +50 -0
  48. package/host-cp/peripheral-services/manifests/91-servicemonitor-host-cp.yaml +70 -0
  49. package/host-cp/peripheral-services/manifests/92-servicemonitor-kg-service.yaml +70 -0
  50. package/host-cp/peripheral-services/manifests/93-servicemonitor-memory-service.yaml +87 -0
  51. package/host-cp/peripheral-services/manifests/95-prom-recording-rules.yaml +108 -0
  52. package/host-cp/peripheral-services/manifests/96-kyverno-cardinality-mutate.yaml +195 -0
  53. package/host-cp/src/plan-chat-service.mjs +147 -1
  54. 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: path93, errorMaps, issueData } = params;
496
- const fullPath = [...path93, ...issueData.path || []];
495
+ const { data, path: path94, errorMaps, issueData } = params;
496
+ const fullPath = [...path94, ...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, path93, key) {
804
+ constructor(parent, value, path94, key) {
805
805
  this._cachedPath = [];
806
806
  this.parent = parent;
807
807
  this.data = value;
808
- this._path = path93;
808
+ this._path = path94;
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, path93, ctx, rejectSource) {
4289
+ function refineForbiddenKeys(value, path94, 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, path93, ctx, rejectSource) {
4294
4294
  if (FORBIDDEN_KEYS.has(key)) {
4295
4295
  ctx.addIssue({
4296
4296
  code: external_exports.ZodIssueCode.custom,
4297
- path: [...path93, key],
4297
+ path: [...path94, key],
4298
4298
  message: `forbidden key "${key}" (prototype-pollution surface)`
4299
4299
  });
4300
4300
  continue;
4301
4301
  }
4302
- if (rejectSource && path93.length === 0 && key === "source") {
4302
+ if (rejectSource && path94.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, path93, ctx, rejectSource) {
4307
4307
  });
4308
4308
  continue;
4309
4309
  }
4310
- refineForbiddenKeys(value[key], [...path93, key], ctx, false);
4310
+ refineForbiddenKeys(value[key], [...path94, key], ctx, false);
4311
4311
  }
4312
4312
  }
4313
- function rejectForbiddenKeys(value, path93, rejectSource) {
4313
+ function rejectForbiddenKeys(value, path94, 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] ${path93}: forbidden key "${key}" (prototype-pollution surface)`);
4319
+ throw new Error(`[manifest] ${path94}: forbidden key "${key}" (prototype-pollution surface)`);
4320
4320
  }
4321
4321
  if (rejectSource && key === "source") {
4322
- throw new Error(`[manifest] ${path93}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
4322
+ throw new Error(`[manifest] ${path94}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
4323
4323
  }
4324
- rejectForbiddenKeys(value[key], `${path93}.${key}`, false);
4324
+ rejectForbiddenKeys(value[key], `${path94}.${key}`, false);
4325
4325
  }
4326
4326
  }
4327
4327
  function unknownTopLevelKeys(parsed) {
@@ -5500,8 +5500,8 @@ var init_client = __esm({
5500
5500
  throw new Error(`failed to report rate-limit for ${accountId} (HTTP ${res.status})`);
5501
5501
  }
5502
5502
  }
5503
- async request(method, path93, body, attempt = 0) {
5504
- const url2 = `${this.baseUrl}${path93}`;
5503
+ async request(method, path94, body, attempt = 0) {
5504
+ const url2 = `${this.baseUrl}${path94}`;
5505
5505
  const controller = new AbortController();
5506
5506
  const timer = setTimeout(() => controller.abort(), this.timeoutMs);
5507
5507
  const headers = {};
@@ -5519,7 +5519,7 @@ var init_client = __esm({
5519
5519
  } catch (err) {
5520
5520
  if (attempt < RETRY_COUNT && isTransient(err)) {
5521
5521
  await sleep(RETRY_BACKOFF_MS * (attempt + 1));
5522
- return this.request(method, path93, body, attempt + 1);
5522
+ return this.request(method, path94, body, attempt + 1);
5523
5523
  }
5524
5524
  throw err;
5525
5525
  } finally {
@@ -7322,8 +7322,8 @@ var init_provider3 = __esm({
7322
7322
  // -----------------------------------------------------------------------
7323
7323
  // Internal fetch helper
7324
7324
  // -----------------------------------------------------------------------
7325
- async request(path93, method, body) {
7326
- const url2 = `${this.config.workerUrl}${path93}`;
7325
+ async request(path94, method, body) {
7326
+ const url2 = `${this.config.workerUrl}${path94}`;
7327
7327
  const bearer = await this.config.mintToken();
7328
7328
  const headers = {
7329
7329
  Authorization: `Bearer ${bearer}`
@@ -9092,17 +9092,17 @@ function kgRoot() {
9092
9092
  function worldsRoot() {
9093
9093
  return join17(olamHome(), "worlds");
9094
9094
  }
9095
- function assertWithinPrefix(path93, prefix, label) {
9096
- if (!path93.startsWith(prefix + "/")) {
9097
- throw new Error(`${label} escape: ${path93} not under ${prefix}/`);
9095
+ function assertWithinPrefix(path94, prefix, label) {
9096
+ if (!path94.startsWith(prefix + "/")) {
9097
+ throw new Error(`${label} escape: ${path94} not under ${prefix}/`);
9098
9098
  }
9099
9099
  }
9100
9100
  function kgPristinePath(workspace) {
9101
9101
  validateWorkspaceName(workspace);
9102
9102
  const root = kgRoot();
9103
- const path93 = resolve6(join17(root, workspace));
9104
- assertWithinPrefix(path93, root, "kgPristinePath");
9105
- return path93;
9103
+ const path94 = resolve6(join17(root, workspace));
9104
+ assertWithinPrefix(path94, root, "kgPristinePath");
9105
+ return path94;
9106
9106
  }
9107
9107
  var KG_PATHS_INTERNALS;
9108
9108
  var init_storage_paths = __esm({
@@ -11042,7 +11042,7 @@ var init_auto_dispatch_task = __esm({
11042
11042
  });
11043
11043
 
11044
11044
  // ../core/dist/skill-sources/schema.js
11045
- var SKILL_SOURCE_ID_LENGTH, NAME_PATTERN, URL_PATTERN, SkillSourceSchema;
11045
+ var SKILL_SOURCE_ID_LENGTH, NAME_PATTERN, URL_PATTERN, PREFIX_PATTERN, SkillSourceSchema;
11046
11046
  var init_schema3 = __esm({
11047
11047
  "../core/dist/skill-sources/schema.js"() {
11048
11048
  "use strict";
@@ -11050,13 +11050,24 @@ var init_schema3 = __esm({
11050
11050
  SKILL_SOURCE_ID_LENGTH = 12;
11051
11051
  NAME_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
11052
11052
  URL_PATTERN = /^(?:https?:\/\/|git@|ssh:\/\/|file:\/\/|\/).+/;
11053
+ PREFIX_PATTERN = /^[a-z0-9][a-z0-9_-]{0,38}$/;
11053
11054
  SkillSourceSchema = external_exports.object({
11054
11055
  id: external_exports.string().length(SKILL_SOURCE_ID_LENGTH, `skill-source id must be exactly ${SKILL_SOURCE_ID_LENGTH} chars (sha256-of-url prefix)`).regex(/^[a-f0-9]+$/, "skill-source id must be lowercase hex"),
11055
11056
  name: external_exports.string().regex(NAME_PATTERN, "skill-source name must be ASCII lowercase + digits + dash (1-64 chars, no leading/trailing dash)"),
11056
11057
  gitUrl: external_exports.string().min(1, "gitUrl must not be empty").regex(URL_PATTERN, "gitUrl must look like a git URL (https://, git@, ssh://, file://, or absolute path)"),
11057
11058
  branch: external_exports.string().min(1, "branch must not be empty").default("main"),
11058
11059
  addedAt: external_exports.number().int().nonnegative(),
11059
- lastPulledSha: external_exports.string().regex(/^[a-f0-9]{40}$/, "lastPulledSha must be a 40-char lowercase hex git SHA").optional()
11060
+ lastPulledSha: external_exports.string().regex(/^[a-f0-9]{40}$/, "lastPulledSha must be a 40-char lowercase hex git SHA").optional(),
11061
+ /**
11062
+ * Optional rename prefix. When set, skills+agents from this source are
11063
+ * deployed under `<prefix>:<canonical-name>` (both filename + frontmatter
11064
+ * `name:` rewritten). Source clone + atlas-toolbox member overlays remain
11065
+ * canonical-named on disk; the rename is purely a deploy-time view.
11066
+ * Operator overlay files (`~/.claude/{skills,agents}.overrides/`) MUST
11067
+ * use canonical names; `olam flywheel migrate-overlays --push` enforces
11068
+ * this via the reverse validator.
11069
+ */
11070
+ prefix: external_exports.string().regex(PREFIX_PATTERN, "skill-source prefix must be ASCII lowercase + digits + dash/underscore (1-39 chars, no leading/trailing dash)").optional()
11060
11071
  });
11061
11072
  }
11062
11073
  });
@@ -15613,10 +15624,10 @@ async function readHostCpToken2() {
15613
15624
  if (!fs26.existsSync(tp)) return null;
15614
15625
  return fs26.readFileSync(tp, "utf-8").trim();
15615
15626
  }
15616
- async function callHostCpProxy(method, worldId, path93, body) {
15627
+ async function callHostCpProxy(method, worldId, path94, body) {
15617
15628
  const token = await readHostCpToken2();
15618
15629
  if (!token) return { ok: false, status: 0, error: "no token (host CP not started)" };
15619
- const url2 = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path93}`;
15630
+ const url2 = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path94}`;
15620
15631
  try {
15621
15632
  const headers = {
15622
15633
  Authorization: `Bearer ${token}`
@@ -16282,7 +16293,8 @@ var init_trust_audit_log = __esm({
16282
16293
  "removed",
16283
16294
  "meta-hook-stripped",
16284
16295
  "setup-skill-source-picked",
16285
- "setup-project-sweep-completed"
16296
+ "setup-project-sweep-completed",
16297
+ "prefix-collision"
16286
16298
  ]);
16287
16299
  TrustMethodSchema = external_exports.enum(["flag", "interactive", "auto-reject-tty", "none"]);
16288
16300
  TrustAuditEntrySchema = external_exports.object({
@@ -16395,24 +16407,49 @@ function updateSkillSource(id, patch) {
16395
16407
  throw new Error(`skill-source name "${patch.name}" already in use by id "${collision.id}".`);
16396
16408
  }
16397
16409
  }
16410
+ if (patch.prefix !== void 0 && patch.prefix !== null) {
16411
+ if (!PREFIX_PATTERN2.test(patch.prefix)) {
16412
+ throw new Error(`prefix must match /^[a-z0-9][a-z0-9_-]{0,38}$/ \u2014 got "${patch.prefix}"`);
16413
+ }
16414
+ }
16398
16415
  const existing = config.skillSources[idx];
16416
+ let prefixUpdate = {};
16417
+ if (patch.prefix === null) {
16418
+ const { prefix: _dropped, ...rest } = existing;
16419
+ void _dropped;
16420
+ const updated2 = {
16421
+ ...rest,
16422
+ ...patch.name !== void 0 ? { name: patch.name } : {},
16423
+ ...patch.branch !== void 0 ? { branch: patch.branch } : {},
16424
+ ...patch.lastPulledSha !== void 0 ? { lastPulledSha: patch.lastPulledSha } : {}
16425
+ };
16426
+ const next2 = [...config.skillSources];
16427
+ next2[idx] = updated2;
16428
+ writeGlobalConfig({ ...config, skillSources: next2 });
16429
+ return updated2;
16430
+ } else if (patch.prefix !== void 0) {
16431
+ prefixUpdate = { prefix: patch.prefix };
16432
+ }
16399
16433
  const updated = {
16400
16434
  ...existing,
16401
16435
  ...patch.name !== void 0 ? { name: patch.name } : {},
16402
16436
  ...patch.branch !== void 0 ? { branch: patch.branch } : {},
16403
- ...patch.lastPulledSha !== void 0 ? { lastPulledSha: patch.lastPulledSha } : {}
16437
+ ...patch.lastPulledSha !== void 0 ? { lastPulledSha: patch.lastPulledSha } : {},
16438
+ ...prefixUpdate
16404
16439
  };
16405
16440
  const next = [...config.skillSources];
16406
16441
  next[idx] = updated;
16407
16442
  writeGlobalConfig({ ...config, skillSources: next });
16408
16443
  return updated;
16409
16444
  }
16445
+ var PREFIX_PATTERN2;
16410
16446
  var init_store3 = __esm({
16411
16447
  "../core/dist/skill-sources/store.js"() {
16412
16448
  "use strict";
16413
16449
  init_store2();
16414
16450
  init_schema3();
16415
16451
  init_trust_audit_log();
16452
+ PREFIX_PATTERN2 = /^[a-z0-9][a-z0-9_-]{0,38}$/;
16416
16453
  }
16417
16454
  });
16418
16455
 
@@ -18739,17 +18776,195 @@ var init_managed_merge = __esm({
18739
18776
  }
18740
18777
  });
18741
18778
 
18742
- // ../core/dist/skill-sync/engine.js
18779
+ // ../core/dist/skill-sync/prefix-rules.js
18780
+ function applyPrefix(name, prefix, otherKnownPrefixes = []) {
18781
+ if (prefix.length === 0) {
18782
+ throw new Error("applyPrefix: prefix must be non-empty");
18783
+ }
18784
+ if (prefix.includes(":")) {
18785
+ throw new Error(`applyPrefix: prefix must not contain ':' (got "${prefix}")`);
18786
+ }
18787
+ if (name.startsWith(`${prefix}:`))
18788
+ return name;
18789
+ for (const other of otherKnownPrefixes) {
18790
+ if (other.length > 0 && name.startsWith(`${other}:`))
18791
+ return name;
18792
+ }
18793
+ return `${prefix}:${name}`;
18794
+ }
18795
+ function rewriteFrontmatterName(content, rewriter) {
18796
+ const text = content.toString("utf-8");
18797
+ const parsed = parseFrontmatter3(text);
18798
+ if (Object.keys(parsed.fm).length === 0)
18799
+ return content;
18800
+ const currentName = parsed.fm["name"];
18801
+ if (currentName === void 0)
18802
+ return content;
18803
+ const newName = rewriter(currentName);
18804
+ if (newName === currentName)
18805
+ return content;
18806
+ const nextFm = { ...parsed.fm, name: newName };
18807
+ const rebuilt = serializeFrontmatter(nextFm) + parsed.body;
18808
+ return Buffer.from(rebuilt, "utf-8");
18809
+ }
18810
+ function validateCanonical(filenameBasename, content, registeredPrefixes) {
18811
+ if (registeredPrefixes.length === 0)
18812
+ return { ok: true };
18813
+ const bareName = filenameBasename.replace(/\.md$/, "");
18814
+ for (const prefix of registeredPrefixes) {
18815
+ if (prefix.length === 0)
18816
+ continue;
18817
+ if (bareName.startsWith(`${prefix}:`)) {
18818
+ return {
18819
+ ok: false,
18820
+ violation: { kind: "filename", prefix, value: filenameBasename }
18821
+ };
18822
+ }
18823
+ }
18824
+ const text = content.toString("utf-8");
18825
+ const parsed = parseFrontmatter3(text);
18826
+ const fmName = parsed.fm["name"];
18827
+ if (fmName === void 0)
18828
+ return { ok: true };
18829
+ for (const prefix of registeredPrefixes) {
18830
+ if (prefix.length === 0)
18831
+ continue;
18832
+ if (fmName.startsWith(`${prefix}:`)) {
18833
+ return {
18834
+ ok: false,
18835
+ violation: { kind: "frontmatter", prefix, value: fmName }
18836
+ };
18837
+ }
18838
+ }
18839
+ return { ok: true };
18840
+ }
18841
+ function formatCanonicalViolation(filePath, violation) {
18842
+ const surface = violation.kind === "filename" ? "filename" : "frontmatter `name:` field";
18843
+ const stripped = violation.value.replace(new RegExp(`^${violation.prefix}:`), "");
18844
+ return [
18845
+ `overlay ${filePath} carries registered prefix "${violation.prefix}:" in its ${surface} ("${violation.value}").`,
18846
+ `Overlays MUST use canonical names \u2014 renaming is a deploy-time view, not a content rewrite.`,
18847
+ `Fix: rename to "${stripped}" (also strip from frontmatter name: if present).`,
18848
+ `See docs/plans/skill-prefix-rules/README.md \xA7 Bidirectional invariant.`
18849
+ ].join("\n ");
18850
+ }
18851
+ var init_prefix_rules = __esm({
18852
+ "../core/dist/skill-sync/prefix-rules.js"() {
18853
+ "use strict";
18854
+ init_markdown_merger();
18855
+ }
18856
+ });
18857
+
18858
+ // ../core/dist/skill-sync/prefix-deploy.js
18743
18859
  import * as fs68 from "node:fs";
18744
- import * as os36 from "node:os";
18745
18860
  import * as path67 from "node:path";
18861
+ function buildSourcePrefixMap(sources) {
18862
+ const byId = /* @__PURE__ */ new Map();
18863
+ const prefixes = /* @__PURE__ */ new Set();
18864
+ for (const s of sources) {
18865
+ if (s.prefix !== void 0 && s.prefix.length > 0) {
18866
+ byId.set(s.id, s.prefix);
18867
+ prefixes.add(s.prefix);
18868
+ }
18869
+ }
18870
+ return {
18871
+ get: (sourceId) => byId.get(sourceId),
18872
+ registeredPrefixes: Array.from(prefixes)
18873
+ };
18874
+ }
18875
+ function applyPrefixRewrites(baseArtifacts, sourceMap, claudeDir2, dryRun) {
18876
+ const result = { rewrittenCount: 0, entries: [] };
18877
+ for (const artifact of baseArtifacts) {
18878
+ if (artifact.kind !== "skill" && artifact.kind !== "agent")
18879
+ continue;
18880
+ const prefix = sourceMap.get(artifact.sourceId);
18881
+ if (prefix === void 0)
18882
+ continue;
18883
+ const canonical = artifact.deployBasename;
18884
+ const otherPrefixes = sourceMap.registeredPrefixes.filter((p) => p !== prefix);
18885
+ const renamed = applyPrefix(canonical, prefix, otherPrefixes);
18886
+ if (renamed === canonical)
18887
+ continue;
18888
+ const renamedFrontmatterName = renamed.replace(/\.md$/, "");
18889
+ if (dryRun) {
18890
+ artifact.deployBasename = renamed;
18891
+ result.rewrittenCount += 1;
18892
+ result.entries.push({
18893
+ sourceId: artifact.sourceId,
18894
+ kind: artifact.kind,
18895
+ canonicalBasename: canonical,
18896
+ renamedBasename: renamed,
18897
+ prefix
18898
+ });
18899
+ continue;
18900
+ }
18901
+ if (artifact.kind === "skill") {
18902
+ const skillMdPath = path67.join(artifact.sourcePath, "SKILL.md");
18903
+ const content = fs68.readFileSync(skillMdPath);
18904
+ const rewritten = rewriteFrontmatterName(content, () => renamedFrontmatterName);
18905
+ const managedDir = materializeMergedSkill({
18906
+ sourceId: artifact.sourceId,
18907
+ sourcePath: artifact.sourcePath,
18908
+ deployBasename: renamed,
18909
+ mergedContent: rewritten,
18910
+ claudeDir: claudeDir2
18911
+ });
18912
+ artifact.sourcePath = managedDir;
18913
+ artifact.deployBasename = renamed;
18914
+ } else {
18915
+ const content = artifact.resolvedContent !== void 0 ? artifact.resolvedContent : fs68.readFileSync(artifact.sourcePath);
18916
+ const rewritten = rewriteFrontmatterName(content, () => renamedFrontmatterName);
18917
+ artifact.resolvedContent = rewritten;
18918
+ artifact.deployBasename = renamed;
18919
+ }
18920
+ result.rewrittenCount += 1;
18921
+ result.entries.push({
18922
+ sourceId: artifact.sourceId,
18923
+ kind: artifact.kind,
18924
+ canonicalBasename: canonical,
18925
+ renamedBasename: renamed,
18926
+ prefix
18927
+ });
18928
+ }
18929
+ return result;
18930
+ }
18931
+ function detectPrefixCollisions(sources) {
18932
+ const byPrefix = /* @__PURE__ */ new Map();
18933
+ for (const s of sources) {
18934
+ if (s.prefix === void 0 || s.prefix.length === 0)
18935
+ continue;
18936
+ const ids = byPrefix.get(s.prefix) ?? [];
18937
+ ids.push(s.id);
18938
+ byPrefix.set(s.prefix, ids);
18939
+ }
18940
+ const collisions = [];
18941
+ for (const [prefix, ids] of byPrefix.entries()) {
18942
+ if (ids.length < 2)
18943
+ continue;
18944
+ const [winner, ...losers] = ids;
18945
+ collisions.push({ prefix, winnerSourceId: winner, loserSourceIds: losers });
18946
+ }
18947
+ return collisions;
18948
+ }
18949
+ var init_prefix_deploy = __esm({
18950
+ "../core/dist/skill-sync/prefix-deploy.js"() {
18951
+ "use strict";
18952
+ init_prefix_rules();
18953
+ init_managed_merge();
18954
+ }
18955
+ });
18956
+
18957
+ // ../core/dist/skill-sync/engine.js
18958
+ import * as fs69 from "node:fs";
18959
+ import * as os36 from "node:os";
18960
+ import * as path68 from "node:path";
18746
18961
  function resolveAtlasUser(override) {
18747
18962
  if (override)
18748
18963
  return override;
18749
- const claudeDir2 = process.env["OLAM_CLAUDE_DIR"] || path67.join(os36.homedir(), ".claude");
18750
- const f = path67.join(claudeDir2, ".atlas-user");
18751
- if (fs68.existsSync(f)) {
18752
- return fs68.readFileSync(f, "utf-8").trim() || void 0;
18964
+ const claudeDir2 = process.env["OLAM_CLAUDE_DIR"] || path68.join(os36.homedir(), ".claude");
18965
+ const f = path68.join(claudeDir2, ".atlas-user");
18966
+ if (fs69.existsSync(f)) {
18967
+ return fs69.readFileSync(f, "utf-8").trim() || void 0;
18753
18968
  }
18754
18969
  return void 0;
18755
18970
  }
@@ -18761,7 +18976,7 @@ async function syncSkills(opts = {}) {
18761
18976
  const perSource = [];
18762
18977
  for (const source of sources) {
18763
18978
  const clonePath = skillSourceClonePath(source.id);
18764
- if (!fs68.existsSync(clonePath))
18979
+ if (!fs69.existsSync(clonePath))
18765
18980
  continue;
18766
18981
  const { artifacts, subscription } = await withFileLock(clonePath, () => {
18767
18982
  const pinRef = projectOverride?.override.pin?.[source.id];
@@ -18799,9 +19014,15 @@ async function syncSkills(opts = {}) {
18799
19014
  const memberOverlaysEnabled = process.env["OLAM_MEMBER_OVERLAYS"] === "1";
18800
19015
  const baseArtifacts = projectFilteredArtifacts.filter((a) => a.kind !== "overlay");
18801
19016
  const overlayArtifacts = memberOverlaysEnabled ? projectFilteredArtifacts.filter((a) => a.kind === "overlay") : [];
18802
- if (memberOverlaysEnabled && overlayArtifacts.length > 0 && !opts.dryRun) {
19017
+ const sourcePrefixMap = buildSourcePrefixMap(sources);
19018
+ const hasPrefixRewrites = sources.some((s) => s.prefix !== void 0 && s.prefix.length > 0);
19019
+ const willMutateManagedDir = !opts.dryRun && (memberOverlaysEnabled && overlayArtifacts.length > 0 || hasPrefixRewrites);
19020
+ if (willMutateManagedDir) {
18803
19021
  const claude = claudeDir();
18804
19022
  cleanMergedDir(claude);
19023
+ }
19024
+ if (memberOverlaysEnabled && overlayArtifacts.length > 0 && !opts.dryRun) {
19025
+ const claude = claudeDir();
18805
19026
  for (const overlay of overlayArtifacts) {
18806
19027
  if (!overlay.targetKind)
18807
19028
  continue;
@@ -18811,13 +19032,13 @@ async function syncSkills(opts = {}) {
18811
19032
  let baseContent;
18812
19033
  let basePath;
18813
19034
  if (overlay.targetKind === "skill") {
18814
- basePath = path67.join(base.sourcePath, "SKILL.md");
18815
- baseContent = fs68.readFileSync(basePath, "utf-8");
19035
+ basePath = path68.join(base.sourcePath, "SKILL.md");
19036
+ baseContent = fs69.readFileSync(basePath, "utf-8");
18816
19037
  } else {
18817
19038
  basePath = base.sourcePath;
18818
- baseContent = fs68.readFileSync(basePath, "utf-8");
19039
+ baseContent = fs69.readFileSync(basePath, "utf-8");
18819
19040
  }
18820
- const overlayContent = fs68.readFileSync(overlay.sourcePath, "utf-8");
19041
+ const overlayContent = fs69.readFileSync(overlay.sourcePath, "utf-8");
18821
19042
  const label = `${overlay.sourceId}/${overlay.deployBasename}`;
18822
19043
  const mergeResult = mergeMarkdown(baseContent, overlayContent, label, basePath, overlay.sourcePath);
18823
19044
  if ("error" in mergeResult) {
@@ -18841,6 +19062,23 @@ async function syncSkills(opts = {}) {
18841
19062
  }
18842
19063
  const hookFiles = projectFilteredArtifacts.filter((a) => a.kind === "hook").map((a) => a.sourcePath);
18843
19064
  const permissionFiles = projectFilteredArtifacts.filter((a) => a.kind === "permission").map((a) => a.sourcePath);
19065
+ const claudeDirForRewrites = claudeDir();
19066
+ const prefixRewriteResult = applyPrefixRewrites(baseArtifacts, sourcePrefixMap, claudeDirForRewrites, opts.dryRun === true);
19067
+ const prefixCollisions = detectPrefixCollisions(sources);
19068
+ if (!opts.dryRun) {
19069
+ for (const collision of prefixCollisions) {
19070
+ try {
19071
+ appendTrustAudit({
19072
+ gitUrl: "internal:prefix-collision",
19073
+ action: "prefix-collision",
19074
+ trustMethod: "none",
19075
+ sourceId: collision.winnerSourceId,
19076
+ note: `prefix="${collision.prefix}"; winner=${collision.winnerSourceId}; losers=${collision.loserSourceIds.join(",")}`
19077
+ });
19078
+ } catch {
19079
+ }
19080
+ }
19081
+ }
18844
19082
  const summary2 = {
18845
19083
  sourceCount: sources.length,
18846
19084
  artifactCount: projectFilteredArtifacts.length,
@@ -18851,13 +19089,15 @@ async function syncSkills(opts = {}) {
18851
19089
  deploy: void 0,
18852
19090
  merge: void 0,
18853
19091
  metaHooks: void 0,
18854
- perSource
19092
+ perSource,
19093
+ prefixRewrites: prefixRewriteResult.entries,
19094
+ prefixCollisions
18855
19095
  };
18856
19096
  if (opts.dryRun) {
18857
19097
  summary2.collisions = detectCollisions(baseArtifacts).collisions;
18858
19098
  return summary2;
18859
19099
  }
18860
- const claudeDirPath = process.env["OLAM_CLAUDE_DIR"] || path67.join(os36.homedir(), ".claude");
19100
+ const claudeDirPath = process.env["OLAM_CLAUDE_DIR"] || path68.join(os36.homedir(), ".claude");
18861
19101
  const overlayReferences = scanOverlayReferences(claudeDirPath, SHIM_TARGETS.map((t) => t.basename));
18862
19102
  summary2.deploy = deployArtifacts(baseArtifacts, {
18863
19103
  installedOlamVersion,
@@ -18883,19 +19123,19 @@ async function injectMetaHooksIntoSettings(opts) {
18883
19123
  const result = await withSettingsJsonLock(() => {
18884
19124
  let currentSettings = {};
18885
19125
  let settingsExisted = false;
18886
- if (fs68.existsSync(settingsFile)) {
19126
+ if (fs69.existsSync(settingsFile)) {
18887
19127
  settingsExisted = true;
18888
19128
  try {
18889
- const raw = fs68.readFileSync(settingsFile, "utf-8");
19129
+ const raw = fs69.readFileSync(settingsFile, "utf-8");
18890
19130
  currentSettings = raw.trim() ? JSON.parse(raw) : {};
18891
19131
  } catch {
18892
19132
  try {
18893
- const raw = fs68.readFileSync(settingsFile);
18894
- const bakDir = path67.join(path67.dirname(settingsFile), ".malformed-backups");
18895
- fs68.mkdirSync(bakDir, { recursive: true });
19133
+ const raw = fs69.readFileSync(settingsFile);
19134
+ const bakDir = path68.join(path68.dirname(settingsFile), ".malformed-backups");
19135
+ fs69.mkdirSync(bakDir, { recursive: true });
18896
19136
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
18897
- const bakFile = path67.join(bakDir, `settings.json.malformed.${stamp}.bak`);
18898
- fs68.writeFileSync(bakFile, raw, { mode: 384 });
19137
+ const bakFile = path68.join(bakDir, `settings.json.malformed.${stamp}.bak`);
19138
+ fs69.writeFileSync(bakFile, raw, { mode: 384 });
18899
19139
  snapshotError = `settings.json was malformed; original bytes preserved at ${bakFile}`;
18900
19140
  } catch (bakErr) {
18901
19141
  snapshotError = `settings.json malformed AND .bak write failed: ${bakErr instanceof Error ? bakErr.message : String(bakErr)}`;
@@ -18945,10 +19185,10 @@ async function injectMetaHooksIntoSettings(opts) {
18945
19185
  } catch {
18946
19186
  }
18947
19187
  }
18948
- fs68.mkdirSync(path67.dirname(settingsFile), { recursive: true });
19188
+ fs69.mkdirSync(path68.dirname(settingsFile), { recursive: true });
18949
19189
  const tmpPath = `${settingsFile}.tmp-${process.pid}-${Date.now()}`;
18950
- fs68.writeFileSync(tmpPath, JSON.stringify(inject.nextSettings, null, 2) + "\n");
18951
- fs68.renameSync(tmpPath, settingsFile);
19190
+ fs69.writeFileSync(tmpPath, JSON.stringify(inject.nextSettings, null, 2) + "\n");
19191
+ fs69.renameSync(tmpPath, settingsFile);
18952
19192
  return inject;
18953
19193
  }, { reason: `syncSkills meta-hook injection (mode=${mode})` });
18954
19194
  return {
@@ -18982,23 +19222,24 @@ var init_engine = __esm({
18982
19222
  init_meta_hook_injector();
18983
19223
  init_markdown_merger();
18984
19224
  init_managed_merge();
19225
+ init_prefix_deploy();
18985
19226
  }
18986
19227
  });
18987
19228
 
18988
19229
  // ../core/dist/skill-sync/shadow-backup-manager.js
18989
- import * as fs69 from "node:fs";
18990
- import * as path68 from "node:path";
19230
+ import * as fs70 from "node:fs";
19231
+ import * as path69 from "node:path";
18991
19232
  function listShadowBackups(opts = {}) {
18992
19233
  const claude = opts.claudeDirOverride ?? claudeDir();
18993
19234
  const now = opts.now ?? Date.now();
18994
19235
  const out = [];
18995
19236
  for (const bucket of SHADOW_BACKUP_BUCKETS) {
18996
- const bucketDir = path68.join(claude, bucket);
18997
- if (!fs69.existsSync(bucketDir))
19237
+ const bucketDir = path69.join(claude, bucket);
19238
+ if (!fs70.existsSync(bucketDir))
18998
19239
  continue;
18999
19240
  let entries;
19000
19241
  try {
19001
- entries = fs69.readdirSync(bucketDir);
19242
+ entries = fs70.readdirSync(bucketDir);
19002
19243
  } catch {
19003
19244
  continue;
19004
19245
  }
@@ -19009,10 +19250,10 @@ function listShadowBackups(opts = {}) {
19009
19250
  const epochSeconds = Number.parseInt(match2[1], 10);
19010
19251
  if (!Number.isFinite(epochSeconds) || epochSeconds < 0)
19011
19252
  continue;
19012
- const full = path68.join(bucketDir, name);
19253
+ const full = path69.join(bucketDir, name);
19013
19254
  let sizeBytes = 0;
19014
19255
  try {
19015
- const st = fs69.statSync(full);
19256
+ const st = fs70.statSync(full);
19016
19257
  if (st.isDirectory())
19017
19258
  continue;
19018
19259
  sizeBytes = st.size;
@@ -19025,7 +19266,7 @@ function listShadowBackups(opts = {}) {
19025
19266
  bucket,
19026
19267
  basename: name,
19027
19268
  originalBasename,
19028
- originalPath: path68.join(bucketDir, originalBasename),
19269
+ originalPath: path69.join(bucketDir, originalBasename),
19029
19270
  epochSeconds,
19030
19271
  ageMs: now - epochSeconds * 1e3,
19031
19272
  sizeBytes
@@ -19068,7 +19309,7 @@ function pruneShadowBackups(opts) {
19068
19309
  }
19069
19310
  if (!opts.dryRun) {
19070
19311
  try {
19071
- fs69.unlinkSync(b.path);
19312
+ fs70.unlinkSync(b.path);
19072
19313
  } catch {
19073
19314
  skipped.push(b);
19074
19315
  continue;
@@ -19079,24 +19320,24 @@ function pruneShadowBackups(opts) {
19079
19320
  return { deleted, skipped };
19080
19321
  }
19081
19322
  function restoreShadowBackup(opts) {
19082
- const abs = path68.resolve(opts.backupPath);
19083
- if (!fs69.existsSync(abs)) {
19323
+ const abs = path69.resolve(opts.backupPath);
19324
+ if (!fs70.existsSync(abs)) {
19084
19325
  throw new Error(`backup file not found: ${abs}`);
19085
19326
  }
19086
- const basename16 = path68.basename(abs);
19327
+ const basename16 = path69.basename(abs);
19087
19328
  const match2 = SHADOW_BACKUP_SUFFIX_RE.exec(basename16);
19088
19329
  if (!match2) {
19089
19330
  throw new Error(`not a shadow-backup file (basename "${basename16}" does not match \`.shadow-backup-<epoch>\`): ${abs}`);
19090
19331
  }
19091
19332
  const originalBasename = basename16.slice(0, basename16.length - match2[0].length);
19092
- const originalPath = path68.join(path68.dirname(abs), originalBasename);
19093
- if (fs69.existsSync(originalPath) && !opts.force) {
19333
+ const originalPath = path69.join(path69.dirname(abs), originalBasename);
19334
+ if (fs70.existsSync(originalPath) && !opts.force) {
19094
19335
  throw new Error(`original path already occupied: ${originalPath}. Move/rename it first OR re-run with --force.`);
19095
19336
  }
19096
- if (opts.force && fs69.existsSync(originalPath)) {
19097
- fs69.unlinkSync(originalPath);
19337
+ if (opts.force && fs70.existsSync(originalPath)) {
19338
+ fs70.unlinkSync(originalPath);
19098
19339
  }
19099
- fs69.renameSync(abs, originalPath);
19340
+ fs70.renameSync(abs, originalPath);
19100
19341
  return { restoredTo: originalPath };
19101
19342
  }
19102
19343
  var SHADOW_BACKUP_BUCKETS, SHADOW_BACKUP_SUFFIX_RE;
@@ -19110,12 +19351,12 @@ var init_shadow_backup_manager = __esm({
19110
19351
  });
19111
19352
 
19112
19353
  // ../core/dist/global-config/repos.js
19113
- import * as fs70 from "node:fs";
19354
+ import * as fs71 from "node:fs";
19114
19355
  import * as os37 from "node:os";
19115
- import * as path69 from "node:path";
19356
+ import * as path70 from "node:path";
19116
19357
  function expandPath(p) {
19117
19358
  if (p === "~" || p.startsWith("~/")) {
19118
- return path69.join(os37.homedir(), p.slice(1));
19359
+ return path70.join(os37.homedir(), p.slice(1));
19119
19360
  }
19120
19361
  return p;
19121
19362
  }
@@ -19128,7 +19369,7 @@ function addRepo(entry) {
19128
19369
  throw new Error(`repo "${entry.name}" already registered. Use "olam repos update" to change its path.`);
19129
19370
  }
19130
19371
  const resolvedPath = expandPath(entry.path);
19131
- if (!fs70.existsSync(resolvedPath)) {
19372
+ if (!fs71.existsSync(resolvedPath)) {
19132
19373
  throw new Error(`path "${entry.path}" does not exist. Verify the path is correct.`);
19133
19374
  }
19134
19375
  const now = Date.now();
@@ -19157,7 +19398,7 @@ function updateRepo(name, updates) {
19157
19398
  throw new Error(`repo "${name}" is not registered. Run "olam repos list" to see registered repos.`);
19158
19399
  }
19159
19400
  const resolvedUpdatePath = updates.path !== void 0 ? expandPath(updates.path) : void 0;
19160
- if (resolvedUpdatePath !== void 0 && !fs70.existsSync(resolvedUpdatePath)) {
19401
+ if (resolvedUpdatePath !== void 0 && !fs71.existsSync(resolvedUpdatePath)) {
19161
19402
  throw new Error(`path "${updates.path}" does not exist. Verify the path is correct.`);
19162
19403
  }
19163
19404
  const existing = config.repos[idx];
@@ -19226,14 +19467,14 @@ var init_global_config = __esm({
19226
19467
  });
19227
19468
 
19228
19469
  // ../core/dist/skill-sources/doctor-checks.js
19229
- import * as fs71 from "node:fs";
19230
- import * as path70 from "node:path";
19470
+ import * as fs72 from "node:fs";
19471
+ import * as path71 from "node:path";
19231
19472
  import * as os38 from "node:os";
19232
19473
  function claudeDirInternal3() {
19233
19474
  const override = process.env["OLAM_CLAUDE_DIR"];
19234
19475
  if (override && override.length > 0)
19235
19476
  return override;
19236
- return path70.join(os38.homedir(), ".claude");
19477
+ return path71.join(os38.homedir(), ".claude");
19237
19478
  }
19238
19479
  function checkStateFileParse() {
19239
19480
  const filePath = globalConfigPath();
@@ -19242,11 +19483,11 @@ function checkStateFileParse() {
19242
19483
  healthy: true,
19243
19484
  description: `~/.olam state file (${filePath})`
19244
19485
  };
19245
- if (!fs71.existsSync(filePath)) {
19486
+ if (!fs72.existsSync(filePath)) {
19246
19487
  result.details = ["(file does not yet exist \u2014 will be created on first write)"];
19247
19488
  return result;
19248
19489
  }
19249
- const raw = fs71.readFileSync(filePath, "utf-8");
19490
+ const raw = fs72.readFileSync(filePath, "utf-8");
19250
19491
  let parsed;
19251
19492
  try {
19252
19493
  parsed = JSON.parse(raw);
@@ -19256,8 +19497,8 @@ function checkStateFileParse() {
19256
19497
  result.details = [err instanceof Error ? err.message : String(err)];
19257
19498
  result.repair = () => {
19258
19499
  const aside = `${filePath}.corrupt-${Math.floor(Date.now() / 1e3)}`;
19259
- fs71.renameSync(filePath, aside);
19260
- fs71.writeFileSync(filePath, JSON.stringify({ schemaVersion: 1, repos: [], runbooks: [], skillSources: [] }, null, 2));
19500
+ fs72.renameSync(filePath, aside);
19501
+ fs72.writeFileSync(filePath, JSON.stringify({ schemaVersion: 1, repos: [], runbooks: [], skillSources: [] }, null, 2));
19261
19502
  };
19262
19503
  return result;
19263
19504
  }
@@ -19268,7 +19509,7 @@ function checkStateFileParse() {
19268
19509
  result.details = validation.error.issues.map((e) => `${e.path.join(".")}: ${e.message}`);
19269
19510
  result.repair = () => {
19270
19511
  const aside = `${filePath}.corrupt-${Math.floor(Date.now() / 1e3)}`;
19271
- fs71.copyFileSync(filePath, aside);
19512
+ fs72.copyFileSync(filePath, aside);
19272
19513
  const base = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
19273
19514
  const next = {
19274
19515
  ...base,
@@ -19277,7 +19518,7 @@ function checkStateFileParse() {
19277
19518
  runbooks: [],
19278
19519
  skillSources: []
19279
19520
  };
19280
- fs71.writeFileSync(filePath, JSON.stringify(next, null, 2));
19521
+ fs72.writeFileSync(filePath, JSON.stringify(next, null, 2));
19281
19522
  };
19282
19523
  return result;
19283
19524
  }
@@ -19288,16 +19529,16 @@ function checkDanglingSymlinks() {
19288
19529
  const buckets = ["commands", "agents", "skills", "scripts", "rules"];
19289
19530
  const dangling = [];
19290
19531
  for (const bucket of buckets) {
19291
- const dir = path70.join(claude, bucket);
19292
- if (!fs71.existsSync(dir))
19532
+ const dir = path71.join(claude, bucket);
19533
+ if (!fs72.existsSync(dir))
19293
19534
  continue;
19294
- for (const name of fs71.readdirSync(dir)) {
19295
- const linkPath = path70.join(dir, name);
19535
+ for (const name of fs72.readdirSync(dir)) {
19536
+ const linkPath = path71.join(dir, name);
19296
19537
  try {
19297
- const lst = fs71.lstatSync(linkPath);
19538
+ const lst = fs72.lstatSync(linkPath);
19298
19539
  if (!lst.isSymbolicLink())
19299
19540
  continue;
19300
- if (!fs71.existsSync(linkPath)) {
19541
+ if (!fs72.existsSync(linkPath)) {
19301
19542
  dangling.push(linkPath);
19302
19543
  }
19303
19544
  } catch {
@@ -19315,7 +19556,7 @@ function checkDanglingSymlinks() {
19315
19556
  result.repair = () => {
19316
19557
  for (const p of dangling) {
19317
19558
  try {
19318
- fs71.unlinkSync(p);
19559
+ fs72.unlinkSync(p);
19319
19560
  } catch {
19320
19561
  }
19321
19562
  }
@@ -19330,19 +19571,19 @@ function checkOrphanedSnapshots() {
19330
19571
  healthy: true,
19331
19572
  description: `orphaned migration snapshots under ${dir}`
19332
19573
  };
19333
- if (!fs71.existsSync(dir)) {
19574
+ if (!fs72.existsSync(dir)) {
19334
19575
  return result;
19335
19576
  }
19336
19577
  const orphans = [];
19337
- for (const name of fs71.readdirSync(dir)) {
19578
+ for (const name of fs72.readdirSync(dir)) {
19338
19579
  if (!name.endsWith(".json"))
19339
19580
  continue;
19340
- const full = path70.join(dir, name);
19581
+ const full = path71.join(dir, name);
19341
19582
  try {
19342
- const stat = fs71.statSync(full);
19583
+ const stat = fs72.statSync(full);
19343
19584
  if (!stat.isFile())
19344
19585
  continue;
19345
- const raw = fs71.readFileSync(full, "utf-8");
19586
+ const raw = fs72.readFileSync(full, "utf-8");
19346
19587
  let parsed;
19347
19588
  try {
19348
19589
  parsed = JSON.parse(raw);
@@ -19367,7 +19608,7 @@ function checkOrphanedSnapshots() {
19367
19608
  result.repair = () => {
19368
19609
  for (const o of orphans) {
19369
19610
  try {
19370
- fs71.unlinkSync(o.path);
19611
+ fs72.unlinkSync(o.path);
19371
19612
  } catch {
19372
19613
  }
19373
19614
  }
@@ -19382,12 +19623,12 @@ function checkSentinelDrift() {
19382
19623
  healthy: true,
19383
19624
  description: `olam-skills sentinel block in ${filePath}`
19384
19625
  };
19385
- if (!fs71.existsSync(filePath)) {
19626
+ if (!fs72.existsSync(filePath)) {
19386
19627
  return result;
19387
19628
  }
19388
19629
  let parsed;
19389
19630
  try {
19390
- parsed = JSON.parse(fs71.readFileSync(filePath, "utf-8"));
19631
+ parsed = JSON.parse(fs72.readFileSync(filePath, "utf-8"));
19391
19632
  } catch {
19392
19633
  return result;
19393
19634
  }
@@ -19428,7 +19669,7 @@ function checkSentinelDrift() {
19428
19669
  backupSettings();
19429
19670
  } catch {
19430
19671
  }
19431
- const next = JSON.parse(fs71.readFileSync(filePath, "utf-8"));
19672
+ const next = JSON.parse(fs72.readFileSync(filePath, "utf-8"));
19432
19673
  if (!next.hooks)
19433
19674
  return;
19434
19675
  for (const stage of Object.keys(next.hooks)) {
@@ -19451,7 +19692,7 @@ function checkSentinelDrift() {
19451
19692
  return bad === void 0;
19452
19693
  });
19453
19694
  }
19454
- fs71.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
19695
+ fs72.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
19455
19696
  };
19456
19697
  }
19457
19698
  return result;
@@ -19475,8 +19716,8 @@ function checkMemberNameMissing() {
19475
19716
  return result;
19476
19717
  }
19477
19718
  const claudeDir2 = claudeDirInternal3();
19478
- const atlasUserPath = path70.join(claudeDir2, ".atlas-user");
19479
- const value = fs71.existsSync(atlasUserPath) ? fs71.readFileSync(atlasUserPath, "utf-8").trim() : "";
19719
+ const atlasUserPath = path71.join(claudeDir2, ".atlas-user");
19720
+ const value = fs72.existsSync(atlasUserPath) ? fs72.readFileSync(atlasUserPath, "utf-8").trim() : "";
19480
19721
  if (value.length > 0) {
19481
19722
  result.details = [`atlas-user: ${value}`];
19482
19723
  return result;
@@ -19484,10 +19725,10 @@ function checkMemberNameMissing() {
19484
19725
  result.healthy = false;
19485
19726
  result.issue = "atlas-toolbox source registered but ~/.claude/.atlas-user not set";
19486
19727
  const clonePath = skillSourceClonePath(atlasSource.id);
19487
- const membersDir = path70.join(clonePath, "members");
19488
- const existing = fs71.existsSync(membersDir) ? fs71.readdirSync(membersDir).filter((e) => {
19728
+ const membersDir = path71.join(clonePath, "members");
19729
+ const existing = fs72.existsSync(membersDir) ? fs72.readdirSync(membersDir).filter((e) => {
19489
19730
  try {
19490
- return fs71.statSync(path70.join(membersDir, e)).isDirectory();
19731
+ return fs72.statSync(path71.join(membersDir, e)).isDirectory();
19491
19732
  } catch {
19492
19733
  return false;
19493
19734
  }
@@ -19501,8 +19742,8 @@ function checkMemberNameMissing() {
19501
19742
  }
19502
19743
  function checkMemberOverlayDrift() {
19503
19744
  const claudeDir2 = claudeDirInternal3();
19504
- const atlasUserPath = path70.join(claudeDir2, ".atlas-user");
19505
- const atlasUser = fs71.existsSync(atlasUserPath) ? fs71.readFileSync(atlasUserPath, "utf-8").trim() : "";
19745
+ const atlasUserPath = path71.join(claudeDir2, ".atlas-user");
19746
+ const atlasUser = fs72.existsSync(atlasUserPath) ? fs72.readFileSync(atlasUserPath, "utf-8").trim() : "";
19506
19747
  if (atlasUser.length === 0) {
19507
19748
  return [];
19508
19749
  }
@@ -19518,26 +19759,26 @@ function checkMemberOverlayDrift() {
19518
19759
  const clonePath = skillSourceClonePath(atlasSource.id);
19519
19760
  const results = [];
19520
19761
  for (const kind of ["skills", "agents"]) {
19521
- const localRoot = path70.join(claudeDir2, `${kind}.overrides`);
19522
- if (!fs71.existsSync(localRoot))
19762
+ const localRoot = path71.join(claudeDir2, `${kind}.overrides`);
19763
+ if (!fs72.existsSync(localRoot))
19523
19764
  continue;
19524
19765
  let entries;
19525
19766
  try {
19526
- entries = fs71.readdirSync(localRoot);
19767
+ entries = fs72.readdirSync(localRoot);
19527
19768
  } catch {
19528
19769
  continue;
19529
19770
  }
19530
19771
  for (const entry of entries) {
19531
- const localFile = path70.join(localRoot, entry);
19772
+ const localFile = path71.join(localRoot, entry);
19532
19773
  let stat;
19533
19774
  try {
19534
- stat = fs71.statSync(localFile);
19775
+ stat = fs72.statSync(localFile);
19535
19776
  } catch {
19536
19777
  continue;
19537
19778
  }
19538
19779
  if (!stat.isFile())
19539
19780
  continue;
19540
- const cloneFile = path70.join(clonePath, "members", atlasUser, `${kind}.overrides`, entry);
19781
+ const cloneFile = path71.join(clonePath, "members", atlasUser, `${kind}.overrides`, entry);
19541
19782
  const localSha = sha256OfPath(localFile);
19542
19783
  const cloneSha = sha256OfPath(cloneFile);
19543
19784
  if (localSha === cloneSha) {
@@ -19698,7 +19939,7 @@ var project_sweep_exports = {};
19698
19939
  __export(project_sweep_exports, {
19699
19940
  walkProjectRoot: () => walkProjectRoot
19700
19941
  });
19701
- import * as path71 from "node:path";
19942
+ import * as path72 from "node:path";
19702
19943
  import { readdirSync as readdirSync24, lstatSync as lstatSync6, statSync as statSync25, existsSync as existsSync81 } from "node:fs";
19703
19944
  function isSkipped(basename16, extra) {
19704
19945
  if (DEFAULT_SKIP.has(basename16))
@@ -19710,7 +19951,7 @@ function isSkipped(basename16, extra) {
19710
19951
  return false;
19711
19952
  }
19712
19953
  function resolveMtime(dirPath, manifestFile, fsAdapter) {
19713
- const gitHead = path71.join(dirPath, ".git", "HEAD");
19954
+ const gitHead = path72.join(dirPath, ".git", "HEAD");
19714
19955
  if (fsAdapter.existsSync(gitHead)) {
19715
19956
  try {
19716
19957
  return fsAdapter.statSync(gitHead).mtimeMs;
@@ -19724,8 +19965,8 @@ function resolveMtime(dirPath, manifestFile, fsAdapter) {
19724
19965
  }
19725
19966
  }
19726
19967
  function walk2(currentPath, depth, maxDepth, extraExclude, fsAdapter, results) {
19727
- const adbManifest = path71.join(currentPath, ".adb.yaml");
19728
- const olamManifest = path71.join(currentPath, ".olam.yaml");
19968
+ const adbManifest = path72.join(currentPath, ".adb.yaml");
19969
+ const olamManifest = path72.join(currentPath, ".olam.yaml");
19729
19970
  if (fsAdapter.existsSync(adbManifest)) {
19730
19971
  const mtime = resolveMtime(currentPath, adbManifest, fsAdapter);
19731
19972
  results.push({ path: currentPath, manifestType: "adb", mtime });
@@ -19747,7 +19988,7 @@ function walk2(currentPath, depth, maxDepth, extraExclude, fsAdapter, results) {
19747
19988
  for (const entry of entries) {
19748
19989
  if (isSkipped(entry, extraExclude))
19749
19990
  continue;
19750
- const childPath = path71.join(currentPath, entry);
19991
+ const childPath = path72.join(currentPath, entry);
19751
19992
  let stat;
19752
19993
  try {
19753
19994
  stat = fsAdapter.lstatSync(childPath);
@@ -19804,17 +20045,17 @@ __export(kg_eager_exports, {
19804
20045
  runEagerKgBuild: () => runEagerKgBuild,
19805
20046
  writeQueue: () => writeQueue
19806
20047
  });
19807
- import * as fs72 from "node:fs";
19808
- import * as path72 from "node:path";
20048
+ import * as fs73 from "node:fs";
20049
+ import * as path73 from "node:path";
19809
20050
  import * as os39 from "node:os";
19810
20051
  function defaultQueuePath() {
19811
- const stateDir = process.env["OLAM_STATE_DIR"] ?? path72.join(os39.homedir(), ".olam", "state");
19812
- return path72.join(stateDir, "kg-pending.jsonl");
20052
+ const stateDir = process.env["OLAM_STATE_DIR"] ?? path73.join(os39.homedir(), ".olam", "state");
20053
+ return path73.join(stateDir, "kg-pending.jsonl");
19813
20054
  }
19814
20055
  function readQueue(queuePath) {
19815
- if (!fs72.existsSync(queuePath))
20056
+ if (!fs73.existsSync(queuePath))
19816
20057
  return [];
19817
- const raw = fs72.readFileSync(queuePath, "utf-8");
20058
+ const raw = fs73.readFileSync(queuePath, "utf-8");
19818
20059
  const entries = [];
19819
20060
  for (const line of raw.split("\n")) {
19820
20061
  const trimmed = line.trim();
@@ -19828,16 +20069,16 @@ function readQueue(queuePath) {
19828
20069
  return entries;
19829
20070
  }
19830
20071
  function writeQueue(queuePath, entries) {
19831
- fs72.mkdirSync(path72.dirname(queuePath), { recursive: true });
20072
+ fs73.mkdirSync(path73.dirname(queuePath), { recursive: true });
19832
20073
  const content = entries.map((e) => JSON.stringify(e)).join("\n") + (entries.length > 0 ? "\n" : "");
19833
- fs72.writeFileSync(queuePath, content, "utf-8");
20074
+ fs73.writeFileSync(queuePath, content, "utf-8");
19834
20075
  }
19835
20076
  function appendQueue(queuePath, repos, nowMs) {
19836
20077
  if (repos.length === 0)
19837
20078
  return;
19838
- fs72.mkdirSync(path72.dirname(queuePath), { recursive: true });
20079
+ fs73.mkdirSync(path73.dirname(queuePath), { recursive: true });
19839
20080
  const lines = repos.map((r) => JSON.stringify({ path: r.path, addedAt: nowMs })).join("\n") + "\n";
19840
- fs72.appendFileSync(queuePath, lines, "utf-8");
20081
+ fs73.appendFileSync(queuePath, lines, "utf-8");
19841
20082
  }
19842
20083
  async function defaultBuildOne(_repo) {
19843
20084
  return { ok: true, ms: 0 };
@@ -19890,16 +20131,16 @@ __export(machine_schema_exports, {
19890
20131
  readMachineConfig: () => readMachineConfig,
19891
20132
  writeMachineConfig: () => writeMachineConfig
19892
20133
  });
19893
- import * as fs75 from "node:fs";
19894
- import * as path76 from "node:path";
20134
+ import * as fs76 from "node:fs";
20135
+ import * as path77 from "node:path";
19895
20136
  import * as os40 from "node:os";
19896
20137
  import { parse as parseYaml6, stringify as stringifyYaml5 } from "yaml";
19897
20138
  function readMachineConfig(configPath) {
19898
20139
  const p = configPath ?? DEFAULT_CONFIG_PATH;
19899
- if (!fs75.existsSync(p))
20140
+ if (!fs76.existsSync(p))
19900
20141
  return null;
19901
20142
  try {
19902
- const raw = fs75.readFileSync(p, "utf-8");
20143
+ const raw = fs76.readFileSync(p, "utf-8");
19903
20144
  const parsed = parseYaml6(raw);
19904
20145
  return MachineConfigSchema.parse(parsed);
19905
20146
  } catch {
@@ -19908,8 +20149,8 @@ function readMachineConfig(configPath) {
19908
20149
  }
19909
20150
  function writeMachineConfig(config, configPath) {
19910
20151
  const p = configPath ?? DEFAULT_CONFIG_PATH;
19911
- fs75.mkdirSync(path76.dirname(p), { recursive: true });
19912
- fs75.writeFileSync(p, stringifyYaml5({ ...config }), { mode: 420 });
20152
+ fs76.mkdirSync(path77.dirname(p), { recursive: true });
20153
+ fs76.writeFileSync(p, stringifyYaml5({ ...config }), { mode: 420 });
19913
20154
  }
19914
20155
  function initMachineConfig(opts = {}) {
19915
20156
  const configPath = opts.configPath ?? DEFAULT_CONFIG_PATH;
@@ -19932,9 +20173,9 @@ var init_machine_schema = __esm({
19932
20173
  channel: external_exports.enum(["stable", "beta", "edge"]).default("stable"),
19933
20174
  auto_update: external_exports.boolean().default(true),
19934
20175
  telemetry: external_exports.boolean().default(true),
19935
- worlds_dir: external_exports.string().default(() => path76.join(os40.homedir(), ".olam", "worlds"))
20176
+ worlds_dir: external_exports.string().default(() => path77.join(os40.homedir(), ".olam", "worlds"))
19936
20177
  });
19937
- DEFAULT_CONFIG_PATH = path76.join(os40.homedir(), ".olam", "config.yaml");
20178
+ DEFAULT_CONFIG_PATH = path77.join(os40.homedir(), ".olam", "config.yaml");
19938
20179
  }
19939
20180
  });
19940
20181
 
@@ -20128,16 +20369,16 @@ function isValidConfig(value) {
20128
20369
  if (typeof v.install_id !== "string" || v.install_id.length === 0) return false;
20129
20370
  return true;
20130
20371
  }
20131
- function atomicWriteJSON(path93, value, stderr = process.stderr) {
20372
+ function atomicWriteJSON(path94, value, stderr = process.stderr) {
20132
20373
  ensureStateDir();
20133
- const dir = dirname3(path93);
20374
+ const dir = dirname3(path94);
20134
20375
  if (!existsSync6(dir)) {
20135
20376
  mkdirSync2(dir, { recursive: true });
20136
20377
  }
20137
- const tmp = `${path93}.tmp.${process.pid}`;
20378
+ const tmp = `${path94}.tmp.${process.pid}`;
20138
20379
  try {
20139
20380
  writeFileSync2(tmp, JSON.stringify(value, null, 2) + "\n", { encoding: "utf8" });
20140
- renameSync2(tmp, path93);
20381
+ renameSync2(tmp, path94);
20141
20382
  } catch (err) {
20142
20383
  if (existsSync6(tmp)) {
20143
20384
  try {
@@ -20473,9 +20714,9 @@ var UnknownArchetypeError = class extends Error {
20473
20714
  };
20474
20715
  var ArchetypeCycleError = class extends Error {
20475
20716
  path;
20476
- constructor(path93) {
20477
- super(`Archetype inheritance cycle detected: ${path93.join(" \u2192 ")} \u2192 ${path93[0] ?? "?"}`);
20478
- this.path = path93;
20717
+ constructor(path94) {
20718
+ super(`Archetype inheritance cycle detected: ${path94.join(" \u2192 ")} \u2192 ${path94[0] ?? "?"}`);
20719
+ this.path = path94;
20479
20720
  this.name = "ArchetypeCycleError";
20480
20721
  }
20481
20722
  };
@@ -21197,7 +21438,7 @@ function step(label) {
21197
21438
  process.stdout.write("\n" + pc6.bold(pc6.cyan(`==> ${label}`)) + "\n");
21198
21439
  }
21199
21440
  function preflight(opts) {
21200
- step("0/5 \u2014 preflight (tool detection)");
21441
+ step("0/6 \u2014 preflight (tool detection)");
21201
21442
  const missing = detectMissingTools();
21202
21443
  if (missing.length === 0) {
21203
21444
  printSuccess("all required tools present");
@@ -21239,23 +21480,23 @@ function preflight(opts) {
21239
21480
  printSuccess("docker daemon reachable");
21240
21481
  }
21241
21482
  function ensureSecrets() {
21242
- step("1/5 \u2014 operator secrets");
21483
+ step("1/6 \u2014 operator secrets");
21243
21484
  mkdirSync19(OLAM_HOME3, { recursive: true });
21244
21485
  for (const name of SECRET_FILES) {
21245
- const path93 = join34(OLAM_HOME3, name);
21246
- if (existsSync29(path93)) {
21486
+ const path94 = join34(OLAM_HOME3, name);
21487
+ if (existsSync29(path94)) {
21247
21488
  printInfo("skip", `~/.olam/${name} already exists`);
21248
21489
  continue;
21249
21490
  }
21250
21491
  const hex = randomBytes7(32).toString("hex");
21251
- writeFileSync15(path93, hex + "\n", { encoding: "utf8", mode: 384 });
21252
- chmodSync4(path93, 384);
21492
+ writeFileSync15(path94, hex + "\n", { encoding: "utf8", mode: 384 });
21493
+ chmodSync4(path94, 384);
21253
21494
  printSuccess(`generated ~/.olam/${name}`);
21254
21495
  }
21255
21496
  }
21256
21497
  function ensureColima() {
21257
21498
  if (platform() !== "darwin") return;
21258
- step("2/5 \u2014 colima (macOS)");
21499
+ step("2/6 \u2014 colima (macOS)");
21259
21500
  if (!runCapture("colima", ["status"]).ok) {
21260
21501
  printWarning("colima not running \u2014 starting");
21261
21502
  runOrFail(
@@ -21274,10 +21515,10 @@ function ensureColima() {
21274
21515
  }
21275
21516
  function ensureCluster(opts) {
21276
21517
  if (opts.skipClusterCreate) {
21277
- step("3/5 \u2014 cluster (skipped via --skip-cluster-create)");
21518
+ step("3/6 \u2014 cluster (skipped via --skip-cluster-create)");
21278
21519
  return;
21279
21520
  }
21280
- step(`3/5 \u2014 k3d cluster create (${opts.cluster})`);
21521
+ step(`3/6 \u2014 k3d cluster create (${opts.cluster})`);
21281
21522
  if (runCapture("k3d", ["cluster", "list", opts.cluster]).ok) {
21282
21523
  printInfo("cluster", `'${opts.cluster}' already exists`);
21283
21524
  return;
@@ -21304,26 +21545,51 @@ function resolveObservabilityScriptsDir() {
21304
21545
  }
21305
21546
  return null;
21306
21547
  }
21548
+ function resolvePeripheralServicesDir() {
21549
+ const installed = join34(installRoot(), "host-cp", "peripheral-services");
21550
+ if (existsSync29(installed)) return installed;
21551
+ const k8sRoot = resolveK8sAssetsRoot();
21552
+ if (k8sRoot) {
21553
+ const dev = join34(k8sRoot, "..", "..", "peripheral-services");
21554
+ if (existsSync29(dev)) return dev;
21555
+ }
21556
+ return null;
21557
+ }
21558
+ function resolveBundleRoot() {
21559
+ const installed = join34(installRoot(), "host-cp");
21560
+ if (existsSync29(join34(installed, "peripheral-services"))) return installed;
21561
+ const k8sRoot = resolveK8sAssetsRoot();
21562
+ if (k8sRoot) {
21563
+ const dev = join34(k8sRoot, "..", "..");
21564
+ if (existsSync29(join34(dev, "peripheral-services"))) return dev;
21565
+ }
21566
+ return null;
21567
+ }
21307
21568
  function installObservability(opts) {
21308
21569
  if (opts.skipObservability) {
21309
- step("4/5 \u2014 observability (skipped via --skip-observability)");
21570
+ step("4/6 \u2014 observability (skipped via --skip-observability)");
21310
21571
  return;
21311
21572
  }
21312
- step("4/5 \u2014 observability stack (Loki + Promtail + Grafana + Prometheus + Kyverno)");
21573
+ step("4/6 \u2014 observability stack (Loki + Promtail + Grafana + Prometheus + Kyverno)");
21313
21574
  const observabilityDir = resolveObservabilityScriptsDir();
21314
21575
  if (!observabilityDir) {
21315
21576
  printWarning("bundled observability scripts not found \u2014 skipping");
21316
21577
  printWarning(" (expected in published CLI installs; missing only in dev tarballs without bundling)");
21317
21578
  return;
21318
21579
  }
21580
+ const bundleRoot = resolveBundleRoot();
21581
+ const scriptEnv = { ...process.env };
21582
+ if (bundleRoot) {
21583
+ scriptEnv.OLAM_BUNDLE_ROOT = bundleRoot;
21584
+ }
21319
21585
  for (const script of OBSERVABILITY_SCRIPTS) {
21320
- const path93 = join34(observabilityDir, script);
21321
- if (!existsSync29(path93)) {
21586
+ const path94 = join34(observabilityDir, script);
21587
+ if (!existsSync29(path94)) {
21322
21588
  printWarning(`observability script missing: ${script} \u2014 skipping`);
21323
21589
  continue;
21324
21590
  }
21325
21591
  printInfo("run", script);
21326
- const result = spawnSync10("bash", [path93], { stdio: "inherit" });
21592
+ const result = spawnSync10("bash", [path94], { stdio: "inherit", env: scriptEnv });
21327
21593
  if (result.status !== 0) {
21328
21594
  if (script === "loki-ingest.sh") {
21329
21595
  printWarning("loki-ingest non-zero \u2014 likely Promtail scrub-wait flake; continuing");
@@ -21336,8 +21602,28 @@ function installObservability(opts) {
21336
21602
  }
21337
21603
  }
21338
21604
  }
21605
+ function applyPeripheralServicesManifests() {
21606
+ step("5/6 \u2014 peripheral-services manifests (IngressRoutes + ServiceMonitors + recording rules + dashboards + Kyverno)");
21607
+ const dir = resolvePeripheralServicesDir();
21608
+ if (!dir) {
21609
+ printWarning("bundled peripheral-services manifests not found \u2014 skipping");
21610
+ return;
21611
+ }
21612
+ const manifestsDir = join34(dir, "manifests");
21613
+ if (!existsSync29(manifestsDir)) {
21614
+ printWarning(`peripheral-services/manifests not found at ${manifestsDir} \u2014 skipping`);
21615
+ return;
21616
+ }
21617
+ printInfo("apply", manifestsDir);
21618
+ const result = spawnSync10("kubectl", ["apply", "-f", manifestsDir], { stdio: "inherit" });
21619
+ if (result.status !== 0) {
21620
+ printError("kubectl apply failed \u2014 peripheral-services manifests not applied");
21621
+ process.exit(result.status ?? 1);
21622
+ }
21623
+ printSuccess("peripheral-services manifests applied");
21624
+ }
21339
21625
  function delegateToUpgrade() {
21340
- step("5/5 \u2014 apply manifests + rollout (olam upgrade)");
21626
+ step("6/6 \u2014 apply host-cp + peripherals + rollout (olam upgrade)");
21341
21627
  const olamBin = process.argv[1] ?? "olam";
21342
21628
  const result = spawnSync10(process.execPath, [olamBin, "upgrade", "-y"], { stdio: "inherit" });
21343
21629
  if (result.status !== 0) {
@@ -21363,23 +21649,25 @@ function summary(opts) {
21363
21649
  `);
21364
21650
  }
21365
21651
  async function runBootstrapKubernetes(rawOpts) {
21652
+ const defaultAutoInstall = platform() === "darwin";
21366
21653
  const opts = {
21367
21654
  cluster: rawOpts.cluster ?? DEFAULT_K3S_CLUSTER,
21368
- autoInstall: rawOpts.autoInstall ?? false,
21655
+ autoInstall: rawOpts.autoInstall ?? defaultAutoInstall,
21369
21656
  skipObservability: rawOpts.skipObservability ?? false,
21370
21657
  skipClusterCreate: rawOpts.skipClusterCreate ?? false
21371
21658
  };
21372
- printHeader("olam bootstrap \u2014 k3s mode");
21659
+ printHeader("olam setup \u2014 k3s mode");
21373
21660
  printInfo("mode", "one-command bring-up of olam peripherals + observability on a local k3d cluster");
21374
21661
  preflight(opts);
21375
21662
  ensureSecrets();
21376
21663
  ensureColima();
21377
21664
  ensureCluster(opts);
21378
21665
  installObservability(opts);
21666
+ applyPeripheralServicesManifests();
21379
21667
  delegateToUpgrade();
21380
21668
  summary(opts);
21381
- printSuccess("bootstrap complete");
21382
- return { exitCode: 0, summary: `bootstrap complete on cluster ${opts.cluster}` };
21669
+ printSuccess("setup complete");
21670
+ return { exitCode: 0, summary: `setup complete on cluster ${opts.cluster}` };
21383
21671
  }
21384
21672
 
21385
21673
  // src/commands/bootstrap.ts
@@ -21673,13 +21961,13 @@ async function runBootstrap2(opts, deps = {}) {
21673
21961
  printInfo("next", '`olam create --task "your task"` to spawn a world');
21674
21962
  return { exitCode: 0, summary: "stack ready" };
21675
21963
  }
21676
- function registerBootstrap(program2) {
21677
- program2.command("bootstrap").description(
21678
- "Bootstrap the olam stack. Substrate-aware: on kubernetes (default), detects tools, generates secrets, creates a k3d cluster, installs observability (Loki + Promtail + Grafana + Prometheus + Kyverno), and applies all peripheral manifests. On compose, pulls 3 images by digest + starts host-cp + auth + runs auth login."
21679
- ).option("--with-smoke", "After bootstrap, create a smoke-test world to verify end-to-end").option("--skip-auth-login", "Skip the interactive PKCE step (CI / scripted use only)").option("--skip-postgres-singleton", "Skip the olam-postgres singleton bring-up (operators with host postgres opt-out, or CI)").option("--skip-memory", "Skip the agent-memory Docker container bring-up (CI / scripted use, or hosts without Docker)").option("--skip-kg-service", "Skip the olam-kg-service container pull + start (classifier-augmented retrieval; v2 feature)").option(
21964
+ function buildSetupCommand(program2, name) {
21965
+ return program2.command(name).description(
21966
+ "Bring up the olam substrate. Substrate-aware: on kubernetes (default), detects tools, auto-installs missing brew formulae on macOS, generates secrets, creates a k3d cluster, installs observability (Loki + Promtail + Grafana + Prometheus + Kyverno), applies peripheral-services manifests (IngressRoutes + ServiceMonitors + dashboards), and runs the `olam upgrade` flow for host-cp + peripherals + rollout. On compose, pulls 3 images by digest + starts host-cp + auth. The full operator-onboarding wizard is `olam setup` \u2014 this command is the substrate primitive it calls."
21967
+ ).option("--with-smoke", "After setup, create a smoke-test world to verify end-to-end").option("--skip-auth-login", "Skip the interactive PKCE step (CI / scripted use only)").option("--skip-postgres-singleton", "Skip the olam-postgres singleton bring-up (operators with host postgres opt-out, or CI)").option("--skip-memory", "Skip the agent-memory Docker container bring-up (CI / scripted use, or hosts without Docker)").option("--skip-kg-service", "Skip the olam-kg-service container pull + start (classifier-augmented retrieval; v2 feature)").option(
21680
21968
  "--registry <ref>",
21681
21969
  "Override the registry prefix (default: read from image-digests.json or fall back to ghcr.io/pleri)"
21682
- ).option("--k3s-cluster <name>", `[k3s] k3d cluster name (default: ${DEFAULT_K3S_CLUSTER})`, DEFAULT_K3S_CLUSTER).option("--auto-install", "[k3s] auto-install missing tools via brew on macOS", false).option("--skip-observability", "[k3s] skip Loki/Promtail/Grafana/Prom install (already in place)", false).option("--skip-cluster-create", "[k3s] cluster already exists; install substrate only", false).action(async (opts) => {
21970
+ ).option("--k3s-cluster <name>", `[k3s] k3d cluster name (default: ${DEFAULT_K3S_CLUSTER})`, DEFAULT_K3S_CLUSTER).option("--auto-install", "[k3s] auto-install missing tools via brew on macOS (default: ON for macOS)", void 0).option("--no-auto-install", "[k3s] disable auto-install (operator runs brew themselves)").option("--skip-observability", "[k3s] skip Loki/Promtail/Grafana/Prom install (already in place)", false).option("--skip-cluster-create", "[k3s] cluster already exists; install substrate only", false).action(async (opts) => {
21683
21971
  try {
21684
21972
  const result = await runBootstrap2({
21685
21973
  withSmoke: opts.withSmoke === true,
@@ -21689,7 +21977,10 @@ function registerBootstrap(program2) {
21689
21977
  skipKgService: opts.skipKgService === true,
21690
21978
  registry: opts.registry,
21691
21979
  k3sCluster: opts.k3sCluster,
21692
- autoInstall: opts.autoInstall === true,
21980
+ // Tri-state: undefined = let runBootstrapKubernetes apply the
21981
+ // platform-default (ON for macOS, OFF otherwise). `--no-auto-install`
21982
+ // sets autoInstall=false explicitly.
21983
+ autoInstall: opts.autoInstall,
21693
21984
  skipObservability: opts.skipObservability === true,
21694
21985
  skipClusterCreate: opts.skipClusterCreate === true
21695
21986
  });
@@ -21700,6 +21991,9 @@ function registerBootstrap(program2) {
21700
21991
  }
21701
21992
  });
21702
21993
  }
21994
+ function registerBootstrap(program2) {
21995
+ buildSetupCommand(program2, "bootstrap");
21996
+ }
21703
21997
 
21704
21998
  // src/commands/auth-upgrade.ts
21705
21999
  init_exit_codes();
@@ -22270,56 +22564,56 @@ var SECRET_LEN_BYTES = 32;
22270
22564
  function generateSecret() {
22271
22565
  return randomBytes8(SECRET_LEN_BYTES).toString("hex");
22272
22566
  }
22273
- function writeSecretAtPath(path93, value) {
22274
- mkdirSync21(dirname22(path93), { recursive: true });
22275
- const tmp = `${path93}.tmp.${process.pid}`;
22567
+ function writeSecretAtPath(path94, value) {
22568
+ mkdirSync21(dirname22(path94), { recursive: true });
22569
+ const tmp = `${path94}.tmp.${process.pid}`;
22276
22570
  writeFileSync16(tmp, value, { mode: 384 });
22277
22571
  chmodSync5(tmp, 384);
22278
- renameSync6(tmp, path93);
22572
+ renameSync6(tmp, path94);
22279
22573
  }
22280
- function readSecretAtPathOrNull(path93) {
22281
- if (!existsSync32(path93)) return null;
22282
- const mode = statSync8(path93).mode & 511;
22574
+ function readSecretAtPathOrNull(path94) {
22575
+ if (!existsSync32(path94)) return null;
22576
+ const mode = statSync8(path94).mode & 511;
22283
22577
  if (mode !== 384) {
22284
22578
  process.stderr.write(
22285
- `warn: ${path93} has mode 0${mode.toString(8)}; expected 0600. Run 'olam memory secret rotate' to regenerate.
22579
+ `warn: ${path94} has mode 0${mode.toString(8)}; expected 0600. Run 'olam memory secret rotate' to regenerate.
22286
22580
  `
22287
22581
  );
22288
22582
  }
22289
- return readFileSync25(path93, "utf8").trim();
22583
+ return readFileSync25(path94, "utf8").trim();
22290
22584
  }
22291
- function readSecretAtPath(path93) {
22292
- const v = readSecretAtPathOrNull(path93);
22585
+ function readSecretAtPath(path94) {
22586
+ const v = readSecretAtPathOrNull(path94);
22293
22587
  if (v === null) {
22294
22588
  throw new Error(
22295
- `Secret not found at ${path93}. Run 'olam memory start' to generate it.`
22589
+ `Secret not found at ${path94}. Run 'olam memory start' to generate it.`
22296
22590
  );
22297
22591
  }
22298
22592
  return v;
22299
22593
  }
22300
- function ensureMemorySecret(path93 = MEMORY_SECRET_PATH) {
22301
- const existing = readSecretAtPathOrNull(path93);
22594
+ function ensureMemorySecret(path94 = MEMORY_SECRET_PATH) {
22595
+ const existing = readSecretAtPathOrNull(path94);
22302
22596
  if (existing) return existing;
22303
22597
  const fresh = generateSecret();
22304
- writeSecretAtPath(path93, fresh);
22598
+ writeSecretAtPath(path94, fresh);
22305
22599
  return fresh;
22306
22600
  }
22307
- function readMemorySecretOrNull(path93 = MEMORY_SECRET_PATH) {
22308
- return readSecretAtPathOrNull(path93);
22601
+ function readMemorySecretOrNull(path94 = MEMORY_SECRET_PATH) {
22602
+ return readSecretAtPathOrNull(path94);
22309
22603
  }
22310
- function readMemorySecret(path93 = MEMORY_SECRET_PATH) {
22311
- return readSecretAtPath(path93);
22604
+ function readMemorySecret(path94 = MEMORY_SECRET_PATH) {
22605
+ return readSecretAtPath(path94);
22312
22606
  }
22313
- function rotateMemorySecret(path93 = MEMORY_SECRET_PATH) {
22607
+ function rotateMemorySecret(path94 = MEMORY_SECRET_PATH) {
22314
22608
  const fresh = generateSecret();
22315
- writeSecretAtPath(path93, fresh);
22609
+ writeSecretAtPath(path94, fresh);
22316
22610
  return fresh;
22317
22611
  }
22318
- function hasMemorySecret(path93 = MEMORY_SECRET_PATH) {
22319
- return existsSync32(path93);
22612
+ function hasMemorySecret(path94 = MEMORY_SECRET_PATH) {
22613
+ return existsSync32(path94);
22320
22614
  }
22321
- function writeCloudMemorySecret(value, path93 = CLOUD_MEMORY_SECRET_PATH) {
22322
- writeSecretAtPath(path93, value);
22615
+ function writeCloudMemorySecret(value, path94 = CLOUD_MEMORY_SECRET_PATH) {
22616
+ writeSecretAtPath(path94, value);
22323
22617
  }
22324
22618
 
22325
22619
  // src/commands/memory-service-container.ts
@@ -23361,7 +23655,7 @@ function appendAuditEntry(entry, auditLogPath, writeFileSyncImpl) {
23361
23655
  async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}, peripheral) {
23362
23656
  const auditLogPath = deps.auditLogPath ?? MANIFEST_REFRESH_AUDIT_LOG;
23363
23657
  const readdirSync32 = deps.readdirSync ?? fs31.readdirSync;
23364
- const readFileSync91 = deps.readFileSync ?? fs31.readFileSync;
23658
+ const readFileSync92 = deps.readFileSync ?? fs31.readFileSync;
23365
23659
  const writeFileSyncImpl = deps.writeFileSync ?? fs31.writeFileSync;
23366
23660
  const existsSync112 = deps.existsSync ?? fs31.existsSync;
23367
23661
  const now = deps.now ? deps.now() : /* @__PURE__ */ new Date();
@@ -23387,7 +23681,7 @@ async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}, per
23387
23681
  const filePath = path32.join(targetDir, file);
23388
23682
  let content;
23389
23683
  try {
23390
- content = readFileSync91(filePath, "utf8");
23684
+ content = readFileSync92(filePath, "utf8");
23391
23685
  } catch {
23392
23686
  continue;
23393
23687
  }
@@ -23639,11 +23933,11 @@ async function checkSecretPreCondition(context, deps) {
23639
23933
  }
23640
23934
  async function applyConfigMapSubstitution(context, manifestsDir, deps) {
23641
23935
  const wrap = deps.kubectlWrapImpl ?? kubectlWrap;
23642
- const readFileSync91 = deps.readFileSyncImpl ?? fs32.readFileSync;
23936
+ const readFileSync92 = deps.readFileSyncImpl ?? fs32.readFileSync;
23643
23937
  const configMapPath = path33.join(manifestsDir, "30-configmap.yaml");
23644
23938
  let rawYaml;
23645
23939
  try {
23646
- rawYaml = readFileSync91(configMapPath, "utf8");
23940
+ rawYaml = readFileSync92(configMapPath, "utf8");
23647
23941
  } catch (err) {
23648
23942
  return `Failed to read ConfigMap at ${configMapPath}: ${err instanceof Error ? err.message : String(err)}`;
23649
23943
  }
@@ -24464,9 +24758,9 @@ function formatFreshnessWarning(result, image = DEFAULT_DEVBOX_IMAGE) {
24464
24758
  "These source files have changed since the image was built; the",
24465
24759
  "changes will NOT take effect in fresh worlds until you rebuild:"
24466
24760
  ];
24467
- for (const { path: path93, mtimeMs } of result.newerSources) {
24761
+ for (const { path: path94, mtimeMs } of result.newerSources) {
24468
24762
  const when = new Date(mtimeMs).toISOString();
24469
- lines.push(` \u2022 ${path93} (modified ${when})`);
24763
+ lines.push(` \u2022 ${path94} (modified ${when})`);
24470
24764
  }
24471
24765
  lines.push("");
24472
24766
  lines.push("Rebuild with:");
@@ -24845,15 +25139,15 @@ var AGENTMEMORY_LOCAL_URL = "http://host.docker.internal:3111";
24845
25139
  var HOST_CP_URL = "http://127.0.0.1:19000";
24846
25140
  async function readHostCpTokenForCreate() {
24847
25141
  try {
24848
- const { default: fs94 } = await import("node:fs");
25142
+ const { default: fs95 } = await import("node:fs");
24849
25143
  const { default: os49 } = await import("node:os");
24850
- const { default: path93 } = await import("node:path");
24851
- const tp = path93.join(
24852
- process.env.OLAM_HOME ?? path93.join(os49.homedir(), ".olam"),
25144
+ const { default: path94 } = await import("node:path");
25145
+ const tp = path94.join(
25146
+ process.env.OLAM_HOME ?? path94.join(os49.homedir(), ".olam"),
24853
25147
  "host-cp.token"
24854
25148
  );
24855
- if (!fs94.existsSync(tp)) return null;
24856
- return fs94.readFileSync(tp, "utf-8").trim();
25149
+ if (!fs95.existsSync(tp)) return null;
25150
+ return fs95.readFileSync(tp, "utf-8").trim();
24857
25151
  } catch {
24858
25152
  return null;
24859
25153
  }
@@ -25290,12 +25584,12 @@ function defaultNameFromPrompt(prompt) {
25290
25584
  }
25291
25585
  async function readHostCpToken3() {
25292
25586
  try {
25293
- const { default: fs94 } = await import("node:fs");
25587
+ const { default: fs95 } = await import("node:fs");
25294
25588
  const { default: os49 } = await import("node:os");
25295
- const { default: path93 } = await import("node:path");
25296
- const tp = path93.join(os49.homedir(), ".olam", "host-cp.token");
25297
- if (!fs94.existsSync(tp)) return null;
25298
- const raw = fs94.readFileSync(tp, "utf-8").trim();
25589
+ const { default: path94 } = await import("node:path");
25590
+ const tp = path94.join(os49.homedir(), ".olam", "host-cp.token");
25591
+ if (!fs95.existsSync(tp)) return null;
25592
+ const raw = fs95.readFileSync(tp, "utf-8").trim();
25299
25593
  return raw.length > 0 ? raw : null;
25300
25594
  } catch {
25301
25595
  return null;
@@ -29102,11 +29396,11 @@ function zodIssueToError(issue, doc, lineCounter) {
29102
29396
  suggestion: deriveSuggestion(issue)
29103
29397
  };
29104
29398
  }
29105
- function formatJsonPath(path93) {
29106
- if (path93.length === 0)
29399
+ function formatJsonPath(path94) {
29400
+ if (path94.length === 0)
29107
29401
  return "<root>";
29108
29402
  let out = "";
29109
- for (const seg of path93) {
29403
+ for (const seg of path94) {
29110
29404
  if (typeof seg === "number") {
29111
29405
  out += `[${seg}]`;
29112
29406
  } else {
@@ -29115,11 +29409,11 @@ function formatJsonPath(path93) {
29115
29409
  }
29116
29410
  return out;
29117
29411
  }
29118
- function resolveYamlLocation(path93, doc, lineCounter) {
29412
+ function resolveYamlLocation(path94, doc, lineCounter) {
29119
29413
  let bestLine = 0;
29120
29414
  let bestColumn = 0;
29121
- for (let depth = path93.length; depth >= 0; depth -= 1) {
29122
- const segment = path93.slice(0, depth);
29415
+ for (let depth = path94.length; depth >= 0; depth -= 1) {
29416
+ const segment = path94.slice(0, depth);
29123
29417
  try {
29124
29418
  const node = doc.getIn(segment, true);
29125
29419
  if (node && typeof node === "object" && "range" in node) {
@@ -29337,11 +29631,11 @@ function topoSort(nodes) {
29337
29631
  }
29338
29632
  function traceCycle(start, byId) {
29339
29633
  const seen = /* @__PURE__ */ new Set();
29340
- const path93 = [];
29634
+ const path94 = [];
29341
29635
  let current = start;
29342
29636
  while (current && !seen.has(current)) {
29343
29637
  seen.add(current);
29344
- path93.push(current);
29638
+ path94.push(current);
29345
29639
  const node = byId.get(current);
29346
29640
  const next = node?.dependsOn[0];
29347
29641
  if (next === void 0)
@@ -29349,10 +29643,10 @@ function traceCycle(start, byId) {
29349
29643
  current = next;
29350
29644
  }
29351
29645
  if (current && seen.has(current)) {
29352
- const idx = path93.indexOf(current);
29353
- return [...path93.slice(idx), current];
29646
+ const idx = path94.indexOf(current);
29647
+ return [...path94.slice(idx), current];
29354
29648
  }
29355
- return path93;
29649
+ return path94;
29356
29650
  }
29357
29651
 
29358
29652
  // ../core/dist/executor/types.js
@@ -34059,8 +34353,8 @@ function checkWorld(container, hostShas, dockerExec) {
34059
34353
  const m = shaLine.match(/^([a-f0-9]{64})\s+(.+)$/);
34060
34354
  if (!m) continue;
34061
34355
  const sha = m[1];
34062
- const path93 = m[2];
34063
- const filename = path93?.split("/").pop();
34356
+ const path94 = m[2];
34357
+ const filename = path94?.split("/").pop();
34064
34358
  if (!filename) continue;
34065
34359
  const mtimeSecs = parseInt(mtimeLine.trim(), 10);
34066
34360
  if (Number.isNaN(mtimeSecs) || !sha) continue;
@@ -34927,9 +35221,9 @@ var TasksClient = class {
34927
35221
  this.olamNodeId = opts.olamNodeId;
34928
35222
  this.sessionId = opts.sessionId;
34929
35223
  }
34930
- async call(method, path93, scopes, body, query) {
35224
+ async call(method, path94, scopes, body, query) {
34931
35225
  const qs = query ? "?" + new URLSearchParams(Object.entries(query).filter(([, v]) => v !== void 0)).toString() : "";
34932
- const url2 = `${this.baseUrl}${path93}${qs}`;
35226
+ const url2 = `${this.baseUrl}${path94}${qs}`;
34933
35227
  const res = await fetch(url2, {
34934
35228
  method,
34935
35229
  headers: {
@@ -34980,8 +35274,8 @@ function parseFrontmatter2(raw) {
34980
35274
  }
34981
35275
  return { frontmatter: fm, body };
34982
35276
  }
34983
- function parseTracker(path93) {
34984
- const raw = readFileSync46(path93, "utf8");
35277
+ function parseTracker(path94) {
35278
+ const raw = readFileSync46(path94, "utf8");
34985
35279
  const { frontmatter, body } = parseFrontmatter2(raw);
34986
35280
  const lines = body.split("\n");
34987
35281
  const tasks = [];
@@ -35218,8 +35512,8 @@ function registerTasks(program2) {
35218
35512
  `);
35219
35513
  }
35220
35514
  });
35221
- 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 (path93, opts) => {
35222
- const parsed = parseTracker(path93);
35515
+ 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 (path94, opts) => {
35516
+ const parsed = parseTracker(path94);
35223
35517
  if (opts.dryRun) {
35224
35518
  process.stdout.write(JSON.stringify(parsed, null, 2) + "\n");
35225
35519
  return;
@@ -35376,7 +35670,7 @@ init_health_probes();
35376
35670
  import { spawn as spawn7 } from "node:child_process";
35377
35671
  import { existsSync as existsSync84 } from "node:fs";
35378
35672
  import { homedir as homedir43 } from "node:os";
35379
- import path74 from "node:path";
35673
+ import path75 from "node:path";
35380
35674
  import { createInterface as createInterface3 } from "node:readline";
35381
35675
 
35382
35676
  // src/lib/shell-rc.ts
@@ -35566,8 +35860,8 @@ async function pickSkillSourcePhase(opts, deps) {
35566
35860
 
35567
35861
  // src/commands/setup-phase-5b-project-sweep.ts
35568
35862
  import { homedir as homedir42 } from "node:os";
35569
- import * as path73 from "node:path";
35570
- import * as fs73 from "node:fs";
35863
+ import * as path74 from "node:path";
35864
+ import * as fs74 from "node:fs";
35571
35865
  async function loadWalkFn() {
35572
35866
  const m = await Promise.resolve().then(() => (init_project_sweep(), project_sweep_exports));
35573
35867
  return m.walkProjectRoot;
@@ -35585,9 +35879,9 @@ async function loadAppendTrustAuditFn() {
35585
35879
  return m.appendTrustAudit;
35586
35880
  }
35587
35881
  function deriveRepoName(repoPath, existingNames) {
35588
- const base = path73.basename(repoPath).toLowerCase().replace(/[^a-z0-9-]/g, "-");
35882
+ const base = path74.basename(repoPath).toLowerCase().replace(/[^a-z0-9-]/g, "-");
35589
35883
  if (!existingNames.has(base)) return base;
35590
- const parent = path73.basename(path73.dirname(repoPath)).toLowerCase().replace(/[^a-z0-9-]/g, "-");
35884
+ const parent = path74.basename(path74.dirname(repoPath)).toLowerCase().replace(/[^a-z0-9-]/g, "-");
35591
35885
  const composite = `${parent}-${base}`;
35592
35886
  if (!existingNames.has(composite)) return composite;
35593
35887
  let suffix = 2;
@@ -35599,8 +35893,8 @@ async function runProjectSweepPhase(opts, deps, sweepDeps = {}) {
35599
35893
  return { ok: true, skipped: true, message: "skipped via --skip-project-sweep" };
35600
35894
  }
35601
35895
  const home = deps.home ?? homedir42();
35602
- const projectsRoot = opts.projects ?? path73.join(home, "Projects");
35603
- const existsSyncFn = sweepDeps.existsSync ?? fs73.existsSync;
35896
+ const projectsRoot = opts.projects ?? path74.join(home, "Projects");
35897
+ const existsSyncFn = sweepDeps.existsSync ?? fs74.existsSync;
35604
35898
  if (!existsSyncFn(projectsRoot)) {
35605
35899
  return {
35606
35900
  ok: true,
@@ -35807,7 +36101,7 @@ async function phase4ShellInit(opts, deps) {
35807
36101
  message: `unsupported $SHELL (${shellEnv ?? "unset"}); add \`eval "$(olam completion <shell>)"\` to your shell rc manually`
35808
36102
  };
35809
36103
  }
35810
- const shellBasename = path74.basename(shellEnv);
36104
+ const shellBasename = path75.basename(shellEnv);
35811
36105
  const evalLine = `eval "$(olam completion ${shellBasename})"`;
35812
36106
  const result = appendIdempotent({
35813
36107
  rcPath,
@@ -35833,7 +36127,7 @@ async function phase4ShellInit(opts, deps) {
35833
36127
  async function phase5InitProject(opts, deps) {
35834
36128
  const cwd = deps.cwd ?? process.cwd();
35835
36129
  const projectRoot = findProjectRoot(cwd);
35836
- const configPath = path74.join(projectRoot, ".olam", "config.yaml");
36130
+ const configPath = path75.join(projectRoot, ".olam", "config.yaml");
35837
36131
  if (existsSync84(configPath)) {
35838
36132
  return { ok: true, message: `${configPath} present (no change)` };
35839
36133
  }
@@ -36146,24 +36440,24 @@ function registerSetupLinuxGate(program2) {
36146
36440
  }
36147
36441
 
36148
36442
  // src/commands/update.ts
36149
- import * as fs76 from "node:fs";
36443
+ import * as fs77 from "node:fs";
36150
36444
  import * as os41 from "node:os";
36151
- import * as path77 from "node:path";
36445
+ import * as path78 from "node:path";
36152
36446
  import { execSync as execSync14 } from "node:child_process";
36153
36447
  import pc28 from "picocolors";
36154
36448
 
36155
36449
  // src/lib/symlink-reconcile.ts
36156
- import * as fs74 from "node:fs";
36157
- import * as path75 from "node:path";
36450
+ import * as fs75 from "node:fs";
36451
+ import * as path76 from "node:path";
36158
36452
  var realFs = {
36159
- readdirSync: (p) => fs74.readdirSync(p),
36160
- existsSync: (p) => fs74.existsSync(p),
36161
- lstatSync: (p) => fs74.lstatSync(p),
36162
- readlinkSync: (p) => fs74.readlinkSync(p),
36163
- symlinkSync: (t, l) => fs74.symlinkSync(t, l),
36164
- unlinkSync: (p) => fs74.unlinkSync(p),
36453
+ readdirSync: (p) => fs75.readdirSync(p),
36454
+ existsSync: (p) => fs75.existsSync(p),
36455
+ lstatSync: (p) => fs75.lstatSync(p),
36456
+ readlinkSync: (p) => fs75.readlinkSync(p),
36457
+ symlinkSync: (t, l) => fs75.symlinkSync(t, l),
36458
+ unlinkSync: (p) => fs75.unlinkSync(p),
36165
36459
  mkdirSync: (p, o) => {
36166
- fs74.mkdirSync(p, o);
36460
+ fs75.mkdirSync(p, o);
36167
36461
  }
36168
36462
  };
36169
36463
  function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir2, _fs = realFs) {
@@ -36173,8 +36467,8 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir2, _fs = realFs) {
36173
36467
  _fs.mkdirSync(claudeSkillsDir2, { recursive: true });
36174
36468
  const sourceSkills = _fs.existsSync(npmSkillsDir) ? _fs.readdirSync(npmSkillsDir).filter((d) => d.startsWith("olam-")) : [];
36175
36469
  for (const skill of sourceSkills) {
36176
- const linkPath = path75.join(claudeSkillsDir2, skill);
36177
- const target = path75.join(npmSkillsDir, skill);
36470
+ const linkPath = path76.join(claudeSkillsDir2, skill);
36471
+ const target = path76.join(npmSkillsDir, skill);
36178
36472
  if (!_fs.existsSync(linkPath)) {
36179
36473
  try {
36180
36474
  _fs.symlinkSync(target, linkPath);
@@ -36187,7 +36481,7 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir2, _fs = realFs) {
36187
36481
  }
36188
36482
  const deployedEntries = _fs.existsSync(claudeSkillsDir2) ? _fs.readdirSync(claudeSkillsDir2).filter((d) => d.startsWith("olam-")) : [];
36189
36483
  for (const entry of deployedEntries) {
36190
- const linkPath = path75.join(claudeSkillsDir2, entry);
36484
+ const linkPath = path76.join(claudeSkillsDir2, entry);
36191
36485
  let isSymlink = false;
36192
36486
  try {
36193
36487
  isSymlink = _fs.lstatSync(linkPath).isSymbolicLink();
@@ -36212,9 +36506,9 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir2, _fs = realFs) {
36212
36506
 
36213
36507
  // src/commands/update.ts
36214
36508
  var PACKAGE_NAME = "@pleri/olam-cli";
36215
- var CACHE_DIR2 = path77.join(os41.homedir(), ".olam", "cache");
36216
- var LOG_DIR2 = path77.join(os41.homedir(), ".olam", "log");
36217
- var LAST_STABLE_FILE = path77.join(CACHE_DIR2, "last-stable.txt");
36509
+ var CACHE_DIR2 = path78.join(os41.homedir(), ".olam", "cache");
36510
+ var LOG_DIR2 = path78.join(os41.homedir(), ".olam", "log");
36511
+ var LAST_STABLE_FILE = path78.join(CACHE_DIR2, "last-stable.txt");
36218
36512
  function defaultExec(cmd) {
36219
36513
  try {
36220
36514
  const stdout = execSync14(cmd, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
@@ -36236,22 +36530,22 @@ function getCurrentVersion(_exec = defaultExec) {
36236
36530
  }
36237
36531
  function readLastStable(file = LAST_STABLE_FILE) {
36238
36532
  try {
36239
- const v = fs76.readFileSync(file, "utf-8").trim();
36533
+ const v = fs77.readFileSync(file, "utf-8").trim();
36240
36534
  return v || null;
36241
36535
  } catch {
36242
36536
  return null;
36243
36537
  }
36244
36538
  }
36245
36539
  function writeLastStable(version, file = LAST_STABLE_FILE) {
36246
- fs76.mkdirSync(path77.dirname(file), { recursive: true });
36247
- fs76.writeFileSync(file, version, { mode: 420 });
36540
+ fs77.mkdirSync(path78.dirname(file), { recursive: true });
36541
+ fs77.writeFileSync(file, version, { mode: 420 });
36248
36542
  }
36249
36543
  function logUpdateFailure(stderr) {
36250
36544
  const ts = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
36251
- const logFile = path77.join(LOG_DIR2, `update-${ts}.log`);
36545
+ const logFile = path78.join(LOG_DIR2, `update-${ts}.log`);
36252
36546
  try {
36253
- fs76.mkdirSync(LOG_DIR2, { recursive: true });
36254
- fs76.appendFileSync(logFile, `[update-failure ${(/* @__PURE__ */ new Date()).toISOString()}]
36547
+ fs77.mkdirSync(LOG_DIR2, { recursive: true });
36548
+ fs77.appendFileSync(logFile, `[update-failure ${(/* @__PURE__ */ new Date()).toISOString()}]
36255
36549
  ${stderr}
36256
36550
  `, "utf-8");
36257
36551
  } catch {
@@ -36338,8 +36632,8 @@ async function doUpdate(opts, _exec = defaultExec, _reconcile = reconcileSkillSy
36338
36632
  let symlinkResult = { added: [], removed: [] };
36339
36633
  if (npmRootResult.exitCode === 0) {
36340
36634
  const npmRoot = npmRootResult.stdout.trim();
36341
- const npmSkillsDir = path77.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills");
36342
- const claudeSkillsDir2 = path77.join(os41.homedir(), ".claude", "skills");
36635
+ const npmSkillsDir = path78.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills");
36636
+ const claudeSkillsDir2 = path78.join(os41.homedir(), ".claude", "skills");
36343
36637
  const rec = _reconcile(npmSkillsDir, claudeSkillsDir2);
36344
36638
  symlinkResult = { added: rec.added, removed: rec.removed };
36345
36639
  if (!quiet && (rec.added.length > 0 || rec.removed.length > 0)) {
@@ -36385,8 +36679,8 @@ async function doRollback(_exec = defaultExec, _reconcile = reconcileSkillSymlin
36385
36679
  if (npmRootResult.exitCode === 0) {
36386
36680
  const npmRoot = npmRootResult.stdout.trim();
36387
36681
  _reconcile(
36388
- path77.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills"),
36389
- path77.join(os41.homedir(), ".claude", "skills")
36682
+ path78.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills"),
36683
+ path78.join(os41.homedir(), ".claude", "skills")
36390
36684
  );
36391
36685
  }
36392
36686
  return { action: "rolled-back", restoredVersion: prev, exitCode: 0 };
@@ -36469,7 +36763,7 @@ function registerBegin(program2) {
36469
36763
  // src/commands/config.ts
36470
36764
  init_global_config();
36471
36765
  init_store2();
36472
- import * as fs77 from "node:fs";
36766
+ import * as fs78 from "node:fs";
36473
36767
  import { createRequire as createRequire4 } from "node:module";
36474
36768
  var _require4 = createRequire4(import.meta.url);
36475
36769
  var { parse: parseWithMap } = _require4("json-source-map");
@@ -36477,14 +36771,14 @@ function registerConfig(program2) {
36477
36771
  const config = program2.command("config").description("Manage global olam configuration");
36478
36772
  config.command("validate [path]").description("Validate ~/.olam/config.json (or a custom path) against the schema").action((filePath) => {
36479
36773
  const resolvedPath = filePath ?? globalConfigPath();
36480
- if (!fs77.existsSync(resolvedPath)) {
36774
+ if (!fs78.existsSync(resolvedPath)) {
36481
36775
  process.stderr.write(`config file not found: ${resolvedPath}
36482
36776
  `);
36483
36777
  process.exit(1);
36484
36778
  }
36485
36779
  let raw;
36486
36780
  try {
36487
- raw = fs77.readFileSync(resolvedPath, "utf-8");
36781
+ raw = fs78.readFileSync(resolvedPath, "utf-8");
36488
36782
  } catch (err) {
36489
36783
  const msg = err instanceof Error ? err.message : String(err);
36490
36784
  process.stderr.write(`cannot read ${resolvedPath}: ${msg}
@@ -36742,9 +37036,9 @@ import * as readline2 from "node:readline";
36742
37036
  import pc32 from "picocolors";
36743
37037
 
36744
37038
  // src/commands/flywheel/install-shims.ts
36745
- import { copyFileSync as copyFileSync9, existsSync as existsSync88, mkdirSync as mkdirSync53, readFileSync as readFileSync70, writeFileSync as writeFileSync44 } from "node:fs";
37039
+ import { copyFileSync as copyFileSync9, existsSync as existsSync88, mkdirSync as mkdirSync53, readFileSync as readFileSync71, writeFileSync as writeFileSync44 } from "node:fs";
36746
37040
  import { homedir as homedir46 } from "node:os";
36747
- import { dirname as dirname48, join as join84 } from "node:path";
37041
+ import { dirname as dirname48, join as join85 } from "node:path";
36748
37042
 
36749
37043
  // src/lib/shim-generator.ts
36750
37044
  var SHIM_SPECS = Object.freeze([
@@ -36807,7 +37101,7 @@ ${argsBlock}
36807
37101
  // src/commands/flywheel/install-shims.ts
36808
37102
  var SHIM_HEADER_MARKER = "# AUTO-GENERATED by `olam flywheel install-shims`";
36809
37103
  function refreshShims(opts = {}) {
36810
- const targetDir = opts.targetDir ?? join84(homedir46(), ".claude", "scripts");
37104
+ const targetDir = opts.targetDir ?? join85(homedir46(), ".claude", "scripts");
36811
37105
  const results = [];
36812
37106
  let written = 0;
36813
37107
  let overwritten = 0;
@@ -36837,7 +37131,7 @@ function isOlamGeneratedShim(text) {
36837
37131
  return text.includes(SHIM_HEADER_MARKER);
36838
37132
  }
36839
37133
  function installOne(spec, targetDir, opts) {
36840
- const targetPath = join84(targetDir, spec.basename);
37134
+ const targetPath = join85(targetDir, spec.basename);
36841
37135
  const newContent = generateShim(spec);
36842
37136
  if (!existsSync88(targetPath)) {
36843
37137
  if (opts.dryRun !== true) {
@@ -36846,7 +37140,7 @@ function installOne(spec, targetDir, opts) {
36846
37140
  }
36847
37141
  return { basename: spec.basename, action: "written", targetPath };
36848
37142
  }
36849
- const existing = readFileSync70(targetPath, "utf8");
37143
+ const existing = readFileSync71(targetPath, "utf8");
36850
37144
  if (existing === newContent) {
36851
37145
  return { basename: spec.basename, action: "unchanged", targetPath };
36852
37146
  }
@@ -36868,7 +37162,7 @@ function installOne(spec, targetDir, opts) {
36868
37162
  }
36869
37163
  function registerFlywheelInstallShims(parent) {
36870
37164
  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) => {
36871
- const targetDir = opts.targetDir ?? join84(homedir46(), ".claude", "scripts");
37165
+ const targetDir = opts.targetDir ?? join85(homedir46(), ".claude", "scripts");
36872
37166
  const summary2 = refreshShims(opts);
36873
37167
  const lines = [];
36874
37168
  const dryRunSuffix = opts.dryRun === true ? " (dry-run)" : "";
@@ -36975,16 +37269,28 @@ function registerSkillsSource(program2) {
36975
37269
  const when = new Date(s.addedAt).toISOString().slice(0, 10);
36976
37270
  const sha = s.lastPulledSha ? s.lastPulledSha.slice(0, 8) : pc32.dim("(unpulled)");
36977
37271
  const ord = pc32.dim(`[${i + 1}]`);
37272
+ const prefixCol = s.prefix ? pc32.cyan(s.prefix.padEnd(12)) : pc32.dim("\u2014".padEnd(12));
36978
37273
  console.log(
36979
- ` ${ord} ${pc32.bold(s.id.padEnd(14))} ${s.name.padEnd(24)} ${s.branch.padEnd(12)} ${sha.padEnd(12)} ${pc32.dim(when)} ${pc32.dim(s.gitUrl)}`
37274
+ ` ${ord} ${pc32.bold(s.id.padEnd(14))} ${s.name.padEnd(24)} ${s.branch.padEnd(12)} ${sha.padEnd(12)} ${prefixCol} ${pc32.dim(when)} ${pc32.dim(s.gitUrl)}`
36980
37275
  );
36981
37276
  }
36982
37277
  });
36983
- source.command("add").description("Register and clone a skill source (T6 capability-class: requires --trust OR interactive ack)").requiredOption("--name <name>", "Display name (lowercase, digits, dash)").requiredOption("--git-url <url>", "git URL (https://, git@, ssh://, file://, or absolute path)").option("--branch <branch>", "Branch to track", "main").option("--trust", "Acknowledge that registering grants symlink-into-~/.claude permission (skips interactive picker)").option("--sync-now", "Run `olam skills sync` immediately after add (skips interactive prompt)").option("--no-sync-now", "Skip the post-add sync (skips interactive prompt)").option("--install-hook", "Install the SessionStart hook after add (skips interactive prompt)").option("--no-install-hook", "Skip installing the SessionStart hook (skips interactive prompt)").option(
37278
+ source.command("add").description("Register and clone a skill source (T6 capability-class: requires --trust OR interactive ack)").requiredOption("--name <name>", "Display name (lowercase, digits, dash)").requiredOption("--git-url <url>", "git URL (https://, git@, ssh://, file://, or absolute path)").option("--branch <branch>", "Branch to track", "main").option(
37279
+ "--prefix <prefix>",
37280
+ 'Deploy prefix: skills+agents from this source deploy as <prefix>:<canonical-name> (e.g. "atl", "pln"). Must match /^[a-z0-9][a-z0-9_-]{0,38}$/'
37281
+ ).option("--trust", "Acknowledge that registering grants symlink-into-~/.claude permission (skips interactive picker)").option("--sync-now", "Run `olam skills sync` immediately after add (skips interactive prompt)").option("--no-sync-now", "Skip the post-add sync (skips interactive prompt)").option("--install-hook", "Install the SessionStart hook after add (skips interactive prompt)").option("--no-install-hook", "Skip installing the SessionStart hook (skips interactive prompt)").option(
36984
37282
  "--hook-scope <scope>",
36985
37283
  "When installing the hook (post-add): project (<cwd>/.claude) or user (~/.claude)",
36986
37284
  "project"
36987
37285
  ).action(async (opts) => {
37286
+ const PREFIX_PATTERN3 = /^[a-z0-9][a-z0-9_-]{0,38}$/;
37287
+ if (opts.prefix !== void 0 && !PREFIX_PATTERN3.test(opts.prefix)) {
37288
+ printError(
37289
+ `prefix must match /^[a-z0-9][a-z0-9_-]{0,38}$/ \u2014 got "${opts.prefix}"`
37290
+ );
37291
+ process.exitCode = 1;
37292
+ return;
37293
+ }
36988
37294
  const isTTY = Boolean(process.stdout.isTTY);
36989
37295
  const testPromptFn = globalThis.__olamTestTrustPrompt;
36990
37296
  let decision;
@@ -37022,6 +37328,9 @@ function registerSkillsSource(program2) {
37022
37328
  branch: opts.branch,
37023
37329
  trustMethod: decision.method
37024
37330
  });
37331
+ if (opts.prefix !== void 0) {
37332
+ updateSkillSource(entry.id, { prefix: opts.prefix });
37333
+ }
37025
37334
  } catch (err) {
37026
37335
  try {
37027
37336
  appendTrustAudit({
@@ -37231,14 +37540,50 @@ function registerSkillsSource(program2) {
37231
37540
  console.log(`${pc32.bold("lastPulledSha:")} ${entry.lastPulledSha ?? pc32.dim("(unpulled)")}`);
37232
37541
  console.log(`${pc32.bold("clonePath:")} ${skillSourceClonePath(entry.id)}`);
37233
37542
  });
37543
+ source.command("set-prefix").description(
37544
+ "Set the deploy prefix for a registered skill source (skills+agents deploy as <prefix>:<canonical-name>)"
37545
+ ).argument("<name>", 'Display name of the skill source (from "olam skills source list")').argument("<prefix>", "Prefix value (must match /^[a-z0-9][a-z0-9_-]{0,38}$/)").action((name, prefix) => {
37546
+ const entry = getSkillSourceByName(name);
37547
+ if (entry === null) {
37548
+ printError(
37549
+ `skill source "${name}" is not registered. Run "olam skills source list" to see registered sources.`
37550
+ );
37551
+ process.exitCode = 1;
37552
+ return;
37553
+ }
37554
+ try {
37555
+ updateSkillSource(entry.id, { prefix });
37556
+ printSuccess(`set prefix "${prefix}" on source "${name}" (${entry.id})`);
37557
+ } catch (err) {
37558
+ printError(asMessage3(err));
37559
+ process.exitCode = 1;
37560
+ }
37561
+ });
37562
+ source.command("unset-prefix").description("Remove the deploy prefix from a registered skill source (reverts to canonical deploy names)").argument("<name>", 'Display name of the skill source (from "olam skills source list")').action((name) => {
37563
+ const entry = getSkillSourceByName(name);
37564
+ if (entry === null) {
37565
+ printError(
37566
+ `skill source "${name}" is not registered. Run "olam skills source list" to see registered sources.`
37567
+ );
37568
+ process.exitCode = 1;
37569
+ return;
37570
+ }
37571
+ try {
37572
+ updateSkillSource(entry.id, { prefix: null });
37573
+ printSuccess(`unset prefix on source "${name}" (${entry.id})`);
37574
+ } catch (err) {
37575
+ printError(asMessage3(err));
37576
+ process.exitCode = 1;
37577
+ }
37578
+ });
37234
37579
  }
37235
37580
 
37236
37581
  // src/commands/skills.ts
37237
37582
  init_skill_sources();
37238
37583
  init_output();
37239
- import * as fs78 from "node:fs";
37584
+ import * as fs79 from "node:fs";
37240
37585
  import * as os42 from "node:os";
37241
- import * as path78 from "node:path";
37586
+ import * as path79 from "node:path";
37242
37587
  import * as readline3 from "node:readline";
37243
37588
  import pc33 from "picocolors";
37244
37589
 
@@ -37251,14 +37596,14 @@ import {
37251
37596
  lstatSync as lstatSync8,
37252
37597
  mkdirSync as mkdirSync54,
37253
37598
  readdirSync as readdirSync26,
37254
- readFileSync as readFileSync71,
37599
+ readFileSync as readFileSync72,
37255
37600
  readlinkSync as readlinkSync4,
37256
37601
  rmSync as rmSync9,
37257
37602
  statSync as statSync27,
37258
37603
  writeFileSync as writeFileSync45
37259
37604
  } from "node:fs";
37260
37605
  import { homedir as homedir47 } from "node:os";
37261
- import { basename as basename8, dirname as dirname49, isAbsolute as isAbsolute4, join as join85, relative as relative5, resolve as resolve21 } from "node:path";
37606
+ import { basename as basename8, dirname as dirname49, isAbsolute as isAbsolute4, join as join86, relative as relative5, resolve as resolve21 } from "node:path";
37262
37607
 
37263
37608
  // src/commands/flywheel/sanitize-persona-output.ts
37264
37609
  var FORBIDDEN_HEADERS = [
@@ -37320,7 +37665,7 @@ function registerFlywheelSanitizePersonaOutput(parent) {
37320
37665
 
37321
37666
  // src/lib/skills-apply-overlays.ts
37322
37667
  function claudeRoot(opts) {
37323
- return opts.claudeDir ?? opts.fixtureRoot ?? join85(homedir47(), ".claude");
37668
+ return opts.claudeDir ?? opts.fixtureRoot ?? join86(homedir47(), ".claude");
37324
37669
  }
37325
37670
  function ensureRealDir(p) {
37326
37671
  if (!existsSync89(p)) {
@@ -37335,8 +37680,8 @@ function ensureRealDir(p) {
37335
37680
  mkdirSync54(p, { recursive: true });
37336
37681
  if (existsSync89(target) && statSync27(target).isDirectory()) {
37337
37682
  for (const entry of readdirSync26(target)) {
37338
- const src = join85(target, entry);
37339
- const dest = join85(p, entry);
37683
+ const src = join86(target, entry);
37684
+ const dest = join86(p, entry);
37340
37685
  const srcStat = lstatSync8(src);
37341
37686
  if (srcStat.isDirectory()) {
37342
37687
  try {
@@ -37358,8 +37703,8 @@ function postMergeSanitize(mergedText, label) {
37358
37703
  return { ok: false, reason: `[post-merge-sanitize] ${label} merged output failed sanitizer: ${result.reason}` };
37359
37704
  }
37360
37705
  function mergeOne(upstreamPath, overlayPath, destPath2, label, dryRun, messages) {
37361
- const upstreamText = readFileSync71(upstreamPath, "utf8");
37362
- const overlayText = readFileSync71(overlayPath, "utf8");
37706
+ const upstreamText = readFileSync72(upstreamPath, "utf8");
37707
+ const overlayText = readFileSync72(overlayPath, "utf8");
37363
37708
  const result = mergeMarkdown(upstreamText, overlayText, label, upstreamPath, overlayPath);
37364
37709
  if ("error" in result) {
37365
37710
  messages.push(`ERROR ${result.error.reason}`);
@@ -37379,7 +37724,7 @@ function mergeOne(upstreamPath, overlayPath, destPath2, label, dryRun, messages)
37379
37724
  }
37380
37725
  function isNewAgentOverlay(overlayPath) {
37381
37726
  try {
37382
- const text = readFileSync71(overlayPath, "utf8");
37727
+ const text = readFileSync72(overlayPath, "utf8");
37383
37728
  const { fm } = parseFrontmatter3(text);
37384
37729
  return fm["overlay-intent"] === "new-agent";
37385
37730
  } catch {
@@ -37396,9 +37741,9 @@ function copyNewAgent(overlayPath, destPath2, label, dryRun, messages) {
37396
37741
  function walkSkillsOverlays(skillsOverridesDir, skillsDir, opts, result) {
37397
37742
  if (!existsSync89(skillsOverridesDir)) return;
37398
37743
  for (const skillName of readdirSync26(skillsOverridesDir)) {
37399
- const overlaySkillDir = join85(skillsOverridesDir, skillName);
37744
+ const overlaySkillDir = join86(skillsOverridesDir, skillName);
37400
37745
  if (!statSync27(overlaySkillDir).isDirectory()) continue;
37401
- const upstreamSkillDir = join85(skillsDir, skillName);
37746
+ const upstreamSkillDir = join86(skillsDir, skillName);
37402
37747
  if (!existsSync89(upstreamSkillDir)) {
37403
37748
  result.messages.push(`SKIP ${skillName}: no upstream skill at ${upstreamSkillDir} (skill overlays require an upstream skill dir)`);
37404
37749
  continue;
@@ -37412,7 +37757,7 @@ function walkOverlayTree(overlayRoot, upstreamRoot, labelPrefix, opts, result, i
37412
37757
  while (stack.length > 0) {
37413
37758
  const current = stack.pop();
37414
37759
  for (const entry of readdirSync26(current)) {
37415
- const overlayPath = join85(current, entry);
37760
+ const overlayPath = join86(current, entry);
37416
37761
  const stat = lstatSync8(overlayPath);
37417
37762
  if (stat.isDirectory()) {
37418
37763
  stack.push(overlayPath);
@@ -37420,7 +37765,7 @@ function walkOverlayTree(overlayRoot, upstreamRoot, labelPrefix, opts, result, i
37420
37765
  }
37421
37766
  if (!stat.isFile() && !stat.isSymbolicLink()) continue;
37422
37767
  const rel = relative5(overlayRoot, overlayPath);
37423
- const upstreamPath = join85(upstreamRoot, rel);
37768
+ const upstreamPath = join86(upstreamRoot, rel);
37424
37769
  const label = `${labelPrefix} ${rel}`;
37425
37770
  if (!entry.endsWith(".md")) {
37426
37771
  if (!opts.dryRun) {
@@ -37465,10 +37810,10 @@ function walkAgentsOverlays(agentsOverridesDir, agentsDir, opts, result) {
37465
37810
  }
37466
37811
  async function applyOverlays(opts = {}) {
37467
37812
  const root = claudeRoot(opts);
37468
- const skillsDir = join85(root, "skills");
37469
- const agentsDir = join85(root, "agents");
37470
- const skillsOverridesDir = join85(root, "skills.overrides");
37471
- const agentsOverridesDir = join85(root, "agents.overrides");
37813
+ const skillsDir = join86(root, "skills");
37814
+ const agentsDir = join86(root, "agents");
37815
+ const skillsOverridesDir = join86(root, "skills.overrides");
37816
+ const agentsOverridesDir = join86(root, "agents.overrides");
37472
37817
  const result = {
37473
37818
  rc: 0,
37474
37819
  skillsMerged: 0,
@@ -37517,12 +37862,12 @@ function asMessage4(err) {
37517
37862
  }
37518
37863
  var ATLAS_USER_PICKER_RE = /^[a-z0-9][a-z0-9_-]{0,38}$/;
37519
37864
  function listMemberNames(clonePath) {
37520
- const membersDir = path78.join(clonePath, "members");
37521
- if (!fs78.existsSync(membersDir)) return [];
37865
+ const membersDir = path79.join(clonePath, "members");
37866
+ if (!fs79.existsSync(membersDir)) return [];
37522
37867
  try {
37523
- return fs78.readdirSync(membersDir).filter((e) => {
37868
+ return fs79.readdirSync(membersDir).filter((e) => {
37524
37869
  try {
37525
- return fs78.statSync(path78.join(membersDir, e)).isDirectory();
37870
+ return fs79.statSync(path79.join(membersDir, e)).isDirectory();
37526
37871
  } catch {
37527
37872
  return false;
37528
37873
  }
@@ -37543,10 +37888,10 @@ function defaultAtlasUserPrompt(question) {
37543
37888
  async function resolveAtlasUserWithPicker(cliOverride, opts) {
37544
37889
  if (cliOverride !== void 0) return cliOverride;
37545
37890
  const ATLAS_USER_RE2 = /^[a-z0-9][a-z0-9_-]{0,38}$/;
37546
- const claudeDirPathForRead = opts?._testClaudeDir ?? (process.env["OLAM_CLAUDE_DIR"] ?? path78.join(os42.homedir(), ".claude"));
37547
- const atlasUserFile = path78.join(claudeDirPathForRead, ".atlas-user");
37548
- if (fs78.existsSync(atlasUserFile)) {
37549
- const existing = fs78.readFileSync(atlasUserFile, "utf-8").trim();
37891
+ const claudeDirPathForRead = opts?._testClaudeDir ?? (process.env["OLAM_CLAUDE_DIR"] ?? path79.join(os42.homedir(), ".claude"));
37892
+ const atlasUserFile = path79.join(claudeDirPathForRead, ".atlas-user");
37893
+ if (fs79.existsSync(atlasUserFile)) {
37894
+ const existing = fs79.readFileSync(atlasUserFile, "utf-8").trim();
37550
37895
  if (existing.length > 0) {
37551
37896
  if (ATLAS_USER_RE2.test(existing)) {
37552
37897
  return existing;
@@ -37605,10 +37950,10 @@ async function resolveAtlasUserWithPicker(cliOverride, opts) {
37605
37950
  );
37606
37951
  return void 0;
37607
37952
  }
37608
- const claudeDirPath = opts?._testClaudeDir ?? (process.env["OLAM_CLAUDE_DIR"] ?? path78.join(os42.homedir(), ".claude"));
37609
- fs78.mkdirSync(claudeDirPath, { recursive: true });
37610
- fs78.writeFileSync(path78.join(claudeDirPath, ".atlas-user"), picked + "\n", "utf8");
37611
- process.stdout.write(pc33.green(`\u2713 atlas-user set to "${picked}" (written to ${path78.join(claudeDirPath, ".atlas-user")})
37953
+ const claudeDirPath = opts?._testClaudeDir ?? (process.env["OLAM_CLAUDE_DIR"] ?? path79.join(os42.homedir(), ".claude"));
37954
+ fs79.mkdirSync(claudeDirPath, { recursive: true });
37955
+ fs79.writeFileSync(path79.join(claudeDirPath, ".atlas-user"), picked + "\n", "utf8");
37956
+ process.stdout.write(pc33.green(`\u2713 atlas-user set to "${picked}" (written to ${path79.join(claudeDirPath, ".atlas-user")})
37612
37957
  `));
37613
37958
  return picked;
37614
37959
  }
@@ -37620,14 +37965,14 @@ function listDeployed() {
37620
37965
  );
37621
37966
  const entries = [];
37622
37967
  for (const bucket of ["skills", "agents", "scripts", "rules", "commands"]) {
37623
- const bucketDir = path78.join(dir, bucket);
37624
- if (!fs78.existsSync(bucketDir)) continue;
37625
- for (const name of fs78.readdirSync(bucketDir)) {
37626
- const full = path78.join(bucketDir, name);
37968
+ const bucketDir = path79.join(dir, bucket);
37969
+ if (!fs79.existsSync(bucketDir)) continue;
37970
+ for (const name of fs79.readdirSync(bucketDir)) {
37971
+ const full = path79.join(bucketDir, name);
37627
37972
  try {
37628
- const stat = fs78.lstatSync(full);
37973
+ const stat = fs79.lstatSync(full);
37629
37974
  if (!stat.isSymbolicLink()) continue;
37630
- const target = fs78.readlinkSync(full);
37975
+ const target = fs79.readlinkSync(full);
37631
37976
  let sourceId;
37632
37977
  for (const [clonePath, id] of sourcePaths.entries()) {
37633
37978
  if (target.startsWith(clonePath)) {
@@ -37702,6 +38047,19 @@ function printSyncSummary(summary2, dryRun) {
37702
38047
  console.log(` ${pc33.red(" (migrate-hooks-back will not be able to undo this sync)")}`);
37703
38048
  }
37704
38049
  }
38050
+ if (summary2.prefixRewrites.length > 0) {
38051
+ console.log(` prefix rewrites: ${summary2.prefixRewrites.length}`);
38052
+ }
38053
+ if (summary2.prefixCollisions.length > 0) {
38054
+ const allSources = summary2.perSource;
38055
+ for (const col of summary2.prefixCollisions) {
38056
+ const winnerName = allSources.find((s) => s.sourceId === col.winnerSourceId)?.name ?? col.winnerSourceId.slice(0, 8);
38057
+ const loserNames = col.loserSourceIds.map((id) => allSources.find((s) => s.sourceId === id)?.name ?? id.slice(0, 8)).join(", ");
38058
+ console.log(
38059
+ ` ${pc33.yellow(`\u26A0 prefix collision: '${col.prefix}' used by ${winnerName} (winner) + ${loserNames}; first-registered wins`)}`
38060
+ );
38061
+ }
38062
+ }
37705
38063
  console.log();
37706
38064
  for (const s of summary2.perSource) {
37707
38065
  const sub = s.fromSubscriptionsFile ? "(subscribed)" : "(all categories)";
@@ -37813,12 +38171,12 @@ function registerSkills(program2) {
37813
38171
  // src/commands/skills-hook.ts
37814
38172
  init_skill_sources();
37815
38173
  init_output();
37816
- import * as fs79 from "node:fs";
38174
+ import * as fs80 from "node:fs";
37817
38175
  function backup(filePath) {
37818
- if (!fs79.existsSync(filePath)) return null;
38176
+ if (!fs80.existsSync(filePath)) return null;
37819
38177
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
37820
38178
  const backupPath = `${filePath}.olam-bak.${ts}`;
37821
- fs79.copyFileSync(filePath, backupPath);
38179
+ fs80.copyFileSync(filePath, backupPath);
37822
38180
  return backupPath;
37823
38181
  }
37824
38182
  function registerSkillsHook(program2) {
@@ -37866,7 +38224,7 @@ function registerSkillsHook(program2) {
37866
38224
  printInfo("olam-skills hook", `not found in ${filePath} \u2014 already uninstalled`);
37867
38225
  if (backupPath) {
37868
38226
  try {
37869
- fs79.unlinkSync(backupPath);
38227
+ fs80.unlinkSync(backupPath);
37870
38228
  } catch {
37871
38229
  }
37872
38230
  }
@@ -38048,24 +38406,24 @@ init_skill_sources();
38048
38406
  init_merge_settings();
38049
38407
  init_skill_sources();
38050
38408
  init_output();
38051
- import * as fs80 from "node:fs";
38052
- import * as path79 from "node:path";
38409
+ import * as fs81 from "node:fs";
38410
+ import * as path80 from "node:path";
38053
38411
  var MIGRATE_FROM_TOOLBOX_COMMAND = "migrate-from-toolbox";
38054
38412
  function asMessage6(err) {
38055
38413
  return err instanceof Error ? err.message : String(err);
38056
38414
  }
38057
38415
  function isOlamSkillsHookPresent(filePath) {
38058
- if (!fs80.existsSync(filePath)) return false;
38416
+ if (!fs81.existsSync(filePath)) return false;
38059
38417
  try {
38060
- const raw = fs80.readFileSync(filePath, "utf-8");
38418
+ const raw = fs81.readFileSync(filePath, "utf-8");
38061
38419
  return raw.includes(OLAM_SKILLS_HOOK_SENTINEL);
38062
38420
  } catch {
38063
38421
  return false;
38064
38422
  }
38065
38423
  }
38066
38424
  function uninstallLegacyToolboxSessionStartHook(filePath, toolboxPath) {
38067
- if (!fs80.existsSync(filePath)) return { removed: 0 };
38068
- const raw = fs80.readFileSync(filePath, "utf-8");
38425
+ if (!fs81.existsSync(filePath)) return { removed: 0 };
38426
+ const raw = fs81.readFileSync(filePath, "utf-8");
38069
38427
  const settings = raw.trim() ? JSON.parse(raw) : {};
38070
38428
  const ss = settings?.hooks?.SessionStart;
38071
38429
  if (!Array.isArray(ss)) return { removed: 0 };
@@ -38094,7 +38452,7 @@ function uninstallLegacyToolboxSessionStartHook(filePath, toolboxPath) {
38094
38452
  if (otherStages.length === 0) delete next.hooks;
38095
38453
  else delete next.hooks.SessionStart;
38096
38454
  }
38097
- fs80.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
38455
+ fs81.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
38098
38456
  return { removed };
38099
38457
  }
38100
38458
  function registerSkillsMigrate(program2) {
@@ -38117,7 +38475,7 @@ function registerSkillsMigrate(program2) {
38117
38475
  return;
38118
38476
  }
38119
38477
  const toolboxPath = opts.path;
38120
- const namespace = opts.namespace ?? path79.basename(toolboxPath);
38478
+ const namespace = opts.namespace ?? path80.basename(toolboxPath);
38121
38479
  const sourceName = opts.sourceName ?? namespace;
38122
38480
  const snapshot = detectToolboxState({ toolboxPath, namespace });
38123
38481
  if (!snapshot) {
@@ -38171,9 +38529,9 @@ function registerSkillsMigrate(program2) {
38171
38529
  printWarning(`legacy hook removal failed: ${asMessage6(err)}; proceeding`);
38172
38530
  }
38173
38531
  const scope = opts.scope === "user" ? "user" : "project";
38174
- const olamHookPath = scope === "user" ? settingsFile : path79.join(process.cwd(), ".claude", "settings.json");
38532
+ const olamHookPath = scope === "user" ? settingsFile : path80.join(process.cwd(), ".claude", "settings.json");
38175
38533
  try {
38176
- fs80.mkdirSync(path79.dirname(olamHookPath), { recursive: true });
38534
+ fs81.mkdirSync(path80.dirname(olamHookPath), { recursive: true });
38177
38535
  const result = mergeHomeSettingsJson(olamHookPath, {
38178
38536
  ensureHook: {
38179
38537
  stage: OLAM_SKILLS_HOOK_STAGE,
@@ -38206,8 +38564,8 @@ function registerSkillsMigrate(program2) {
38206
38564
  // src/commands/skills-migrate-back.ts
38207
38565
  init_skill_sources();
38208
38566
  init_output();
38209
- import * as fs81 from "node:fs";
38210
- import * as path80 from "node:path";
38567
+ import * as fs82 from "node:fs";
38568
+ import * as path81 from "node:path";
38211
38569
  var MIGRATE_BACK_TO_TOOLBOX_COMMAND = "migrate-back-to-toolbox";
38212
38570
  function asMessage7(err) {
38213
38571
  return err instanceof Error ? err.message : String(err);
@@ -38215,16 +38573,16 @@ function asMessage7(err) {
38215
38573
  function claudeDirInternal4() {
38216
38574
  const override = process.env["OLAM_CLAUDE_DIR"];
38217
38575
  if (override && override.length > 0) return override;
38218
- return path80.join(process.env["HOME"] ?? "", ".claude");
38576
+ return path81.join(process.env["HOME"] ?? "", ".claude");
38219
38577
  }
38220
38578
  function restoreSessionStartFromSnapshot(filePath, originalSessionStartHook) {
38221
38579
  if (!originalSessionStartHook || originalSessionStartHook.length === 0) {
38222
38580
  return { restored: false };
38223
38581
  }
38224
38582
  let settings;
38225
- if (fs81.existsSync(filePath)) {
38583
+ if (fs82.existsSync(filePath)) {
38226
38584
  try {
38227
- const raw = fs81.readFileSync(filePath, "utf-8");
38585
+ const raw = fs82.readFileSync(filePath, "utf-8");
38228
38586
  settings = raw.trim() ? JSON.parse(raw) : {};
38229
38587
  } catch {
38230
38588
  settings = {};
@@ -38240,8 +38598,8 @@ function restoreSessionStartFromSnapshot(filePath, originalSessionStartHook) {
38240
38598
  SessionStart: originalSessionStartHook
38241
38599
  }
38242
38600
  };
38243
- fs81.mkdirSync(path80.dirname(filePath), { recursive: true });
38244
- fs81.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
38601
+ fs82.mkdirSync(path81.dirname(filePath), { recursive: true });
38602
+ fs82.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
38245
38603
  return { restored: true };
38246
38604
  }
38247
38605
  function removeOlamManagedSymlinks() {
@@ -38250,16 +38608,16 @@ function removeOlamManagedSymlinks() {
38250
38608
  const olamClonePaths = sources.map((s) => skillSourceClonePath(s.id));
38251
38609
  let removed = 0;
38252
38610
  for (const bucket of ["skills", "agents", "scripts", "rules", "commands"]) {
38253
- const dir = path80.join(claude, bucket);
38254
- if (!fs81.existsSync(dir)) continue;
38255
- for (const name of fs81.readdirSync(dir)) {
38256
- const linkPath = path80.join(dir, name);
38611
+ const dir = path81.join(claude, bucket);
38612
+ if (!fs82.existsSync(dir)) continue;
38613
+ for (const name of fs82.readdirSync(dir)) {
38614
+ const linkPath = path81.join(dir, name);
38257
38615
  try {
38258
- const stat = fs81.lstatSync(linkPath);
38616
+ const stat = fs82.lstatSync(linkPath);
38259
38617
  if (!stat.isSymbolicLink()) continue;
38260
- const target = fs81.readlinkSync(linkPath);
38618
+ const target = fs82.readlinkSync(linkPath);
38261
38619
  if (olamClonePaths.some((cp) => target.startsWith(cp))) {
38262
- fs81.unlinkSync(linkPath);
38620
+ fs82.unlinkSync(linkPath);
38263
38621
  removed += 1;
38264
38622
  }
38265
38623
  } catch {
@@ -38272,18 +38630,18 @@ function restoreToolboxSymlinks(symlinks) {
38272
38630
  let restored = 0;
38273
38631
  for (const { link, target } of symlinks) {
38274
38632
  try {
38275
- fs81.mkdirSync(path80.dirname(link), { recursive: true });
38276
- if (fs81.existsSync(link) || (() => {
38633
+ fs82.mkdirSync(path81.dirname(link), { recursive: true });
38634
+ if (fs82.existsSync(link) || (() => {
38277
38635
  try {
38278
- fs81.lstatSync(link);
38636
+ fs82.lstatSync(link);
38279
38637
  return true;
38280
38638
  } catch {
38281
38639
  return false;
38282
38640
  }
38283
38641
  })()) {
38284
- fs81.unlinkSync(link);
38642
+ fs82.unlinkSync(link);
38285
38643
  }
38286
- fs81.symlinkSync(target, link);
38644
+ fs82.symlinkSync(target, link);
38287
38645
  restored += 1;
38288
38646
  } catch {
38289
38647
  }
@@ -38292,9 +38650,9 @@ function restoreToolboxSymlinks(symlinks) {
38292
38650
  }
38293
38651
  function restoreAtlasUserMarker(atlasUser) {
38294
38652
  if (!atlasUser) return false;
38295
- const file = path80.join(claudeDirInternal4(), ".atlas-user");
38296
- fs81.mkdirSync(path80.dirname(file), { recursive: true });
38297
- fs81.writeFileSync(file, atlasUser);
38653
+ const file = path81.join(claudeDirInternal4(), ".atlas-user");
38654
+ fs82.mkdirSync(path81.dirname(file), { recursive: true });
38655
+ fs82.writeFileSync(file, atlasUser);
38298
38656
  return true;
38299
38657
  }
38300
38658
  function registerSkillsMigrateBack(program2) {
@@ -38307,15 +38665,15 @@ function registerSkillsMigrateBack(program2) {
38307
38665
  let snapshot;
38308
38666
  try {
38309
38667
  if (opts.snapshot) {
38310
- snapshotPath = path80.resolve(opts.snapshot);
38311
- if (!fs81.existsSync(snapshotPath)) {
38668
+ snapshotPath = path81.resolve(opts.snapshot);
38669
+ if (!fs82.existsSync(snapshotPath)) {
38312
38670
  printError(`snapshot not found at ${snapshotPath}`);
38313
38671
  process.exitCode = 1;
38314
38672
  return;
38315
38673
  }
38316
38674
  snapshot = readMigrationSnapshotFromPath(snapshotPath);
38317
38675
  } else {
38318
- const filterNamespace = opts.namespace ?? (opts.path ? path80.basename(opts.path) : void 0);
38676
+ const filterNamespace = opts.namespace ?? (opts.path ? path81.basename(opts.path) : void 0);
38319
38677
  const latest = readLatestMigrationSnapshot({ namespace: filterNamespace });
38320
38678
  if (!latest) {
38321
38679
  const where = filterNamespace ? ` for namespace "${filterNamespace}"` : "";
@@ -38392,8 +38750,8 @@ init_meta_hooks_migration_snapshot();
38392
38750
  init_trust_audit_log();
38393
38751
  init_atlas_hook_strip();
38394
38752
  init_output();
38395
- import * as fs82 from "node:fs";
38396
- import * as path81 from "node:path";
38753
+ import * as fs83 from "node:fs";
38754
+ import * as path82 from "node:path";
38397
38755
  import pc35 from "picocolors";
38398
38756
  var MIGRATE_HOOKS_COMMAND = "migrate-hooks";
38399
38757
  function settingsHasOlamMetaSentinel(settings) {
@@ -38414,16 +38772,16 @@ function settingsHasOlamMetaSentinel(settings) {
38414
38772
  return false;
38415
38773
  }
38416
38774
  function readSettings2(filePath) {
38417
- if (!fs82.existsSync(filePath)) return null;
38418
- const raw = fs82.readFileSync(filePath, "utf-8");
38775
+ if (!fs83.existsSync(filePath)) return null;
38776
+ const raw = fs83.readFileSync(filePath, "utf-8");
38419
38777
  if (raw.trim().length === 0) return {};
38420
38778
  return JSON.parse(raw);
38421
38779
  }
38422
38780
  function writeSettings(filePath, settings) {
38423
- fs82.mkdirSync(path81.dirname(filePath), { recursive: true });
38781
+ fs83.mkdirSync(path82.dirname(filePath), { recursive: true });
38424
38782
  const tmp = `${filePath}.tmp-migrate-hooks-${process.pid}-${Date.now()}`;
38425
- fs82.writeFileSync(tmp, JSON.stringify(settings, null, 2) + "\n");
38426
- fs82.renameSync(tmp, filePath);
38783
+ fs83.writeFileSync(tmp, JSON.stringify(settings, null, 2) + "\n");
38784
+ fs83.renameSync(tmp, filePath);
38427
38785
  }
38428
38786
  function printSummary(candidates2, opts) {
38429
38787
  if (candidates2.length === 0) {
@@ -38503,7 +38861,7 @@ function registerSkillsMigrateHooks(program2) {
38503
38861
  init_meta_hooks_migration_snapshot();
38504
38862
  init_skill_sources();
38505
38863
  init_output();
38506
- import * as path82 from "node:path";
38864
+ import * as path83 from "node:path";
38507
38865
  function asMessage9(err) {
38508
38866
  return err instanceof Error ? err.message : String(err);
38509
38867
  }
@@ -38520,16 +38878,16 @@ function registerSkillsMigrateHooksBack(program2) {
38520
38878
  return;
38521
38879
  }
38522
38880
  if (opts.snapshot) {
38523
- const resolved = path82.resolve(opts.snapshot);
38524
- const allowedDir = path82.resolve(migrationSnapshotsDir2());
38525
- if (!resolved.startsWith(allowedDir + path82.sep)) {
38881
+ const resolved = path83.resolve(opts.snapshot);
38882
+ const allowedDir = path83.resolve(migrationSnapshotsDir2());
38883
+ if (!resolved.startsWith(allowedDir + path83.sep)) {
38526
38884
  printError(
38527
38885
  `--snapshot path must be inside ${allowedDir} (got "${resolved}"). Refusing to restore from an arbitrary path \u2014 settings.json would land operator-chosen content.`
38528
38886
  );
38529
38887
  process.exitCode = 1;
38530
38888
  return;
38531
38889
  }
38532
- const basename16 = path82.basename(resolved);
38890
+ const basename16 = path83.basename(resolved);
38533
38891
  if (!basename16.startsWith(META_HOOKS_SNAPSHOT_PREFIX)) {
38534
38892
  printError(
38535
38893
  `--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.`
@@ -38558,7 +38916,7 @@ function registerSkillsMigrateHooksBack(program2) {
38558
38916
  // src/commands/skills-shadow-backups.ts
38559
38917
  init_skill_sources();
38560
38918
  init_output();
38561
- import * as fs83 from "node:fs";
38919
+ import * as fs84 from "node:fs";
38562
38920
  import pc36 from "picocolors";
38563
38921
  function asMessage10(err) {
38564
38922
  return err instanceof Error ? err.message : String(err);
@@ -38641,7 +38999,7 @@ function registerSkillsShadowBackups(program2) {
38641
38999
  });
38642
39000
  sb.command("restore").description("Move a shadow-backup file back to its original path").argument("<path>", "Absolute path to the .shadow-backup-<epoch> file").option("--force", "Overwrite the original path if it already exists").action((p, opts) => {
38643
39001
  try {
38644
- if (!fs83.existsSync(p)) {
39002
+ if (!fs84.existsSync(p)) {
38645
39003
  printError(`backup file not found: ${p}`);
38646
39004
  process.exitCode = 1;
38647
39005
  return;
@@ -38764,8 +39122,8 @@ init_skill_sources();
38764
39122
  init_cli_version();
38765
39123
  init_output();
38766
39124
  import { execFileSync as execFileSync15 } from "node:child_process";
38767
- import * as fs84 from "node:fs";
38768
- import * as path83 from "node:path";
39125
+ import * as fs85 from "node:fs";
39126
+ import * as path84 from "node:path";
38769
39127
  var CHAIN_SKILL_NAMES = [
38770
39128
  "10x:brainstorm",
38771
39129
  "10x:plan-hard",
@@ -38788,13 +39146,13 @@ function hasBeadsCli() {
38788
39146
  }
38789
39147
  }
38790
39148
  function hasBeadsProjectInit(cwd) {
38791
- return fs84.existsSync(path83.join(cwd, ".beads"));
39149
+ return fs85.existsSync(path84.join(cwd, ".beads"));
38792
39150
  }
38793
39151
  function hasBeadsClaudeSetup() {
38794
- const settingsPath = path83.join(claudeDir(), "settings.json");
38795
- if (!fs84.existsSync(settingsPath)) return false;
39152
+ const settingsPath = path84.join(claudeDir(), "settings.json");
39153
+ if (!fs85.existsSync(settingsPath)) return false;
38796
39154
  try {
38797
- const content = fs84.readFileSync(settingsPath, "utf8");
39155
+ const content = fs85.readFileSync(settingsPath, "utf8");
38798
39156
  return /"command"\s*:\s*"bd\b/.test(content) || /"bd setup\b/.test(content);
38799
39157
  } catch {
38800
39158
  return false;
@@ -38859,12 +39217,12 @@ function shortSha(sha) {
38859
39217
  return sha.slice(0, 8);
38860
39218
  }
38861
39219
  function listInstalledClaudeSkills() {
38862
- const skillsDir = path83.join(claudeDir(), "skills");
38863
- if (!fs84.existsSync(skillsDir)) return [];
39220
+ const skillsDir = path84.join(claudeDir(), "skills");
39221
+ if (!fs85.existsSync(skillsDir)) return [];
38864
39222
  try {
38865
- return fs84.readdirSync(skillsDir).filter((name) => {
39223
+ return fs85.readdirSync(skillsDir).filter((name) => {
38866
39224
  try {
38867
- const stat = fs84.lstatSync(path83.join(skillsDir, name));
39225
+ const stat = fs85.lstatSync(path84.join(skillsDir, name));
38868
39226
  return stat.isSymbolicLink() || stat.isDirectory();
38869
39227
  } catch {
38870
39228
  return false;
@@ -38939,20 +39297,20 @@ function registerSkills10x(program2) {
38939
39297
  tenx.command("uninstall").description(
38940
39298
  "Remove /10x: chain skill symlinks from ~/.claude/skills (preserves user-authored skills + non-chain skill sources)"
38941
39299
  ).action(() => {
38942
- const skillsDir = path83.join(claudeDir(), "skills");
38943
- if (!fs84.existsSync(skillsDir)) {
39300
+ const skillsDir = path84.join(claudeDir(), "skills");
39301
+ if (!fs85.existsSync(skillsDir)) {
38944
39302
  printWarning("No ~/.claude/skills/ directory found; nothing to uninstall");
38945
39303
  return;
38946
39304
  }
38947
39305
  let removed = 0;
38948
- for (const name of fs84.readdirSync(skillsDir)) {
38949
- const full = path83.join(skillsDir, name);
39306
+ for (const name of fs85.readdirSync(skillsDir)) {
39307
+ const full = path84.join(skillsDir, name);
38950
39308
  try {
38951
- const stat = fs84.lstatSync(full);
39309
+ const stat = fs85.lstatSync(full);
38952
39310
  if (!stat.isSymbolicLink()) continue;
38953
- const target = fs84.readlinkSync(full);
39311
+ const target = fs85.readlinkSync(full);
38954
39312
  if (isChainSkill(name) || /\/10x[-:]/.test(target)) {
38955
- fs84.unlinkSync(full);
39313
+ fs85.unlinkSync(full);
38956
39314
  removed += 1;
38957
39315
  }
38958
39316
  } catch {
@@ -39020,22 +39378,22 @@ function registerSkills10x(program2) {
39020
39378
 
39021
39379
  // src/commands/hermes.ts
39022
39380
  init_output();
39023
- import * as fs85 from "node:fs";
39381
+ import * as fs86 from "node:fs";
39024
39382
  import * as os43 from "node:os";
39025
- import * as path84 from "node:path";
39383
+ import * as path85 from "node:path";
39026
39384
  import * as child_process from "node:child_process";
39027
39385
  import { parse as yamlParse2, stringify as yamlStringify3 } from "yaml";
39028
39386
  function hermesConfigPath() {
39029
- return path84.join(os43.homedir(), ".hermes", "config.yaml");
39387
+ return path85.join(os43.homedir(), ".hermes", "config.yaml");
39030
39388
  }
39031
39389
  function hermesSkillsDir() {
39032
- return path84.join(os43.homedir(), ".hermes", "skills");
39390
+ return path85.join(os43.homedir(), ".hermes", "skills");
39033
39391
  }
39034
39392
  function claudeSkillsDir() {
39035
- return path84.join(os43.homedir(), ".claude", "skills");
39393
+ return path85.join(os43.homedir(), ".claude", "skills");
39036
39394
  }
39037
39395
  function readHermesConfig(configPath) {
39038
- const raw = fs85.readFileSync(configPath, "utf-8");
39396
+ const raw = fs86.readFileSync(configPath, "utf-8");
39039
39397
  const parsed = yamlParse2(raw);
39040
39398
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
39041
39399
  throw new Error(`${configPath} is not a YAML mapping`);
@@ -39043,13 +39401,13 @@ function readHermesConfig(configPath) {
39043
39401
  return parsed;
39044
39402
  }
39045
39403
  function writeHermesConfig(configPath, config) {
39046
- fs85.writeFileSync(configPath, yamlStringify3(config), "utf-8");
39404
+ fs86.writeFileSync(configPath, yamlStringify3(config), "utf-8");
39047
39405
  }
39048
39406
  function resolveOlamBinary() {
39049
39407
  try {
39050
39408
  const result = child_process.spawnSync("which", ["olam"], { encoding: "utf-8" });
39051
39409
  const found = result.stdout.trim();
39052
- if (found && fs85.existsSync(found)) return found;
39410
+ if (found && fs86.existsSync(found)) return found;
39053
39411
  } catch {
39054
39412
  }
39055
39413
  return process.argv[1] ?? "olam";
@@ -39062,7 +39420,7 @@ function resolveWorkspaceDir() {
39062
39420
  { encoding: "utf-8" }
39063
39421
  );
39064
39422
  const out = result.stdout.trim();
39065
- if (out && fs85.existsSync(out)) return out;
39423
+ if (out && fs86.existsSync(out)) return out;
39066
39424
  } catch {
39067
39425
  }
39068
39426
  return process.cwd();
@@ -39132,22 +39490,22 @@ function ensureTerminalBackendLocal(config, dryRun, summary2) {
39132
39490
  }
39133
39491
  function mirrorSkillSymlinks(dryRun, summary2) {
39134
39492
  const srcDir = claudeSkillsDir();
39135
- if (!fs85.existsSync(srcDir)) {
39493
+ if (!fs86.existsSync(srcDir)) {
39136
39494
  summary2.skipped.push("skills mirror (no ~/.claude/skills/ found)");
39137
39495
  return;
39138
39496
  }
39139
39497
  const destDir = hermesSkillsDir();
39140
39498
  if (!dryRun) {
39141
- fs85.mkdirSync(destDir, { recursive: true });
39499
+ fs86.mkdirSync(destDir, { recursive: true });
39142
39500
  }
39143
- const entries = fs85.readdirSync(srcDir);
39501
+ const entries = fs86.readdirSync(srcDir);
39144
39502
  let mirrored = 0;
39145
39503
  let collisions = 0;
39146
39504
  for (const entry of entries) {
39147
- const srcPath = path84.join(srcDir, entry);
39148
- const destPath2 = path84.join(destDir, entry);
39149
- if (fs85.existsSync(destPath2) || fs85.lstatSync(srcPath).isFile()) {
39150
- if (fs85.existsSync(destPath2)) collisions++;
39505
+ const srcPath = path85.join(srcDir, entry);
39506
+ const destPath2 = path85.join(destDir, entry);
39507
+ if (fs86.existsSync(destPath2) || fs86.lstatSync(srcPath).isFile()) {
39508
+ if (fs86.existsSync(destPath2)) collisions++;
39151
39509
  continue;
39152
39510
  }
39153
39511
  if (dryRun) {
@@ -39155,7 +39513,7 @@ function mirrorSkillSymlinks(dryRun, summary2) {
39155
39513
  continue;
39156
39514
  }
39157
39515
  try {
39158
- fs85.symlinkSync(srcPath, destPath2);
39516
+ fs86.symlinkSync(srcPath, destPath2);
39159
39517
  mirrored++;
39160
39518
  } catch (err) {
39161
39519
  printWarning(`skills mirror: skipping ${entry} \u2014 ${err instanceof Error ? err.message : String(err)}`);
@@ -39174,7 +39532,7 @@ async function runHermesBootstrap(opts, deps = {}) {
39174
39532
  const writeConfig2 = deps.writeConfig ?? writeHermesConfig;
39175
39533
  const mirrorSkillsFn = deps.mirrorSkills ?? mirrorSkillSymlinks;
39176
39534
  const installHookFn = deps.installHook ?? installKgFirstHookForHermes;
39177
- if (!fs85.existsSync(configPath)) {
39535
+ if (!fs86.existsSync(configPath)) {
39178
39536
  printError(`~/.hermes/config.yaml not found at ${configPath}`);
39179
39537
  printInfo(
39180
39538
  "remedy",
@@ -39200,7 +39558,7 @@ async function runHermesBootstrap(opts, deps = {}) {
39200
39558
  } else {
39201
39559
  summary2.skipped.push("mcp_servers.agentmemory-atlas (AGENTMEMORY_BRIDGE_URL/SECRET not set; use --bridge-url/--bridge-secret to add)");
39202
39560
  }
39203
- const hooksDir = path84.join(path84.dirname(configPath), "hooks");
39561
+ const hooksDir = path85.join(path85.dirname(configPath), "hooks");
39204
39562
  const hookResult = installHookFn(hooksDir, dryRun);
39205
39563
  switch (hookResult.status) {
39206
39564
  case "installed":
@@ -39247,7 +39605,7 @@ async function runHermesBootstrap(opts, deps = {}) {
39247
39605
  }
39248
39606
  var HOOK_MATCHERS = ["terminal", "bash", "shell", "search_files", "grep", "ripgrep"];
39249
39607
  function ensureHermesHookEntry(config, hooksDir, dryRun, summary2) {
39250
- const hookScriptPath = path84.join(hooksDir, "kg-first.sh");
39608
+ const hookScriptPath = path85.join(hooksDir, "kg-first.sh");
39251
39609
  const hooks = config["hooks"] ?? {};
39252
39610
  const preToolCall = Array.isArray(hooks["pre_tool_call"]) ? hooks["pre_tool_call"] : [];
39253
39611
  const alreadyPresent = preToolCall.some(
@@ -39520,8 +39878,8 @@ var SECRET = process.env["OLAM_MCP_AUTH_SECRET"] ?? "";
39520
39878
  function authHeaders() {
39521
39879
  return SECRET ? { "X-Olam-Mcp-Secret": SECRET } : {};
39522
39880
  }
39523
- async function apiFetch(path93, init = {}) {
39524
- const res = await fetch(`${BASE_URL}${path93}`, {
39881
+ async function apiFetch(path94, init = {}) {
39882
+ const res = await fetch(`${BASE_URL}${path94}`, {
39525
39883
  ...init,
39526
39884
  headers: {
39527
39885
  "Content-Type": "application/json",
@@ -39781,12 +40139,12 @@ import * as readline6 from "node:readline";
39781
40139
  import pc40 from "picocolors";
39782
40140
 
39783
40141
  // src/commands/mcp/import-discovery.ts
39784
- import * as fs86 from "node:fs";
40142
+ import * as fs87 from "node:fs";
39785
40143
  import * as os44 from "node:os";
39786
- import * as path85 from "node:path";
40144
+ import * as path86 from "node:path";
39787
40145
  function readJsonFile(filePath) {
39788
40146
  try {
39789
- const raw = fs86.readFileSync(filePath, "utf-8");
40147
+ const raw = fs87.readFileSync(filePath, "utf-8");
39790
40148
  return JSON.parse(raw);
39791
40149
  } catch {
39792
40150
  return null;
@@ -39815,24 +40173,24 @@ function extractMcpServers(obj, source, sourceLabel) {
39815
40173
  }
39816
40174
  function getClaudeDesktopPath() {
39817
40175
  if (process.platform === "darwin") {
39818
- return path85.join(os44.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
40176
+ return path86.join(os44.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
39819
40177
  }
39820
40178
  if (process.platform === "win32") {
39821
- const appData = process.env["APPDATA"] ?? path85.join(os44.homedir(), "AppData", "Roaming");
39822
- return path85.join(appData, "Claude", "claude_desktop_config.json");
40179
+ const appData = process.env["APPDATA"] ?? path86.join(os44.homedir(), "AppData", "Roaming");
40180
+ return path86.join(appData, "Claude", "claude_desktop_config.json");
39823
40181
  }
39824
- return path85.join(os44.homedir(), ".config", "Claude", "claude_desktop_config.json");
40182
+ return path86.join(os44.homedir(), ".config", "Claude", "claude_desktop_config.json");
39825
40183
  }
39826
40184
  function getOlamRepoPaths() {
39827
40185
  const configPaths = [
39828
- path85.join(os44.homedir(), ".olam", "config.yaml"),
39829
- path85.join(process.cwd(), ".olam", "config.yaml")
40186
+ path86.join(os44.homedir(), ".olam", "config.yaml"),
40187
+ path86.join(process.cwd(), ".olam", "config.yaml")
39830
40188
  ];
39831
40189
  const paths = [];
39832
40190
  for (const configPath of configPaths) {
39833
- if (!fs86.existsSync(configPath)) continue;
40191
+ if (!fs87.existsSync(configPath)) continue;
39834
40192
  try {
39835
- const raw = fs86.readFileSync(configPath, "utf-8");
40193
+ const raw = fs87.readFileSync(configPath, "utf-8");
39836
40194
  const repoMatches = [...raw.matchAll(/path:\s*["']?([^\s"'\n]+)/g)];
39837
40195
  for (const m of repoMatches) {
39838
40196
  if (m[1]) paths.push(m[1]);
@@ -39848,7 +40206,7 @@ async function discoverMcpSources(repoPaths) {
39848
40206
  const sources = [];
39849
40207
  const sourceDefs = [
39850
40208
  {
39851
- path: path85.join(os44.homedir(), ".claude.json"),
40209
+ path: path86.join(os44.homedir(), ".claude.json"),
39852
40210
  label: "Claude Code (~/.claude.json)"
39853
40211
  },
39854
40212
  {
@@ -39856,19 +40214,19 @@ async function discoverMcpSources(repoPaths) {
39856
40214
  label: "Claude Desktop"
39857
40215
  },
39858
40216
  {
39859
- path: path85.join(os44.homedir(), ".cursor", "mcp.json"),
40217
+ path: path86.join(os44.homedir(), ".cursor", "mcp.json"),
39860
40218
  label: "Cursor (~/.cursor/mcp.json)"
39861
40219
  },
39862
40220
  {
39863
- path: path85.join(os44.homedir(), ".codeium", "windsurf", "mcp_config.json"),
40221
+ path: path86.join(os44.homedir(), ".codeium", "windsurf", "mcp_config.json"),
39864
40222
  label: "Windsurf (~/.codeium/windsurf/mcp_config.json)"
39865
40223
  }
39866
40224
  ];
39867
40225
  const resolvedRepoPaths = repoPaths ?? getOlamRepoPaths();
39868
40226
  for (const repoPath of resolvedRepoPaths) {
39869
40227
  sourceDefs.push({
39870
- path: path85.join(repoPath, ".mcp.json"),
39871
- label: `.mcp.json (${path85.basename(repoPath)})`
40228
+ path: path86.join(repoPath, ".mcp.json"),
40229
+ label: `.mcp.json (${path86.basename(repoPath)})`
39872
40230
  });
39873
40231
  }
39874
40232
  const reads = await Promise.all(
@@ -40104,27 +40462,27 @@ function registerMcp(program2) {
40104
40462
  init_output();
40105
40463
 
40106
40464
  // src/lib/memory-host-process-migration.ts
40107
- import { existsSync as existsSync100, readFileSync as readFileSync79, unlinkSync as unlinkSync23 } from "node:fs";
40465
+ import { existsSync as existsSync100, readFileSync as readFileSync80, unlinkSync as unlinkSync23 } from "node:fs";
40108
40466
  import { spawnSync as spawnSync28 } from "node:child_process";
40109
40467
 
40110
40468
  // src/commands/memory/_paths.ts
40111
40469
  import { homedir as homedir51 } from "node:os";
40112
- import { join as join92, dirname as dirname55 } from "node:path";
40470
+ import { join as join93, dirname as dirname55 } from "node:path";
40113
40471
  import { fileURLToPath as fileURLToPath8 } from "node:url";
40114
- var OLAM_HOME4 = join92(homedir51(), ".olam");
40115
- var MEMORY_PID_PATH = join92(OLAM_HOME4, "memory.pid");
40116
- var MEMORY_LOG_PATH = join92(OLAM_HOME4, "memory-service.log");
40117
- var MEMORY_DATA_DIR = join92(OLAM_HOME4, "memory-data");
40472
+ var OLAM_HOME4 = join93(homedir51(), ".olam");
40473
+ var MEMORY_PID_PATH = join93(OLAM_HOME4, "memory.pid");
40474
+ var MEMORY_LOG_PATH = join93(OLAM_HOME4, "memory-service.log");
40475
+ var MEMORY_DATA_DIR = join93(OLAM_HOME4, "memory-data");
40118
40476
  var MEMORY_REST_PORT = 3111;
40119
40477
  var MEMORY_LIVEZ_URL = `http://localhost:${MEMORY_REST_PORT}/agentmemory/livez`;
40120
40478
  var here2 = dirname55(fileURLToPath8(import.meta.url));
40121
40479
  var candidates = [
40122
40480
  // 1. Workspace dev (built): packages/cli/dist/commands/memory/_paths.js → packages/cli → packages/memory-service
40123
- join92(here2, "..", "..", "..", "..", "memory-service"),
40481
+ join93(here2, "..", "..", "..", "..", "memory-service"),
40124
40482
  // 2. Workspace bundled: packages/cli/dist/index.js → packages/cli → packages/memory-service
40125
- join92(here2, "..", "..", "memory-service"),
40483
+ join93(here2, "..", "..", "memory-service"),
40126
40484
  // 3. CWD fallback
40127
- join92(process.cwd(), "packages", "memory-service")
40485
+ join93(process.cwd(), "packages", "memory-service")
40128
40486
  ];
40129
40487
  var MEMORY_SERVICE_CANDIDATES = candidates;
40130
40488
 
@@ -40173,7 +40531,7 @@ function migrateFromHostProcess(opts = {}) {
40173
40531
  }
40174
40532
  function readPidFromFile(pidPath2) {
40175
40533
  try {
40176
- const raw = readFileSync79(pidPath2, "utf8").trim();
40534
+ const raw = readFileSync80(pidPath2, "utf8").trim();
40177
40535
  const pid = parseInt(raw, 10);
40178
40536
  if (!Number.isFinite(pid) || pid <= 0) return null;
40179
40537
  return pid;
@@ -40606,13 +40964,13 @@ function registerMemoryUninstall(cmd) {
40606
40964
  // src/commands/memory/mode.ts
40607
40965
  init_schema2();
40608
40966
  init_output();
40609
- import { existsSync as existsSync103, readFileSync as readFileSync80, writeFileSync as writeFileSync51 } from "node:fs";
40610
- import { join as join93 } from "node:path";
40967
+ import { existsSync as existsSync103, readFileSync as readFileSync81, writeFileSync as writeFileSync51 } from "node:fs";
40968
+ import { join as join94 } from "node:path";
40611
40969
  import * as readline7 from "node:readline/promises";
40612
40970
  import { parse as parseYaml7, stringify as stringifyYaml6 } from "yaml";
40613
40971
  var CONFIG_REL = ".olam/config.yaml";
40614
40972
  function locateConfig(cwd) {
40615
- const absPath = join93(cwd, CONFIG_REL);
40973
+ const absPath = join94(cwd, CONFIG_REL);
40616
40974
  if (!existsSync103(absPath)) {
40617
40975
  throw new Error(
40618
40976
  `No ${CONFIG_REL} at ${cwd}. Run \`olam init\` in your workspace root first.`
@@ -40621,7 +40979,7 @@ function locateConfig(cwd) {
40621
40979
  return { absPath };
40622
40980
  }
40623
40981
  function readConfigYaml(absPath) {
40624
- const raw = readFileSync80(absPath, "utf-8");
40982
+ const raw = readFileSync81(absPath, "utf-8");
40625
40983
  const parsed = parseYaml7(raw) ?? {};
40626
40984
  if (typeof parsed !== "object" || parsed === null) {
40627
40985
  throw new Error(`${absPath} is not a YAML object`);
@@ -40750,7 +41108,7 @@ function registerMemoryMode(cmd) {
40750
41108
  init_output();
40751
41109
  import { spawn as spawn11 } from "node:child_process";
40752
41110
  import { existsSync as existsSync104 } from "node:fs";
40753
- import { join as join94 } from "node:path";
41111
+ import { join as join95 } from "node:path";
40754
41112
  var DEFAULT_PORT2 = 8788;
40755
41113
  function resolveMemoryServiceDir() {
40756
41114
  for (const c of MEMORY_SERVICE_CANDIDATES) {
@@ -40761,13 +41119,13 @@ function resolveMemoryServiceDir() {
40761
41119
  );
40762
41120
  }
40763
41121
  function resolveLocalBridgeScript(serviceDir) {
40764
- const path93 = join94(serviceDir, "scripts", "local-bridge-server.mjs");
40765
- if (!existsSync104(path93)) {
41122
+ const path94 = join95(serviceDir, "scripts", "local-bridge-server.mjs");
41123
+ if (!existsSync104(path94)) {
40766
41124
  throw new Error(
40767
- `Could not find local-bridge-server.mjs at ${path93}. Verify packages/memory-service ships the scripts/ directory.`
41125
+ `Could not find local-bridge-server.mjs at ${path94}. Verify packages/memory-service ships the scripts/ directory.`
40768
41126
  );
40769
41127
  }
40770
- return path93;
41128
+ return path94;
40771
41129
  }
40772
41130
  function validateBridgeOpts(opts) {
40773
41131
  const local = opts.local ?? false;
@@ -41108,9 +41466,9 @@ function registerMemoryStats(cmd) {
41108
41466
  }
41109
41467
 
41110
41468
  // src/commands/memory/install-hooks.ts
41111
- import { copyFileSync as copyFileSync12, existsSync as existsSync105, mkdirSync as mkdirSync60, readFileSync as readFileSync81, writeFileSync as writeFileSync52 } from "node:fs";
41469
+ import { copyFileSync as copyFileSync12, existsSync as existsSync105, mkdirSync as mkdirSync60, readFileSync as readFileSync82, writeFileSync as writeFileSync52 } from "node:fs";
41112
41470
  import { homedir as homedir52 } from "node:os";
41113
- import { dirname as dirname56, join as join95, resolve as resolve25 } from "node:path";
41471
+ import { dirname as dirname56, join as join96, resolve as resolve25 } from "node:path";
41114
41472
  import { fileURLToPath as fileURLToPath9 } from "node:url";
41115
41473
  var HOOK_BASENAMES = [
41116
41474
  "agentmemory-session-recall.js",
@@ -41126,12 +41484,12 @@ function defaultSourceDir() {
41126
41484
  return candidate;
41127
41485
  }
41128
41486
  function installOne2(basename16, sourceDir, targetDir, opts) {
41129
- const sourcePath = join95(sourceDir, basename16);
41130
- const targetPath = join95(targetDir, basename16);
41487
+ const sourcePath = join96(sourceDir, basename16);
41488
+ const targetPath = join96(targetDir, basename16);
41131
41489
  if (!existsSync105(sourcePath)) {
41132
41490
  throw new Error(`canonical hook source missing at ${sourcePath} \u2014 olam install corrupt or sourceDir is wrong`);
41133
41491
  }
41134
- const newContent = readFileSync81(sourcePath, "utf8");
41492
+ const newContent = readFileSync82(sourcePath, "utf8");
41135
41493
  if (!existsSync105(targetPath)) {
41136
41494
  if (opts.dryRun !== true) {
41137
41495
  mkdirSync60(dirname56(targetPath), { recursive: true });
@@ -41139,7 +41497,7 @@ function installOne2(basename16, sourceDir, targetDir, opts) {
41139
41497
  }
41140
41498
  return { basename: basename16, action: "written", targetPath };
41141
41499
  }
41142
- const existing = readFileSync81(targetPath, "utf8");
41500
+ const existing = readFileSync82(targetPath, "utf8");
41143
41501
  if (existing === newContent) {
41144
41502
  return { basename: basename16, action: "unchanged", targetPath };
41145
41503
  }
@@ -41162,13 +41520,13 @@ Add these hook entries to ~/.claude/settings.json:
41162
41520
  {
41163
41521
  "hooks": {
41164
41522
  "SessionStart": [
41165
- { "command": "node ${join95(targetDir, "agentmemory-session-recall.js")}" }
41523
+ { "command": "node ${join96(targetDir, "agentmemory-session-recall.js")}" }
41166
41524
  ],
41167
41525
  "PreToolUse": [
41168
- { "command": "node ${join95(targetDir, "agentmemory-recall-trigger.mjs")}" }
41526
+ { "command": "node ${join96(targetDir, "agentmemory-recall-trigger.mjs")}" }
41169
41527
  ],
41170
41528
  "PostToolUse": [
41171
- { "command": "node ${join95(targetDir, "agentmemory-classify-queue.mjs")}" }
41529
+ { "command": "node ${join96(targetDir, "agentmemory-classify-queue.mjs")}" }
41172
41530
  ]
41173
41531
  }
41174
41532
  }
@@ -41178,7 +41536,7 @@ If existing entries already point at the same paths, no edit needed.
41178
41536
  }
41179
41537
  function registerMemoryInstallHooks(parent) {
41180
41538
  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) => {
41181
- const targetDir = opts.targetDir ?? join95(homedir52(), ".claude", "scripts", "hooks");
41539
+ const targetDir = opts.targetDir ?? join96(homedir52(), ".claude", "scripts", "hooks");
41182
41540
  const sourceDir = opts.sourceDir ?? defaultSourceDir();
41183
41541
  let written = 0;
41184
41542
  let unchanged = 0;
@@ -41256,9 +41614,9 @@ function registerMemory(program2) {
41256
41614
  // src/commands/kg-build.ts
41257
41615
  init_storage_paths();
41258
41616
  init_workspace_name();
41259
- import * as fs91 from "node:fs";
41617
+ import * as fs92 from "node:fs";
41260
41618
  import * as os47 from "node:os";
41261
- import * as path90 from "node:path";
41619
+ import * as path91 from "node:path";
41262
41620
 
41263
41621
  // ../core/dist/kg/kg-service-client.js
41264
41622
  var KG_SERVICE_PORT_DEFAULT = 9997;
@@ -41269,8 +41627,8 @@ function port() {
41269
41627
  const n = Number.parseInt(env, 10);
41270
41628
  return Number.isFinite(n) && n > 0 ? n : KG_SERVICE_PORT_DEFAULT;
41271
41629
  }
41272
- function url(path93) {
41273
- return `http://127.0.0.1:${port()}${path93}`;
41630
+ function url(path94) {
41631
+ return `http://127.0.0.1:${port()}${path94}`;
41274
41632
  }
41275
41633
  function kgServiceHealthUrl() {
41276
41634
  return url("/health");
@@ -41350,39 +41708,39 @@ init_storage_paths();
41350
41708
  init_workspace_name();
41351
41709
  init_kg_caps();
41352
41710
  init_output();
41353
- import fs87 from "node:fs";
41711
+ import fs88 from "node:fs";
41354
41712
  import { homedir as homedir53 } from "node:os";
41355
- import path86 from "node:path";
41713
+ import path87 from "node:path";
41356
41714
  function olamHome4() {
41357
- return process.env.OLAM_HOME ?? path86.join(homedir53(), ".olam");
41715
+ return process.env.OLAM_HOME ?? path87.join(homedir53(), ".olam");
41358
41716
  }
41359
41717
  function kgRoot2() {
41360
- return path86.join(olamHome4(), "kg");
41718
+ return path87.join(olamHome4(), "kg");
41361
41719
  }
41362
41720
  function worldsRoot2() {
41363
- return path86.join(olamHome4(), "worlds");
41721
+ return path87.join(olamHome4(), "worlds");
41364
41722
  }
41365
41723
  function dirSizeBytes2(dir) {
41366
- if (!fs87.existsSync(dir)) return 0;
41724
+ if (!fs88.existsSync(dir)) return 0;
41367
41725
  let total = 0;
41368
41726
  const stack = [dir];
41369
41727
  while (stack.length > 0) {
41370
41728
  const cur = stack.pop();
41371
41729
  let entries;
41372
41730
  try {
41373
- entries = fs87.readdirSync(cur, { withFileTypes: true });
41731
+ entries = fs88.readdirSync(cur, { withFileTypes: true });
41374
41732
  } catch {
41375
41733
  continue;
41376
41734
  }
41377
41735
  for (const entry of entries) {
41378
- const full = path86.join(cur, entry.name);
41736
+ const full = path87.join(cur, entry.name);
41379
41737
  if (entry.isSymbolicLink()) continue;
41380
41738
  if (entry.isDirectory()) {
41381
41739
  stack.push(full);
41382
41740
  continue;
41383
41741
  }
41384
41742
  try {
41385
- total += fs87.statSync(full).size;
41743
+ total += fs88.statSync(full).size;
41386
41744
  } catch {
41387
41745
  }
41388
41746
  }
@@ -41396,10 +41754,10 @@ function formatBytes5(n) {
41396
41754
  return `${(n / 1024 / 1024 / 1024).toFixed(2)} GB`;
41397
41755
  }
41398
41756
  function readFreshness(workspace) {
41399
- const file = path86.join(kgPristinePath(workspace), "freshness.json");
41400
- if (!fs87.existsSync(file)) return null;
41757
+ const file = path87.join(kgPristinePath(workspace), "freshness.json");
41758
+ if (!fs88.existsSync(file)) return null;
41401
41759
  try {
41402
- const raw = JSON.parse(fs87.readFileSync(file, "utf-8"));
41760
+ const raw = JSON.parse(fs88.readFileSync(file, "utf-8"));
41403
41761
  if (raw && typeof raw === "object") return raw;
41404
41762
  return null;
41405
41763
  } catch {
@@ -41407,10 +41765,10 @@ function readFreshness(workspace) {
41407
41765
  }
41408
41766
  }
41409
41767
  function readOverlayNodeCount(graphifyOutDir) {
41410
- const graphPath = path86.join(graphifyOutDir, "graph.json");
41411
- if (!fs87.existsSync(graphPath)) return null;
41768
+ const graphPath = path87.join(graphifyOutDir, "graph.json");
41769
+ if (!fs88.existsSync(graphPath)) return null;
41412
41770
  try {
41413
- const raw = JSON.parse(fs87.readFileSync(graphPath, "utf-8"));
41771
+ const raw = JSON.parse(fs88.readFileSync(graphPath, "utf-8"));
41414
41772
  if (raw && typeof raw === "object") {
41415
41773
  const nodes = raw.nodes;
41416
41774
  if (Array.isArray(nodes)) return nodes.length;
@@ -41422,28 +41780,28 @@ function readOverlayNodeCount(graphifyOutDir) {
41422
41780
  }
41423
41781
  function listOverlays() {
41424
41782
  const root = worldsRoot2();
41425
- if (!fs87.existsSync(root)) return [];
41783
+ if (!fs88.existsSync(root)) return [];
41426
41784
  const records = [];
41427
41785
  let worldDirs;
41428
41786
  try {
41429
- worldDirs = fs87.readdirSync(root, { withFileTypes: true });
41787
+ worldDirs = fs88.readdirSync(root, { withFileTypes: true });
41430
41788
  } catch {
41431
41789
  return [];
41432
41790
  }
41433
41791
  for (const worldEntry of worldDirs) {
41434
41792
  if (!worldEntry.isDirectory()) continue;
41435
41793
  const worldId = worldEntry.name;
41436
- const worldDir = path86.join(root, worldId);
41794
+ const worldDir = path87.join(root, worldId);
41437
41795
  let cloneDirs;
41438
41796
  try {
41439
- cloneDirs = fs87.readdirSync(worldDir, { withFileTypes: true });
41797
+ cloneDirs = fs88.readdirSync(worldDir, { withFileTypes: true });
41440
41798
  } catch {
41441
41799
  continue;
41442
41800
  }
41443
41801
  for (const cloneEntry of cloneDirs) {
41444
41802
  if (!cloneEntry.isDirectory()) continue;
41445
- const graphifyOut = path86.join(worldDir, cloneEntry.name, "graphify-out");
41446
- if (!fs87.existsSync(graphifyOut)) continue;
41803
+ const graphifyOut = path87.join(worldDir, cloneEntry.name, "graphify-out");
41804
+ if (!fs88.existsSync(graphifyOut)) continue;
41447
41805
  records.push({
41448
41806
  world_id: worldId,
41449
41807
  clone_dir: cloneEntry.name,
@@ -41457,11 +41815,11 @@ function listOverlays() {
41457
41815
  }
41458
41816
  function listPristines(overlays) {
41459
41817
  const root = kgRoot2();
41460
- if (!fs87.existsSync(root)) return [];
41818
+ if (!fs88.existsSync(root)) return [];
41461
41819
  const records = [];
41462
41820
  let entries;
41463
41821
  try {
41464
- entries = fs87.readdirSync(root, { withFileTypes: true });
41822
+ entries = fs88.readdirSync(root, { withFileTypes: true });
41465
41823
  } catch {
41466
41824
  return [];
41467
41825
  }
@@ -41474,7 +41832,7 @@ function listPristines(overlays) {
41474
41832
  continue;
41475
41833
  }
41476
41834
  const fresh = readFreshness(workspace);
41477
- const graphifyOut = path86.join(kgPristinePath(workspace), "graphify-out");
41835
+ const graphifyOut = path87.join(kgPristinePath(workspace), "graphify-out");
41478
41836
  const size = dirSizeBytes2(graphifyOut);
41479
41837
  const worldCount = overlays.filter((o) => o.clone_dir === workspace).length;
41480
41838
  records.push({
@@ -41610,10 +41968,10 @@ init_storage_paths();
41610
41968
  init_workspace_name();
41611
41969
  init_output();
41612
41970
  import { spawn as spawn12 } from "node:child_process";
41613
- import fs88 from "node:fs";
41614
- import path87 from "node:path";
41971
+ import fs89 from "node:fs";
41972
+ import path88 from "node:path";
41615
41973
  function pidFilePath2(workspace) {
41616
- return path87.join(kgPristinePath(workspace), ".watch.pid");
41974
+ return path88.join(kgPristinePath(workspace), ".watch.pid");
41617
41975
  }
41618
41976
  function isPidAlive3(pid) {
41619
41977
  if (!Number.isInteger(pid) || pid <= 0) return false;
@@ -41628,39 +41986,39 @@ function isPidAlive3(pid) {
41628
41986
  }
41629
41987
  function readAndClassifyPid(workspace) {
41630
41988
  const file = pidFilePath2(workspace);
41631
- if (!fs88.existsSync(file)) return { status: "no-pidfile", pid: null };
41989
+ if (!fs89.existsSync(file)) return { status: "no-pidfile", pid: null };
41632
41990
  let pid;
41633
41991
  try {
41634
- const raw = fs88.readFileSync(file, "utf-8").trim();
41992
+ const raw = fs89.readFileSync(file, "utf-8").trim();
41635
41993
  pid = Number.parseInt(raw, 10);
41636
41994
  } catch {
41637
- fs88.rmSync(file, { force: true });
41995
+ fs89.rmSync(file, { force: true });
41638
41996
  return { status: "stale-reclaimed", pid: null };
41639
41997
  }
41640
41998
  if (!Number.isInteger(pid) || pid <= 0) {
41641
- fs88.rmSync(file, { force: true });
41999
+ fs89.rmSync(file, { force: true });
41642
42000
  return { status: "stale-reclaimed", pid: null };
41643
42001
  }
41644
42002
  if (isPidAlive3(pid)) return { status: "active", pid };
41645
- fs88.rmSync(file, { force: true });
42003
+ fs89.rmSync(file, { force: true });
41646
42004
  return { status: "stale-reclaimed", pid: null };
41647
42005
  }
41648
42006
  function writePidFile2(workspace, pid) {
41649
42007
  const file = pidFilePath2(workspace);
41650
- const dir = path87.dirname(file);
41651
- fs88.mkdirSync(dir, { recursive: true });
41652
- fs88.writeFileSync(file, String(pid), { encoding: "utf-8" });
42008
+ const dir = path88.dirname(file);
42009
+ fs89.mkdirSync(dir, { recursive: true });
42010
+ fs89.writeFileSync(file, String(pid), { encoding: "utf-8" });
41653
42011
  }
41654
42012
  function removePidFile(workspace) {
41655
42013
  const file = pidFilePath2(workspace);
41656
42014
  try {
41657
- fs88.rmSync(file, { force: true });
42015
+ fs89.rmSync(file, { force: true });
41658
42016
  } catch {
41659
42017
  }
41660
42018
  }
41661
42019
  async function runKgWatch(workspaceArg, opts, deps = {}) {
41662
42020
  const cwd = deps.cwd ?? opts.cwd ?? process.cwd();
41663
- const name = workspaceArg ?? path87.basename(cwd).toLowerCase();
42021
+ const name = workspaceArg ?? path88.basename(cwd).toLowerCase();
41664
42022
  try {
41665
42023
  validateWorkspaceName(name);
41666
42024
  } catch (err) {
@@ -41668,7 +42026,7 @@ async function runKgWatch(workspaceArg, opts, deps = {}) {
41668
42026
  return { exitCode: 1, pidWritten: false };
41669
42027
  }
41670
42028
  const pristinePath = kgPristinePath(name);
41671
- const graphPath = path87.join(pristinePath, "graphify-out", "graph.json");
42029
+ const graphPath = path88.join(pristinePath, "graphify-out", "graph.json");
41672
42030
  const pidState = readAndClassifyPid(name);
41673
42031
  if (pidState.status === "active") {
41674
42032
  printError(
@@ -41906,8 +42264,8 @@ function registerKgDoctorCommand(kg) {
41906
42264
 
41907
42265
  // src/commands/kg-install-hook.ts
41908
42266
  init_merge_settings();
41909
- import * as fs89 from "node:fs";
41910
- import * as path88 from "node:path";
42267
+ import * as fs90 from "node:fs";
42268
+ import * as path89 from "node:path";
41911
42269
  import * as os45 from "node:os";
41912
42270
  import { parse as yamlParse3, stringify as yamlStringify4 } from "yaml";
41913
42271
 
@@ -41960,27 +42318,27 @@ function buildHookMatcherEntry(opts) {
41960
42318
  init_output();
41961
42319
  function settingsPathFor2(scope) {
41962
42320
  if (scope === "user") {
41963
- return path88.join(os45.homedir(), ".claude", "settings.json");
42321
+ return path89.join(os45.homedir(), ".claude", "settings.json");
41964
42322
  }
41965
- return path88.join(process.cwd(), ".claude", "settings.json");
42323
+ return path89.join(process.cwd(), ".claude", "settings.json");
41966
42324
  }
41967
42325
  function backup2(filePath) {
41968
- if (!fs89.existsSync(filePath)) return null;
42326
+ if (!fs90.existsSync(filePath)) return null;
41969
42327
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
41970
42328
  const backupPath = `${filePath}.olam-bak.${ts}`;
41971
- fs89.copyFileSync(filePath, backupPath);
42329
+ fs90.copyFileSync(filePath, backupPath);
41972
42330
  return backupPath;
41973
42331
  }
41974
42332
  var HERMES_HOOK_MATCHERS = ["terminal", "bash", "shell", "search_files", "grep", "ripgrep"];
41975
42333
  function hermesConfigPath2() {
41976
- return path88.join(os45.homedir(), ".hermes", "config.yaml");
42334
+ return path89.join(os45.homedir(), ".hermes", "config.yaml");
41977
42335
  }
41978
42336
  function hermesHooksDir() {
41979
- return path88.join(os45.homedir(), ".hermes", "hooks");
42337
+ return path89.join(os45.homedir(), ".hermes", "hooks");
41980
42338
  }
41981
42339
  function patchHermesConfigForHook(action) {
41982
42340
  const configPath = hermesConfigPath2();
41983
- const raw = fs89.readFileSync(configPath, "utf-8");
42341
+ const raw = fs90.readFileSync(configPath, "utf-8");
41984
42342
  const config = yamlParse3(raw);
41985
42343
  const hooks = config["hooks"] ?? {};
41986
42344
  const preToolCall = Array.isArray(hooks["pre_tool_call"]) ? hooks["pre_tool_call"] : [];
@@ -41989,7 +42347,7 @@ function patchHermesConfigForHook(action) {
41989
42347
  (e) => typeof e["command"] === "string" && e["command"].includes(HERMES_KG_HOOK_SENTINEL)
41990
42348
  );
41991
42349
  if (alreadyPresent) return "already-present";
41992
- const hookScriptPath = path88.join(hermesHooksDir(), "kg-first.sh");
42350
+ const hookScriptPath = path89.join(hermesHooksDir(), "kg-first.sh");
41993
42351
  const entry = {
41994
42352
  matcher: HERMES_HOOK_MATCHERS.join("|"),
41995
42353
  command: `${hookScriptPath} # ${HERMES_KG_HOOK_SENTINEL}`
@@ -41999,7 +42357,7 @@ function patchHermesConfigForHook(action) {
41999
42357
  hooks: { ...hooks, pre_tool_call: [...preToolCall, entry] },
42000
42358
  hooks_auto_accept: true
42001
42359
  };
42002
- fs89.writeFileSync(configPath, yamlStringify4(updated2), "utf-8");
42360
+ fs90.writeFileSync(configPath, yamlStringify4(updated2), "utf-8");
42003
42361
  return "patched";
42004
42362
  }
42005
42363
  const filtered = preToolCall.filter(
@@ -42010,12 +42368,12 @@ function patchHermesConfigForHook(action) {
42010
42368
  ...config,
42011
42369
  hooks: { ...hooks, pre_tool_call: filtered }
42012
42370
  };
42013
- fs89.writeFileSync(configPath, yamlStringify4(updated), "utf-8");
42371
+ fs90.writeFileSync(configPath, yamlStringify4(updated), "utf-8");
42014
42372
  return "patched";
42015
42373
  }
42016
42374
  function doInstallForHermes() {
42017
42375
  const configPath = hermesConfigPath2();
42018
- if (!fs89.existsSync(configPath)) {
42376
+ if (!fs90.existsSync(configPath)) {
42019
42377
  printError(`~/.hermes/config.yaml not found at ${configPath}`);
42020
42378
  printInfo("remedy", "Install Hermes first, then re-run `olam kg install-hook --for hermes`");
42021
42379
  process.exitCode = 1;
@@ -42043,17 +42401,17 @@ function doInstallForHermes() {
42043
42401
  function doUninstallForHermes() {
42044
42402
  const configPath = hermesConfigPath2();
42045
42403
  const hooksDir = hermesHooksDir();
42046
- const hookScriptPath = path88.join(hooksDir, "kg-first.sh");
42404
+ const hookScriptPath = path89.join(hooksDir, "kg-first.sh");
42047
42405
  let scriptRemoved = false;
42048
- if (fs89.existsSync(hookScriptPath)) {
42049
- const content = fs89.readFileSync(hookScriptPath, "utf-8");
42406
+ if (fs90.existsSync(hookScriptPath)) {
42407
+ const content = fs90.readFileSync(hookScriptPath, "utf-8");
42050
42408
  if (content.includes(HERMES_KG_HOOK_SENTINEL)) {
42051
- fs89.unlinkSync(hookScriptPath);
42409
+ fs90.unlinkSync(hookScriptPath);
42052
42410
  scriptRemoved = true;
42053
42411
  }
42054
42412
  }
42055
42413
  let configPatched = false;
42056
- if (fs89.existsSync(configPath)) {
42414
+ if (fs90.existsSync(configPath)) {
42057
42415
  const result = patchHermesConfigForHook("uninstall");
42058
42416
  configPatched = result === "patched";
42059
42417
  }
@@ -42078,9 +42436,9 @@ function registerKgInstallHookCommand(kg) {
42078
42436
  const scope = opts.scope === "user" ? "user" : "project";
42079
42437
  const filePath = settingsPathFor2(scope);
42080
42438
  try {
42081
- fs89.mkdirSync(path88.dirname(filePath), { recursive: true });
42439
+ fs90.mkdirSync(path89.dirname(filePath), { recursive: true });
42082
42440
  } catch (err) {
42083
- printError(`could not create ${path88.dirname(filePath)}: ${err instanceof Error ? err.message : String(err)}`);
42441
+ printError(`could not create ${path89.dirname(filePath)}: ${err instanceof Error ? err.message : String(err)}`);
42084
42442
  process.exitCode = 1;
42085
42443
  return;
42086
42444
  }
@@ -42104,7 +42462,7 @@ function registerKgInstallHookCommand(kg) {
42104
42462
  printInfo("kg-service hook", `already installed at ${filePath}`);
42105
42463
  if (backupPath) {
42106
42464
  try {
42107
- fs89.unlinkSync(backupPath);
42465
+ fs90.unlinkSync(backupPath);
42108
42466
  } catch {
42109
42467
  }
42110
42468
  }
@@ -42122,15 +42480,15 @@ function registerKgInstallHookCommand(kg) {
42122
42480
  }
42123
42481
 
42124
42482
  // src/commands/kg-uninstall-hook.ts
42125
- import * as fs90 from "node:fs";
42126
- import * as path89 from "node:path";
42483
+ import * as fs91 from "node:fs";
42484
+ import * as path90 from "node:path";
42127
42485
  import * as os46 from "node:os";
42128
42486
  init_output();
42129
42487
  function settingsPathFor3(scope) {
42130
42488
  if (scope === "user") {
42131
- return path89.join(os46.homedir(), ".claude", "settings.json");
42489
+ return path90.join(os46.homedir(), ".claude", "settings.json");
42132
42490
  }
42133
- return path89.join(process.cwd(), ".claude", "settings.json");
42491
+ return path90.join(process.cwd(), ".claude", "settings.json");
42134
42492
  }
42135
42493
  function dropSentinel(matchers) {
42136
42494
  let changed = false;
@@ -42160,13 +42518,13 @@ function registerKgUninstallHookCommand(kg) {
42160
42518
  kg.command("uninstall-hook").description("Remove kg-service PreToolUse hook from .claude/settings.json (sentinel-matched; surgical)").option("--scope <scope>", "project (default) or user", "project").action((opts) => {
42161
42519
  const scope = opts.scope === "user" ? "user" : "project";
42162
42520
  const filePath = settingsPathFor3(scope);
42163
- if (!fs90.existsSync(filePath)) {
42521
+ if (!fs91.existsSync(filePath)) {
42164
42522
  printInfo("kg-service hook", `no settings.json at ${filePath} \u2014 nothing to remove`);
42165
42523
  return;
42166
42524
  }
42167
42525
  let settings;
42168
42526
  try {
42169
- const raw = fs90.readFileSync(filePath, "utf-8");
42527
+ const raw = fs91.readFileSync(filePath, "utf-8");
42170
42528
  settings = raw.trim() ? JSON.parse(raw) : {};
42171
42529
  } catch (err) {
42172
42530
  printError(`could not parse ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
@@ -42186,7 +42544,7 @@ function registerKgUninstallHookCommand(kg) {
42186
42544
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
42187
42545
  const backupPath = `${filePath}.olam-bak.${ts}`;
42188
42546
  try {
42189
- fs90.copyFileSync(filePath, backupPath);
42547
+ fs91.copyFileSync(filePath, backupPath);
42190
42548
  } catch {
42191
42549
  }
42192
42550
  const next = {
@@ -42205,7 +42563,7 @@ function registerKgUninstallHookCommand(kg) {
42205
42563
  }
42206
42564
  }
42207
42565
  try {
42208
- fs90.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
42566
+ fs91.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
42209
42567
  printSuccess(`kg-service hook removed from ${filePath}`);
42210
42568
  printInfo("backup", backupPath);
42211
42569
  } catch (err) {
@@ -42278,8 +42636,8 @@ function registerKgSavingsCommand(kg) {
42278
42636
 
42279
42637
  // src/commands/kg-build.ts
42280
42638
  function readQueueFromDisk(queuePath) {
42281
- if (!fs91.existsSync(queuePath)) return [];
42282
- const raw = fs91.readFileSync(queuePath, "utf-8");
42639
+ if (!fs92.existsSync(queuePath)) return [];
42640
+ const raw = fs92.readFileSync(queuePath, "utf-8");
42283
42641
  const entries = [];
42284
42642
  for (const line of raw.split("\n")) {
42285
42643
  const t = line.trim();
@@ -42292,14 +42650,14 @@ function readQueueFromDisk(queuePath) {
42292
42650
  return entries;
42293
42651
  }
42294
42652
  function writeQueueToDisk(queuePath, entries) {
42295
- fs91.mkdirSync(path90.dirname(queuePath), { recursive: true });
42653
+ fs92.mkdirSync(path91.dirname(queuePath), { recursive: true });
42296
42654
  const content = entries.map((e) => JSON.stringify(e)).join("\n") + (entries.length > 0 ? "\n" : "");
42297
- fs91.writeFileSync(queuePath, content, "utf-8");
42655
+ fs92.writeFileSync(queuePath, content, "utf-8");
42298
42656
  }
42299
42657
  async function runKgBuildPending(opts = {}) {
42300
42658
  const queuePath = opts.queuePath ?? (() => {
42301
- const stateDir = process.env["OLAM_STATE_DIR"] ?? path90.join(os47.homedir(), ".olam", "state");
42302
- return path90.join(stateDir, "kg-pending.jsonl");
42659
+ const stateDir = process.env["OLAM_STATE_DIR"] ?? path91.join(os47.homedir(), ".olam", "state");
42660
+ return path91.join(stateDir, "kg-pending.jsonl");
42303
42661
  })();
42304
42662
  const readQueue2 = opts.readQueueFn ?? readQueueFromDisk;
42305
42663
  const writeQueue2 = opts.writeQueueFn ?? writeQueueToDisk;
@@ -42315,7 +42673,7 @@ async function runKgBuildPending(opts = {}) {
42315
42673
  const remaining = [];
42316
42674
  for (const entry of deduped) {
42317
42675
  const repoPath = entry.path;
42318
- const workspaceName = path90.basename(repoPath).toLowerCase();
42676
+ const workspaceName = path91.basename(repoPath).toLowerCase();
42319
42677
  printInfo("kg build --pending", `building ${repoPath} (workspace=${workspaceName})`);
42320
42678
  let containerPath;
42321
42679
  try {
@@ -42353,20 +42711,20 @@ async function runKgBuildPending(opts = {}) {
42353
42711
  }
42354
42712
  function resolveWorkspace(arg) {
42355
42713
  const cwd = process.cwd();
42356
- const name = arg ?? path90.basename(cwd).toLowerCase();
42714
+ const name = arg ?? path91.basename(cwd).toLowerCase();
42357
42715
  validateWorkspaceName(name);
42358
42716
  return { name, sourcePath: cwd };
42359
42717
  }
42360
42718
  function toContainerPath(hostPath) {
42361
42719
  const home = os47.homedir();
42362
- const resolved = path90.resolve(hostPath);
42363
- if (!resolved.startsWith(home + path90.sep) && resolved !== home) {
42720
+ const resolved = path91.resolve(hostPath);
42721
+ if (!resolved.startsWith(home + path91.sep) && resolved !== home) {
42364
42722
  throw new Error(
42365
42723
  `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.`
42366
42724
  );
42367
42725
  }
42368
- const rel = path90.relative(home, resolved);
42369
- return rel === "" ? "/host-home" : path90.posix.join("/host-home", rel.split(path90.sep).join("/"));
42726
+ const rel = path91.relative(home, resolved);
42727
+ return rel === "" ? "/host-home" : path91.posix.join("/host-home", rel.split(path91.sep).join("/"));
42370
42728
  }
42371
42729
  async function runKgBuild(workspaceArg, options = {}) {
42372
42730
  let workspace;
@@ -42384,7 +42742,7 @@ async function runKgBuild(workspaceArg, options = {}) {
42384
42742
  return { exitCode: 2 };
42385
42743
  }
42386
42744
  const outDir = kgPristinePath(workspace.name);
42387
- fs91.mkdirSync(outDir, { recursive: true });
42745
+ fs92.mkdirSync(outDir, { recursive: true });
42388
42746
  const human = !options.json;
42389
42747
  if (human) {
42390
42748
  printInfo("kg build", `workspace=${workspace.name} source=${workspace.sourcePath}`);
@@ -42417,12 +42775,12 @@ async function runKgBuild(workspaceArg, options = {}) {
42417
42775
  workspace: workspace.name,
42418
42776
  graphify_path: "container"
42419
42777
  };
42420
- fs91.writeFileSync(
42421
- path90.join(outDir, "freshness.json"),
42778
+ fs92.writeFileSync(
42779
+ path91.join(outDir, "freshness.json"),
42422
42780
  JSON.stringify(freshness, null, 2) + "\n",
42423
42781
  "utf-8"
42424
42782
  );
42425
- const finalOut = path90.join(outDir, "graphify-out");
42783
+ const finalOut = path91.join(outDir, "graphify-out");
42426
42784
  if (options.json) {
42427
42785
  process.stdout.write(JSON.stringify(freshness) + "\n");
42428
42786
  } else {
@@ -42465,11 +42823,11 @@ function registerKg(program2) {
42465
42823
  init_file_lock();
42466
42824
  import { mkdirSync as mkdirSync63, appendFileSync as appendFileSync6 } from "node:fs";
42467
42825
  import { homedir as homedir57 } from "node:os";
42468
- import { dirname as dirname59, join as join99 } from "node:path";
42826
+ import { dirname as dirname59, join as join100 } from "node:path";
42469
42827
  import { randomUUID as randomUUID3 } from "node:crypto";
42470
42828
  var VALID_SEVERITIES = /* @__PURE__ */ new Set(["critical", "high", "medium", "low", "info", "warn"]);
42471
42829
  var PROMPT_FEEDING_FIELDS = ["extracted_pattern", "severity", "affected_persona", "proposed_edit"];
42472
- var BREADCRUMBS_BASE = join99(homedir57(), ".local", "share", "claude", "breadcrumbs");
42830
+ var BREADCRUMBS_BASE = join100(homedir57(), ".local", "share", "claude", "breadcrumbs");
42473
42831
  var LOCK_FILENAME = ".flywheel-emit.lock";
42474
42832
  function buildRecord(opts) {
42475
42833
  const rec = {
@@ -42516,7 +42874,7 @@ function validatePromptFeeding(rec) {
42516
42874
  }
42517
42875
  function destPath(projectSlug) {
42518
42876
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
42519
- return join99(BREADCRUMBS_BASE, projectSlug, `${today}.jsonl`);
42877
+ return join100(BREADCRUMBS_BASE, projectSlug, `${today}.jsonl`);
42520
42878
  }
42521
42879
  async function emitBreadcrumb(opts) {
42522
42880
  if (!VALID_SEVERITIES.has(opts.severity)) {
@@ -42535,14 +42893,14 @@ async function emitBreadcrumb(opts) {
42535
42893
  );
42536
42894
  process.exit(2);
42537
42895
  }
42538
- const path93 = destPath(rec.project_slug);
42539
- const lockDir = dirname59(path93);
42896
+ const path94 = destPath(rec.project_slug);
42897
+ const lockDir = dirname59(path94);
42540
42898
  mkdirSync63(lockDir, { recursive: true });
42541
42899
  const line = JSON.stringify(rec) + "\n";
42542
42900
  await withFileLock(
42543
42901
  lockDir,
42544
42902
  () => {
42545
- appendFileSync6(path93, line, "utf8");
42903
+ appendFileSync6(path94, line, "utf8");
42546
42904
  },
42547
42905
  {
42548
42906
  lockFilename: LOCK_FILENAME,
@@ -42552,7 +42910,7 @@ async function emitBreadcrumb(opts) {
42552
42910
  acquireTimeoutMs: 5e3
42553
42911
  }
42554
42912
  );
42555
- process.stdout.write(`[K7-emit] ${path93}: ${rec.extracted_pattern} (${rec.severity})
42913
+ process.stdout.write(`[K7-emit] ${path94}: ${rec.extracted_pattern} (${rec.severity})
42556
42914
  `);
42557
42915
  }
42558
42916
  function registerFlywheelEmitBreadcrumb(parent) {
@@ -42617,7 +42975,7 @@ function registerFlywheelK5Score(parent) {
42617
42975
  }
42618
42976
 
42619
42977
  // src/commands/flywheel/k5-validate.ts
42620
- import { readFileSync as readFileSync85, statSync as statSync30 } from "node:fs";
42978
+ import { readFileSync as readFileSync86, statSync as statSync30 } from "node:fs";
42621
42979
  import { parse as parseYAML } from "yaml";
42622
42980
  var K5_DIMS = ["direction", "approach", "open_questions", "constraints", "reuse"];
42623
42981
  var MAX_PLAN_BYTES = 1048576;
@@ -42675,38 +43033,38 @@ function validateK5ScoredAt(scoredAt) {
42675
43033
  }
42676
43034
  return null;
42677
43035
  }
42678
- function validatePlan(path93) {
43036
+ function validatePlan(path94) {
42679
43037
  let stat;
42680
43038
  try {
42681
- stat = statSync30(path93);
43039
+ stat = statSync30(path94);
42682
43040
  } catch (err) {
42683
- return { ok: false, message: `FAIL cannot stat ${path93}: ${err instanceof Error ? err.message : "unknown"}` };
43041
+ return { ok: false, message: `FAIL cannot stat ${path94}: ${err instanceof Error ? err.message : "unknown"}` };
42684
43042
  }
42685
43043
  if (stat.size > MAX_PLAN_BYTES) {
42686
- return { ok: false, message: `FAIL ${path93}: plan file exceeds 1MB (${stat.size} bytes); refusing to parse` };
43044
+ return { ok: false, message: `FAIL ${path94}: plan file exceeds 1MB (${stat.size} bytes); refusing to parse` };
42687
43045
  }
42688
43046
  let text;
42689
43047
  try {
42690
- text = readFileSync85(path93, "utf8");
43048
+ text = readFileSync86(path94, "utf8");
42691
43049
  } catch (err) {
42692
- return { ok: false, message: `FAIL cannot read ${path93}: ${err instanceof Error ? err.message : "unknown"}` };
43050
+ return { ok: false, message: `FAIL cannot read ${path94}: ${err instanceof Error ? err.message : "unknown"}` };
42693
43051
  }
42694
43052
  if (!text.replace(/^/, "").startsWith("---")) {
42695
- return { ok: false, message: `FAIL ${path93}: no YAML frontmatter (missing opening --- marker)` };
43053
+ return { ok: false, message: `FAIL ${path94}: no YAML frontmatter (missing opening --- marker)` };
42696
43054
  }
42697
43055
  if (!text.includes("\n---", 3)) {
42698
- return { ok: false, message: `FAIL ${path93}: frontmatter block never closed (missing closing --- marker)` };
43056
+ return { ok: false, message: `FAIL ${path94}: frontmatter block never closed (missing closing --- marker)` };
42699
43057
  }
42700
43058
  const fm = extractFrontmatter(text);
42701
43059
  if (fm === null) {
42702
- return { ok: false, message: `FAIL ${path93}: frontmatter could not be parsed as YAML` };
43060
+ return { ok: false, message: `FAIL ${path94}: frontmatter could not be parsed as YAML` };
42703
43061
  }
42704
43062
  const hasScores = "k5_scores" in fm;
42705
43063
  const hasBoost = "k5_boost" in fm;
42706
43064
  const hasComposite = "k5_composite" in fm;
42707
43065
  const hasScoredAt = "k5_scored_at" in fm;
42708
43066
  if (!hasScores && !hasBoost && !hasComposite && !hasScoredAt) {
42709
- return { ok: true, message: `PASS ${path93}: k5_scores absent (acceptable \u2014 legacy plan)` };
43067
+ return { ok: true, message: `PASS ${path94}: k5_scores absent (acceptable \u2014 legacy plan)` };
42710
43068
  }
42711
43069
  const errors = [];
42712
43070
  if (hasScores) {
@@ -42726,9 +43084,9 @@ function validatePlan(path93) {
42726
43084
  if (err !== null) errors.push(err);
42727
43085
  }
42728
43086
  if (errors.length > 0) {
42729
- return { ok: false, message: `FAIL ${path93}: ${errors.join("; ")}` };
43087
+ return { ok: false, message: `FAIL ${path94}: ${errors.join("; ")}` };
42730
43088
  }
42731
- const lines = [`PASS ${path93}: k5_scores valid`];
43089
+ const lines = [`PASS ${path94}: k5_scores valid`];
42732
43090
  if (hasScores && typeof fm.k5_scores === "object" && fm.k5_scores !== null) {
42733
43091
  const scoresObj = fm.k5_scores;
42734
43092
  const vals = [];
@@ -42769,7 +43127,7 @@ function registerFlywheelK5Validate(parent) {
42769
43127
  }
42770
43128
 
42771
43129
  // src/commands/flywheel/k10-measure.ts
42772
- import { readFileSync as readFileSync86 } from "node:fs";
43130
+ import { readFileSync as readFileSync87 } from "node:fs";
42773
43131
 
42774
43132
  // ../core/dist/lib/k10-budget.js
42775
43133
  var K10_TOKEN_CAP = 5500;
@@ -42826,7 +43184,7 @@ function registerFlywheelK10Measure(parent) {
42826
43184
  parent.command("k10-measure").description("Measure K10 token budget for upstream + optional overlay; emit PASS/REJECT verdict").requiredOption("--upstream <path>", "path to upstream file (e.g. persona prompt)").option("--overlay <path>", "path to overlay file (omit if none \u2014 PASS without enforcement)").option("--json", "emit verdict as JSON instead of human-readable").action((opts) => {
42827
43185
  let upstreamText;
42828
43186
  try {
42829
- upstreamText = readFileSync86(opts.upstream, "utf8");
43187
+ upstreamText = readFileSync87(opts.upstream, "utf8");
42830
43188
  } catch (err) {
42831
43189
  process.stderr.write(
42832
43190
  `[k10-measure-error] cannot read upstream ${opts.upstream}: ${err instanceof Error ? err.message : "unknown"}
@@ -42838,7 +43196,7 @@ function registerFlywheelK10Measure(parent) {
42838
43196
  let overlayTokens = null;
42839
43197
  if (opts.overlay !== void 0) {
42840
43198
  try {
42841
- const overlayText = readFileSync86(opts.overlay, "utf8");
43199
+ const overlayText = readFileSync87(opts.overlay, "utf8");
42842
43200
  overlayTokens = tokensFromText(overlayText);
42843
43201
  } catch (err) {
42844
43202
  process.stderr.write(
@@ -42872,13 +43230,13 @@ function registerFlywheelK10Measure(parent) {
42872
43230
  }
42873
43231
 
42874
43232
  // src/commands/flywheel/check-persona-skeleton.ts
42875
- import { existsSync as existsSync109, readFileSync as readFileSync87, statSync as statSync31 } from "node:fs";
43233
+ import { existsSync as existsSync109, readFileSync as readFileSync88, statSync as statSync31 } from "node:fs";
42876
43234
  import { homedir as homedir58 } from "node:os";
42877
- import { basename as basename14, join as join100 } from "node:path";
43235
+ import { basename as basename14, join as join101 } from "node:path";
42878
43236
  import { parse as parseYAML2 } from "yaml";
42879
43237
  var CHARS_PER_TOKEN3 = 4;
42880
43238
  var K10_TOKEN_CAP2 = 6e3;
42881
- var AGENTS_DIR = join100(homedir58(), ".claude", "agents");
43239
+ var AGENTS_DIR = join101(homedir58(), ".claude", "agents");
42882
43240
  var REQUIRED_FRONTMATTER_KEYS = ["name", "description", "allowed-tools"];
42883
43241
  var REQUIRED_SECTIONS = [
42884
43242
  "## Role",
@@ -42921,7 +43279,7 @@ function checkFile(filepath) {
42921
43279
  if (!existsSync109(filepath) || !statSync31(filepath).isFile()) {
42922
43280
  return { passed: false, failures: [`file not found: ${filepath}`], tokens: 0, mergedSkipped: false };
42923
43281
  }
42924
- const text = readFileSync87(filepath, "utf8");
43282
+ const text = readFileSync88(filepath, "utf8");
42925
43283
  const { fm, body } = parseFile(text);
42926
43284
  const failures = [];
42927
43285
  for (const key of REQUIRED_FRONTMATTER_KEYS) {
@@ -42934,7 +43292,7 @@ function checkFile(filepath) {
42934
43292
  const agentName = typeof fm.name === "string" ? fm.name : "";
42935
43293
  let mergedSkipped = false;
42936
43294
  if (!isNewAgent && agentName !== "") {
42937
- const upstreamPath = join100(AGENTS_DIR, `${agentName}.md`);
43295
+ const upstreamPath = join101(AGENTS_DIR, `${agentName}.md`);
42938
43296
  if (existsSync109(upstreamPath)) {
42939
43297
  mergedSkipped = true;
42940
43298
  }
@@ -42987,7 +43345,7 @@ Results: ${passCount} passed, ${failCount} failed
42987
43345
  }
42988
43346
 
42989
43347
  // src/commands/flywheel/diversity-check.ts
42990
- import { readFileSync as readFileSync88 } from "node:fs";
43348
+ import { readFileSync as readFileSync89 } from "node:fs";
42991
43349
  import { basename as basename15 } from "node:path";
42992
43350
  import { globSync as globSync2 } from "node:fs";
42993
43351
 
@@ -43096,7 +43454,7 @@ function registerFlywheelDiversityCheck(parent) {
43096
43454
  const personas = /* @__PURE__ */ new Map();
43097
43455
  for (const filepath of files) {
43098
43456
  try {
43099
- const body = readFileSync88(filepath, "utf8");
43457
+ const body = readFileSync89(filepath, "utf8");
43100
43458
  if (body.trim().length > 0) {
43101
43459
  personas.set(basename15(filepath, ".md"), body);
43102
43460
  }
@@ -43129,7 +43487,7 @@ ${formatRedivergencePrompt(persona_a, persona_b, score, void 0, void 0, threshol
43129
43487
  // src/commands/flywheel/ping.ts
43130
43488
  import { mkdirSync as mkdirSync64, writeFileSync as writeFileSync56 } from "node:fs";
43131
43489
  import { homedir as homedir59 } from "node:os";
43132
- import { dirname as dirname60, join as join101 } from "node:path";
43490
+ import { dirname as dirname60, join as join102 } from "node:path";
43133
43491
  var COLD_START_BUDGET_GOOD_MS = 200;
43134
43492
  var COLD_START_BUDGET_FAIR_MS = 500;
43135
43493
  function classifyColdStart(coldStartMs) {
@@ -43145,7 +43503,7 @@ function readOlamVersion() {
43145
43503
  }
43146
43504
  }
43147
43505
  function writeBaseline(record) {
43148
- const baselinePath = join101(homedir59(), ".local", "share", "olam", "flywheel-baseline.json");
43506
+ const baselinePath = join102(homedir59(), ".local", "share", "olam", "flywheel-baseline.json");
43149
43507
  mkdirSync64(dirname60(baselinePath), { recursive: true });
43150
43508
  writeFileSync56(baselinePath, JSON.stringify(record, null, 2) + "\n", "utf8");
43151
43509
  return baselinePath;
@@ -43184,18 +43542,19 @@ function registerFlywheelPing(parent) {
43184
43542
  // src/commands/flywheel/migrate-overlays.ts
43185
43543
  init_shim_targets();
43186
43544
  init_skill_sources();
43545
+ init_prefix_rules();
43187
43546
  import {
43188
43547
  copyFileSync as copyFileSync15,
43189
43548
  existsSync as existsSync110,
43190
43549
  mkdirSync as mkdirSync65,
43191
- readFileSync as readFileSync89,
43550
+ readFileSync as readFileSync90,
43192
43551
  readdirSync as readdirSync31,
43193
43552
  statSync as statSync32,
43194
43553
  writeFileSync as writeFileSync57
43195
43554
  } from "node:fs";
43196
43555
  import { spawnSync as spawnSync29 } from "node:child_process";
43197
43556
  import { homedir as homedir60 } from "node:os";
43198
- import { dirname as dirname61, join as join102, relative as relative7 } from "node:path";
43557
+ import { dirname as dirname61, join as join103, relative as relative7 } from "node:path";
43199
43558
  function escapeRegex(s) {
43200
43559
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
43201
43560
  }
@@ -43232,7 +43591,7 @@ function walkOverlayFiles(dir) {
43232
43591
  return [];
43233
43592
  }
43234
43593
  for (const entry of entries) {
43235
- const fullPath = join102(dir, entry);
43594
+ const fullPath = join103(dir, entry);
43236
43595
  let stat;
43237
43596
  try {
43238
43597
  stat = statSync32(fullPath);
@@ -43271,10 +43630,10 @@ function resolveAtlasUser2(opts) {
43271
43630
  assertValidAtlasUser(v);
43272
43631
  return v;
43273
43632
  }
43274
- const claudeDir2 = opts._testClaudeDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join102(homedir60(), ".claude");
43275
- const f = join102(claudeDir2, ".atlas-user");
43633
+ const claudeDir2 = opts._testClaudeDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join103(homedir60(), ".claude");
43634
+ const f = join103(claudeDir2, ".atlas-user");
43276
43635
  if (existsSync110(f)) {
43277
- const v = readFileSync89(f, "utf-8").trim();
43636
+ const v = readFileSync90(f, "utf-8").trim();
43278
43637
  if (v.length === 0) return null;
43279
43638
  assertValidAtlasUser(v);
43280
43639
  return v;
@@ -43296,8 +43655,8 @@ function runGit2(args, cwd) {
43296
43655
  function walkPushSourceFiles(claudeDir2) {
43297
43656
  const result = [];
43298
43657
  const roots = [
43299
- { dir: join102(claudeDir2, "skills.overrides"), overlayKind: "skills" },
43300
- { dir: join102(claudeDir2, "agents.overrides"), overlayKind: "agents" }
43658
+ { dir: join103(claudeDir2, "skills.overrides"), overlayKind: "skills" },
43659
+ { dir: join103(claudeDir2, "agents.overrides"), overlayKind: "agents" }
43301
43660
  ];
43302
43661
  for (const { dir, overlayKind } of roots) {
43303
43662
  const files = walkOverlayFiles(dir);
@@ -43408,6 +43767,27 @@ function pushOverlays(opts) {
43408
43767
  Run \`olam skills atlas-user set <name>\` to configure your atlas user.`
43409
43768
  );
43410
43769
  }
43770
+ const claudeDir2 = opts._testClaudeDir ?? opts.targetDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join103(homedir60(), ".claude");
43771
+ const sourceFiles = walkPushSourceFiles(claudeDir2);
43772
+ const registeredPrefixes = (opts._testSkillSources ?? listSkillSources()).map((s) => s.prefix).filter((p) => typeof p === "string" && p.length > 0);
43773
+ if (registeredPrefixes.length > 0) {
43774
+ for (const { srcFile, relPath } of sourceFiles) {
43775
+ const basename16 = relPath.split("/").pop() ?? relPath;
43776
+ let content;
43777
+ try {
43778
+ content = readFileSync90(srcFile);
43779
+ } catch {
43780
+ continue;
43781
+ }
43782
+ const validation = validateCanonical(basename16, content, registeredPrefixes);
43783
+ if (!validation.ok && validation.violation !== void 0) {
43784
+ throw new PushError(
43785
+ 1,
43786
+ formatCanonicalViolation(relPath, validation.violation)
43787
+ );
43788
+ }
43789
+ }
43790
+ }
43411
43791
  let clonePath;
43412
43792
  if (opts._testClonePath !== void 0) {
43413
43793
  clonePath = opts._testClonePath;
@@ -43426,8 +43806,6 @@ function pushOverlays(opts) {
43426
43806
  }
43427
43807
  clonePath = skillSourceClonePath(source.id);
43428
43808
  }
43429
- const claudeDir2 = opts._testClaudeDir ?? opts.targetDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join102(homedir60(), ".claude");
43430
- const sourceFiles = walkPushSourceFiles(claudeDir2);
43431
43809
  if (opts.dryRun === true) {
43432
43810
  const { preflightWarnings } = runPreFlight(clonePath, opts.forceCurrentBranch === true, true);
43433
43811
  if (preflightWarnings.length > 0) {
@@ -43436,21 +43814,21 @@ function pushOverlays(opts) {
43436
43814
  ` + preflightWarnings.map((w) => ` - ${w.split("\n")[0]}`).join("\n") + "\n"
43437
43815
  );
43438
43816
  }
43439
- const membersBase2 = join102(clonePath, "members", atlasUser);
43817
+ const membersBase2 = join103(clonePath, "members", atlasUser);
43440
43818
  let wouldCopy = 0;
43441
43819
  let wouldUnchange = 0;
43442
43820
  let wouldCreate = 0;
43443
43821
  for (const { srcFile, overlayKind, relPath } of sourceFiles) {
43444
- const targetDir = join102(membersBase2, `${overlayKind}.overrides`);
43445
- const targetFile = join102(targetDir, relPath);
43822
+ const targetDir = join103(membersBase2, `${overlayKind}.overrides`);
43823
+ const targetFile = join103(targetDir, relPath);
43446
43824
  let srcBuf;
43447
43825
  try {
43448
- srcBuf = readFileSync89(srcFile);
43826
+ srcBuf = readFileSync90(srcFile);
43449
43827
  } catch {
43450
43828
  continue;
43451
43829
  }
43452
43830
  if (existsSync110(targetFile)) {
43453
- const dstBuf = readFileSync89(targetFile);
43831
+ const dstBuf = readFileSync90(targetFile);
43454
43832
  if (srcBuf.equals(dstBuf)) {
43455
43833
  wouldUnchange += 1;
43456
43834
  process.stdout.write(` [skip] ${overlayKind}.overrides/${relPath} (unchanged)
@@ -43491,23 +43869,23 @@ function pushOverlays(opts) {
43491
43869
  `failed to create branch "${branchName}": ${err instanceof Error ? err.message : String(err)}`
43492
43870
  );
43493
43871
  }
43494
- const membersBase = join102(clonePath, "members", atlasUser);
43872
+ const membersBase = join103(clonePath, "members", atlasUser);
43495
43873
  let filesCopied = 0;
43496
43874
  let filesUnchanged = 0;
43497
43875
  let filesCreated = 0;
43498
43876
  try {
43499
43877
  for (const { srcFile, overlayKind, relPath } of sourceFiles) {
43500
- const targetDir = join102(membersBase, `${overlayKind}.overrides`, dirname61(relPath));
43501
- const targetFile = join102(membersBase, `${overlayKind}.overrides`, relPath);
43878
+ const targetDir = join103(membersBase, `${overlayKind}.overrides`, dirname61(relPath));
43879
+ const targetFile = join103(membersBase, `${overlayKind}.overrides`, relPath);
43502
43880
  let srcBuf;
43503
43881
  try {
43504
- srcBuf = readFileSync89(srcFile);
43882
+ srcBuf = readFileSync90(srcFile);
43505
43883
  } catch {
43506
43884
  continue;
43507
43885
  }
43508
43886
  const targetExists = existsSync110(targetFile);
43509
43887
  if (targetExists) {
43510
- const dstBuf = readFileSync89(targetFile);
43888
+ const dstBuf = readFileSync90(targetFile);
43511
43889
  if (srcBuf.equals(dstBuf)) {
43512
43890
  filesUnchanged += 1;
43513
43891
  continue;
@@ -43584,7 +43962,7 @@ function initMember(opts) {
43584
43962
  clonePath = skillSourceClonePath(source.id);
43585
43963
  }
43586
43964
  const atlasUser = resolveAtlasUser2(opts) ?? memberName;
43587
- const memberDir = join102(clonePath, "members", memberName);
43965
+ const memberDir = join103(clonePath, "members", memberName);
43588
43966
  if (existsSync110(memberDir)) {
43589
43967
  throw new PushError(
43590
43968
  1,
@@ -43593,9 +43971,9 @@ function initMember(opts) {
43593
43971
  );
43594
43972
  }
43595
43973
  const wouldCreate = [
43596
- join102(memberDir, "skills.overrides", ".gitkeep"),
43597
- join102(memberDir, "agents.overrides", ".gitkeep"),
43598
- join102(memberDir, "README.md")
43974
+ join103(memberDir, "skills.overrides", ".gitkeep"),
43975
+ join103(memberDir, "agents.overrides", ".gitkeep"),
43976
+ join103(memberDir, "README.md")
43599
43977
  ];
43600
43978
  if (opts.dryRun === true) {
43601
43979
  const { preflightWarnings } = runPreFlight(clonePath, opts.forceCurrentBranch === true, true);
@@ -43651,12 +44029,12 @@ function initMember(opts) {
43651
44029
  );
43652
44030
  }
43653
44031
  try {
43654
- mkdirSync65(join102(memberDir, "skills.overrides"), { recursive: true });
43655
- writeFileSync57(join102(memberDir, "skills.overrides", ".gitkeep"), "");
43656
- mkdirSync65(join102(memberDir, "agents.overrides"), { recursive: true });
43657
- writeFileSync57(join102(memberDir, "agents.overrides", ".gitkeep"), "");
44032
+ mkdirSync65(join103(memberDir, "skills.overrides"), { recursive: true });
44033
+ writeFileSync57(join103(memberDir, "skills.overrides", ".gitkeep"), "");
44034
+ mkdirSync65(join103(memberDir, "agents.overrides"), { recursive: true });
44035
+ writeFileSync57(join103(memberDir, "agents.overrides", ".gitkeep"), "");
43658
44036
  writeFileSync57(
43659
- join102(memberDir, "README.md"),
44037
+ join103(memberDir, "README.md"),
43660
44038
  `# Member overlays for \`${memberName}\`
43661
44039
 
43662
44040
  See docs/plans/member-overlays-sync/ for layer architecture.
@@ -43697,10 +44075,10 @@ Next steps (run in ${clonePath}):`,
43697
44075
  };
43698
44076
  }
43699
44077
  function migrateOverlays(opts = {}) {
43700
- const root = opts.targetDir ?? join102(homedir60(), ".claude");
44078
+ const root = opts.targetDir ?? join103(homedir60(), ".claude");
43701
44079
  const overrideRoots = [
43702
- join102(root, "skills.overrides"),
43703
- join102(root, "agents.overrides")
44080
+ join103(root, "skills.overrides"),
44081
+ join103(root, "agents.overrides")
43704
44082
  ];
43705
44083
  const allFiles = [];
43706
44084
  for (const overrideRoot of overrideRoots) {
@@ -43716,7 +44094,7 @@ function migrateOverlays(opts = {}) {
43716
44094
  for (const filePath of allFiles) {
43717
44095
  let original;
43718
44096
  try {
43719
- original = readFileSync89(filePath, "utf8");
44097
+ original = readFileSync90(filePath, "utf8");
43720
44098
  } catch {
43721
44099
  continue;
43722
44100
  }
@@ -43819,7 +44197,7 @@ function registerFlywheelMigrateOverlays(parent) {
43819
44197
  }
43820
44198
  return;
43821
44199
  }
43822
- const root = opts.targetDir ?? join102(homedir60(), ".claude");
44200
+ const root = opts.targetDir ?? join103(homedir60(), ".claude");
43823
44201
  const summary2 = migrateOverlays(opts);
43824
44202
  if (opts.json === true) {
43825
44203
  process.stdout.write(JSON.stringify(summary2, null, 2) + "\n");
@@ -44123,14 +44501,14 @@ init_manager();
44123
44501
  init_context();
44124
44502
  init_output();
44125
44503
  import { spawnSync as defaultSpawnSync } from "node:child_process";
44126
- import * as fs92 from "node:fs";
44504
+ import * as fs93 from "node:fs";
44127
44505
  import * as os48 from "node:os";
44128
- import * as path91 from "node:path";
44506
+ import * as path92 from "node:path";
44129
44507
  function devboxContainerName(worldId) {
44130
44508
  return `olam-${worldId}-devbox`;
44131
44509
  }
44132
44510
  function olamHomeDir() {
44133
- return process.env["OLAM_HOME"] ?? path91.join(os48.homedir(), ".olam");
44511
+ return process.env["OLAM_HOME"] ?? path92.join(os48.homedir(), ".olam");
44134
44512
  }
44135
44513
  function defaultRestartContainer(name, spawn13 = defaultSpawnSync) {
44136
44514
  const r = spawn13("docker", ["restart", "--time", "30", name], {
@@ -44143,8 +44521,8 @@ function defaultRestartContainer(name, spawn13 = defaultSpawnSync) {
44143
44521
  };
44144
44522
  }
44145
44523
  function defaultAppendAuditLog(homeDir, line) {
44146
- fs92.mkdirSync(homeDir, { recursive: true });
44147
- fs92.appendFileSync(path91.join(homeDir, "usage.log"), line.endsWith("\n") ? line : line + "\n", {
44524
+ fs93.mkdirSync(homeDir, { recursive: true });
44525
+ fs93.appendFileSync(path92.join(homeDir, "usage.log"), line.endsWith("\n") ? line : line + "\n", {
44148
44526
  encoding: "utf-8"
44149
44527
  });
44150
44528
  }
@@ -44189,19 +44567,19 @@ async function doRekey(worldId, deps) {
44189
44567
  );
44190
44568
  const rotatedAt = deps.now().toISOString();
44191
44569
  const homeDir = deps.olamHomeDir();
44192
- const worldDir = path91.join(homeDir, "worlds", worldId);
44193
- fs92.mkdirSync(worldDir, { recursive: true });
44194
- const credentialsPath = path91.join(worldDir, "credentials.json");
44570
+ const worldDir = path92.join(homeDir, "worlds", worldId);
44571
+ fs93.mkdirSync(worldDir, { recursive: true });
44572
+ const credentialsPath = path92.join(worldDir, "credentials.json");
44195
44573
  const payload = {
44196
44574
  worldRoleName,
44197
44575
  password,
44198
44576
  rotatedAt
44199
44577
  };
44200
- fs92.writeFileSync(credentialsPath, JSON.stringify(payload, null, 2) + "\n", {
44578
+ fs93.writeFileSync(credentialsPath, JSON.stringify(payload, null, 2) + "\n", {
44201
44579
  encoding: "utf-8",
44202
44580
  mode: 384
44203
44581
  });
44204
- fs92.chmodSync(credentialsPath, 384);
44582
+ fs93.chmodSync(credentialsPath, 384);
44205
44583
  const restart = deps.restartContainer(devboxContainerName(worldId));
44206
44584
  deps.appendAuditLog(`${rotatedAt} ${worldId} rekey`);
44207
44585
  if (!restart.ok) {
@@ -44265,18 +44643,18 @@ function registerRekey(program2) {
44265
44643
  }
44266
44644
 
44267
44645
  // src/pleri-config.ts
44268
- import * as fs93 from "node:fs";
44269
- import * as path92 from "node:path";
44646
+ import * as fs94 from "node:fs";
44647
+ import * as path93 from "node:path";
44270
44648
  function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
44271
44649
  if (process.env.PLERI_BASE_URL) {
44272
44650
  return true;
44273
44651
  }
44274
- const configPath = path92.join(configDir, "config.yaml");
44275
- if (!fs93.existsSync(configPath)) {
44652
+ const configPath = path93.join(configDir, "config.yaml");
44653
+ if (!fs94.existsSync(configPath)) {
44276
44654
  return false;
44277
44655
  }
44278
44656
  try {
44279
- const contents = fs93.readFileSync(configPath, "utf8");
44657
+ const contents = fs94.readFileSync(configPath, "utf8");
44280
44658
  return /^[^#\n]*\bpleri:/m.test(contents);
44281
44659
  } catch {
44282
44660
  return false;