@pleri/olam-cli 0.1.146 → 0.1.147

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.
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: path78, errorMaps, issueData } = params;
496
- const fullPath = [...path78, ...issueData.path || []];
495
+ const { data, path: path82, errorMaps, issueData } = params;
496
+ const fullPath = [...path82, ...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, path78, key) {
804
+ constructor(parent, value, path82, key) {
805
805
  this._cachedPath = [];
806
806
  this.parent = parent;
807
807
  this.data = value;
808
- this._path = path78;
808
+ this._path = path82;
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, path78, ctx, rejectSource) {
4289
+ function refineForbiddenKeys(value, path82, 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, path78, ctx, rejectSource) {
4294
4294
  if (FORBIDDEN_KEYS.has(key)) {
4295
4295
  ctx.addIssue({
4296
4296
  code: external_exports.ZodIssueCode.custom,
4297
- path: [...path78, key],
4297
+ path: [...path82, key],
4298
4298
  message: `forbidden key "${key}" (prototype-pollution surface)`
4299
4299
  });
4300
4300
  continue;
4301
4301
  }
4302
- if (rejectSource && path78.length === 0 && key === "source") {
4302
+ if (rejectSource && path82.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, path78, ctx, rejectSource) {
4307
4307
  });
4308
4308
  continue;
4309
4309
  }
4310
- refineForbiddenKeys(value[key], [...path78, key], ctx, false);
4310
+ refineForbiddenKeys(value[key], [...path82, key], ctx, false);
4311
4311
  }
4312
4312
  }
4313
- function rejectForbiddenKeys(value, path78, rejectSource) {
4313
+ function rejectForbiddenKeys(value, path82, 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] ${path78}: forbidden key "${key}" (prototype-pollution surface)`);
4319
+ throw new Error(`[manifest] ${path82}: forbidden key "${key}" (prototype-pollution surface)`);
4320
4320
  }
4321
4321
  if (rejectSource && key === "source") {
4322
- throw new Error(`[manifest] ${path78}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
4322
+ throw new Error(`[manifest] ${path82}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
4323
4323
  }
4324
- rejectForbiddenKeys(value[key], `${path78}.${key}`, false);
4324
+ rejectForbiddenKeys(value[key], `${path82}.${key}`, false);
4325
4325
  }
4326
4326
  }
4327
4327
  function unknownTopLevelKeys(parsed) {
@@ -5389,7 +5389,7 @@ async function safeText(res) {
5389
5389
  }
5390
5390
  }
5391
5391
  function sleep(ms) {
5392
- return new Promise((resolve18) => setTimeout(resolve18, ms));
5392
+ return new Promise((resolve19) => setTimeout(resolve19, ms));
5393
5393
  }
5394
5394
  var DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, RETRY_COUNT, RETRY_BACKOFF_MS, AuthClient;
5395
5395
  var init_client = __esm({
@@ -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, path78, body, attempt = 0) {
5504
- const url2 = `${this.baseUrl}${path78}`;
5503
+ async request(method, path82, body, attempt = 0) {
5504
+ const url2 = `${this.baseUrl}${path82}`;
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, path78, body, attempt + 1);
5522
+ return this.request(method, path82, body, attempt + 1);
5523
5523
  }
5524
5524
  throw err;
5525
5525
  } finally {
@@ -5541,7 +5541,7 @@ function resolveAuthServicePath() {
5541
5541
  return path9.join(pkgsDir, "auth-service");
5542
5542
  }
5543
5543
  function sleep2(ms) {
5544
- return new Promise((resolve18) => setTimeout(resolve18, ms));
5544
+ return new Promise((resolve19) => setTimeout(resolve19, ms));
5545
5545
  }
5546
5546
  var DEFAULT_PORT, DEFAULT_VOLUME, DEFAULT_CONTAINER, DEFAULT_IMAGE, AuthContainerController;
5547
5547
  var init_container = __esm({
@@ -5839,7 +5839,7 @@ var init_network = __esm({
5839
5839
  // ../adapters/dist/docker/pull.js
5840
5840
  import { spawn } from "node:child_process";
5841
5841
  function spawnAsync(cmd, args, opts = {}) {
5842
- return new Promise((resolve18) => {
5842
+ return new Promise((resolve19) => {
5843
5843
  const child = spawn(cmd, [...args], {
5844
5844
  stdio: ["ignore", "pipe", "pipe"],
5845
5845
  signal: opts.signal
@@ -5853,10 +5853,10 @@ function spawnAsync(cmd, args, opts = {}) {
5853
5853
  stderr += chunk.toString();
5854
5854
  });
5855
5855
  child.on("error", (err) => {
5856
- resolve18({ exitCode: -1, stdout, stderr: stderr + err.message });
5856
+ resolve19({ exitCode: -1, stdout, stderr: stderr + err.message });
5857
5857
  });
5858
5858
  child.on("close", (code) => {
5859
- resolve18({ exitCode: code ?? -1, stdout, stderr });
5859
+ resolve19({ exitCode: code ?? -1, stdout, stderr });
5860
5860
  });
5861
5861
  });
5862
5862
  }
@@ -6330,7 +6330,7 @@ var demuxStream, execInContainer;
6330
6330
  var init_exec = __esm({
6331
6331
  "../adapters/dist/docker/exec.js"() {
6332
6332
  "use strict";
6333
- demuxStream = (stream) => new Promise((resolve18, reject) => {
6333
+ demuxStream = (stream) => new Promise((resolve19, reject) => {
6334
6334
  const stdoutChunks = [];
6335
6335
  const stderrChunks = [];
6336
6336
  const stdout = new PassThrough();
@@ -6344,7 +6344,7 @@ var init_exec = __esm({
6344
6344
  stream.pipe(stdout);
6345
6345
  }
6346
6346
  stream.on("end", () => {
6347
- resolve18({
6347
+ resolve19({
6348
6348
  stdout: Buffer.concat(stdoutChunks).toString("utf-8"),
6349
6349
  stderr: Buffer.concat(stderrChunks).toString("utf-8")
6350
6350
  });
@@ -6804,7 +6804,7 @@ var init_connection = __esm({
6804
6804
  // -----------------------------------------------------------------------
6805
6805
  async exec(host, command) {
6806
6806
  const client = await this.getConnection(host);
6807
- return new Promise((resolve18, reject) => {
6807
+ return new Promise((resolve19, reject) => {
6808
6808
  client.exec(command, (err, stream) => {
6809
6809
  if (err) {
6810
6810
  reject(new Error(`SSH exec failed on ${host}: ${err.message}`));
@@ -6819,7 +6819,7 @@ var init_connection = __esm({
6819
6819
  stderr += data.toString();
6820
6820
  });
6821
6821
  stream.on("close", (code) => {
6822
- resolve18({
6822
+ resolve19({
6823
6823
  exitCode: code ?? 0,
6824
6824
  stdout: stdout.trimEnd(),
6825
6825
  stderr: stderr.trimEnd()
@@ -6850,10 +6850,10 @@ var init_connection = __esm({
6850
6850
  throw new Error(`No SSH configuration found for host: ${host}`);
6851
6851
  }
6852
6852
  const client = new SSHClient();
6853
- return new Promise((resolve18, reject) => {
6853
+ return new Promise((resolve19, reject) => {
6854
6854
  client.on("ready", () => {
6855
6855
  this.connections.set(host, client);
6856
- resolve18(client);
6856
+ resolve19(client);
6857
6857
  }).on("error", (err) => {
6858
6858
  this.connections.delete(host);
6859
6859
  reject(new Error(`SSH connection to ${host} failed: ${err.message}`));
@@ -7292,8 +7292,8 @@ var init_provider3 = __esm({
7292
7292
  // -----------------------------------------------------------------------
7293
7293
  // Internal fetch helper
7294
7294
  // -----------------------------------------------------------------------
7295
- async request(path78, method, body) {
7296
- const url2 = `${this.config.workerUrl}${path78}`;
7295
+ async request(path82, method, body) {
7296
+ const url2 = `${this.config.workerUrl}${path82}`;
7297
7297
  const bearer = await this.config.mintToken();
7298
7298
  const headers = {
7299
7299
  Authorization: `Bearer ${bearer}`
@@ -8640,17 +8640,17 @@ function kgRoot() {
8640
8640
  function worldsRoot() {
8641
8641
  return join16(olamHome(), "worlds");
8642
8642
  }
8643
- function assertWithinPrefix(path78, prefix, label) {
8644
- if (!path78.startsWith(prefix + "/")) {
8645
- throw new Error(`${label} escape: ${path78} not under ${prefix}/`);
8643
+ function assertWithinPrefix(path82, prefix, label) {
8644
+ if (!path82.startsWith(prefix + "/")) {
8645
+ throw new Error(`${label} escape: ${path82} not under ${prefix}/`);
8646
8646
  }
8647
8647
  }
8648
8648
  function kgPristinePath(workspace) {
8649
8649
  validateWorkspaceName(workspace);
8650
8650
  const root = kgRoot();
8651
- const path78 = resolve5(join16(root, workspace));
8652
- assertWithinPrefix(path78, root, "kgPristinePath");
8653
- return path78;
8651
+ const path82 = resolve5(join16(root, workspace));
8652
+ assertWithinPrefix(path82, root, "kgPristinePath");
8653
+ return path82;
8654
8654
  }
8655
8655
  var KG_PATHS_INTERNALS;
8656
8656
  var init_storage_paths = __esm({
@@ -8765,8 +8765,8 @@ import { execFileSync as execFileSync4 } from "node:child_process";
8765
8765
  import * as fs15 from "node:fs";
8766
8766
  import * as os9 from "node:os";
8767
8767
  import * as path16 from "node:path";
8768
- function expandHome2(p, homedir45) {
8769
- return p.replace(/^~(?=$|\/|\\)/, homedir45());
8768
+ function expandHome2(p, homedir47) {
8769
+ return p.replace(/^~(?=$|\/|\\)/, homedir47());
8770
8770
  }
8771
8771
  function sanitizeRepoFilename(name) {
8772
8772
  const sanitized = name.replace(/[^A-Za-z0-9._-]/g, "_");
@@ -8789,7 +8789,7 @@ ${stderr}`;
8789
8789
  }
8790
8790
  function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
8791
8791
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync4(cmd, args, opts));
8792
- const homedir45 = deps.homedir ?? (() => os9.homedir());
8792
+ const homedir47 = deps.homedir ?? (() => os9.homedir());
8793
8793
  const baselineDir = path16.join(workspacePath, ".olam", "baseline");
8794
8794
  try {
8795
8795
  fs15.mkdirSync(baselineDir, { recursive: true });
@@ -8805,7 +8805,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
8805
8805
  continue;
8806
8806
  const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
8807
8807
  const outPath = path16.join(baselineDir, filename);
8808
- const repoPath = expandHome2(repo.path, homedir45);
8808
+ const repoPath = expandHome2(repo.path, homedir47);
8809
8809
  if (!fs15.existsSync(repoPath)) {
8810
8810
  writeBaselineFile(outPath, `# repo: ${repo.name}
8811
8811
  # (skipped: path ${repoPath} does not exist)
@@ -8925,21 +8925,21 @@ function extractStderr(err) {
8925
8925
  }
8926
8926
  function carryUncommittedEdits(repos, workspacePath, deps = {}) {
8927
8927
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync4(cmd, args, opts));
8928
- const homedir45 = deps.homedir ?? (() => os9.homedir());
8929
- const existsSync86 = deps.existsSync ?? ((p) => fs15.existsSync(p));
8928
+ const homedir47 = deps.homedir ?? (() => os9.homedir());
8929
+ const existsSync90 = deps.existsSync ?? ((p) => fs15.existsSync(p));
8930
8930
  const copyFileSync12 = deps.copyFileSync ?? ((src, dest) => fs15.copyFileSync(src, dest));
8931
- const mkdirSync47 = deps.mkdirSync ?? ((dirPath, opts) => {
8931
+ const mkdirSync51 = deps.mkdirSync ?? ((dirPath, opts) => {
8932
8932
  fs15.mkdirSync(dirPath, opts);
8933
8933
  });
8934
8934
  const plans = [];
8935
8935
  for (const repo of repos) {
8936
8936
  if (!repo.path)
8937
8937
  continue;
8938
- const repoPath = expandHome2(repo.path, homedir45);
8938
+ const repoPath = expandHome2(repo.path, homedir47);
8939
8939
  const worktreePath = path16.join(workspacePath, repo.name);
8940
- if (!existsSync86(repoPath))
8940
+ if (!existsSync90(repoPath))
8941
8941
  continue;
8942
- if (!existsSync86(worktreePath)) {
8942
+ if (!existsSync90(worktreePath)) {
8943
8943
  console.warn(`[carry] ${repo.name}: world worktree ${worktreePath} missing; skipping carry for this repo`);
8944
8944
  continue;
8945
8945
  }
@@ -8999,10 +8999,10 @@ function carryUncommittedEdits(repos, workspacePath, deps = {}) {
8999
8999
  for (const rel of plan.diff.untracked) {
9000
9000
  const src = path16.join(plan.repoPath, rel);
9001
9001
  const dest = path16.join(plan.worktreePath, rel);
9002
- if (!existsSync86(src))
9002
+ if (!existsSync90(src))
9003
9003
  continue;
9004
9004
  try {
9005
- mkdirSync47(path16.dirname(dest), { recursive: true });
9005
+ mkdirSync51(path16.dirname(dest), { recursive: true });
9006
9006
  copyFileSync12(src, dest);
9007
9007
  } catch (err) {
9008
9008
  const msg = err instanceof Error ? err.message : String(err);
@@ -10515,7 +10515,7 @@ var init_loader2 = __esm({
10515
10515
  });
10516
10516
 
10517
10517
  // ../core/dist/world/auto-dispatch-task.js
10518
- async function probeHealth(containerName, dockerExec, budgetMs, sleep7) {
10518
+ async function probeHealth(containerName, dockerExec, budgetMs, sleep8) {
10519
10519
  const deadline = Date.now() + budgetMs;
10520
10520
  const cadenceMs = 100;
10521
10521
  let lastErr = "";
@@ -10528,7 +10528,7 @@ async function probeHealth(containerName, dockerExec, budgetMs, sleep7) {
10528
10528
  } catch (err) {
10529
10529
  lastErr = err instanceof Error ? err.message.slice(0, 200) : String(err).slice(0, 200);
10530
10530
  }
10531
- await sleep7(cadenceMs);
10531
+ await sleep8(cadenceMs);
10532
10532
  }
10533
10533
  throw new TaskDispatchError(`container-cp /health did not return 200 within ${budgetMs}ms`, "health-probe", lastErr || "no response");
10534
10534
  }
@@ -10564,9 +10564,9 @@ function composeTaskPrompt(task, policies, formatPoliciesBrief2) {
10564
10564
  ${task}`;
10565
10565
  }
10566
10566
  async function autoDispatchTask(opts) {
10567
- const { containerName, task, policies, dockerExec, healthBudgetMs = 15e3, sleep: sleep7 = DEFAULT_SLEEP, logger = console, formatPoliciesBrief: formatPoliciesBrief2 } = opts;
10567
+ const { containerName, task, policies, dockerExec, healthBudgetMs = 15e3, sleep: sleep8 = DEFAULT_SLEEP, logger = console, formatPoliciesBrief: formatPoliciesBrief2 } = opts;
10568
10568
  const finalPrompt = composeTaskPrompt(task, policies, formatPoliciesBrief2);
10569
- await probeHealth(containerName, dockerExec, healthBudgetMs, sleep7);
10569
+ await probeHealth(containerName, dockerExec, healthBudgetMs, sleep8);
10570
10570
  startAgent(containerName, dockerExec);
10571
10571
  dispatch(containerName, finalPrompt, dockerExec);
10572
10572
  logger.log(`[world] Task auto-dispatched (${finalPrompt.length} chars)`);
@@ -10585,7 +10585,7 @@ var init_auto_dispatch_task = __esm({
10585
10585
  this.name = "TaskDispatchError";
10586
10586
  }
10587
10587
  };
10588
- DEFAULT_SLEEP = (ms) => new Promise((resolve18) => setTimeout(resolve18, ms));
10588
+ DEFAULT_SLEEP = (ms) => new Promise((resolve19) => setTimeout(resolve19, ms));
10589
10589
  }
10590
10590
  });
10591
10591
 
@@ -10616,7 +10616,7 @@ function isAbsoluteOrTilde(p) {
10616
10616
  function hasNoTraversalComponents(p) {
10617
10617
  return !p.split("/").some((seg) => seg === "..");
10618
10618
  }
10619
- var RepoEntrySchema, PortMapSchema, SeedSqlFileSchema, SeedCommandSchema, SeedFixtureCopySchema, SeedSchema, RunbookSchema, GlobalConfigSchema, DEFAULT_GLOBAL_CONFIG;
10619
+ var RepoEntrySchema, PortMapSchema, SeedSqlFileSchema, SeedCommandSchema, SeedFixtureCopySchema, SeedSchema, RunbookSchema, MetaHookBlockKindSchema, GlobalConfigSchema, DEFAULT_GLOBAL_CONFIG;
10620
10620
  var init_schema4 = __esm({
10621
10621
  "../core/dist/global-config/schema.js"() {
10622
10622
  "use strict";
@@ -10666,11 +10666,19 @@ var init_schema4 = __esm({
10666
10666
  env: external_exports.record(external_exports.string().min(1), external_exports.record(external_exports.string().min(1), external_exports.string())).optional(),
10667
10667
  updatedAt: external_exports.number().int().nonnegative()
10668
10668
  });
10669
+ MetaHookBlockKindSchema = external_exports.enum(["memory-recall", "memory-classify"]);
10669
10670
  GlobalConfigSchema = external_exports.object({
10670
10671
  schemaVersion: external_exports.literal(1),
10671
10672
  repos: external_exports.array(RepoEntrySchema).optional().default([]),
10672
10673
  runbooks: external_exports.array(RunbookSchema).optional().default([]),
10673
- skillSources: external_exports.array(SkillSourceSchema).optional().default([])
10674
+ skillSources: external_exports.array(SkillSourceSchema).optional().default([]),
10675
+ /**
10676
+ * Phase B B4 — per-block disable list. Operator escape-hatch when a
10677
+ * specific meta-hook misbehaves; engine `injectMetaHooks` filters
10678
+ * these out regardless of services-status detection. CLI
10679
+ * `--meta-hooks-disabled <a,b>` flag (deferred) can override per-call.
10680
+ */
10681
+ metaHooksDisabled: external_exports.array(MetaHookBlockKindSchema).optional().default([])
10674
10682
  }).strip().superRefine((val, ctx) => {
10675
10683
  const repoNames = val.repos.map((r) => r.name);
10676
10684
  const repoDupes = repoNames.filter((n, i) => repoNames.indexOf(n) !== i);
@@ -10697,7 +10705,8 @@ var init_schema4 = __esm({
10697
10705
  schemaVersion: 1,
10698
10706
  repos: [],
10699
10707
  runbooks: [],
10700
- skillSources: []
10708
+ skillSources: [],
10709
+ metaHooksDisabled: []
10701
10710
  };
10702
10711
  }
10703
10712
  });
@@ -11106,7 +11115,7 @@ async function startSupervisedApps(containerName, worldId, repos, exec, options
11106
11115
  const probeTimeoutMs = options.probeTimeoutMs ?? 3e4;
11107
11116
  const probeIntervalMs = options.probeIntervalMs ?? 1e3;
11108
11117
  const clock = options.clock ?? Date.now;
11109
- const sleep7 = options.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
11118
+ const sleep8 = options.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
11110
11119
  for (const repo of repos) {
11111
11120
  if (isPortBound(exec, containerName, repo.hostPort)) {
11112
11121
  throw new PortInUseError(repo.hostPort, repo.name, repo.manifestPath);
@@ -11131,7 +11140,7 @@ async function startSupervisedApps(containerName, worldId, repos, exec, options
11131
11140
  probeTimeoutMs,
11132
11141
  probeIntervalMs,
11133
11142
  clock,
11134
- sleep: sleep7
11143
+ sleep: sleep8
11135
11144
  })));
11136
11145
  return {
11137
11146
  sessionName,
@@ -14249,7 +14258,7 @@ function isCloudflaredAvailable() {
14249
14258
  }
14250
14259
  }
14251
14260
  function startTunnel(port2) {
14252
- return new Promise((resolve18, reject) => {
14261
+ return new Promise((resolve19, reject) => {
14253
14262
  const child = spawn3("cloudflared", ["tunnel", "--url", `http://localhost:${port2}`], {
14254
14263
  stdio: ["ignore", "pipe", "pipe"],
14255
14264
  detached: false
@@ -14271,7 +14280,7 @@ function startTunnel(port2) {
14271
14280
  if (match2) {
14272
14281
  resolved = true;
14273
14282
  clearTimeout(timeout);
14274
- resolve18(match2[0]);
14283
+ resolve19(match2[0]);
14275
14284
  }
14276
14285
  }
14277
14286
  child.stdout?.on("data", scan);
@@ -14358,8 +14367,8 @@ var init_dashboard = __esm({
14358
14367
  }
14359
14368
  throw err;
14360
14369
  }
14361
- await new Promise((resolve18, reject) => {
14362
- this.server.on("listening", resolve18);
14370
+ await new Promise((resolve19, reject) => {
14371
+ this.server.on("listening", resolve19);
14363
14372
  this.server.on("error", reject);
14364
14373
  });
14365
14374
  this.info = { localUrl: `http://localhost:${port2}` };
@@ -14405,8 +14414,8 @@ var init_dashboard = __esm({
14405
14414
  async stop() {
14406
14415
  stopTunnel();
14407
14416
  if (this.server) {
14408
- await new Promise((resolve18) => {
14409
- this.server.close(() => resolve18());
14417
+ await new Promise((resolve19) => {
14418
+ this.server.close(() => resolve19());
14410
14419
  });
14411
14420
  this.server = null;
14412
14421
  }
@@ -15095,10 +15104,10 @@ async function readHostCpToken2() {
15095
15104
  if (!fs26.existsSync(tp)) return null;
15096
15105
  return fs26.readFileSync(tp, "utf-8").trim();
15097
15106
  }
15098
- async function callHostCpProxy(method, worldId, path78, body) {
15107
+ async function callHostCpProxy(method, worldId, path82, body) {
15099
15108
  const token = await readHostCpToken2();
15100
15109
  if (!token) return { ok: false, status: 0, error: "no token (host CP not started)" };
15101
- const url2 = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path78}`;
15110
+ const url2 = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path82}`;
15102
15111
  try {
15103
15112
  const headers = {
15104
15113
  Authorization: `Bearer ${token}`
@@ -15492,7 +15501,7 @@ async function ensureOlamPostgresSingleton(options = {}) {
15492
15501
  };
15493
15502
  }
15494
15503
  function sleep3(ms) {
15495
- return new Promise((resolve18) => setTimeout(resolve18, ms));
15504
+ return new Promise((resolve19) => setTimeout(resolve19, ms));
15496
15505
  }
15497
15506
  var DEFAULT_POSTGRES_NETWORK, DEFAULT_POSTGRES_CONTAINER, DEFAULT_POSTGRES_HOST_PORT, DEFAULT_POSTGRES_IMAGE, DEFAULT_POSTGRES_USER, DEFAULT_POSTGRES_PASSWORD, DEFAULT_POSTGRES_DB, DEFAULT_POSTGRES_READY_TIMEOUT_MS;
15498
15507
  var init_postgres_init_helpers = __esm({
@@ -16135,9 +16144,9 @@ var UnknownArchetypeError = class extends Error {
16135
16144
  };
16136
16145
  var ArchetypeCycleError = class extends Error {
16137
16146
  path;
16138
- constructor(path78) {
16139
- super(`Archetype inheritance cycle detected: ${path78.join(" \u2192 ")} \u2192 ${path78[0] ?? "?"}`);
16140
- this.path = path78;
16147
+ constructor(path82) {
16148
+ super(`Archetype inheritance cycle detected: ${path82.join(" \u2192 ")} \u2192 ${path82[0] ?? "?"}`);
16149
+ this.path = path82;
16141
16150
  this.name = "ArchetypeCycleError";
16142
16151
  }
16143
16152
  };
@@ -16765,10 +16774,10 @@ async function confirm(message) {
16765
16774
  if (!process.stdin.isTTY) return true;
16766
16775
  const { createInterface: createInterface9 } = await import("node:readline");
16767
16776
  const rl = createInterface9({ input: process.stdin, output: process.stdout });
16768
- return new Promise((resolve18) => {
16777
+ return new Promise((resolve19) => {
16769
16778
  rl.question(`${message} [y/N] `, (answer) => {
16770
16779
  rl.close();
16771
- resolve18(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
16780
+ resolve19(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
16772
16781
  });
16773
16782
  });
16774
16783
  }
@@ -17219,7 +17228,7 @@ var KgServiceContainerController = class {
17219
17228
  }
17220
17229
  };
17221
17230
  function sleep4(ms) {
17222
- return new Promise((resolve18) => setTimeout(resolve18, ms));
17231
+ return new Promise((resolve19) => setTimeout(resolve19, ms));
17223
17232
  }
17224
17233
 
17225
17234
  // src/commands/services.ts
@@ -17307,7 +17316,7 @@ var McpAuthContainerController = class {
17307
17316
  }
17308
17317
  };
17309
17318
  function sleep5(ms) {
17310
- return new Promise((resolve18) => setTimeout(resolve18, ms));
17319
+ return new Promise((resolve19) => setTimeout(resolve19, ms));
17311
17320
  }
17312
17321
  function dumpContainerLogs(container, tail = 40) {
17313
17322
  try {
@@ -17725,9 +17734,9 @@ function formatFreshnessWarning(result, image = DEFAULT_DEVBOX_IMAGE) {
17725
17734
  "These source files have changed since the image was built; the",
17726
17735
  "changes will NOT take effect in fresh worlds until you rebuild:"
17727
17736
  ];
17728
- for (const { path: path78, mtimeMs } of result.newerSources) {
17737
+ for (const { path: path82, mtimeMs } of result.newerSources) {
17729
17738
  const when = new Date(mtimeMs).toISOString();
17730
- lines.push(` \u2022 ${path78} (modified ${when})`);
17739
+ lines.push(` \u2022 ${path82} (modified ${when})`);
17731
17740
  }
17732
17741
  lines.push("");
17733
17742
  lines.push("Rebuild with:");
@@ -17895,56 +17904,56 @@ var SECRET_LEN_BYTES = 32;
17895
17904
  function generateSecret() {
17896
17905
  return randomBytes6(SECRET_LEN_BYTES).toString("hex");
17897
17906
  }
17898
- function writeSecretAtPath(path78, value) {
17899
- mkdirSync18(dirname19(path78), { recursive: true });
17900
- const tmp = `${path78}.tmp.${process.pid}`;
17907
+ function writeSecretAtPath(path82, value) {
17908
+ mkdirSync18(dirname19(path82), { recursive: true });
17909
+ const tmp = `${path82}.tmp.${process.pid}`;
17901
17910
  writeFileSync13(tmp, value, { mode: 384 });
17902
17911
  chmodSync3(tmp, 384);
17903
- renameSync4(tmp, path78);
17912
+ renameSync4(tmp, path82);
17904
17913
  }
17905
- function readSecretAtPathOrNull(path78) {
17906
- if (!existsSync28(path78)) return null;
17907
- const mode = statSync7(path78).mode & 511;
17914
+ function readSecretAtPathOrNull(path82) {
17915
+ if (!existsSync28(path82)) return null;
17916
+ const mode = statSync7(path82).mode & 511;
17908
17917
  if (mode !== 384) {
17909
17918
  process.stderr.write(
17910
- `warn: ${path78} has mode 0${mode.toString(8)}; expected 0600. Run 'olam memory secret rotate' to regenerate.
17919
+ `warn: ${path82} has mode 0${mode.toString(8)}; expected 0600. Run 'olam memory secret rotate' to regenerate.
17911
17920
  `
17912
17921
  );
17913
17922
  }
17914
- return readFileSync20(path78, "utf8").trim();
17923
+ return readFileSync20(path82, "utf8").trim();
17915
17924
  }
17916
- function readSecretAtPath(path78) {
17917
- const v = readSecretAtPathOrNull(path78);
17925
+ function readSecretAtPath(path82) {
17926
+ const v = readSecretAtPathOrNull(path82);
17918
17927
  if (v === null) {
17919
17928
  throw new Error(
17920
- `Secret not found at ${path78}. Run 'olam memory start' to generate it.`
17929
+ `Secret not found at ${path82}. Run 'olam memory start' to generate it.`
17921
17930
  );
17922
17931
  }
17923
17932
  return v;
17924
17933
  }
17925
- function ensureMemorySecret(path78 = MEMORY_SECRET_PATH) {
17926
- const existing = readSecretAtPathOrNull(path78);
17934
+ function ensureMemorySecret(path82 = MEMORY_SECRET_PATH) {
17935
+ const existing = readSecretAtPathOrNull(path82);
17927
17936
  if (existing) return existing;
17928
17937
  const fresh = generateSecret();
17929
- writeSecretAtPath(path78, fresh);
17938
+ writeSecretAtPath(path82, fresh);
17930
17939
  return fresh;
17931
17940
  }
17932
- function readMemorySecretOrNull(path78 = MEMORY_SECRET_PATH) {
17933
- return readSecretAtPathOrNull(path78);
17941
+ function readMemorySecretOrNull(path82 = MEMORY_SECRET_PATH) {
17942
+ return readSecretAtPathOrNull(path82);
17934
17943
  }
17935
- function readMemorySecret(path78 = MEMORY_SECRET_PATH) {
17936
- return readSecretAtPath(path78);
17944
+ function readMemorySecret(path82 = MEMORY_SECRET_PATH) {
17945
+ return readSecretAtPath(path82);
17937
17946
  }
17938
- function rotateMemorySecret(path78 = MEMORY_SECRET_PATH) {
17947
+ function rotateMemorySecret(path82 = MEMORY_SECRET_PATH) {
17939
17948
  const fresh = generateSecret();
17940
- writeSecretAtPath(path78, fresh);
17949
+ writeSecretAtPath(path82, fresh);
17941
17950
  return fresh;
17942
17951
  }
17943
- function hasMemorySecret(path78 = MEMORY_SECRET_PATH) {
17944
- return existsSync28(path78);
17952
+ function hasMemorySecret(path82 = MEMORY_SECRET_PATH) {
17953
+ return existsSync28(path82);
17945
17954
  }
17946
- function writeCloudMemorySecret(value, path78 = CLOUD_MEMORY_SECRET_PATH) {
17947
- writeSecretAtPath(path78, value);
17955
+ function writeCloudMemorySecret(value, path82 = CLOUD_MEMORY_SECRET_PATH) {
17956
+ writeSecretAtPath(path82, value);
17948
17957
  }
17949
17958
 
17950
17959
  // src/lib/world-mcp-register.ts
@@ -18016,15 +18025,15 @@ var AGENTMEMORY_LOCAL_URL = "http://host.docker.internal:3111";
18016
18025
  var HOST_CP_URL = "http://127.0.0.1:19000";
18017
18026
  async function readHostCpTokenForCreate() {
18018
18027
  try {
18019
- const { default: fs77 } = await import("node:fs");
18020
- const { default: os43 } = await import("node:os");
18021
- const { default: path78 } = await import("node:path");
18022
- const tp = path78.join(
18023
- process.env.OLAM_HOME ?? path78.join(os43.homedir(), ".olam"),
18028
+ const { default: fs82 } = await import("node:fs");
18029
+ const { default: os45 } = await import("node:os");
18030
+ const { default: path82 } = await import("node:path");
18031
+ const tp = path82.join(
18032
+ process.env.OLAM_HOME ?? path82.join(os45.homedir(), ".olam"),
18024
18033
  "host-cp.token"
18025
18034
  );
18026
- if (!fs77.existsSync(tp)) return null;
18027
- return fs77.readFileSync(tp, "utf-8").trim();
18035
+ if (!fs82.existsSync(tp)) return null;
18036
+ return fs82.readFileSync(tp, "utf-8").trim();
18028
18037
  } catch {
18029
18038
  return null;
18030
18039
  }
@@ -18432,12 +18441,12 @@ function defaultNameFromPrompt(prompt) {
18432
18441
  }
18433
18442
  async function readHostCpToken3() {
18434
18443
  try {
18435
- const { default: fs77 } = await import("node:fs");
18436
- const { default: os43 } = await import("node:os");
18437
- const { default: path78 } = await import("node:path");
18438
- const tp = path78.join(os43.homedir(), ".olam", "host-cp.token");
18439
- if (!fs77.existsSync(tp)) return null;
18440
- const raw = fs77.readFileSync(tp, "utf-8").trim();
18444
+ const { default: fs82 } = await import("node:fs");
18445
+ const { default: os45 } = await import("node:os");
18446
+ const { default: path82 } = await import("node:path");
18447
+ const tp = path82.join(os45.homedir(), ".olam", "host-cp.token");
18448
+ if (!fs82.existsSync(tp)) return null;
18449
+ const raw = fs82.readFileSync(tp, "utf-8").trim();
18441
18450
  return raw.length > 0 ? raw : null;
18442
18451
  } catch {
18443
18452
  return null;
@@ -18680,7 +18689,7 @@ function parseRuntimeStatus(raw) {
18680
18689
  last_event_age_seconds
18681
18690
  };
18682
18691
  }
18683
- var fetchWorldRuntimeStatus = (worldId, token) => new Promise((resolve18) => {
18692
+ var fetchWorldRuntimeStatus = (worldId, token) => new Promise((resolve19) => {
18684
18693
  const opts = {
18685
18694
  host: "127.0.0.1",
18686
18695
  port: HOST_CP_PORT2,
@@ -18692,7 +18701,7 @@ var fetchWorldRuntimeStatus = (worldId, token) => new Promise((resolve18) => {
18692
18701
  const req = http3.request(opts, (res) => {
18693
18702
  if (res.statusCode !== 200) {
18694
18703
  res.resume();
18695
- return resolve18(null);
18704
+ return resolve19(null);
18696
18705
  }
18697
18706
  let body = "";
18698
18707
  res.setEncoding("utf-8");
@@ -18702,17 +18711,17 @@ var fetchWorldRuntimeStatus = (worldId, token) => new Promise((resolve18) => {
18702
18711
  res.on("end", () => {
18703
18712
  try {
18704
18713
  const parsed = parseRuntimeStatus(JSON.parse(body));
18705
- resolve18(parsed);
18714
+ resolve19(parsed);
18706
18715
  } catch {
18707
- resolve18(null);
18716
+ resolve19(null);
18708
18717
  }
18709
18718
  });
18710
- res.on("error", () => resolve18(null));
18719
+ res.on("error", () => resolve19(null));
18711
18720
  });
18712
- req.on("error", () => resolve18(null));
18721
+ req.on("error", () => resolve19(null));
18713
18722
  req.on("timeout", () => {
18714
18723
  req.destroy();
18715
- resolve18(null);
18724
+ resolve19(null);
18716
18725
  });
18717
18726
  req.end();
18718
18727
  });
@@ -19181,14 +19190,14 @@ function printTable(entries) {
19181
19190
  async function confirmInteractive() {
19182
19191
  process.stdout.write(" Type `yes` to proceed: ");
19183
19192
  const buf = [];
19184
- return new Promise((resolve18) => {
19193
+ return new Promise((resolve19) => {
19185
19194
  const onData = (chunk) => {
19186
19195
  buf.push(chunk);
19187
19196
  if (Buffer.concat(buf).toString("utf-8").includes("\n")) {
19188
19197
  process.stdin.removeListener("data", onData);
19189
19198
  process.stdin.pause();
19190
19199
  const answer = Buffer.concat(buf).toString("utf-8").trim();
19191
- resolve18(answer.toLowerCase() === "yes");
19200
+ resolve19(answer.toLowerCase() === "yes");
19192
19201
  }
19193
19202
  };
19194
19203
  process.stdin.resume();
@@ -22244,11 +22253,11 @@ function zodIssueToError(issue, doc, lineCounter) {
22244
22253
  suggestion: deriveSuggestion(issue)
22245
22254
  };
22246
22255
  }
22247
- function formatJsonPath(path78) {
22248
- if (path78.length === 0)
22256
+ function formatJsonPath(path82) {
22257
+ if (path82.length === 0)
22249
22258
  return "<root>";
22250
22259
  let out = "";
22251
- for (const seg of path78) {
22260
+ for (const seg of path82) {
22252
22261
  if (typeof seg === "number") {
22253
22262
  out += `[${seg}]`;
22254
22263
  } else {
@@ -22257,11 +22266,11 @@ function formatJsonPath(path78) {
22257
22266
  }
22258
22267
  return out;
22259
22268
  }
22260
- function resolveYamlLocation(path78, doc, lineCounter) {
22269
+ function resolveYamlLocation(path82, doc, lineCounter) {
22261
22270
  let bestLine = 0;
22262
22271
  let bestColumn = 0;
22263
- for (let depth = path78.length; depth >= 0; depth -= 1) {
22264
- const segment = path78.slice(0, depth);
22272
+ for (let depth = path82.length; depth >= 0; depth -= 1) {
22273
+ const segment = path82.slice(0, depth);
22265
22274
  try {
22266
22275
  const node = doc.getIn(segment, true);
22267
22276
  if (node && typeof node === "object" && "range" in node) {
@@ -22479,11 +22488,11 @@ function topoSort(nodes) {
22479
22488
  }
22480
22489
  function traceCycle(start, byId) {
22481
22490
  const seen = /* @__PURE__ */ new Set();
22482
- const path78 = [];
22491
+ const path82 = [];
22483
22492
  let current = start;
22484
22493
  while (current && !seen.has(current)) {
22485
22494
  seen.add(current);
22486
- path78.push(current);
22495
+ path82.push(current);
22487
22496
  const node = byId.get(current);
22488
22497
  const next = node?.dependsOn[0];
22489
22498
  if (next === void 0)
@@ -22491,10 +22500,10 @@ function traceCycle(start, byId) {
22491
22500
  current = next;
22492
22501
  }
22493
22502
  if (current && seen.has(current)) {
22494
- const idx = path78.indexOf(current);
22495
- return [...path78.slice(idx), current];
22503
+ const idx = path82.indexOf(current);
22504
+ return [...path82.slice(idx), current];
22496
22505
  }
22497
- return path78;
22506
+ return path82;
22498
22507
  }
22499
22508
 
22500
22509
  // ../core/dist/executor/types.js
@@ -24669,16 +24678,16 @@ function isValidConfig(value) {
24669
24678
  if (typeof v.install_id !== "string" || v.install_id.length === 0) return false;
24670
24679
  return true;
24671
24680
  }
24672
- function atomicWriteJSON(path78, value, stderr = process.stderr) {
24681
+ function atomicWriteJSON(path82, value, stderr = process.stderr) {
24673
24682
  ensureStateDir();
24674
- const dir = dirname24(path78);
24683
+ const dir = dirname24(path82);
24675
24684
  if (!existsSync39(dir)) {
24676
24685
  mkdirSync24(dir, { recursive: true });
24677
24686
  }
24678
- const tmp = `${path78}.tmp.${process.pid}`;
24687
+ const tmp = `${path82}.tmp.${process.pid}`;
24679
24688
  try {
24680
24689
  writeFileSync18(tmp, JSON.stringify(value, null, 2) + "\n", { encoding: "utf8" });
24681
- renameSync5(tmp, path78);
24690
+ renameSync5(tmp, path82);
24682
24691
  } catch (err) {
24683
24692
  if (existsSync39(tmp)) {
24684
24693
  try {
@@ -24756,7 +24765,7 @@ async function kubectlWrap(args, opts = {}) {
24756
24765
  const spawnImpl = opts.spawnImpl ?? spawn5;
24757
24766
  const stdout = [];
24758
24767
  const stderr = [];
24759
- return new Promise((resolve18) => {
24768
+ return new Promise((resolve19) => {
24760
24769
  let resolved = false;
24761
24770
  let killTimer = null;
24762
24771
  let sigkillTimer = null;
@@ -24771,7 +24780,7 @@ async function kubectlWrap(args, opts = {}) {
24771
24780
  clearTimeout(sigkillTimer);
24772
24781
  sigkillTimer = null;
24773
24782
  }
24774
- resolve18(r);
24783
+ resolve19(r);
24775
24784
  }
24776
24785
  let child;
24777
24786
  try {
@@ -24780,7 +24789,7 @@ async function kubectlWrap(args, opts = {}) {
24780
24789
  env: { ...process.env, ...opts.env ?? {} }
24781
24790
  });
24782
24791
  } catch (err) {
24783
- resolve18({
24792
+ resolve19({
24784
24793
  ok: false,
24785
24794
  stdout: "",
24786
24795
  stderr: err instanceof Error ? err.message : String(err),
@@ -24857,14 +24866,14 @@ async function probePortForwardLiveness(deps = {}) {
24857
24866
  return probe2("127.0.0.1", PORT_FORWARD_PORT, TCP_PROBE_TIMEOUT_MS);
24858
24867
  }
24859
24868
  function realTcpProbe(host, port2, timeoutMs) {
24860
- return new Promise((resolve18) => {
24869
+ return new Promise((resolve19) => {
24861
24870
  const socket = new net3.Socket();
24862
24871
  let done = false;
24863
24872
  function finish(result) {
24864
24873
  if (done) return;
24865
24874
  done = true;
24866
24875
  socket.destroy();
24867
- resolve18(result);
24876
+ resolve19(result);
24868
24877
  }
24869
24878
  const timer = setTimeout(() => finish(false), timeoutMs);
24870
24879
  socket.once("connect", () => {
@@ -25090,12 +25099,12 @@ function appendAuditEntry(entry, auditLogPath, writeFileSyncImpl) {
25090
25099
  }
25091
25100
  async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}) {
25092
25101
  const auditLogPath = deps.auditLogPath ?? MANIFEST_REFRESH_AUDIT_LOG;
25093
- const readdirSync22 = deps.readdirSync ?? fs37.readdirSync;
25094
- const readFileSync61 = deps.readFileSync ?? fs37.readFileSync;
25102
+ const readdirSync23 = deps.readdirSync ?? fs37.readdirSync;
25103
+ const readFileSync66 = deps.readFileSync ?? fs37.readFileSync;
25095
25104
  const writeFileSyncImpl = deps.writeFileSync ?? fs37.writeFileSync;
25096
- const existsSync86 = deps.existsSync ?? fs37.existsSync;
25105
+ const existsSync90 = deps.existsSync ?? fs37.existsSync;
25097
25106
  const now = deps.now ? deps.now() : /* @__PURE__ */ new Date();
25098
- if (!existsSync86(manifestsDir)) {
25107
+ if (!existsSync90(manifestsDir)) {
25099
25108
  return {
25100
25109
  ok: false,
25101
25110
  message: `manifests directory not found: ${manifestsDir}`
@@ -25103,7 +25112,7 @@ async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}) {
25103
25112
  }
25104
25113
  let files;
25105
25114
  try {
25106
- const entries = readdirSync22(manifestsDir, { withFileTypes: true });
25115
+ const entries = readdirSync23(manifestsDir, { withFileTypes: true });
25107
25116
  files = entries.filter((e) => e.isFile() && (e.name.endsWith(".yaml") || e.name.endsWith(".json"))).map((e) => e.name);
25108
25117
  } catch (err) {
25109
25118
  return {
@@ -25116,7 +25125,7 @@ async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}) {
25116
25125
  const filePath = path39.join(manifestsDir, file);
25117
25126
  let content;
25118
25127
  try {
25119
- content = readFileSync61(filePath, "utf8");
25128
+ content = readFileSync66(filePath, "utf8");
25120
25129
  } catch {
25121
25130
  continue;
25122
25131
  }
@@ -25697,10 +25706,10 @@ async function confirm2(message) {
25697
25706
  if (!process.stdin.isTTY) return true;
25698
25707
  const { createInterface: createInterface9 } = await import("node:readline");
25699
25708
  const rl = createInterface9({ input: process.stdin, output: process.stdout });
25700
- return new Promise((resolve18) => {
25709
+ return new Promise((resolve19) => {
25701
25710
  rl.question(`${message} [y/N] `, (answer) => {
25702
25711
  rl.close();
25703
- resolve18(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
25712
+ resolve19(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
25704
25713
  });
25705
25714
  });
25706
25715
  }
@@ -28699,9 +28708,9 @@ function appendIdempotent(opts) {
28699
28708
  }
28700
28709
  function resolveShellRc(home, shellEnv) {
28701
28710
  if (!shellEnv) return null;
28702
- const basename11 = path48.basename(shellEnv);
28703
- if (basename11 === "zsh") return path48.join(home, ".zshrc");
28704
- if (basename11 === "bash") return path48.join(home, ".bashrc");
28711
+ const basename12 = path48.basename(shellEnv);
28712
+ if (basename12 === "zsh") return path48.join(home, ".zshrc");
28713
+ if (basename12 === "bash") return path48.join(home, ".bashrc");
28705
28714
  return null;
28706
28715
  }
28707
28716
 
@@ -28713,10 +28722,10 @@ var NEXT_STEPS_DOCS = [
28713
28722
  "docs/architecture/manifest-spec.md \u2014 per-repo .adb.yaml schema",
28714
28723
  "docs/architecture/config-spec.md \u2014 workspace .olam/config.yaml schema"
28715
28724
  ];
28716
- var defaultSpawn = (cmd, args) => new Promise((resolve18) => {
28725
+ var defaultSpawn = (cmd, args) => new Promise((resolve19) => {
28717
28726
  const child = spawn7(cmd, [...args], { stdio: "inherit" });
28718
- child.on("exit", (code) => resolve18({ status: code }));
28719
- child.on("error", () => resolve18({ status: 1 }));
28727
+ child.on("exit", (code) => resolve19({ status: code }));
28728
+ child.on("error", () => resolve19({ status: 1 }));
28720
28729
  });
28721
28730
  var defaultPrompt = (question, defaultYes) => {
28722
28731
  if (!process.stdin.isTTY) {
@@ -28726,18 +28735,18 @@ var defaultPrompt = (question, defaultYes) => {
28726
28735
  );
28727
28736
  return Promise.resolve(defaultYes);
28728
28737
  }
28729
- return new Promise((resolve18) => {
28738
+ return new Promise((resolve19) => {
28730
28739
  const rl = createInterface3({ input: process.stdin, output: process.stdout });
28731
28740
  const suffix = defaultYes ? " [Y/n]: " : " [y/N]: ";
28732
28741
  rl.question(`${question}${suffix}`, (answer) => {
28733
28742
  rl.close();
28734
28743
  const t = answer.trim().toLowerCase();
28735
- if (t === "") resolve18(defaultYes);
28736
- else if (t === "y" || t === "yes") resolve18(true);
28737
- else if (t === "n" || t === "no") resolve18(false);
28738
- else resolve18(defaultYes);
28744
+ if (t === "") resolve19(defaultYes);
28745
+ else if (t === "y" || t === "yes") resolve19(true);
28746
+ else if (t === "n" || t === "no") resolve19(false);
28747
+ else resolve19(defaultYes);
28739
28748
  });
28740
- rl.on("close", () => resolve18(defaultYes));
28749
+ rl.on("close", () => resolve19(defaultYes));
28741
28750
  });
28742
28751
  };
28743
28752
  async function phase1SystemCheck(deps) {
@@ -29290,7 +29299,7 @@ function registerBegin(program2) {
29290
29299
  }
29291
29300
 
29292
29301
  // src/commands/config.ts
29293
- import * as fs63 from "node:fs";
29302
+ import * as fs67 from "node:fs";
29294
29303
  import { createRequire as createRequire4 } from "node:module";
29295
29304
 
29296
29305
  // ../core/dist/global-config/index.js
@@ -29382,7 +29391,14 @@ import * as fs49 from "node:fs";
29382
29391
  import * as path54 from "node:path";
29383
29392
  import * as os29 from "node:os";
29384
29393
  var SKILL_SOURCES_AUDIT_LOG_FILENAME = "skill-sources-audit.log";
29385
- var TrustActionSchema = external_exports.enum(["added", "rejected", "auto-rejected", "failed", "removed"]);
29394
+ var TrustActionSchema = external_exports.enum([
29395
+ "added",
29396
+ "rejected",
29397
+ "auto-rejected",
29398
+ "failed",
29399
+ "removed",
29400
+ "meta-hook-stripped"
29401
+ ]);
29386
29402
  var TrustMethodSchema = external_exports.enum(["flag", "interactive", "auto-reject-tty", "none"]);
29387
29403
  var TrustAuditEntrySchema = external_exports.object({
29388
29404
  timestamp: external_exports.string().min(1),
@@ -29968,6 +29984,9 @@ function readMigrationSnapshotFromPath(p) {
29968
29984
  return JSON.parse(fs54.readFileSync(p, "utf-8"));
29969
29985
  }
29970
29986
 
29987
+ // ../core/dist/skill-sync/engine.js
29988
+ init_store2();
29989
+
29971
29990
  // ../core/dist/skill-sync/artifact-resolver.js
29972
29991
  import * as fs55 from "node:fs";
29973
29992
  import * as path59 from "node:path";
@@ -30191,11 +30210,11 @@ function detectCollisions(artifacts) {
30191
30210
  }
30192
30211
  const collisions = [];
30193
30212
  for (const [key, loserList] of losersByKey.entries()) {
30194
- const [bucket, basename11] = key.split("\0");
30213
+ const [bucket, basename12] = key.split("\0");
30195
30214
  const winner = seen.get(key);
30196
30215
  collisions.push({
30197
30216
  bucket,
30198
- basename: basename11,
30217
+ basename: basename12,
30199
30218
  winnerSourceId: winner.sourceId,
30200
30219
  winnerSourcePath: winner.sourcePath,
30201
30220
  loserSourceIds: loserList.map((l) => l.sourceId),
@@ -30271,11 +30290,161 @@ function deployArtifacts(artifacts) {
30271
30290
  }
30272
30291
 
30273
30292
  // ../core/dist/skill-sync/settings-merger.js
30274
- import * as fs57 from "node:fs";
30293
+ import * as fs59 from "node:fs";
30275
30294
  import * as os34 from "node:os";
30276
30295
  import * as path61 from "node:path";
30296
+
30297
+ // ../core/dist/meta-hooks/memory-recall.js
30298
+ import * as fs57 from "node:fs";
30299
+ var OLAM_META_MEMORY_RECALL_SENTINEL = "olam-meta-memory-recall-v1";
30300
+ var OLAM_META_MEMORY_RECALL_STAGE = "PreToolUse";
30301
+ var OLAM_META_MEMORY_RECALL_MATCHER = "Bash|Edit|MultiEdit|Write|Read|NotebookEdit";
30302
+ var OLAM_META_MEMORY_RECALL_TIMEOUT_MS = 5e3;
30303
+ var OLAM_META_MEMORY_RECALL_SCRIPT_PATH = "$HOME/.claude/scripts/agentmemory-classifier/agentmemory-recall-trigger.mjs";
30304
+ var OLAM_META_NOOP_GUARD = "command -v olam >/dev/null 2>&1 || exit 0;";
30305
+ function buildMemoryRecallHookEntry() {
30306
+ return {
30307
+ matcher: OLAM_META_MEMORY_RECALL_MATCHER,
30308
+ hooks: [
30309
+ {
30310
+ type: "command",
30311
+ command: `OLAM_META_SENTINEL=${OLAM_META_MEMORY_RECALL_SENTINEL}; ${OLAM_META_NOOP_GUARD} node "${OLAM_META_MEMORY_RECALL_SCRIPT_PATH}"`,
30312
+ timeout: OLAM_META_MEMORY_RECALL_TIMEOUT_MS
30313
+ }
30314
+ ]
30315
+ };
30316
+ }
30317
+ function computeMemoryRecallUninstall(settings) {
30318
+ const matchers = settings.hooks?.PreToolUse;
30319
+ if (!Array.isArray(matchers) || matchers.length === 0) {
30320
+ return { status: "not-found" };
30321
+ }
30322
+ let changed = false;
30323
+ const filteredMatchers = [];
30324
+ for (const matcher of matchers) {
30325
+ const innerHooks = matcher.hooks ?? [];
30326
+ const keptInner = innerHooks.filter((h) => {
30327
+ if (typeof h.command === "string" && h.command.includes(OLAM_META_MEMORY_RECALL_SENTINEL)) {
30328
+ changed = true;
30329
+ return false;
30330
+ }
30331
+ return true;
30332
+ });
30333
+ if (keptInner.length === 0 && innerHooks.length > 0) {
30334
+ changed = true;
30335
+ continue;
30336
+ }
30337
+ if (keptInner.length === innerHooks.length) {
30338
+ filteredMatchers.push(matcher);
30339
+ } else {
30340
+ filteredMatchers.push({ ...matcher, hooks: keptInner });
30341
+ }
30342
+ }
30343
+ if (!changed)
30344
+ return { status: "not-found" };
30345
+ const next = {
30346
+ ...settings,
30347
+ hooks: {
30348
+ ...settings.hooks,
30349
+ PreToolUse: filteredMatchers
30350
+ }
30351
+ };
30352
+ if (filteredMatchers.length === 0) {
30353
+ const otherStages = Object.keys(next.hooks ?? {}).filter((k) => k !== "PreToolUse");
30354
+ if (otherStages.length === 0) {
30355
+ delete next.hooks;
30356
+ } else {
30357
+ delete next.hooks.PreToolUse;
30358
+ }
30359
+ }
30360
+ return { status: "removed", settingsAfter: next };
30361
+ }
30362
+ function matchMemoryRecallSentinel(commandLine) {
30363
+ return commandLine.includes(OLAM_META_MEMORY_RECALL_SENTINEL);
30364
+ }
30365
+
30366
+ // ../core/dist/meta-hooks/memory-classify.js
30367
+ import * as fs58 from "node:fs";
30368
+ var OLAM_META_MEMORY_CLASSIFY_SENTINEL = "olam-meta-memory-classify-v1";
30369
+ var OLAM_META_MEMORY_CLASSIFY_STAGE = "PostToolUse";
30370
+ var OLAM_META_MEMORY_CLASSIFY_MATCHER = "Bash|Edit|MultiEdit|Write|Read|NotebookEdit";
30371
+ var OLAM_META_MEMORY_CLASSIFY_TIMEOUT_MS = 5e3;
30372
+ var OLAM_META_MEMORY_CLASSIFY_SCRIPT_PATH = "$HOME/.claude/scripts/agentmemory-classifier/agentmemory-classify-queue.mjs";
30373
+ var OLAM_META_NOOP_GUARD2 = "command -v olam >/dev/null 2>&1 || exit 0;";
30374
+ function buildMemoryClassifyHookEntry() {
30375
+ return {
30376
+ matcher: OLAM_META_MEMORY_CLASSIFY_MATCHER,
30377
+ hooks: [
30378
+ {
30379
+ type: "command",
30380
+ command: `OLAM_META_SENTINEL=${OLAM_META_MEMORY_CLASSIFY_SENTINEL}; ${OLAM_META_NOOP_GUARD2} node "${OLAM_META_MEMORY_CLASSIFY_SCRIPT_PATH}"`,
30381
+ timeout: OLAM_META_MEMORY_CLASSIFY_TIMEOUT_MS
30382
+ }
30383
+ ]
30384
+ };
30385
+ }
30386
+ function computeMemoryClassifyUninstall(settings) {
30387
+ const matchers = settings.hooks?.PostToolUse;
30388
+ if (!Array.isArray(matchers) || matchers.length === 0) {
30389
+ return { status: "not-found" };
30390
+ }
30391
+ let changed = false;
30392
+ const filteredMatchers = [];
30393
+ for (const matcher of matchers) {
30394
+ const innerHooks = matcher.hooks ?? [];
30395
+ const keptInner = innerHooks.filter((h) => {
30396
+ if (typeof h.command === "string" && h.command.includes(OLAM_META_MEMORY_CLASSIFY_SENTINEL)) {
30397
+ changed = true;
30398
+ return false;
30399
+ }
30400
+ return true;
30401
+ });
30402
+ if (keptInner.length === 0 && innerHooks.length > 0) {
30403
+ changed = true;
30404
+ continue;
30405
+ }
30406
+ if (keptInner.length === innerHooks.length) {
30407
+ filteredMatchers.push(matcher);
30408
+ } else {
30409
+ filteredMatchers.push({ ...matcher, hooks: keptInner });
30410
+ }
30411
+ }
30412
+ if (!changed)
30413
+ return { status: "not-found" };
30414
+ const next = {
30415
+ ...settings,
30416
+ hooks: {
30417
+ ...settings.hooks,
30418
+ PostToolUse: filteredMatchers
30419
+ }
30420
+ };
30421
+ if (filteredMatchers.length === 0) {
30422
+ const otherStages = Object.keys(next.hooks ?? {}).filter((k) => k !== "PostToolUse");
30423
+ if (otherStages.length === 0) {
30424
+ delete next.hooks;
30425
+ } else {
30426
+ delete next.hooks.PostToolUse;
30427
+ }
30428
+ }
30429
+ return { status: "removed", settingsAfter: next };
30430
+ }
30431
+ function matchMemoryClassifySentinel(commandLine) {
30432
+ return commandLine.includes(OLAM_META_MEMORY_CLASSIFY_SENTINEL);
30433
+ }
30434
+
30435
+ // ../core/dist/skill-sync/settings-merger.js
30277
30436
  var OLAM_SKILLS_MARKER = "_olamSkillsManaged";
30278
30437
  var BACKUP_RETENTION = 30;
30438
+ var DUAL_WRITE_DEDUP_RULES = [
30439
+ {
30440
+ preservedSentinel: OLAM_META_MEMORY_RECALL_SENTINEL,
30441
+ incomingCommandSubstring: "agentmemory-recall-trigger.mjs"
30442
+ },
30443
+ {
30444
+ preservedSentinel: OLAM_META_MEMORY_CLASSIFY_SENTINEL,
30445
+ incomingCommandSubstring: "agentmemory-classify-queue.mjs"
30446
+ }
30447
+ ];
30279
30448
  function claudeSettingsPath() {
30280
30449
  const override = process.env["OLAM_CLAUDE_SETTINGS_PATH"];
30281
30450
  if (override && override.length > 0)
@@ -30301,32 +30470,66 @@ function dedupeByMatcher(entries) {
30301
30470
  }
30302
30471
  return [...map.values()];
30303
30472
  }
30473
+ function commandsInEntry(entry) {
30474
+ const cmds = [];
30475
+ const direct = entry["command"];
30476
+ if (typeof direct === "string")
30477
+ cmds.push(direct);
30478
+ const inner = entry["hooks"];
30479
+ if (Array.isArray(inner)) {
30480
+ for (const h of inner) {
30481
+ if (h && typeof h === "object" && typeof h.command === "string") {
30482
+ cmds.push(h.command);
30483
+ }
30484
+ }
30485
+ }
30486
+ return cmds;
30487
+ }
30488
+ function applyDualWriteDedup(incoming, preserved) {
30489
+ const preservedCommands = preserved.flatMap(commandsInEntry);
30490
+ const preservedHas = (sentinel) => preservedCommands.some((c) => c.includes(sentinel));
30491
+ let droppedCount = 0;
30492
+ const droppedCommands = [];
30493
+ const kept = incoming.filter((entry) => {
30494
+ const incomingCommands = commandsInEntry(entry);
30495
+ for (const rule of DUAL_WRITE_DEDUP_RULES) {
30496
+ const hasIncomingScript = incomingCommands.some((c) => c.includes(rule.incomingCommandSubstring));
30497
+ if (hasIncomingScript && preservedHas(rule.preservedSentinel)) {
30498
+ droppedCount += 1;
30499
+ droppedCommands.push(...incomingCommands.filter((c) => c.includes(rule.incomingCommandSubstring)));
30500
+ return false;
30501
+ }
30502
+ }
30503
+ return true;
30504
+ });
30505
+ return { kept, droppedCount, droppedCommands };
30506
+ }
30304
30507
  function tagOlam(entry) {
30305
30508
  return { ...entry, [OLAM_SKILLS_MARKER]: true };
30306
30509
  }
30307
30510
  function readJson(file) {
30308
- return JSON.parse(fs57.readFileSync(file, "utf-8"));
30511
+ return JSON.parse(fs59.readFileSync(file, "utf-8"));
30309
30512
  }
30310
30513
  function rotateBackups(backupDir) {
30311
- if (!fs57.existsSync(backupDir))
30514
+ if (!fs59.existsSync(backupDir))
30312
30515
  return;
30313
- const files = fs57.readdirSync(backupDir).filter((f) => f.endsWith(".json")).map((f) => ({ name: f, full: path61.join(backupDir, f), mtime: fs57.statSync(path61.join(backupDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
30516
+ const files = fs59.readdirSync(backupDir).filter((f) => f.endsWith(".json")).map((f) => ({ name: f, full: path61.join(backupDir, f), mtime: fs59.statSync(path61.join(backupDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
30314
30517
  for (const f of files.slice(BACKUP_RETENTION)) {
30315
30518
  try {
30316
- fs57.unlinkSync(f.full);
30519
+ fs59.unlinkSync(f.full);
30317
30520
  } catch {
30318
30521
  }
30319
30522
  }
30320
30523
  }
30321
30524
  function backupSettings() {
30322
30525
  const src = claudeSettingsPath();
30323
- if (!fs57.existsSync(src))
30526
+ if (!fs59.existsSync(src))
30324
30527
  return void 0;
30325
30528
  const dir = settingsBackupDir();
30326
- fs57.mkdirSync(dir, { recursive: true });
30529
+ fs59.mkdirSync(dir, { recursive: true });
30327
30530
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
30328
30531
  const dest = path61.join(dir, `settings-${stamp}.json`);
30329
- fs57.copyFileSync(src, dest);
30532
+ fs59.copyFileSync(src, dest);
30330
30533
  rotateBackups(dir);
30331
30534
  return dest;
30332
30535
  }
@@ -30334,7 +30537,7 @@ function mergeSettings(input) {
30334
30537
  const settingsPath = claudeSettingsPath();
30335
30538
  const backupPath = backupSettings();
30336
30539
  let base = {};
30337
- if (fs57.existsSync(settingsPath)) {
30540
+ if (fs59.existsSync(settingsPath)) {
30338
30541
  try {
30339
30542
  base = readJson(settingsPath);
30340
30543
  } catch {
@@ -30366,13 +30569,18 @@ function mergeSettings(input) {
30366
30569
  ...olamHooksByCategory.keys()
30367
30570
  ]);
30368
30571
  let hooksAdded = 0;
30572
+ let dualWriteDeduped = 0;
30573
+ const dualWriteDroppedCommands = [];
30369
30574
  for (const cat of categories) {
30370
30575
  const existing = Array.isArray(existingHooks[cat]) ? existingHooks[cat] : [];
30371
30576
  const preserved = existing.filter((e) => !e[OLAM_SKILLS_MARKER]);
30372
30577
  const olam = olamHooksByCategory.get(cat) ?? [];
30373
30578
  const olamDeduped = dedupeByMatcher(olam);
30374
- mergedHooks[cat] = [...preserved, ...olamDeduped];
30375
- hooksAdded += olam.length;
30579
+ const { kept: olamFinal, droppedCount, droppedCommands } = applyDualWriteDedup(olamDeduped, preserved);
30580
+ dualWriteDeduped += droppedCount;
30581
+ dualWriteDroppedCommands.push(...droppedCommands);
30582
+ mergedHooks[cat] = [...preserved, ...olamFinal];
30583
+ hooksAdded += olamFinal.length;
30376
30584
  }
30377
30585
  const permSet = /* @__PURE__ */ new Set();
30378
30586
  for (const file of input.permissionFiles) {
@@ -30397,16 +30605,16 @@ function mergeSettings(input) {
30397
30605
  ...input.permissionFiles.length > 0 ? { allow: [...permSet] } : {}
30398
30606
  }
30399
30607
  };
30400
- fs57.mkdirSync(path61.dirname(settingsPath), { recursive: true });
30608
+ fs59.mkdirSync(path61.dirname(settingsPath), { recursive: true });
30401
30609
  const tmp = `${settingsPath}.tmp-${process.pid}`;
30402
- fs57.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n", { mode: 420 });
30403
- fs57.renameSync(tmp, settingsPath);
30404
- return { backupPath, hooksAdded, permissionsCount: permSet.size };
30610
+ fs59.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n", { mode: 420 });
30611
+ fs59.renameSync(tmp, settingsPath);
30612
+ return { backupPath, hooksAdded, permissionsCount: permSet.size, dualWriteDeduped, dualWriteDroppedCommands };
30405
30613
  }
30406
30614
 
30407
30615
  // ../core/dist/skill-sync/per-project-override.js
30408
30616
  import { execFileSync as execFileSync13 } from "node:child_process";
30409
- import * as fs58 from "node:fs";
30617
+ import * as fs60 from "node:fs";
30410
30618
  import * as path62 from "node:path";
30411
30619
  import { parse as parseYaml6 } from "yaml";
30412
30620
 
@@ -30443,8 +30651,8 @@ function findProjectOverride(startDir) {
30443
30651
  const root = path62.parse(dir).root;
30444
30652
  while (true) {
30445
30653
  const candidate = path62.join(dir, PROJECT_OVERRIDE_RELATIVE_PATH);
30446
- if (fs58.existsSync(candidate) && fs58.statSync(candidate).isFile()) {
30447
- const raw = fs58.readFileSync(candidate, "utf-8");
30654
+ if (fs60.existsSync(candidate) && fs60.statSync(candidate).isFile()) {
30655
+ const raw = fs60.readFileSync(candidate, "utf-8");
30448
30656
  let parsed;
30449
30657
  try {
30450
30658
  parsed = parseYaml6(raw);
@@ -30495,7 +30703,7 @@ function restoreCloneToBranchHead(opts) {
30495
30703
  }
30496
30704
 
30497
30705
  // ../core/dist/skill-sync/source-lock.js
30498
- import * as fs59 from "node:fs";
30706
+ import * as fs61 from "node:fs";
30499
30707
  import * as os35 from "node:os";
30500
30708
  import * as path63 from "node:path";
30501
30709
  var SOURCE_LOCK_FILENAME = ".olam-sync.lock";
@@ -30517,11 +30725,11 @@ function defaultIsPidAlive(pid) {
30517
30725
  }
30518
30726
  }
30519
30727
  function sleep6(ms) {
30520
- return new Promise((resolve18) => setTimeout(resolve18, ms));
30728
+ return new Promise((resolve19) => setTimeout(resolve19, ms));
30521
30729
  }
30522
30730
  function readLockMeta(lockPath) {
30523
30731
  try {
30524
- const raw = fs59.readFileSync(lockPath, "utf-8");
30732
+ const raw = fs61.readFileSync(lockPath, "utf-8");
30525
30733
  const parsed = JSON.parse(raw);
30526
30734
  if (typeof parsed?.pid === "number" && typeof parsed?.hostname === "string" && typeof parsed?.timestamp === "number") {
30527
30735
  return parsed;
@@ -30540,12 +30748,12 @@ function isLockStale(meta, opts) {
30540
30748
  }
30541
30749
  function tryAcquireOnce(lockPath, meta, opts) {
30542
30750
  try {
30543
- fs59.mkdirSync(path63.dirname(lockPath), { recursive: true });
30544
- const fd = fs59.openSync(lockPath, "wx", 384);
30751
+ fs61.mkdirSync(path63.dirname(lockPath), { recursive: true });
30752
+ const fd = fs61.openSync(lockPath, "wx", 384);
30545
30753
  try {
30546
- fs59.writeSync(fd, JSON.stringify(meta));
30754
+ fs61.writeSync(fd, JSON.stringify(meta));
30547
30755
  } finally {
30548
- fs59.closeSync(fd);
30756
+ fs61.closeSync(fd);
30549
30757
  }
30550
30758
  return true;
30551
30759
  } catch (err) {
@@ -30555,14 +30763,14 @@ function tryAcquireOnce(lockPath, meta, opts) {
30555
30763
  const existing = readLockMeta(lockPath);
30556
30764
  if (existing === void 0) {
30557
30765
  try {
30558
- fs59.unlinkSync(lockPath);
30766
+ fs61.unlinkSync(lockPath);
30559
30767
  } catch {
30560
30768
  }
30561
30769
  return tryAcquireOnce(lockPath, meta, opts);
30562
30770
  }
30563
30771
  if (isLockStale(existing, opts)) {
30564
30772
  try {
30565
- fs59.unlinkSync(lockPath);
30773
+ fs61.unlinkSync(lockPath);
30566
30774
  } catch {
30567
30775
  }
30568
30776
  return tryAcquireOnce(lockPath, meta, opts);
@@ -30591,7 +30799,7 @@ async function acquireSourceLock(clonePath, options = {}) {
30591
30799
  lockPath,
30592
30800
  release: () => {
30593
30801
  try {
30594
- fs59.unlinkSync(lockPath);
30802
+ fs61.unlinkSync(lockPath);
30595
30803
  } catch {
30596
30804
  }
30597
30805
  }
@@ -30615,17 +30823,464 @@ async function withSourceLock(clonePath, fn, options) {
30615
30823
  }
30616
30824
  }
30617
30825
 
30618
- // ../core/dist/skill-sync/engine.js
30619
- import * as fs60 from "node:fs";
30826
+ // ../core/dist/skill-sync/settings-json-lock.js
30827
+ import * as fs62 from "node:fs";
30620
30828
  import * as os36 from "node:os";
30621
30829
  import * as path64 from "node:path";
30830
+ var SETTINGS_JSON_LOCK_FILENAME = ".settings-json.lock";
30831
+ var DEFAULT_ACQUIRE_TIMEOUT_MS2 = 1e4;
30832
+ var DEFAULT_STALE_LOCK_MS2 = 5 * 6e4;
30833
+ var SettingsJsonLockError = class extends Error {
30834
+ constructor(message) {
30835
+ super(message);
30836
+ this.name = "SettingsJsonLockError";
30837
+ }
30838
+ };
30839
+ function defaultSettingsJsonLockPath() {
30840
+ const stateDir = process.env["OLAM_STATE_DIR"] ?? path64.join(os36.homedir(), ".olam", "state");
30841
+ return path64.join(stateDir, SETTINGS_JSON_LOCK_FILENAME);
30842
+ }
30843
+ function defaultIsPidAlive2(pid) {
30844
+ try {
30845
+ process.kill(pid, 0);
30846
+ return true;
30847
+ } catch (err) {
30848
+ const code = err.code;
30849
+ return code === "EPERM";
30850
+ }
30851
+ }
30852
+ function sleep7(ms) {
30853
+ return new Promise((resolve19) => setTimeout(resolve19, ms));
30854
+ }
30855
+ function readLockMeta2(lockPath) {
30856
+ try {
30857
+ const raw = fs62.readFileSync(lockPath, "utf-8");
30858
+ const parsed = JSON.parse(raw);
30859
+ if (typeof parsed?.pid === "number" && typeof parsed?.hostname === "string" && typeof parsed?.timestamp === "number") {
30860
+ return parsed;
30861
+ }
30862
+ } catch {
30863
+ }
30864
+ return void 0;
30865
+ }
30866
+ var MAX_STEAL_ATTEMPTS = 3;
30867
+ function isLockStale2(meta, opts) {
30868
+ const ageMs = opts.now - meta.timestamp;
30869
+ if (ageMs < opts.staleLockMs / 2)
30870
+ return false;
30871
+ if (meta.hostname !== os36.hostname()) {
30872
+ return ageMs > opts.staleLockMs * 2;
30873
+ }
30874
+ if (!opts.isPidAlive(meta.pid))
30875
+ return true;
30876
+ return ageMs > opts.staleLockMs;
30877
+ }
30878
+ function tryAcquireOnce2(lockPath, meta, opts) {
30879
+ for (let attempt = 0; attempt <= MAX_STEAL_ATTEMPTS; attempt += 1) {
30880
+ try {
30881
+ fs62.mkdirSync(path64.dirname(lockPath), { recursive: true });
30882
+ const fd = fs62.openSync(lockPath, "wx", 384);
30883
+ try {
30884
+ fs62.writeSync(fd, JSON.stringify(meta));
30885
+ } finally {
30886
+ fs62.closeSync(fd);
30887
+ }
30888
+ return true;
30889
+ } catch (err) {
30890
+ const code = err.code;
30891
+ if (code !== "EEXIST")
30892
+ throw err;
30893
+ }
30894
+ if (attempt >= MAX_STEAL_ATTEMPTS) {
30895
+ return false;
30896
+ }
30897
+ const existing = readLockMeta2(lockPath);
30898
+ const isStale = existing === void 0 || isLockStale2(existing, opts);
30899
+ if (!isStale) {
30900
+ return false;
30901
+ }
30902
+ const victimPath = `${lockPath}.victim-${process.pid}-${attempt}-${Date.now()}`;
30903
+ try {
30904
+ fs62.renameSync(lockPath, victimPath);
30905
+ try {
30906
+ fs62.unlinkSync(victimPath);
30907
+ } catch {
30908
+ }
30909
+ } catch (err) {
30910
+ const code = err.code;
30911
+ if (code !== "ENOENT")
30912
+ throw err;
30913
+ }
30914
+ }
30915
+ return false;
30916
+ }
30917
+ async function acquireSettingsJsonLock(options = {}) {
30918
+ const lockPath = options.lockPath ?? defaultSettingsJsonLockPath();
30919
+ const acquireTimeoutMs = options.acquireTimeoutMs ?? DEFAULT_ACQUIRE_TIMEOUT_MS2;
30920
+ const staleLockMs = options.staleLockMs ?? DEFAULT_STALE_LOCK_MS2;
30921
+ const now = options.now ?? Date.now;
30922
+ const isPidAlive4 = options.isPidAlive ?? defaultIsPidAlive2;
30923
+ const deadline = now() + acquireTimeoutMs;
30924
+ let backoffMs = 25;
30925
+ while (true) {
30926
+ const meta = {
30927
+ pid: process.pid,
30928
+ hostname: os36.hostname(),
30929
+ timestamp: now(),
30930
+ ...options.reason ? { reason: options.reason } : {}
30931
+ };
30932
+ const acquired = tryAcquireOnce2(lockPath, meta, { now: now(), staleLockMs, isPidAlive: isPidAlive4 });
30933
+ if (acquired) {
30934
+ return {
30935
+ lockPath,
30936
+ release: () => {
30937
+ try {
30938
+ fs62.unlinkSync(lockPath);
30939
+ } catch {
30940
+ }
30941
+ }
30942
+ };
30943
+ }
30944
+ if (now() >= deadline) {
30945
+ const existing = readLockMeta2(lockPath);
30946
+ const held = existing ? `(held by pid ${existing.pid} on ${existing.hostname}, since ${new Date(existing.timestamp).toISOString()})` : "(holder unknown)";
30947
+ throw new SettingsJsonLockError(`failed to acquire settings.json lock at ${lockPath} within ${acquireTimeoutMs}ms ${held}`);
30948
+ }
30949
+ await sleep7(Math.min(backoffMs, 200));
30950
+ backoffMs = Math.min(backoffMs * 2, 200);
30951
+ }
30952
+ }
30953
+ async function withSettingsJsonLock(fn, options) {
30954
+ const { release: release2 } = await acquireSettingsJsonLock(options);
30955
+ try {
30956
+ return await fn();
30957
+ } finally {
30958
+ release2();
30959
+ }
30960
+ }
30961
+
30962
+ // ../core/dist/services-status/memory-probe.js
30963
+ var DEFAULT_TIMEOUT_MS4 = 2e3;
30964
+ var DEFAULT_MEMORY_PORT = 3111;
30965
+ var DEFAULT_HEALTH_PATH = "/agentmemory/livez";
30966
+ async function probeMemoryBridge(opts = {}) {
30967
+ const port2 = opts.port ?? DEFAULT_MEMORY_PORT;
30968
+ const healthPath = opts.healthPath ?? DEFAULT_HEALTH_PATH;
30969
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS4;
30970
+ const url2 = `http://127.0.0.1:${port2}${healthPath}`;
30971
+ const t0 = Date.now();
30972
+ try {
30973
+ const res = await fetch(url2, {
30974
+ signal: AbortSignal.timeout(timeoutMs),
30975
+ // CP3 LOW fix: refuse to follow redirects. A local attacker
30976
+ // controlling the bridge port (or a misconfigured bridge
30977
+ // returning 3xx) could redirect to an external URL; default
30978
+ // `redirect: 'follow'` would leak timing + reachability.
30979
+ redirect: "error"
30980
+ });
30981
+ await res.text().catch(() => "");
30982
+ const latencyMs = Date.now() - t0;
30983
+ if (res.ok) {
30984
+ return { up: true, latencyMs };
30985
+ }
30986
+ return {
30987
+ up: false,
30988
+ latencyMs,
30989
+ detail: `http ${res.status}`
30990
+ };
30991
+ } catch (err) {
30992
+ const latencyMs = Date.now() - t0;
30993
+ const code = err?.code;
30994
+ const name = err?.name;
30995
+ if (name === "AbortError" || name === "TimeoutError") {
30996
+ return { up: false, latencyMs, detail: `timeout after ${timeoutMs}ms` };
30997
+ }
30998
+ if (code === "ECONNREFUSED") {
30999
+ return { up: false, latencyMs, detail: "connection refused (bridge not running)" };
31000
+ }
31001
+ return {
31002
+ up: false,
31003
+ latencyMs,
31004
+ detail: err instanceof Error ? err.message : String(err)
31005
+ };
31006
+ }
31007
+ }
31008
+
31009
+ // ../core/dist/skill-sources/meta-hooks-migration-snapshot.js
31010
+ init_v3();
31011
+ import * as crypto9 from "node:crypto";
31012
+ import * as fs63 from "node:fs";
31013
+ import * as os37 from "node:os";
31014
+ import * as path65 from "node:path";
31015
+ var META_HOOKS_SNAPSHOT_SCHEMA_VERSION = 1;
31016
+ var META_HOOKS_SNAPSHOT_PREFIX = "meta-hooks-";
31017
+ var SettingsLooseSchema = external_exports.record(external_exports.unknown());
31018
+ var MetaHooksMigrationSnapshotSchema = external_exports.object({
31019
+ schemaVersion: external_exports.literal(META_HOOKS_SNAPSHOT_SCHEMA_VERSION),
31020
+ takenAt: external_exports.string().min(1),
31021
+ namespace: external_exports.literal("meta-hooks"),
31022
+ /**
31023
+ * Full settings.json content captured before injection. Reverting
31024
+ * writes this back verbatim. May be `null` when no settings.json
31025
+ * existed pre-injection (operator's first sync wrote a fresh one);
31026
+ * revert in that case deletes the file.
31027
+ */
31028
+ originalSettings: external_exports.union([SettingsLooseSchema, external_exports.null()])
31029
+ });
31030
+ function migrationSnapshotsDir2() {
31031
+ const override = process.env["OLAM_MIGRATION_SNAPSHOTS_DIR"];
31032
+ if (override && override.length > 0)
31033
+ return override;
31034
+ return path65.join(os37.homedir(), ".olam", "state", "migration-snapshots");
31035
+ }
31036
+ function writeMetaHooksSnapshot(originalSettings) {
31037
+ const snapshot = {
31038
+ schemaVersion: META_HOOKS_SNAPSHOT_SCHEMA_VERSION,
31039
+ takenAt: (/* @__PURE__ */ new Date()).toISOString(),
31040
+ namespace: "meta-hooks",
31041
+ originalSettings
31042
+ };
31043
+ const validated = MetaHooksMigrationSnapshotSchema.parse(snapshot);
31044
+ const dir = migrationSnapshotsDir2();
31045
+ fs63.mkdirSync(dir, { recursive: true });
31046
+ const stamp = validated.takenAt.replace(/[:.]/g, "-");
31047
+ const rand = crypto9.randomBytes(3).toString("hex");
31048
+ const file = path65.join(dir, `${META_HOOKS_SNAPSHOT_PREFIX}${stamp}-${process.pid}-${rand}.json`);
31049
+ fs63.writeFileSync(file, JSON.stringify(validated, null, 2) + "\n", { mode: 384 });
31050
+ return file;
31051
+ }
31052
+ function readMetaHooksSnapshot(filePath) {
31053
+ if (!fs63.existsSync(filePath)) {
31054
+ throw new Error(`snapshot file not found: ${filePath}`);
31055
+ }
31056
+ const raw = fs63.readFileSync(filePath, "utf-8");
31057
+ const parsed = JSON.parse(raw);
31058
+ return MetaHooksMigrationSnapshotSchema.parse(parsed);
31059
+ }
31060
+ function findLatestMetaHooksSnapshot() {
31061
+ const dir = migrationSnapshotsDir2();
31062
+ if (!fs63.existsSync(dir))
31063
+ return void 0;
31064
+ const candidates2 = fs63.readdirSync(dir).filter((n) => n.startsWith(META_HOOKS_SNAPSHOT_PREFIX) && n.endsWith(".json")).sort().reverse();
31065
+ if (candidates2.length === 0)
31066
+ return void 0;
31067
+ return path65.join(dir, candidates2[0]);
31068
+ }
31069
+ function restoreSettingsFromSnapshot(snapshot, settingsPath) {
31070
+ if (snapshot.originalSettings === null) {
31071
+ if (fs63.existsSync(settingsPath)) {
31072
+ fs63.unlinkSync(settingsPath);
31073
+ }
31074
+ return;
31075
+ }
31076
+ fs63.mkdirSync(path65.dirname(settingsPath), { recursive: true });
31077
+ const tmp = `${settingsPath}.tmp-restore-${process.pid}-${Date.now()}`;
31078
+ fs63.writeFileSync(tmp, JSON.stringify(snapshot.originalSettings, null, 2) + "\n");
31079
+ fs63.renameSync(tmp, settingsPath);
31080
+ }
31081
+
31082
+ // ../core/dist/skill-sync/atlas-hook-strip.js
31083
+ var AGENTMEMORY_SCRIPT_PATTERNS = [
31084
+ "agentmemory-recall-trigger.mjs",
31085
+ "agentmemory-classify-queue.mjs"
31086
+ ];
31087
+ var OLAM_META_SENTINELS_GUARDED = [
31088
+ OLAM_META_MEMORY_RECALL_SENTINEL,
31089
+ OLAM_META_MEMORY_CLASSIFY_SENTINEL
31090
+ ];
31091
+ function isStripCommand(command) {
31092
+ for (const sentinel of OLAM_META_SENTINELS_GUARDED) {
31093
+ if (command.includes(sentinel))
31094
+ return { match: false };
31095
+ }
31096
+ for (const pattern of AGENTMEMORY_SCRIPT_PATTERNS) {
31097
+ if (command.includes(pattern))
31098
+ return { match: true, pattern };
31099
+ }
31100
+ return { match: false };
31101
+ }
31102
+ function findStripCandidates(settings) {
31103
+ const stages = ["PreToolUse", "PostToolUse"];
31104
+ const out = [];
31105
+ for (const stage of stages) {
31106
+ const matchers = settings.hooks?.[stage];
31107
+ if (!Array.isArray(matchers))
31108
+ continue;
31109
+ for (let mi = 0; mi < matchers.length; mi += 1) {
31110
+ const matcher = matchers[mi];
31111
+ const inner = Array.isArray(matcher.hooks) ? matcher.hooks : [];
31112
+ for (let ii = 0; ii < inner.length; ii += 1) {
31113
+ const cmd = inner[ii]?.command;
31114
+ if (typeof cmd !== "string")
31115
+ continue;
31116
+ const verdict = isStripCommand(cmd);
31117
+ if (verdict.match) {
31118
+ out.push({
31119
+ stage,
31120
+ matcherIndex: mi,
31121
+ innerIndex: ii,
31122
+ command: cmd,
31123
+ matcher: matcher.matcher,
31124
+ matchedPattern: verdict.pattern
31125
+ });
31126
+ }
31127
+ }
31128
+ }
31129
+ }
31130
+ return out;
31131
+ }
31132
+ function applyStrip(settings, candidates2) {
31133
+ if (candidates2.length === 0) {
31134
+ return { nextSettings: settings, removedCount: 0 };
31135
+ }
31136
+ const stripByStageMatcher = /* @__PURE__ */ new Map();
31137
+ for (const c of candidates2) {
31138
+ const key = `${c.stage}:${c.matcherIndex}`;
31139
+ if (!stripByStageMatcher.has(key))
31140
+ stripByStageMatcher.set(key, /* @__PURE__ */ new Set());
31141
+ stripByStageMatcher.get(key).add(c.innerIndex);
31142
+ }
31143
+ const nextHooks = { ...settings.hooks ?? {} };
31144
+ const stages = ["PreToolUse", "PostToolUse"];
31145
+ for (const stage of stages) {
31146
+ const matchers = settings.hooks?.[stage];
31147
+ if (!Array.isArray(matchers))
31148
+ continue;
31149
+ const nextMatchers = [];
31150
+ for (let mi = 0; mi < matchers.length; mi += 1) {
31151
+ const matcher = matchers[mi];
31152
+ const innerHooks = Array.isArray(matcher.hooks) ? matcher.hooks : [];
31153
+ const stripIdx = stripByStageMatcher.get(`${stage}:${mi}`);
31154
+ const keptInner = stripIdx === void 0 ? innerHooks : innerHooks.filter((_, ii) => !stripIdx.has(ii));
31155
+ if (keptInner.length === innerHooks.length) {
31156
+ nextMatchers.push(matcher);
31157
+ } else if (keptInner.length === 0) {
31158
+ } else {
31159
+ nextMatchers.push({ ...matcher, hooks: keptInner });
31160
+ }
31161
+ }
31162
+ if (nextMatchers.length === 0) {
31163
+ delete nextHooks[stage];
31164
+ } else {
31165
+ nextHooks[stage] = nextMatchers;
31166
+ }
31167
+ }
31168
+ const next = { ...settings };
31169
+ if (Object.keys(nextHooks).length === 0) {
31170
+ delete next.hooks;
31171
+ } else {
31172
+ next.hooks = nextHooks;
31173
+ }
31174
+ return { nextSettings: next, removedCount: candidates2.length };
31175
+ }
31176
+
31177
+ // ../core/dist/skill-sync/meta-hook-injector.js
31178
+ function decideTargetBlocks(opts) {
31179
+ const mode = opts.mode ?? "auto";
31180
+ const disabled = new Set(opts.disabledBlocks ?? []);
31181
+ if (mode === "never")
31182
+ return /* @__PURE__ */ new Set();
31183
+ const wantMemory = mode === "always" || opts.servicesStatus.memory;
31184
+ const target = /* @__PURE__ */ new Set();
31185
+ if (wantMemory && !disabled.has("memory-recall"))
31186
+ target.add("memory-recall");
31187
+ if (wantMemory && !disabled.has("memory-classify"))
31188
+ target.add("memory-classify");
31189
+ return target;
31190
+ }
31191
+ function injectMetaHooks(opts) {
31192
+ const target = decideTargetBlocks(opts);
31193
+ let working = JSON.parse(JSON.stringify(opts.currentSettings ?? {}));
31194
+ const blocksAdded = [];
31195
+ const blocksRemoved = [];
31196
+ const memoryRecallPresent = hasMemoryRecallBlock(working);
31197
+ if (target.has("memory-recall")) {
31198
+ if (!memoryRecallPresent) {
31199
+ working = appendBlock(working, OLAM_META_MEMORY_RECALL_STAGE, buildMemoryRecallHookEntry());
31200
+ blocksAdded.push("memory-recall");
31201
+ }
31202
+ } else {
31203
+ if (memoryRecallPresent) {
31204
+ const r = computeMemoryRecallUninstall(working);
31205
+ if (r.status === "removed" && r.settingsAfter) {
31206
+ working = r.settingsAfter;
31207
+ blocksRemoved.push("memory-recall");
31208
+ }
31209
+ }
31210
+ }
31211
+ const memoryClassifyPresent = hasMemoryClassifyBlock(working);
31212
+ if (target.has("memory-classify")) {
31213
+ if (!memoryClassifyPresent) {
31214
+ working = appendBlock(working, OLAM_META_MEMORY_CLASSIFY_STAGE, buildMemoryClassifyHookEntry());
31215
+ blocksAdded.push("memory-classify");
31216
+ }
31217
+ } else {
31218
+ if (memoryClassifyPresent) {
31219
+ const r = computeMemoryClassifyUninstall(working);
31220
+ if (r.status === "removed" && r.settingsAfter) {
31221
+ working = r.settingsAfter;
31222
+ blocksRemoved.push("memory-classify");
31223
+ }
31224
+ }
31225
+ }
31226
+ return {
31227
+ nextSettings: working,
31228
+ blocksAdded,
31229
+ blocksRemoved,
31230
+ mode: opts.mode ?? "auto"
31231
+ };
31232
+ }
31233
+ function hasMemoryRecallBlock(settings) {
31234
+ const entries = settings.hooks?.PreToolUse;
31235
+ if (!Array.isArray(entries))
31236
+ return false;
31237
+ for (const matcher of entries) {
31238
+ const inner = matcher?.hooks ?? [];
31239
+ if (!Array.isArray(inner))
31240
+ continue;
31241
+ for (const h of inner) {
31242
+ if (typeof h?.command === "string" && matchMemoryRecallSentinel(h.command))
31243
+ return true;
31244
+ }
31245
+ }
31246
+ return false;
31247
+ }
31248
+ function hasMemoryClassifyBlock(settings) {
31249
+ const entries = settings.hooks?.PostToolUse;
31250
+ if (!Array.isArray(entries))
31251
+ return false;
31252
+ for (const matcher of entries) {
31253
+ const inner = matcher?.hooks ?? [];
31254
+ if (!Array.isArray(inner))
31255
+ continue;
31256
+ for (const h of inner) {
31257
+ if (typeof h?.command === "string" && matchMemoryClassifySentinel(h.command))
31258
+ return true;
31259
+ }
31260
+ }
31261
+ return false;
31262
+ }
31263
+ function appendBlock(settings, stage, entry) {
31264
+ const next = { ...settings };
31265
+ const hooks = { ...settings.hooks ?? {} };
31266
+ const stageEntries = Array.isArray(hooks[stage]) ? [...hooks[stage]] : [];
31267
+ stageEntries.push(entry);
31268
+ hooks[stage] = stageEntries;
31269
+ next.hooks = hooks;
31270
+ return next;
31271
+ }
31272
+
31273
+ // ../core/dist/skill-sync/engine.js
31274
+ import * as fs64 from "node:fs";
31275
+ import * as os38 from "node:os";
31276
+ import * as path66 from "node:path";
30622
31277
  function resolveAtlasUser(override) {
30623
31278
  if (override)
30624
31279
  return override;
30625
- const claudeDir2 = process.env["OLAM_CLAUDE_DIR"] || path64.join(os36.homedir(), ".claude");
30626
- const f = path64.join(claudeDir2, ".atlas-user");
30627
- if (fs60.existsSync(f)) {
30628
- return fs60.readFileSync(f, "utf-8").trim() || void 0;
31280
+ const claudeDir2 = process.env["OLAM_CLAUDE_DIR"] || path66.join(os38.homedir(), ".claude");
31281
+ const f = path66.join(claudeDir2, ".atlas-user");
31282
+ if (fs64.existsSync(f)) {
31283
+ return fs64.readFileSync(f, "utf-8").trim() || void 0;
30629
31284
  }
30630
31285
  return void 0;
30631
31286
  }
@@ -30637,7 +31292,7 @@ async function syncSkills(opts = {}) {
30637
31292
  const perSource = [];
30638
31293
  for (const source of sources) {
30639
31294
  const clonePath = skillSourceClonePath(source.id);
30640
- if (!fs60.existsSync(clonePath))
31295
+ if (!fs64.existsSync(clonePath))
30641
31296
  continue;
30642
31297
  const { artifacts, subscription } = await withSourceLock(clonePath, () => {
30643
31298
  const pinRef = projectOverride?.override.pin?.[source.id];
@@ -30673,6 +31328,7 @@ async function syncSkills(opts = {}) {
30673
31328
  projectOverride,
30674
31329
  deploy: void 0,
30675
31330
  merge: void 0,
31331
+ metaHooks: void 0,
30676
31332
  perSource
30677
31333
  };
30678
31334
  if (opts.dryRun) {
@@ -30682,12 +31338,105 @@ async function syncSkills(opts = {}) {
30682
31338
  summary.deploy = deployArtifacts(projectFilteredArtifacts);
30683
31339
  summary.collisions = summary.deploy.collisions;
30684
31340
  summary.merge = mergeSettings({ hookFiles, permissionFiles });
31341
+ if (opts.metaHooks !== "never") {
31342
+ summary.metaHooks = await injectMetaHooksIntoSettings(opts);
31343
+ }
30685
31344
  return summary;
30686
31345
  }
31346
+ async function injectMetaHooksIntoSettings(opts) {
31347
+ const mode = opts.metaHooks ?? "auto";
31348
+ const memoryProbe = await probeMemoryBridge();
31349
+ const servicesStatus2 = {
31350
+ memory: memoryProbe.up,
31351
+ ...memoryProbe.detail !== void 0 ? { memoryDetail: memoryProbe.detail } : {}
31352
+ };
31353
+ const settingsFile = claudeSettingsPath();
31354
+ let snapshotError;
31355
+ let stripCandidates = [];
31356
+ const result = await withSettingsJsonLock(() => {
31357
+ let currentSettings = {};
31358
+ let settingsExisted = false;
31359
+ if (fs64.existsSync(settingsFile)) {
31360
+ settingsExisted = true;
31361
+ try {
31362
+ const raw = fs64.readFileSync(settingsFile, "utf-8");
31363
+ currentSettings = raw.trim() ? JSON.parse(raw) : {};
31364
+ } catch {
31365
+ try {
31366
+ const raw = fs64.readFileSync(settingsFile);
31367
+ const bakDir = path66.join(path66.dirname(settingsFile), ".malformed-backups");
31368
+ fs64.mkdirSync(bakDir, { recursive: true });
31369
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
31370
+ const bakFile = path66.join(bakDir, `settings.json.malformed.${stamp}.bak`);
31371
+ fs64.writeFileSync(bakFile, raw, { mode: 384 });
31372
+ snapshotError = `settings.json was malformed; original bytes preserved at ${bakFile}`;
31373
+ } catch (bakErr) {
31374
+ snapshotError = `settings.json malformed AND .bak write failed: ${bakErr instanceof Error ? bakErr.message : String(bakErr)}`;
31375
+ }
31376
+ currentSettings = {};
31377
+ settingsExisted = false;
31378
+ }
31379
+ }
31380
+ stripCandidates = findStripCandidates(currentSettings);
31381
+ const settingsForInject = stripCandidates.length > 0 ? applyStrip(currentSettings, stripCandidates).nextSettings : currentSettings;
31382
+ let configDisabled = [];
31383
+ try {
31384
+ const cfg = readGlobalConfig();
31385
+ configDisabled = cfg.metaHooksDisabled ?? [];
31386
+ } catch {
31387
+ }
31388
+ const disabledBlocks = Array.from(/* @__PURE__ */ new Set([
31389
+ ...configDisabled,
31390
+ ...opts.metaHooksDisabled ?? []
31391
+ ]));
31392
+ const inject = injectMetaHooks({
31393
+ servicesStatus: servicesStatus2,
31394
+ currentSettings: settingsForInject,
31395
+ mode,
31396
+ ...disabledBlocks.length > 0 ? { disabledBlocks } : {}
31397
+ });
31398
+ const noInjectDelta = inject.blocksAdded.length === 0 && inject.blocksRemoved.length === 0;
31399
+ const noStripDelta = stripCandidates.length === 0;
31400
+ if (noInjectDelta && noStripDelta) {
31401
+ return inject;
31402
+ }
31403
+ let snapshotPath;
31404
+ try {
31405
+ snapshotPath = writeMetaHooksSnapshot(settingsExisted ? currentSettings : null);
31406
+ } catch (err) {
31407
+ snapshotError = err instanceof Error ? err.message : String(err);
31408
+ }
31409
+ if (stripCandidates.length > 0) {
31410
+ try {
31411
+ appendTrustAudit({
31412
+ gitUrl: "internal:olam-meta-hooks",
31413
+ action: "meta-hook-stripped",
31414
+ trustMethod: "none",
31415
+ sourceId: "atlas-toolbox",
31416
+ note: `auto-migration during syncSkills stripped ${stripCandidates.length} agentmemory hook entry(ies)${snapshotPath ? `; snapshot at ${snapshotPath}` : ""}`
31417
+ });
31418
+ } catch {
31419
+ }
31420
+ }
31421
+ fs64.mkdirSync(path66.dirname(settingsFile), { recursive: true });
31422
+ const tmpPath = `${settingsFile}.tmp-${process.pid}-${Date.now()}`;
31423
+ fs64.writeFileSync(tmpPath, JSON.stringify(inject.nextSettings, null, 2) + "\n");
31424
+ fs64.renameSync(tmpPath, settingsFile);
31425
+ return inject;
31426
+ }, { reason: `syncSkills meta-hook injection (mode=${mode})` });
31427
+ return {
31428
+ mode: result.mode,
31429
+ servicesStatus: servicesStatus2,
31430
+ blocksAdded: result.blocksAdded,
31431
+ blocksRemoved: result.blocksRemoved,
31432
+ ...snapshotError !== void 0 ? { snapshotError } : {},
31433
+ ...stripCandidates.length > 0 ? { autoMigrated: { strippedCount: stripCandidates.length, stripCandidates } } : {}
31434
+ };
31435
+ }
30687
31436
 
30688
31437
  // ../core/dist/skill-sync/shadow-backup-manager.js
30689
- import * as fs61 from "node:fs";
30690
- import * as path65 from "node:path";
31438
+ import * as fs65 from "node:fs";
31439
+ import * as path67 from "node:path";
30691
31440
  var SHADOW_BACKUP_BUCKETS = ["commands", "agents", "skills", "scripts", "rules"];
30692
31441
  var SHADOW_BACKUP_SUFFIX_RE = /\.shadow-backup-(\d+)$/;
30693
31442
  function listShadowBackups(opts = {}) {
@@ -30695,12 +31444,12 @@ function listShadowBackups(opts = {}) {
30695
31444
  const now = opts.now ?? Date.now();
30696
31445
  const out = [];
30697
31446
  for (const bucket of SHADOW_BACKUP_BUCKETS) {
30698
- const bucketDir = path65.join(claude, bucket);
30699
- if (!fs61.existsSync(bucketDir))
31447
+ const bucketDir = path67.join(claude, bucket);
31448
+ if (!fs65.existsSync(bucketDir))
30700
31449
  continue;
30701
31450
  let entries;
30702
31451
  try {
30703
- entries = fs61.readdirSync(bucketDir);
31452
+ entries = fs65.readdirSync(bucketDir);
30704
31453
  } catch {
30705
31454
  continue;
30706
31455
  }
@@ -30711,10 +31460,10 @@ function listShadowBackups(opts = {}) {
30711
31460
  const epochSeconds = Number.parseInt(match2[1], 10);
30712
31461
  if (!Number.isFinite(epochSeconds) || epochSeconds < 0)
30713
31462
  continue;
30714
- const full = path65.join(bucketDir, name);
31463
+ const full = path67.join(bucketDir, name);
30715
31464
  let sizeBytes = 0;
30716
31465
  try {
30717
- const st = fs61.statSync(full);
31466
+ const st = fs65.statSync(full);
30718
31467
  if (st.isDirectory())
30719
31468
  continue;
30720
31469
  sizeBytes = st.size;
@@ -30727,7 +31476,7 @@ function listShadowBackups(opts = {}) {
30727
31476
  bucket,
30728
31477
  basename: name,
30729
31478
  originalBasename,
30730
- originalPath: path65.join(bucketDir, originalBasename),
31479
+ originalPath: path67.join(bucketDir, originalBasename),
30731
31480
  epochSeconds,
30732
31481
  ageMs: now - epochSeconds * 1e3,
30733
31482
  sizeBytes
@@ -30770,7 +31519,7 @@ function pruneShadowBackups(opts) {
30770
31519
  }
30771
31520
  if (!opts.dryRun) {
30772
31521
  try {
30773
- fs61.unlinkSync(b.path);
31522
+ fs65.unlinkSync(b.path);
30774
31523
  } catch {
30775
31524
  skipped.push(b);
30776
31525
  continue;
@@ -30781,38 +31530,38 @@ function pruneShadowBackups(opts) {
30781
31530
  return { deleted, skipped };
30782
31531
  }
30783
31532
  function restoreShadowBackup(opts) {
30784
- const abs = path65.resolve(opts.backupPath);
30785
- if (!fs61.existsSync(abs)) {
31533
+ const abs = path67.resolve(opts.backupPath);
31534
+ if (!fs65.existsSync(abs)) {
30786
31535
  throw new Error(`backup file not found: ${abs}`);
30787
31536
  }
30788
- const basename11 = path65.basename(abs);
30789
- const match2 = SHADOW_BACKUP_SUFFIX_RE.exec(basename11);
31537
+ const basename12 = path67.basename(abs);
31538
+ const match2 = SHADOW_BACKUP_SUFFIX_RE.exec(basename12);
30790
31539
  if (!match2) {
30791
- throw new Error(`not a shadow-backup file (basename "${basename11}" does not match \`.shadow-backup-<epoch>\`): ${abs}`);
31540
+ throw new Error(`not a shadow-backup file (basename "${basename12}" does not match \`.shadow-backup-<epoch>\`): ${abs}`);
30792
31541
  }
30793
- const originalBasename = basename11.slice(0, basename11.length - match2[0].length);
30794
- const originalPath = path65.join(path65.dirname(abs), originalBasename);
30795
- if (fs61.existsSync(originalPath) && !opts.force) {
31542
+ const originalBasename = basename12.slice(0, basename12.length - match2[0].length);
31543
+ const originalPath = path67.join(path67.dirname(abs), originalBasename);
31544
+ if (fs65.existsSync(originalPath) && !opts.force) {
30796
31545
  throw new Error(`original path already occupied: ${originalPath}. Move/rename it first OR re-run with --force.`);
30797
31546
  }
30798
- if (opts.force && fs61.existsSync(originalPath)) {
30799
- fs61.unlinkSync(originalPath);
31547
+ if (opts.force && fs65.existsSync(originalPath)) {
31548
+ fs65.unlinkSync(originalPath);
30800
31549
  }
30801
- fs61.renameSync(abs, originalPath);
31550
+ fs65.renameSync(abs, originalPath);
30802
31551
  return { restoredTo: originalPath };
30803
31552
  }
30804
31553
 
30805
31554
  // ../core/dist/skill-sources/doctor-checks.js
30806
31555
  init_v3();
30807
- import * as fs62 from "node:fs";
30808
- import * as path66 from "node:path";
30809
- import * as os37 from "node:os";
31556
+ import * as fs66 from "node:fs";
31557
+ import * as path68 from "node:path";
31558
+ import * as os39 from "node:os";
30810
31559
  init_schema4();
30811
31560
  function claudeDirInternal3() {
30812
31561
  const override = process.env["OLAM_CLAUDE_DIR"];
30813
31562
  if (override && override.length > 0)
30814
31563
  return override;
30815
- return path66.join(os37.homedir(), ".claude");
31564
+ return path68.join(os39.homedir(), ".claude");
30816
31565
  }
30817
31566
  function checkStateFileParse() {
30818
31567
  const filePath = globalConfigPath();
@@ -30821,11 +31570,11 @@ function checkStateFileParse() {
30821
31570
  healthy: true,
30822
31571
  description: `~/.olam state file (${filePath})`
30823
31572
  };
30824
- if (!fs62.existsSync(filePath)) {
31573
+ if (!fs66.existsSync(filePath)) {
30825
31574
  result.details = ["(file does not yet exist \u2014 will be created on first write)"];
30826
31575
  return result;
30827
31576
  }
30828
- const raw = fs62.readFileSync(filePath, "utf-8");
31577
+ const raw = fs66.readFileSync(filePath, "utf-8");
30829
31578
  let parsed;
30830
31579
  try {
30831
31580
  parsed = JSON.parse(raw);
@@ -30835,8 +31584,8 @@ function checkStateFileParse() {
30835
31584
  result.details = [err instanceof Error ? err.message : String(err)];
30836
31585
  result.repair = () => {
30837
31586
  const aside = `${filePath}.corrupt-${Math.floor(Date.now() / 1e3)}`;
30838
- fs62.renameSync(filePath, aside);
30839
- fs62.writeFileSync(filePath, JSON.stringify({ schemaVersion: 1, repos: [], runbooks: [], skillSources: [] }, null, 2));
31587
+ fs66.renameSync(filePath, aside);
31588
+ fs66.writeFileSync(filePath, JSON.stringify({ schemaVersion: 1, repos: [], runbooks: [], skillSources: [] }, null, 2));
30840
31589
  };
30841
31590
  return result;
30842
31591
  }
@@ -30847,7 +31596,7 @@ function checkStateFileParse() {
30847
31596
  result.details = validation.error.issues.map((e) => `${e.path.join(".")}: ${e.message}`);
30848
31597
  result.repair = () => {
30849
31598
  const aside = `${filePath}.corrupt-${Math.floor(Date.now() / 1e3)}`;
30850
- fs62.copyFileSync(filePath, aside);
31599
+ fs66.copyFileSync(filePath, aside);
30851
31600
  const base = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
30852
31601
  const next = {
30853
31602
  ...base,
@@ -30856,7 +31605,7 @@ function checkStateFileParse() {
30856
31605
  runbooks: [],
30857
31606
  skillSources: []
30858
31607
  };
30859
- fs62.writeFileSync(filePath, JSON.stringify(next, null, 2));
31608
+ fs66.writeFileSync(filePath, JSON.stringify(next, null, 2));
30860
31609
  };
30861
31610
  return result;
30862
31611
  }
@@ -30867,16 +31616,16 @@ function checkDanglingSymlinks() {
30867
31616
  const buckets = ["commands", "agents", "skills", "scripts", "rules"];
30868
31617
  const dangling = [];
30869
31618
  for (const bucket of buckets) {
30870
- const dir = path66.join(claude, bucket);
30871
- if (!fs62.existsSync(dir))
31619
+ const dir = path68.join(claude, bucket);
31620
+ if (!fs66.existsSync(dir))
30872
31621
  continue;
30873
- for (const name of fs62.readdirSync(dir)) {
30874
- const linkPath = path66.join(dir, name);
31622
+ for (const name of fs66.readdirSync(dir)) {
31623
+ const linkPath = path68.join(dir, name);
30875
31624
  try {
30876
- const lst = fs62.lstatSync(linkPath);
31625
+ const lst = fs66.lstatSync(linkPath);
30877
31626
  if (!lst.isSymbolicLink())
30878
31627
  continue;
30879
- if (!fs62.existsSync(linkPath)) {
31628
+ if (!fs66.existsSync(linkPath)) {
30880
31629
  dangling.push(linkPath);
30881
31630
  }
30882
31631
  } catch {
@@ -30894,7 +31643,7 @@ function checkDanglingSymlinks() {
30894
31643
  result.repair = () => {
30895
31644
  for (const p of dangling) {
30896
31645
  try {
30897
- fs62.unlinkSync(p);
31646
+ fs66.unlinkSync(p);
30898
31647
  } catch {
30899
31648
  }
30900
31649
  }
@@ -30913,19 +31662,19 @@ function checkOrphanedSnapshots() {
30913
31662
  healthy: true,
30914
31663
  description: `orphaned migration snapshots under ${dir}`
30915
31664
  };
30916
- if (!fs62.existsSync(dir)) {
31665
+ if (!fs66.existsSync(dir)) {
30917
31666
  return result;
30918
31667
  }
30919
31668
  const orphans = [];
30920
- for (const name of fs62.readdirSync(dir)) {
31669
+ for (const name of fs66.readdirSync(dir)) {
30921
31670
  if (!name.endsWith(".json"))
30922
31671
  continue;
30923
- const full = path66.join(dir, name);
31672
+ const full = path68.join(dir, name);
30924
31673
  try {
30925
- const stat = fs62.statSync(full);
31674
+ const stat = fs66.statSync(full);
30926
31675
  if (!stat.isFile())
30927
31676
  continue;
30928
- const raw = fs62.readFileSync(full, "utf-8");
31677
+ const raw = fs66.readFileSync(full, "utf-8");
30929
31678
  let parsed;
30930
31679
  try {
30931
31680
  parsed = JSON.parse(raw);
@@ -30950,7 +31699,7 @@ function checkOrphanedSnapshots() {
30950
31699
  result.repair = () => {
30951
31700
  for (const o of orphans) {
30952
31701
  try {
30953
- fs62.unlinkSync(o.path);
31702
+ fs66.unlinkSync(o.path);
30954
31703
  } catch {
30955
31704
  }
30956
31705
  }
@@ -30965,12 +31714,12 @@ function checkSentinelDrift() {
30965
31714
  healthy: true,
30966
31715
  description: `olam-skills sentinel block in ${filePath}`
30967
31716
  };
30968
- if (!fs62.existsSync(filePath)) {
31717
+ if (!fs66.existsSync(filePath)) {
30969
31718
  return result;
30970
31719
  }
30971
31720
  let parsed;
30972
31721
  try {
30973
- parsed = JSON.parse(fs62.readFileSync(filePath, "utf-8"));
31722
+ parsed = JSON.parse(fs66.readFileSync(filePath, "utf-8"));
30974
31723
  } catch {
30975
31724
  return result;
30976
31725
  }
@@ -31011,7 +31760,7 @@ function checkSentinelDrift() {
31011
31760
  backupSettings();
31012
31761
  } catch {
31013
31762
  }
31014
- const next = JSON.parse(fs62.readFileSync(filePath, "utf-8"));
31763
+ const next = JSON.parse(fs66.readFileSync(filePath, "utf-8"));
31015
31764
  if (!next.hooks)
31016
31765
  return;
31017
31766
  for (const stage of Object.keys(next.hooks)) {
@@ -31034,7 +31783,7 @@ function checkSentinelDrift() {
31034
31783
  return bad === void 0;
31035
31784
  });
31036
31785
  }
31037
- fs62.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
31786
+ fs66.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
31038
31787
  };
31039
31788
  }
31040
31789
  return result;
@@ -31056,14 +31805,14 @@ function registerConfig(program2) {
31056
31805
  const config = program2.command("config").description("Manage global olam configuration");
31057
31806
  config.command("validate [path]").description("Validate ~/.olam/config.json (or a custom path) against the schema").action((filePath) => {
31058
31807
  const resolvedPath = filePath ?? globalConfigPath();
31059
- if (!fs63.existsSync(resolvedPath)) {
31808
+ if (!fs67.existsSync(resolvedPath)) {
31060
31809
  process.stderr.write(`config file not found: ${resolvedPath}
31061
31810
  `);
31062
31811
  process.exit(1);
31063
31812
  }
31064
31813
  let raw;
31065
31814
  try {
31066
- raw = fs63.readFileSync(resolvedPath, "utf-8");
31815
+ raw = fs67.readFileSync(resolvedPath, "utf-8");
31067
31816
  } catch (err) {
31068
31817
  const msg = err instanceof Error ? err.message : String(err);
31069
31818
  process.stderr.write(`cannot read ${resolvedPath}: ${msg}
@@ -31336,7 +32085,7 @@ async function decideTrust(opts) {
31336
32085
  return { granted: yes, method: "interactive" };
31337
32086
  }
31338
32087
  function defaultTrustPrompt(gitUrl) {
31339
- return new Promise((resolve18) => {
32088
+ return new Promise((resolve19) => {
31340
32089
  const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
31341
32090
  process.stdout.write(
31342
32091
  `${pc30.yellow("Trust gate:")} register "${gitUrl}" as a skill source?
@@ -31346,12 +32095,12 @@ Type ${pc30.bold("y")} to add + trust, anything else to cancel: `
31346
32095
  );
31347
32096
  rl.question("", (a) => {
31348
32097
  rl.close();
31349
- resolve18(a);
32098
+ resolve19(a);
31350
32099
  });
31351
32100
  });
31352
32101
  }
31353
32102
  function defaultPostAddPrompt(input) {
31354
- return new Promise((resolve18) => {
32103
+ return new Promise((resolve19) => {
31355
32104
  const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
31356
32105
  process.stdout.write(`
31357
32106
  ${pc30.bold("Sync now?")} ${pc30.dim("[Y/n] ")}`);
@@ -31359,7 +32108,7 @@ ${pc30.bold("Sync now?")} ${pc30.dim("[Y/n] ")}`);
31359
32108
  const sync = !/^n(o)?$/i.test(syncAnswer.trim());
31360
32109
  if (input.hookAlreadyInstalled) {
31361
32110
  rl.close();
31362
- resolve18({ syncNow: sync, installHook: false });
32111
+ resolve19({ syncNow: sync, installHook: false });
31363
32112
  return;
31364
32113
  }
31365
32114
  process.stdout.write(
@@ -31368,7 +32117,7 @@ ${pc30.bold("Sync now?")} ${pc30.dim("[Y/n] ")}`);
31368
32117
  rl.question("", (hookAnswer) => {
31369
32118
  rl.close();
31370
32119
  const installHook = !/^n(o)?$/i.test(hookAnswer.trim());
31371
- resolve18({ syncNow: sync, installHook });
32120
+ resolve19({ syncNow: sync, installHook });
31372
32121
  });
31373
32122
  });
31374
32123
  });
@@ -31642,8 +32391,8 @@ function registerSkillsSource(program2) {
31642
32391
  }
31643
32392
 
31644
32393
  // src/commands/skills.ts
31645
- import * as fs64 from "node:fs";
31646
- import * as path67 from "node:path";
32394
+ import * as fs68 from "node:fs";
32395
+ import * as path69 from "node:path";
31647
32396
  import pc31 from "picocolors";
31648
32397
  init_output();
31649
32398
  function asMessage4(err) {
@@ -31657,14 +32406,14 @@ function listDeployed() {
31657
32406
  );
31658
32407
  const entries = [];
31659
32408
  for (const bucket of ["skills", "agents", "scripts", "rules", "commands"]) {
31660
- const bucketDir = path67.join(dir, bucket);
31661
- if (!fs64.existsSync(bucketDir)) continue;
31662
- for (const name of fs64.readdirSync(bucketDir)) {
31663
- const full = path67.join(bucketDir, name);
32409
+ const bucketDir = path69.join(dir, bucket);
32410
+ if (!fs68.existsSync(bucketDir)) continue;
32411
+ for (const name of fs68.readdirSync(bucketDir)) {
32412
+ const full = path69.join(bucketDir, name);
31664
32413
  try {
31665
- const stat = fs64.lstatSync(full);
32414
+ const stat = fs68.lstatSync(full);
31666
32415
  if (!stat.isSymbolicLink()) continue;
31667
- const target = fs64.readlinkSync(full);
32416
+ const target = fs68.readlinkSync(full);
31668
32417
  let sourceId;
31669
32418
  for (const [clonePath, id] of sourcePaths.entries()) {
31670
32419
  if (target.startsWith(clonePath)) {
@@ -31712,6 +32461,32 @@ function printSyncSummary(summary, dryRun) {
31712
32461
  if (summary.merge.backupPath) {
31713
32462
  console.log(` settings backup: ${pc31.dim(summary.merge.backupPath)}`);
31714
32463
  }
32464
+ if (summary.merge.dualWriteDeduped > 0) {
32465
+ console.log(` ${pc31.dim(`dual-write deduped: ${summary.merge.dualWriteDeduped} (atlas-shipped hook redundant with olam-meta block)`)}`);
32466
+ for (const cmd of summary.merge.dualWriteDroppedCommands) {
32467
+ console.log(` ${pc31.dim("(dropped)")} ${cmd.slice(0, 120)}${cmd.length > 120 ? "\u2026" : ""}`);
32468
+ }
32469
+ }
32470
+ }
32471
+ if (summary.metaHooks) {
32472
+ const mh = summary.metaHooks;
32473
+ const memLabel = mh.servicesStatus.memory ? pc31.green("up") : pc31.dim("down");
32474
+ console.log(` meta-hooks: mode=${mh.mode} \xB7 memory=${memLabel}${mh.servicesStatus.memoryDetail ? pc31.dim(` (${mh.servicesStatus.memoryDetail})`) : ""}`);
32475
+ if (mh.autoMigrated && mh.autoMigrated.strippedCount > 0) {
32476
+ console.log(
32477
+ ` ${pc31.cyan("~ auto-migrated:")} stripped ${mh.autoMigrated.strippedCount} atlas-toolbox-shipped agentmemory hook entry(ies); replaced by olam-injected blocks`
32478
+ );
32479
+ }
32480
+ if (mh.blocksAdded.length > 0) {
32481
+ console.log(` ${pc31.green("+ injected:")} ${mh.blocksAdded.join(", ")}`);
32482
+ }
32483
+ if (mh.blocksRemoved.length > 0) {
32484
+ console.log(` ${pc31.yellow("- stripped:")} ${mh.blocksRemoved.join(", ")}`);
32485
+ }
32486
+ if (mh.snapshotError) {
32487
+ console.log(` ${pc31.red("! snapshot FAILED:")} ${mh.snapshotError}`);
32488
+ console.log(` ${pc31.red(" (migrate-hooks-back will not be able to undo this sync)")}`);
32489
+ }
31715
32490
  }
31716
32491
  console.log();
31717
32492
  for (const s of summary.perSource) {
@@ -31721,9 +32496,23 @@ function printSyncSummary(summary, dryRun) {
31721
32496
  }
31722
32497
  function registerSkills(program2) {
31723
32498
  const skills = program2.commands.find((c) => c.name() === "skills") ?? program2.command("skills").description("Manage skill sources and synchronization");
31724
- skills.command("sync").description("Sync registered skill sources to ~/.claude/").option("--dry-run", "Resolve artifacts but do not deploy or merge").option("--atlas-user <user>", "Override atlas-user (defaults to ~/.claude/.atlas-user)").action(async (opts) => {
32499
+ skills.command("sync").description("Sync registered skill sources to ~/.claude/").option("--dry-run", "Resolve artifacts but do not deploy or merge").option("--atlas-user <user>", "Override atlas-user (defaults to ~/.claude/.atlas-user)").option(
32500
+ "--meta-hooks <mode>",
32501
+ 'olam-meta hook injection mode (B3): "auto" (default) \u2014 inject blocks for detected olam services; "always" \u2014 inject all blocks unconditionally; "never" \u2014 skip injection entirely',
32502
+ "auto"
32503
+ ).action(async (opts) => {
31725
32504
  try {
31726
- const summary = await syncSkills({ dryRun: opts.dryRun, atlasUser: opts.atlasUser });
32505
+ const validModes = ["auto", "always", "never"];
32506
+ if (opts.metaHooks && !validModes.includes(opts.metaHooks)) {
32507
+ printError(`--meta-hooks must be one of: ${validModes.join(", ")} (got "${opts.metaHooks}")`);
32508
+ process.exitCode = 1;
32509
+ return;
32510
+ }
32511
+ const summary = await syncSkills({
32512
+ dryRun: opts.dryRun,
32513
+ atlasUser: opts.atlasUser,
32514
+ metaHooks: opts.metaHooks ?? "auto"
32515
+ });
31727
32516
  printSyncSummary(summary, !!opts.dryRun);
31728
32517
  if (!opts.dryRun) {
31729
32518
  printSuccess(`synced ${summary.sourceCount} source(s), ${summary.artifactCount} artifact(s)`);
@@ -31783,12 +32572,12 @@ function registerSkills(program2) {
31783
32572
 
31784
32573
  // src/commands/skills-hook.ts
31785
32574
  init_output();
31786
- import * as fs65 from "node:fs";
32575
+ import * as fs69 from "node:fs";
31787
32576
  function backup(filePath) {
31788
- if (!fs65.existsSync(filePath)) return null;
32577
+ if (!fs69.existsSync(filePath)) return null;
31789
32578
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
31790
32579
  const backupPath = `${filePath}.olam-bak.${ts}`;
31791
- fs65.copyFileSync(filePath, backupPath);
32580
+ fs69.copyFileSync(filePath, backupPath);
31792
32581
  return backupPath;
31793
32582
  }
31794
32583
  function registerSkillsHook(program2) {
@@ -31836,7 +32625,7 @@ function registerSkillsHook(program2) {
31836
32625
  printInfo("olam-skills hook", `not found in ${filePath} \u2014 already uninstalled`);
31837
32626
  if (backupPath) {
31838
32627
  try {
31839
- fs65.unlinkSync(backupPath);
32628
+ fs69.unlinkSync(backupPath);
31840
32629
  } catch {
31841
32630
  }
31842
32631
  }
@@ -32013,25 +32802,25 @@ function registerSkillsOnboard(program2) {
32013
32802
  }
32014
32803
 
32015
32804
  // src/commands/skills-migrate.ts
32016
- import * as fs66 from "node:fs";
32017
- import * as path68 from "node:path";
32805
+ import * as fs70 from "node:fs";
32806
+ import * as path70 from "node:path";
32018
32807
  init_output();
32019
32808
  var MIGRATE_FROM_TOOLBOX_COMMAND = "migrate-from-toolbox";
32020
32809
  function asMessage6(err) {
32021
32810
  return err instanceof Error ? err.message : String(err);
32022
32811
  }
32023
32812
  function isOlamSkillsHookPresent(filePath) {
32024
- if (!fs66.existsSync(filePath)) return false;
32813
+ if (!fs70.existsSync(filePath)) return false;
32025
32814
  try {
32026
- const raw = fs66.readFileSync(filePath, "utf-8");
32815
+ const raw = fs70.readFileSync(filePath, "utf-8");
32027
32816
  return raw.includes(OLAM_SKILLS_HOOK_SENTINEL);
32028
32817
  } catch {
32029
32818
  return false;
32030
32819
  }
32031
32820
  }
32032
32821
  function uninstallLegacyToolboxSessionStartHook(filePath, toolboxPath) {
32033
- if (!fs66.existsSync(filePath)) return { removed: 0 };
32034
- const raw = fs66.readFileSync(filePath, "utf-8");
32822
+ if (!fs70.existsSync(filePath)) return { removed: 0 };
32823
+ const raw = fs70.readFileSync(filePath, "utf-8");
32035
32824
  const settings = raw.trim() ? JSON.parse(raw) : {};
32036
32825
  const ss = settings?.hooks?.SessionStart;
32037
32826
  if (!Array.isArray(ss)) return { removed: 0 };
@@ -32060,7 +32849,7 @@ function uninstallLegacyToolboxSessionStartHook(filePath, toolboxPath) {
32060
32849
  if (otherStages.length === 0) delete next.hooks;
32061
32850
  else delete next.hooks.SessionStart;
32062
32851
  }
32063
- fs66.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
32852
+ fs70.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
32064
32853
  return { removed };
32065
32854
  }
32066
32855
  function registerSkillsMigrate(program2) {
@@ -32083,7 +32872,7 @@ function registerSkillsMigrate(program2) {
32083
32872
  return;
32084
32873
  }
32085
32874
  const toolboxPath = opts.path;
32086
- const namespace = opts.namespace ?? path68.basename(toolboxPath);
32875
+ const namespace = opts.namespace ?? path70.basename(toolboxPath);
32087
32876
  const sourceName = opts.sourceName ?? namespace;
32088
32877
  const snapshot = detectToolboxState({ toolboxPath, namespace });
32089
32878
  if (!snapshot) {
@@ -32137,9 +32926,9 @@ function registerSkillsMigrate(program2) {
32137
32926
  printWarning(`legacy hook removal failed: ${asMessage6(err)}; proceeding`);
32138
32927
  }
32139
32928
  const scope = opts.scope === "user" ? "user" : "project";
32140
- const olamHookPath = scope === "user" ? settingsFile : path68.join(process.cwd(), ".claude", "settings.json");
32929
+ const olamHookPath = scope === "user" ? settingsFile : path70.join(process.cwd(), ".claude", "settings.json");
32141
32930
  try {
32142
- fs66.mkdirSync(path68.dirname(olamHookPath), { recursive: true });
32931
+ fs70.mkdirSync(path70.dirname(olamHookPath), { recursive: true });
32143
32932
  const result = mergeHomeSettingsJson(olamHookPath, {
32144
32933
  ensureHook: {
32145
32934
  stage: OLAM_SKILLS_HOOK_STAGE,
@@ -32170,8 +32959,8 @@ function registerSkillsMigrate(program2) {
32170
32959
  }
32171
32960
 
32172
32961
  // src/commands/skills-migrate-back.ts
32173
- import * as fs67 from "node:fs";
32174
- import * as path69 from "node:path";
32962
+ import * as fs71 from "node:fs";
32963
+ import * as path71 from "node:path";
32175
32964
  init_output();
32176
32965
  var MIGRATE_BACK_TO_TOOLBOX_COMMAND = "migrate-back-to-toolbox";
32177
32966
  function asMessage7(err) {
@@ -32180,16 +32969,16 @@ function asMessage7(err) {
32180
32969
  function claudeDirInternal4() {
32181
32970
  const override = process.env["OLAM_CLAUDE_DIR"];
32182
32971
  if (override && override.length > 0) return override;
32183
- return path69.join(process.env["HOME"] ?? "", ".claude");
32972
+ return path71.join(process.env["HOME"] ?? "", ".claude");
32184
32973
  }
32185
32974
  function restoreSessionStartFromSnapshot(filePath, originalSessionStartHook) {
32186
32975
  if (!originalSessionStartHook || originalSessionStartHook.length === 0) {
32187
32976
  return { restored: false };
32188
32977
  }
32189
32978
  let settings;
32190
- if (fs67.existsSync(filePath)) {
32979
+ if (fs71.existsSync(filePath)) {
32191
32980
  try {
32192
- const raw = fs67.readFileSync(filePath, "utf-8");
32981
+ const raw = fs71.readFileSync(filePath, "utf-8");
32193
32982
  settings = raw.trim() ? JSON.parse(raw) : {};
32194
32983
  } catch {
32195
32984
  settings = {};
@@ -32205,8 +32994,8 @@ function restoreSessionStartFromSnapshot(filePath, originalSessionStartHook) {
32205
32994
  SessionStart: originalSessionStartHook
32206
32995
  }
32207
32996
  };
32208
- fs67.mkdirSync(path69.dirname(filePath), { recursive: true });
32209
- fs67.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
32997
+ fs71.mkdirSync(path71.dirname(filePath), { recursive: true });
32998
+ fs71.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
32210
32999
  return { restored: true };
32211
33000
  }
32212
33001
  function removeOlamManagedSymlinks() {
@@ -32215,16 +33004,16 @@ function removeOlamManagedSymlinks() {
32215
33004
  const olamClonePaths = sources.map((s) => skillSourceClonePath(s.id));
32216
33005
  let removed = 0;
32217
33006
  for (const bucket of ["skills", "agents", "scripts", "rules", "commands"]) {
32218
- const dir = path69.join(claude, bucket);
32219
- if (!fs67.existsSync(dir)) continue;
32220
- for (const name of fs67.readdirSync(dir)) {
32221
- const linkPath = path69.join(dir, name);
33007
+ const dir = path71.join(claude, bucket);
33008
+ if (!fs71.existsSync(dir)) continue;
33009
+ for (const name of fs71.readdirSync(dir)) {
33010
+ const linkPath = path71.join(dir, name);
32222
33011
  try {
32223
- const stat = fs67.lstatSync(linkPath);
33012
+ const stat = fs71.lstatSync(linkPath);
32224
33013
  if (!stat.isSymbolicLink()) continue;
32225
- const target = fs67.readlinkSync(linkPath);
33014
+ const target = fs71.readlinkSync(linkPath);
32226
33015
  if (olamClonePaths.some((cp) => target.startsWith(cp))) {
32227
- fs67.unlinkSync(linkPath);
33016
+ fs71.unlinkSync(linkPath);
32228
33017
  removed += 1;
32229
33018
  }
32230
33019
  } catch {
@@ -32237,18 +33026,18 @@ function restoreToolboxSymlinks(symlinks) {
32237
33026
  let restored = 0;
32238
33027
  for (const { link, target } of symlinks) {
32239
33028
  try {
32240
- fs67.mkdirSync(path69.dirname(link), { recursive: true });
32241
- if (fs67.existsSync(link) || (() => {
33029
+ fs71.mkdirSync(path71.dirname(link), { recursive: true });
33030
+ if (fs71.existsSync(link) || (() => {
32242
33031
  try {
32243
- fs67.lstatSync(link);
33032
+ fs71.lstatSync(link);
32244
33033
  return true;
32245
33034
  } catch {
32246
33035
  return false;
32247
33036
  }
32248
33037
  })()) {
32249
- fs67.unlinkSync(link);
33038
+ fs71.unlinkSync(link);
32250
33039
  }
32251
- fs67.symlinkSync(target, link);
33040
+ fs71.symlinkSync(target, link);
32252
33041
  restored += 1;
32253
33042
  } catch {
32254
33043
  }
@@ -32257,9 +33046,9 @@ function restoreToolboxSymlinks(symlinks) {
32257
33046
  }
32258
33047
  function restoreAtlasUserMarker(atlasUser) {
32259
33048
  if (!atlasUser) return false;
32260
- const file = path69.join(claudeDirInternal4(), ".atlas-user");
32261
- fs67.mkdirSync(path69.dirname(file), { recursive: true });
32262
- fs67.writeFileSync(file, atlasUser);
33049
+ const file = path71.join(claudeDirInternal4(), ".atlas-user");
33050
+ fs71.mkdirSync(path71.dirname(file), { recursive: true });
33051
+ fs71.writeFileSync(file, atlasUser);
32263
33052
  return true;
32264
33053
  }
32265
33054
  function registerSkillsMigrateBack(program2) {
@@ -32272,15 +33061,15 @@ function registerSkillsMigrateBack(program2) {
32272
33061
  let snapshot;
32273
33062
  try {
32274
33063
  if (opts.snapshot) {
32275
- snapshotPath = path69.resolve(opts.snapshot);
32276
- if (!fs67.existsSync(snapshotPath)) {
33064
+ snapshotPath = path71.resolve(opts.snapshot);
33065
+ if (!fs71.existsSync(snapshotPath)) {
32277
33066
  printError(`snapshot not found at ${snapshotPath}`);
32278
33067
  process.exitCode = 1;
32279
33068
  return;
32280
33069
  }
32281
33070
  snapshot = readMigrationSnapshotFromPath(snapshotPath);
32282
33071
  } else {
32283
- const filterNamespace = opts.namespace ?? (opts.path ? path69.basename(opts.path) : void 0);
33072
+ const filterNamespace = opts.namespace ?? (opts.path ? path71.basename(opts.path) : void 0);
32284
33073
  const latest = readLatestMigrationSnapshot({ namespace: filterNamespace });
32285
33074
  if (!latest) {
32286
33075
  const where = filterNamespace ? ` for namespace "${filterNamespace}"` : "";
@@ -32350,13 +33139,176 @@ function registerSkillsMigrateBack(program2) {
32350
33139
  });
32351
33140
  }
32352
33141
 
32353
- // src/commands/skills-shadow-backups.ts
32354
- import * as fs68 from "node:fs";
33142
+ // src/commands/skills-migrate-hooks.ts
33143
+ import * as fs72 from "node:fs";
33144
+ import * as path72 from "node:path";
32355
33145
  import pc33 from "picocolors";
32356
33146
  init_output();
33147
+ var MIGRATE_HOOKS_COMMAND = "migrate-hooks";
33148
+ function settingsHasOlamMetaSentinel(settings) {
33149
+ for (const stage of ["PreToolUse", "PostToolUse"]) {
33150
+ const matchers = settings.hooks?.[stage];
33151
+ if (!Array.isArray(matchers)) continue;
33152
+ for (const matcher of matchers) {
33153
+ const inner = Array.isArray(matcher.hooks) ? matcher.hooks : [];
33154
+ for (const h of inner) {
33155
+ const cmd = h?.command;
33156
+ if (typeof cmd !== "string") continue;
33157
+ for (const sentinel of OLAM_META_SENTINELS_GUARDED) {
33158
+ if (cmd.includes(sentinel)) return true;
33159
+ }
33160
+ }
33161
+ }
33162
+ }
33163
+ return false;
33164
+ }
33165
+ function readSettings2(filePath) {
33166
+ if (!fs72.existsSync(filePath)) return null;
33167
+ const raw = fs72.readFileSync(filePath, "utf-8");
33168
+ if (raw.trim().length === 0) return {};
33169
+ return JSON.parse(raw);
33170
+ }
33171
+ function writeSettings(filePath, settings) {
33172
+ fs72.mkdirSync(path72.dirname(filePath), { recursive: true });
33173
+ const tmp = `${filePath}.tmp-migrate-hooks-${process.pid}-${Date.now()}`;
33174
+ fs72.writeFileSync(tmp, JSON.stringify(settings, null, 2) + "\n");
33175
+ fs72.renameSync(tmp, filePath);
33176
+ }
33177
+ function printSummary(candidates2, opts) {
33178
+ if (candidates2.length === 0) {
33179
+ printInfo(MIGRATE_HOOKS_COMMAND, "no atlas-toolbox-shipped agentmemory hooks found in settings.json \u2014 nothing to migrate");
33180
+ return;
33181
+ }
33182
+ const verb = opts.dryRun ? "would strip" : "stripped";
33183
+ console.log(pc33.bold(`${verb} ${candidates2.length} atlas-toolbox-shipped agentmemory hook entry(ies):`));
33184
+ for (const c of candidates2) {
33185
+ const matcher = c.matcher ?? "*";
33186
+ const cmdPreview = c.command.length > 120 ? `${c.command.slice(0, 117)}...` : c.command;
33187
+ console.log(` ${pc33.dim(`[${c.stage}]`)} matcher=${pc33.cyan(matcher)} pattern=${pc33.yellow(c.matchedPattern)}`);
33188
+ console.log(` ${pc33.dim(cmdPreview)}`);
33189
+ }
33190
+ if (opts.snapshotPath) {
33191
+ console.log();
33192
+ printInfo("snapshot", opts.snapshotPath);
33193
+ printInfo("reverse", `run \`olam skills migrate-hooks-back\` (or \`migrate-hooks-back --snapshot <path>\`) to restore the pre-strip settings.json`);
33194
+ }
33195
+ }
32357
33196
  function asMessage8(err) {
32358
33197
  return err instanceof Error ? err.message : String(err);
32359
33198
  }
33199
+ function registerSkillsMigrateHooks(program2) {
33200
+ const skills = program2.commands.find((c) => c.name() === "skills") ?? program2.command("skills").description("Manage skill sources and synchronization");
33201
+ skills.command(MIGRATE_HOOKS_COMMAND).description("Strip atlas-toolbox-shipped agentmemory hook entries from ~/.claude/settings.json (forward migration; reverse via migrate-hooks-back)").option("--dry-run", "Show what would be stripped without mutating settings.json or writing a snapshot").action(async (opts) => {
33202
+ try {
33203
+ await withSettingsJsonLock(
33204
+ async () => {
33205
+ const settingsFile = claudeSettingsPath();
33206
+ const settings = readSettings2(settingsFile);
33207
+ if (settings === null) {
33208
+ printInfo(
33209
+ MIGRATE_HOOKS_COMMAND,
33210
+ `${settingsFile} does not exist \u2014 nothing to migrate`
33211
+ );
33212
+ return;
33213
+ }
33214
+ const candidates2 = findStripCandidates(settings);
33215
+ if (opts.dryRun) {
33216
+ printSummary(candidates2, { dryRun: true });
33217
+ return;
33218
+ }
33219
+ if (candidates2.length === 0) {
33220
+ printSummary(candidates2, { dryRun: false });
33221
+ return;
33222
+ }
33223
+ const hasOlamMetaSentinel = settingsHasOlamMetaSentinel(settings);
33224
+ if (!hasOlamMetaSentinel) {
33225
+ printWarning(
33226
+ `stripping ${candidates2.length} atlas-toolbox-shipped agentmemory entry(ies) WITHOUT any olam-meta sentinel-bound block present in settings.json. After the strip, agentmemory recall/classify will NOT fire from this settings.json. If unintended, reverse with \`olam skills migrate-hooks-back\` and re-sync with \`olam skills sync\` (default mode injects olam-meta blocks when memory-bridge is running).`
33227
+ );
33228
+ }
33229
+ const snapshotPath = writeMetaHooksSnapshot(settings);
33230
+ const { nextSettings, removedCount } = applyStrip(settings, candidates2);
33231
+ writeSettings(settingsFile, nextSettings);
33232
+ appendTrustAudit({
33233
+ gitUrl: "internal:olam-meta-hooks",
33234
+ action: "meta-hook-stripped",
33235
+ trustMethod: "none",
33236
+ sourceId: "atlas-toolbox",
33237
+ note: `removed ${removedCount} agentmemory hook entry(ies); snapshot at ${snapshotPath}`
33238
+ });
33239
+ printSummary(candidates2, { dryRun: false, snapshotPath });
33240
+ printSuccess(`stripped ${removedCount} atlas-toolbox-shipped agentmemory hook entry(ies) from ${settingsFile}`);
33241
+ },
33242
+ { reason: `cli:${MIGRATE_HOOKS_COMMAND}` }
33243
+ );
33244
+ } catch (err) {
33245
+ printError(asMessage8(err));
33246
+ process.exitCode = 1;
33247
+ }
33248
+ });
33249
+ }
33250
+
33251
+ // src/commands/skills-migrate-hooks-back.ts
33252
+ import * as path73 from "node:path";
33253
+ init_output();
33254
+ function asMessage9(err) {
33255
+ return err instanceof Error ? err.message : String(err);
33256
+ }
33257
+ function registerSkillsMigrateHooksBack(program2) {
33258
+ const skills = program2.commands.find((c) => c.name() === "skills") ?? program2.command("skills").description("Manage skill sources and synchronization");
33259
+ skills.command("migrate-hooks-back").description("Reverse olam-meta hook injection by restoring ~/.claude/settings.json from a B5 snapshot").option("--snapshot <path>", "Use a specific snapshot file (default: most recent meta-hooks-*.json)").action((opts) => {
33260
+ try {
33261
+ const snapshotPath = opts.snapshot ?? findLatestMetaHooksSnapshot();
33262
+ if (!snapshotPath) {
33263
+ printError(
33264
+ "No meta-hooks-* snapshot found in ~/.olam/state/migration-snapshots/. Engine writes one before every injection that mutates settings.json; if none exist, no reversible injection has happened yet."
33265
+ );
33266
+ process.exitCode = 1;
33267
+ return;
33268
+ }
33269
+ if (opts.snapshot) {
33270
+ const resolved = path73.resolve(opts.snapshot);
33271
+ const allowedDir = path73.resolve(migrationSnapshotsDir2());
33272
+ if (!resolved.startsWith(allowedDir + path73.sep)) {
33273
+ printError(
33274
+ `--snapshot path must be inside ${allowedDir} (got "${resolved}"). Refusing to restore from an arbitrary path \u2014 settings.json would land operator-chosen content.`
33275
+ );
33276
+ process.exitCode = 1;
33277
+ return;
33278
+ }
33279
+ const basename12 = path73.basename(resolved);
33280
+ if (!basename12.startsWith(META_HOOKS_SNAPSHOT_PREFIX)) {
33281
+ printError(
33282
+ `--snapshot filename must start with "${META_HOOKS_SNAPSHOT_PREFIX}" (got "${basename12}"). Cross-namespace snapshots (atlas-toolbox-*) are not valid restore targets for olam-meta hooks.`
33283
+ );
33284
+ process.exitCode = 1;
33285
+ return;
33286
+ }
33287
+ }
33288
+ printInfo("snapshot", snapshotPath);
33289
+ const snapshot = readMetaHooksSnapshot(snapshotPath);
33290
+ printInfo("takenAt", snapshot.takenAt);
33291
+ const settingsFile = claudeSettingsPath();
33292
+ restoreSettingsFromSnapshot(snapshot, settingsFile);
33293
+ if (snapshot.originalSettings === null) {
33294
+ printSuccess(`removed ${settingsFile} (no settings.json existed pre-injection)`);
33295
+ } else {
33296
+ printSuccess(`restored ${settingsFile} to pre-injection state`);
33297
+ }
33298
+ } catch (err) {
33299
+ printError(asMessage9(err));
33300
+ process.exitCode = 1;
33301
+ }
33302
+ });
33303
+ }
33304
+
33305
+ // src/commands/skills-shadow-backups.ts
33306
+ import * as fs73 from "node:fs";
33307
+ import pc34 from "picocolors";
33308
+ init_output();
33309
+ function asMessage10(err) {
33310
+ return err instanceof Error ? err.message : String(err);
33311
+ }
32360
33312
  function formatAge3(ms) {
32361
33313
  if (ms < 0) return "<future>";
32362
33314
  const d = Math.floor(ms / 864e5);
@@ -32377,7 +33329,7 @@ function printBackupRows(backups) {
32377
33329
  for (const b of backups) {
32378
33330
  const when = new Date(b.epochSeconds * 1e3).toISOString().slice(0, 10);
32379
33331
  console.log(
32380
- ` ${pc33.dim(formatAge3(b.ageMs).padStart(6))} ${formatSize(b.sizeBytes).padStart(7)} ${pc33.dim(when)} ${b.bucket}/${pc33.bold(b.basename)}`
33332
+ ` ${pc34.dim(formatAge3(b.ageMs).padStart(6))} ${formatSize(b.sizeBytes).padStart(7)} ${pc34.dim(when)} ${b.bucket}/${pc34.bold(b.basename)}`
32381
33333
  );
32382
33334
  }
32383
33335
  }
@@ -32387,11 +33339,11 @@ function registerSkillsShadowBackups(program2) {
32387
33339
  sb.command("list").description("List all shadow-backup files under ~/.claude/").action(() => {
32388
33340
  const all = listShadowBackups();
32389
33341
  if (all.length === 0) {
32390
- console.log(pc33.dim("No shadow-backup files under ~/.claude/."));
33342
+ console.log(pc34.dim("No shadow-backup files under ~/.claude/."));
32391
33343
  return;
32392
33344
  }
32393
33345
  printHeader(`${all.length} shadow backup(s)`);
32394
- console.log(pc33.dim(" age size created bucket/basename"));
33346
+ console.log(pc34.dim(" age size created bucket/basename"));
32395
33347
  printBackupRows(all);
32396
33348
  });
32397
33349
  sb.command("prune").description("Delete shadow-backup files older than a duration (e.g. 30d) OR all of them with --all --force").option("--older-than <duration>", "Delete backups older than this duration (e.g. 30d, 7d, 24h, 2w)", "30d").option("--all", "Delete every shadow-backup file (requires --force)").option("--force", "Confirm deletion when --all is used").option("--dry-run", "Show what would be deleted without deleting").action((opts) => {
@@ -32418,24 +33370,24 @@ function registerSkillsShadowBackups(program2) {
32418
33370
  const result = pruneShadowBackups(pruneOpts);
32419
33371
  const action = opts.dryRun ? "would delete" : "deleted";
32420
33372
  if (result.deleted.length === 0) {
32421
- console.log(pc33.dim(`No shadow-backups match \u2014 ${result.skipped.length} kept`));
33373
+ console.log(pc34.dim(`No shadow-backups match \u2014 ${result.skipped.length} kept`));
32422
33374
  return;
32423
33375
  }
32424
33376
  printHeader(`${action} ${result.deleted.length} shadow backup(s) (${result.skipped.length} kept)`);
32425
33377
  printBackupRows(result.deleted);
32426
33378
  if (opts.dryRun) {
32427
- console.log(pc33.dim("\n(dry-run \u2014 re-run without --dry-run to delete)"));
33379
+ console.log(pc34.dim("\n(dry-run \u2014 re-run without --dry-run to delete)"));
32428
33380
  } else {
32429
33381
  printSuccess(`pruned ${result.deleted.length} backup(s)`);
32430
33382
  }
32431
33383
  } catch (err) {
32432
- printError(asMessage8(err));
33384
+ printError(asMessage10(err));
32433
33385
  process.exitCode = 1;
32434
33386
  }
32435
33387
  });
32436
33388
  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) => {
32437
33389
  try {
32438
- if (!fs68.existsSync(p)) {
33390
+ if (!fs73.existsSync(p)) {
32439
33391
  printError(`backup file not found: ${p}`);
32440
33392
  process.exitCode = 1;
32441
33393
  return;
@@ -32443,7 +33395,7 @@ function registerSkillsShadowBackups(program2) {
32443
33395
  const result = restoreShadowBackup({ backupPath: p, force: opts.force });
32444
33396
  printSuccess(`restored \u2192 ${result.restoredTo}`);
32445
33397
  } catch (err) {
32446
- printError(asMessage8(err));
33398
+ printError(asMessage10(err));
32447
33399
  process.exitCode = 1;
32448
33400
  }
32449
33401
  });
@@ -32451,17 +33403,17 @@ function registerSkillsShadowBackups(program2) {
32451
33403
 
32452
33404
  // src/commands/skills-doctor.ts
32453
33405
  import * as readline3 from "node:readline";
32454
- import pc34 from "picocolors";
33406
+ import pc35 from "picocolors";
32455
33407
  init_output();
32456
- function asMessage9(err) {
33408
+ function asMessage11(err) {
32457
33409
  return err instanceof Error ? err.message : String(err);
32458
33410
  }
32459
33411
  function defaultDoctorPrompt(question) {
32460
- return new Promise((resolve18) => {
33412
+ return new Promise((resolve19) => {
32461
33413
  const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
32462
33414
  rl.question(question, (a) => {
32463
33415
  rl.close();
32464
- resolve18(a);
33416
+ resolve19(a);
32465
33417
  });
32466
33418
  });
32467
33419
  }
@@ -32475,16 +33427,16 @@ async function confirmRepair(check) {
32475
33427
  }
32476
33428
  function printCheck(check) {
32477
33429
  if (check.healthy) {
32478
- console.log(` ${pc34.green("\u2713")} ${pc34.bold(check.name.padEnd(22))} ${pc34.dim(check.description)}`);
33430
+ console.log(` ${pc35.green("\u2713")} ${pc35.bold(check.name.padEnd(22))} ${pc35.dim(check.description)}`);
32479
33431
  if (check.details && check.details.length > 0) {
32480
- for (const d of check.details) console.log(` ${pc34.dim(d)}`);
33432
+ for (const d of check.details) console.log(` ${pc35.dim(d)}`);
32481
33433
  }
32482
33434
  } else {
32483
- console.log(` ${pc34.red("\u2717")} ${pc34.bold(check.name.padEnd(22))} ${pc34.yellow(check.issue ?? "unhealthy")}`);
32484
- console.log(` ${pc34.dim(check.description)}`);
33435
+ console.log(` ${pc35.red("\u2717")} ${pc35.bold(check.name.padEnd(22))} ${pc35.yellow(check.issue ?? "unhealthy")}`);
33436
+ console.log(` ${pc35.dim(check.description)}`);
32485
33437
  if (check.details) {
32486
- for (const d of check.details.slice(0, 10)) console.log(` ${pc34.dim("\xB7 " + d)}`);
32487
- if (check.details.length > 10) console.log(` ${pc34.dim(`\u2026 and ${check.details.length - 10} more`)}`);
33438
+ for (const d of check.details.slice(0, 10)) console.log(` ${pc35.dim("\xB7 " + d)}`);
33439
+ if (check.details.length > 10) console.log(` ${pc35.dim(`\u2026 and ${check.details.length - 10} more`)}`);
32488
33440
  }
32489
33441
  }
32490
33442
  }
@@ -32501,7 +33453,7 @@ function registerSkillsDoctor(program2) {
32501
33453
  try {
32502
33454
  checks = runAllDoctorChecks();
32503
33455
  } catch (err) {
32504
- printError(`doctor checks crashed: ${asMessage9(err)}`);
33456
+ printError(`doctor checks crashed: ${asMessage11(err)}`);
32505
33457
  process.exitCode = 1;
32506
33458
  return;
32507
33459
  }
@@ -32515,7 +33467,7 @@ function registerSkillsDoctor(program2) {
32515
33467
  console.log();
32516
33468
  printWarning(`${unhealthy.length} of ${checks.length} check(s) report issues`);
32517
33469
  if (opts.checkOnly) {
32518
- console.log(pc34.dim("(--check-only \u2014 exiting without repair)"));
33470
+ console.log(pc35.dim("(--check-only \u2014 exiting without repair)"));
32519
33471
  process.exitCode = 1;
32520
33472
  return;
32521
33473
  }
@@ -32523,22 +33475,22 @@ function registerSkillsDoctor(program2) {
32523
33475
  let skipped = 0;
32524
33476
  for (const check of unhealthy) {
32525
33477
  if (!check.repair) {
32526
- console.log(pc34.dim(` (no auto-repair for ${check.name} \u2014 operator-attention required)`));
33478
+ console.log(pc35.dim(` (no auto-repair for ${check.name} \u2014 operator-attention required)`));
32527
33479
  skipped += 1;
32528
33480
  continue;
32529
33481
  }
32530
33482
  const shouldRepair = opts.autoFix ? true : await confirmRepair(check);
32531
33483
  if (!shouldRepair) {
32532
- console.log(pc34.dim(` skipped: ${check.name}`));
33484
+ console.log(pc35.dim(` skipped: ${check.name}`));
32533
33485
  skipped += 1;
32534
33486
  continue;
32535
33487
  }
32536
33488
  try {
32537
33489
  await check.repair();
32538
- console.log(pc34.green(` repaired: ${check.name}`));
33490
+ console.log(pc35.green(` repaired: ${check.name}`));
32539
33491
  repaired += 1;
32540
33492
  } catch (err) {
32541
- printError(` repair failed for ${check.name}: ${asMessage9(err)}`);
33493
+ printError(` repair failed for ${check.name}: ${asMessage11(err)}`);
32542
33494
  skipped += 1;
32543
33495
  }
32544
33496
  }
@@ -32626,17 +33578,17 @@ function registerWorldUpgrade(program2) {
32626
33578
 
32627
33579
  // src/commands/mcp/serve.ts
32628
33580
  init_output();
32629
- import { existsSync as existsSync74 } from "node:fs";
32630
- import { dirname as dirname38, resolve as resolve16 } from "node:path";
33581
+ import { existsSync as existsSync78 } from "node:fs";
33582
+ import { dirname as dirname42, resolve as resolve17 } from "node:path";
32631
33583
  import { fileURLToPath as fileURLToPath5 } from "node:url";
32632
- var here = dirname38(fileURLToPath5(import.meta.url));
33584
+ var here = dirname42(fileURLToPath5(import.meta.url));
32633
33585
  var BUNDLE_PATH_CANDIDATES = [
32634
33586
  // bundled (`dist/index.js` after bundle-cli.mjs) — sibling
32635
- resolve16(here, "mcp-server.js"),
33587
+ resolve17(here, "mcp-server.js"),
32636
33588
  // dev / tsc-only (`dist/commands/mcp/serve.js`) — up two levels
32637
- resolve16(here, "..", "..", "mcp-server.js")
33589
+ resolve17(here, "..", "..", "mcp-server.js")
32638
33590
  ];
32639
- function resolveBundlePath(candidates2 = BUNDLE_PATH_CANDIDATES, exists = existsSync74) {
33591
+ function resolveBundlePath(candidates2 = BUNDLE_PATH_CANDIDATES, exists = existsSync78) {
32640
33592
  return candidates2.find(exists) ?? null;
32641
33593
  }
32642
33594
  var MISSING_BUNDLE_REMEDY = "olam mcp server bundle missing. Searched: " + BUNDLE_PATH_CANDIDATES.join(", ") + ". For local dev, run: node packages/cli/scripts/bundle-mcp-server.mjs. A fresh `npm install -g @pleri/olam-cli@latest` should always include the bundle (see prepublishOnly in packages/cli/package.json); file an issue if it does not.";
@@ -32793,8 +33745,8 @@ var SECRET = process.env["OLAM_MCP_AUTH_SECRET"] ?? "";
32793
33745
  function authHeaders() {
32794
33746
  return SECRET ? { "X-Olam-Mcp-Secret": SECRET } : {};
32795
33747
  }
32796
- async function apiFetch(path78, init = {}) {
32797
- const res = await fetch(`${BASE_URL}${path78}`, {
33748
+ async function apiFetch(path82, init = {}) {
33749
+ const res = await fetch(`${BASE_URL}${path82}`, {
32798
33750
  ...init,
32799
33751
  headers: {
32800
33752
  "Content-Type": "application/json",
@@ -32881,7 +33833,7 @@ function registerMcpLogin(cmd) {
32881
33833
  init_output();
32882
33834
  import * as readline4 from "node:readline";
32883
33835
  async function readTokenSilent(prompt) {
32884
- return new Promise((resolve18, reject) => {
33836
+ return new Promise((resolve19, reject) => {
32885
33837
  const rl = readline4.createInterface({
32886
33838
  input: process.stdin,
32887
33839
  output: process.stdout,
@@ -32899,7 +33851,7 @@ async function readTokenSilent(prompt) {
32899
33851
  process.stdin.removeListener("data", onData);
32900
33852
  process.stdout.write("\n");
32901
33853
  rl.close();
32902
- resolve18(token);
33854
+ resolve19(token);
32903
33855
  } else if (char === "") {
32904
33856
  if (process.stdin.isTTY) process.stdin.setRawMode(false);
32905
33857
  process.stdin.removeListener("data", onData);
@@ -32946,7 +33898,7 @@ function registerMcpAdd(cmd) {
32946
33898
 
32947
33899
  // src/commands/mcp/list.ts
32948
33900
  init_output();
32949
- import pc35 from "picocolors";
33901
+ import pc36 from "picocolors";
32950
33902
  function registerMcpList(cmd) {
32951
33903
  cmd.command("list").description("List all registered MCP credentials").action(async () => {
32952
33904
  const client = getMcpAuthClient();
@@ -32961,8 +33913,8 @@ function registerMcpList(cmd) {
32961
33913
  }
32962
33914
  const mcps = data.mcps ?? [];
32963
33915
  if (mcps.length === 0) {
32964
- console.log(pc35.dim("No MCP credentials registered."));
32965
- console.log(pc35.dim("Add one with: olam mcp add <service>"));
33916
+ console.log(pc36.dim("No MCP credentials registered."));
33917
+ console.log(pc36.dim("Add one with: olam mcp add <service>"));
32966
33918
  return;
32967
33919
  }
32968
33920
  const [c0, c1, c2, c3] = [16, 20, 10, 24];
@@ -32973,12 +33925,12 @@ function registerMcpList(cmd) {
32973
33925
  "ENV VAR".padEnd(c3),
32974
33926
  "STATUS"
32975
33927
  ].join(" ");
32976
- console.log(pc35.dim(header));
32977
- console.log(pc35.dim("\u2500".repeat(header.length)));
33928
+ console.log(pc36.dim(header));
33929
+ console.log(pc36.dim("\u2500".repeat(header.length)));
32978
33930
  for (const m of mcps) {
32979
- const status2 = !m.validated ? pc35.yellow("unvalidated") : m.expired ? pc35.red("expired") : pc35.green("active");
33931
+ const status2 = !m.validated ? pc36.yellow("unvalidated") : m.expired ? pc36.red("expired") : pc36.green("active");
32980
33932
  const row = [
32981
- pc35.cyan(m.service.padEnd(c0)),
33933
+ pc36.cyan(m.service.padEnd(c0)),
32982
33934
  m.label.padEnd(c1).slice(0, c1),
32983
33935
  m.type.padEnd(c2),
32984
33936
  (m.envName ?? "\u2014").padEnd(c3).slice(0, c3),
@@ -33006,13 +33958,13 @@ function registerMcpRemove(cmd) {
33006
33958
 
33007
33959
  // src/commands/mcp/status.ts
33008
33960
  init_output();
33009
- import pc36 from "picocolors";
33961
+ import pc37 from "picocolors";
33010
33962
  function formatExpiry(expiresAt) {
33011
33963
  if (!expiresAt) return "\u2014";
33012
33964
  const ms = expiresAt - Date.now();
33013
- if (ms <= 0) return pc36.red("expired");
33965
+ if (ms <= 0) return pc37.red("expired");
33014
33966
  const hours = ms / (1e3 * 60 * 60);
33015
- if (hours < 1) return pc36.yellow(`${Math.ceil(ms / 6e4)}m`);
33967
+ if (hours < 1) return pc37.yellow(`${Math.ceil(ms / 6e4)}m`);
33016
33968
  return `${hours.toFixed(1)}h`;
33017
33969
  }
33018
33970
  function registerMcpStatus(cmd) {
@@ -33029,14 +33981,14 @@ function registerMcpStatus(cmd) {
33029
33981
  const mcps = data.mcps ?? [];
33030
33982
  printHeader(`MCP Credentials (${mcps.length})`);
33031
33983
  if (mcps.length === 0) {
33032
- console.log(pc36.dim("No credentials registered."));
33984
+ console.log(pc37.dim("No credentials registered."));
33033
33985
  return;
33034
33986
  }
33035
33987
  for (const m of mcps) {
33036
- const stateColor = !m.validated ? pc36.yellow : m.expired ? pc36.red : pc36.green;
33988
+ const stateColor = !m.validated ? pc37.yellow : m.expired ? pc37.red : pc37.green;
33037
33989
  const stateLabel = !m.validated ? "unvalidated" : m.expired ? "expired" : "active";
33038
33990
  console.log(`
33039
- ${pc36.cyan(m.service)} ${stateColor(`[${stateLabel}]`)}`);
33991
+ ${pc37.cyan(m.service)} ${stateColor(`[${stateLabel}]`)}`);
33040
33992
  console.log(` label: ${m.label}`);
33041
33993
  console.log(` type: ${m.type}`);
33042
33994
  if (m.envName) console.log(` env var: ${m.envName}`);
@@ -33051,15 +34003,15 @@ function registerMcpStatus(cmd) {
33051
34003
  // src/commands/mcp/import.ts
33052
34004
  init_output();
33053
34005
  import * as readline5 from "node:readline";
33054
- import pc37 from "picocolors";
34006
+ import pc38 from "picocolors";
33055
34007
 
33056
34008
  // src/commands/mcp/import-discovery.ts
33057
- import * as fs69 from "node:fs";
33058
- import * as os38 from "node:os";
33059
- import * as path70 from "node:path";
34009
+ import * as fs74 from "node:fs";
34010
+ import * as os40 from "node:os";
34011
+ import * as path74 from "node:path";
33060
34012
  function readJsonFile(filePath) {
33061
34013
  try {
33062
- const raw = fs69.readFileSync(filePath, "utf-8");
34014
+ const raw = fs74.readFileSync(filePath, "utf-8");
33063
34015
  return JSON.parse(raw);
33064
34016
  } catch {
33065
34017
  return null;
@@ -33088,24 +34040,24 @@ function extractMcpServers(obj, source, sourceLabel) {
33088
34040
  }
33089
34041
  function getClaudeDesktopPath() {
33090
34042
  if (process.platform === "darwin") {
33091
- return path70.join(os38.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
34043
+ return path74.join(os40.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
33092
34044
  }
33093
34045
  if (process.platform === "win32") {
33094
- const appData = process.env["APPDATA"] ?? path70.join(os38.homedir(), "AppData", "Roaming");
33095
- return path70.join(appData, "Claude", "claude_desktop_config.json");
34046
+ const appData = process.env["APPDATA"] ?? path74.join(os40.homedir(), "AppData", "Roaming");
34047
+ return path74.join(appData, "Claude", "claude_desktop_config.json");
33096
34048
  }
33097
- return path70.join(os38.homedir(), ".config", "Claude", "claude_desktop_config.json");
34049
+ return path74.join(os40.homedir(), ".config", "Claude", "claude_desktop_config.json");
33098
34050
  }
33099
34051
  function getOlamRepoPaths() {
33100
34052
  const configPaths = [
33101
- path70.join(os38.homedir(), ".olam", "config.yaml"),
33102
- path70.join(process.cwd(), ".olam", "config.yaml")
34053
+ path74.join(os40.homedir(), ".olam", "config.yaml"),
34054
+ path74.join(process.cwd(), ".olam", "config.yaml")
33103
34055
  ];
33104
34056
  const paths = [];
33105
34057
  for (const configPath of configPaths) {
33106
- if (!fs69.existsSync(configPath)) continue;
34058
+ if (!fs74.existsSync(configPath)) continue;
33107
34059
  try {
33108
- const raw = fs69.readFileSync(configPath, "utf-8");
34060
+ const raw = fs74.readFileSync(configPath, "utf-8");
33109
34061
  const repoMatches = [...raw.matchAll(/path:\s*["']?([^\s"'\n]+)/g)];
33110
34062
  for (const m of repoMatches) {
33111
34063
  if (m[1]) paths.push(m[1]);
@@ -33121,7 +34073,7 @@ async function discoverMcpSources(repoPaths) {
33121
34073
  const sources = [];
33122
34074
  const sourceDefs = [
33123
34075
  {
33124
- path: path70.join(os38.homedir(), ".claude.json"),
34076
+ path: path74.join(os40.homedir(), ".claude.json"),
33125
34077
  label: "Claude Code (~/.claude.json)"
33126
34078
  },
33127
34079
  {
@@ -33129,19 +34081,19 @@ async function discoverMcpSources(repoPaths) {
33129
34081
  label: "Claude Desktop"
33130
34082
  },
33131
34083
  {
33132
- path: path70.join(os38.homedir(), ".cursor", "mcp.json"),
34084
+ path: path74.join(os40.homedir(), ".cursor", "mcp.json"),
33133
34085
  label: "Cursor (~/.cursor/mcp.json)"
33134
34086
  },
33135
34087
  {
33136
- path: path70.join(os38.homedir(), ".codeium", "windsurf", "mcp_config.json"),
34088
+ path: path74.join(os40.homedir(), ".codeium", "windsurf", "mcp_config.json"),
33137
34089
  label: "Windsurf (~/.codeium/windsurf/mcp_config.json)"
33138
34090
  }
33139
34091
  ];
33140
34092
  const resolvedRepoPaths = repoPaths ?? getOlamRepoPaths();
33141
34093
  for (const repoPath of resolvedRepoPaths) {
33142
34094
  sourceDefs.push({
33143
- path: path70.join(repoPath, ".mcp.json"),
33144
- label: `.mcp.json (${path70.basename(repoPath)})`
34095
+ path: path74.join(repoPath, ".mcp.json"),
34096
+ label: `.mcp.json (${path74.basename(repoPath)})`
33145
34097
  });
33146
34098
  }
33147
34099
  const reads = await Promise.all(
@@ -33174,7 +34126,7 @@ async function discoverMcpSources(repoPaths) {
33174
34126
  import { spawn as spawn9 } from "node:child_process";
33175
34127
  var VALIDATION_TIMEOUT_MS = 5e3;
33176
34128
  async function validateMcpEntry(entry) {
33177
- return new Promise((resolve18) => {
34129
+ return new Promise((resolve19) => {
33178
34130
  let stdout = "";
33179
34131
  let timedOut = false;
33180
34132
  let child;
@@ -33184,7 +34136,7 @@ async function validateMcpEntry(entry) {
33184
34136
  env: { ...process.env, ...entry.env ?? {} }
33185
34137
  });
33186
34138
  } catch (err) {
33187
- resolve18({
34139
+ resolve19({
33188
34140
  name: entry.name,
33189
34141
  validated: false,
33190
34142
  reason: err instanceof Error ? err.message : "spawn failed"
@@ -33201,11 +34153,11 @@ async function validateMcpEntry(entry) {
33201
34153
  child.on("close", (code) => {
33202
34154
  clearTimeout(timer);
33203
34155
  if (timedOut) {
33204
- resolve18({ name: entry.name, validated: false, reason: "timeout (5s)" });
34156
+ resolve19({ name: entry.name, validated: false, reason: "timeout (5s)" });
33205
34157
  return;
33206
34158
  }
33207
34159
  const validated = code === 0 && stdout.trim().length > 0;
33208
- resolve18({
34160
+ resolve19({
33209
34161
  name: entry.name,
33210
34162
  validated,
33211
34163
  reason: validated ? "ok" : `exit code ${code ?? "null"}`
@@ -33213,7 +34165,7 @@ async function validateMcpEntry(entry) {
33213
34165
  });
33214
34166
  child.on("error", (err) => {
33215
34167
  clearTimeout(timer);
33216
- resolve18({ name: entry.name, validated: false, reason: err.message });
34168
+ resolve19({ name: entry.name, validated: false, reason: err.message });
33217
34169
  });
33218
34170
  });
33219
34171
  }
@@ -33221,18 +34173,18 @@ async function validateMcpEntry(entry) {
33221
34173
  // src/commands/mcp/import.ts
33222
34174
  async function multiSelectPicker(entries) {
33223
34175
  if (entries.length === 0) return [];
33224
- console.log("\n" + pc37.bold("Discovered MCP servers:"));
34176
+ console.log("\n" + pc38.bold("Discovered MCP servers:"));
33225
34177
  entries.forEach((e, i) => {
33226
34178
  console.log(
33227
- ` ${pc37.dim(`[${i + 1}]`)} ${pc37.cyan(e.name.padEnd(20))} ${pc37.dim(e.sourceLabel)}`
34179
+ ` ${pc38.dim(`[${i + 1}]`)} ${pc38.cyan(e.name.padEnd(20))} ${pc38.dim(e.sourceLabel)}`
33228
34180
  );
33229
34181
  });
33230
- console.log("\n" + pc37.dim('Enter numbers to import (e.g. 1,2,3 or "all" or Enter to skip):'));
33231
- const answer = await new Promise((resolve18) => {
34182
+ console.log("\n" + pc38.dim('Enter numbers to import (e.g. 1,2,3 or "all" or Enter to skip):'));
34183
+ const answer = await new Promise((resolve19) => {
33232
34184
  const rl = readline5.createInterface({ input: process.stdin, output: process.stdout });
33233
34185
  rl.question("> ", (ans) => {
33234
34186
  rl.close();
33235
- resolve18(ans.trim());
34187
+ resolve19(ans.trim());
33236
34188
  });
33237
34189
  });
33238
34190
  if (!answer || answer === "") return [];
@@ -33254,7 +34206,7 @@ function registerMcpImport(cmd) {
33254
34206
  const repoPaths = opts.repoPaths ? opts.repoPaths.split(",").map((s) => s.trim()) : void 0;
33255
34207
  const { entries, sources, durationMs } = await discoverMcpSources(repoPaths);
33256
34208
  if (entries.length === 0) {
33257
- console.log(pc37.dim("No MCP servers found in any source path."));
34209
+ console.log(pc38.dim("No MCP servers found in any source path."));
33258
34210
  return;
33259
34211
  }
33260
34212
  printInfo("Sources", sources.length > 0 ? sources.join(", ") : "none");
@@ -33267,15 +34219,15 @@ function registerMcpImport(cmd) {
33267
34219
  candidates2 = filtered;
33268
34220
  }
33269
34221
  if (skippedCount > 0) {
33270
- console.log(pc37.dim(`skipped: ${skippedCount} already registered`));
34222
+ console.log(pc38.dim(`skipped: ${skippedCount} already registered`));
33271
34223
  }
33272
34224
  if (candidates2.length === 0) {
33273
- console.log(pc37.dim("Nothing new to import. Use --reimport to force."));
34225
+ console.log(pc38.dim("Nothing new to import. Use --reimport to force."));
33274
34226
  return;
33275
34227
  }
33276
34228
  const selected = await multiSelectPicker(candidates2);
33277
34229
  if (selected.length === 0) {
33278
- console.log(pc37.dim("No servers selected."));
34230
+ console.log(pc38.dim("No servers selected."));
33279
34231
  return;
33280
34232
  }
33281
34233
  console.log(`
@@ -33286,16 +34238,16 @@ Importing ${selected.length} server(s)\u2026`);
33286
34238
  let validated = false;
33287
34239
  let validationReason = "skipped";
33288
34240
  if (opts.validate !== false) {
33289
- process.stdout.write(` ${pc37.dim("\u2192")} ${entry.name} validating\u2026 `);
34241
+ process.stdout.write(` ${pc38.dim("\u2192")} ${entry.name} validating\u2026 `);
33290
34242
  const vr = await validateMcpEntry(entry);
33291
34243
  validated = vr.validated;
33292
34244
  validationReason = vr.reason;
33293
34245
  process.stdout.write(
33294
- validated ? pc37.green("ok\n") : pc37.yellow(`unvalidated (${vr.reason})
34246
+ validated ? pc38.green("ok\n") : pc38.yellow(`unvalidated (${vr.reason})
33295
34247
  `)
33296
34248
  );
33297
34249
  } else {
33298
- console.log(` ${pc37.dim("\u2192")} ${entry.name} ${pc37.dim("(validation skipped)")}`);
34250
+ console.log(` ${pc38.dim("\u2192")} ${entry.name} ${pc38.dim("(validation skipped)")}`);
33299
34251
  }
33300
34252
  if (validated) validatedCount++;
33301
34253
  const result = await client.staticAdd({
@@ -33310,21 +34262,21 @@ Importing ${selected.length} server(s)\u2026`);
33310
34262
  }
33311
34263
  }
33312
34264
  console.log("");
33313
- console.log(pc37.green(`\u2713 Imported ${importedCount}/${selected.length}`));
34265
+ console.log(pc38.green(`\u2713 Imported ${importedCount}/${selected.length}`));
33314
34266
  if (validatedCount > 0) {
33315
- console.log(pc37.dim(` ${validatedCount} validated, ${importedCount - validatedCount} unvalidated`));
34267
+ console.log(pc38.dim(` ${validatedCount} validated, ${importedCount - validatedCount} unvalidated`));
33316
34268
  }
33317
34269
  });
33318
34270
  }
33319
34271
 
33320
34272
  // src/commands/mcp/revoke.ts
33321
34273
  init_output();
33322
- import pc38 from "picocolors";
34274
+ import pc39 from "picocolors";
33323
34275
  function registerMcpRevoke(cmd) {
33324
34276
  cmd.command("revoke <user> <world> <service>").description("Revoke a user's MCP service entitlement (multi-tenant mode only)").action(async (user, world, service) => {
33325
34277
  const multiTenant = (process.env["OLAM_MCP_MULTI_TENANT"] ?? "").toLowerCase() === "true";
33326
34278
  if (!multiTenant) {
33327
- console.warn(pc38.yellow("\u26A0 revocation only meaningful in multi_tenant mode \u2014 no-op"));
34279
+ console.warn(pc39.yellow("\u26A0 revocation only meaningful in multi_tenant mode \u2014 no-op"));
33328
34280
  return;
33329
34281
  }
33330
34282
  const baseUrl = process.env["OLAM_MCP_AUTH_SERVICE_URL"] ?? "http://127.0.0.1:9998";
@@ -33353,8 +34305,8 @@ function registerMcpRevoke(cmd) {
33353
34305
  process.exitCode = 1;
33354
34306
  return;
33355
34307
  }
33356
- console.log(pc38.green(`\u2713 Revoked: ${user} / ${world} / ${service}`));
33357
- console.log(pc38.dim(" Next fetch-creds call returns 403; token cleared on next merge."));
34308
+ console.log(pc39.green(`\u2713 Revoked: ${user} / ${world} / ${service}`));
34309
+ console.log(pc39.dim(" Next fetch-creds call returns 403; token cleared on next merge."));
33358
34310
  });
33359
34311
  }
33360
34312
 
@@ -33376,34 +34328,34 @@ function registerMcp(program2) {
33376
34328
  // src/commands/memory/start.ts
33377
34329
  init_output();
33378
34330
  import { spawn as spawn10 } from "node:child_process";
33379
- import { existsSync as existsSync76, mkdirSync as mkdirSync43, openSync as openSync6, readFileSync as readFileSync55, writeFileSync as writeFileSync34 } from "node:fs";
33380
- import { join as join71 } from "node:path";
34331
+ import { existsSync as existsSync80, mkdirSync as mkdirSync47, openSync as openSync7, readFileSync as readFileSync60, writeFileSync as writeFileSync39 } from "node:fs";
34332
+ import { join as join73 } from "node:path";
33381
34333
  import { pathToFileURL } from "node:url";
33382
34334
 
33383
34335
  // src/commands/memory/_paths.ts
33384
- import { homedir as homedir39 } from "node:os";
33385
- import { join as join70, dirname as dirname39 } from "node:path";
34336
+ import { homedir as homedir41 } from "node:os";
34337
+ import { join as join72, dirname as dirname43 } from "node:path";
33386
34338
  import { fileURLToPath as fileURLToPath6 } from "node:url";
33387
- var OLAM_HOME2 = join70(homedir39(), ".olam");
33388
- var OLAM_BIN_DIR = join70(OLAM_HOME2, "bin");
33389
- var III_BINARY_PATH = join70(OLAM_BIN_DIR, "iii");
33390
- var MEMORY_PID_PATH = join70(OLAM_HOME2, "memory.pid");
33391
- var MEMORY_LOG_PATH = join70(OLAM_HOME2, "memory-service.log");
33392
- var MEMORY_DATA_DIR = join70(OLAM_HOME2, "memory-data");
34339
+ var OLAM_HOME2 = join72(homedir41(), ".olam");
34340
+ var OLAM_BIN_DIR = join72(OLAM_HOME2, "bin");
34341
+ var III_BINARY_PATH = join72(OLAM_BIN_DIR, "iii");
34342
+ var MEMORY_PID_PATH = join72(OLAM_HOME2, "memory.pid");
34343
+ var MEMORY_LOG_PATH = join72(OLAM_HOME2, "memory-service.log");
34344
+ var MEMORY_DATA_DIR = join72(OLAM_HOME2, "memory-data");
33393
34345
  var MEMORY_REST_PORT = 3111;
33394
34346
  var MEMORY_LIVEZ_URL = `http://localhost:${MEMORY_REST_PORT}/agentmemory/livez`;
33395
- var here2 = dirname39(fileURLToPath6(import.meta.url));
34347
+ var here2 = dirname43(fileURLToPath6(import.meta.url));
33396
34348
  var candidates = [
33397
34349
  // 1. Workspace dev (built): packages/cli/dist/commands/memory/_paths.js → packages/cli → packages/memory-service
33398
- join70(here2, "..", "..", "..", "..", "memory-service"),
34350
+ join72(here2, "..", "..", "..", "..", "memory-service"),
33399
34351
  // 2a. Workspace bundled: packages/cli/dist/index.js → packages/cli → packages/memory-service
33400
- join70(here2, "..", "..", "memory-service"),
34352
+ join72(here2, "..", "..", "memory-service"),
33401
34353
  // 2b. Published tarball: <prefix>/node_modules/@pleri/olam-cli/dist/index.js
33402
34354
  // → <prefix>/node_modules/@pleri/olam-cli/memory-service-bundle
33403
34355
  // (copied at publish time by bundle-cli.mjs)
33404
- join70(here2, "..", "memory-service-bundle"),
34356
+ join72(here2, "..", "memory-service-bundle"),
33405
34357
  // 3. CWD fallback
33406
- join70(process.cwd(), "packages", "memory-service")
34358
+ join72(process.cwd(), "packages", "memory-service")
33407
34359
  ];
33408
34360
  var MEMORY_SERVICE_CANDIDATES = candidates;
33409
34361
 
@@ -33412,7 +34364,7 @@ var READINESS_TIMEOUT_MS = 3e4;
33412
34364
  var READINESS_POLL_MS = 500;
33413
34365
  function resolveMemoryServiceDir() {
33414
34366
  for (const c of MEMORY_SERVICE_CANDIDATES) {
33415
- if (existsSync76(c)) return c;
34367
+ if (existsSync80(c)) return c;
33416
34368
  }
33417
34369
  throw new Error(
33418
34370
  `Could not find packages/memory-service/. Searched: ${MEMORY_SERVICE_CANDIDATES.join(", ")}. If running from a published @pleri/olam-cli tarball, this is a packaging bug \u2014 please file an issue.`
@@ -33420,12 +34372,12 @@ function resolveMemoryServiceDir() {
33420
34372
  }
33421
34373
  function resolveAgentMemoryBin(serviceDir) {
33422
34374
  const candidates2 = [
33423
- join71(serviceDir, "node_modules", ".bin", "agentmemory"),
33424
- join71(serviceDir, "..", "..", "node_modules", ".bin", "agentmemory"),
33425
- join71(serviceDir, "..", "..", "..", "node_modules", ".bin", "agentmemory")
34375
+ join73(serviceDir, "node_modules", ".bin", "agentmemory"),
34376
+ join73(serviceDir, "..", "..", "node_modules", ".bin", "agentmemory"),
34377
+ join73(serviceDir, "..", "..", "..", "node_modules", ".bin", "agentmemory")
33426
34378
  ];
33427
34379
  for (const c of candidates2) {
33428
- if (existsSync76(c)) return c;
34380
+ if (existsSync80(c)) return c;
33429
34381
  }
33430
34382
  throw new Error(
33431
34383
  `Could not find agentmemory bin. Searched: ${candidates2.join(", ")}. Run 'npm install' from the repo root.`
@@ -33440,8 +34392,8 @@ function isProcessAlive(pid) {
33440
34392
  }
33441
34393
  }
33442
34394
  function readPidFromFile() {
33443
- if (!existsSync76(MEMORY_PID_PATH)) return null;
33444
- const raw = readFileSync55(MEMORY_PID_PATH, "utf8").trim();
34395
+ if (!existsSync80(MEMORY_PID_PATH)) return null;
34396
+ const raw = readFileSync60(MEMORY_PID_PATH, "utf8").trim();
33445
34397
  const pid = parseInt(raw, 10);
33446
34398
  if (!Number.isFinite(pid) || pid <= 0) return null;
33447
34399
  return pid;
@@ -33468,7 +34420,7 @@ async function waitForReady(secret) {
33468
34420
  return false;
33469
34421
  }
33470
34422
  async function autoEnsureIiiBinary(serviceDir) {
33471
- const helperPath = join71(serviceDir, "scripts", "ensure-iii-engine.mjs");
34423
+ const helperPath = join73(serviceDir, "scripts", "ensure-iii-engine.mjs");
33472
34424
  const mod = await import(pathToFileURL(helperPath).href);
33473
34425
  const result = await mod.ensureIiiEngine();
33474
34426
  if (!result.ok) {
@@ -33484,7 +34436,7 @@ async function runMemoryStart() {
33484
34436
  printError(err instanceof Error ? err.message : String(err));
33485
34437
  return 1;
33486
34438
  }
33487
- if (!existsSync76(III_BINARY_PATH)) {
34439
+ if (!existsSync80(III_BINARY_PATH)) {
33488
34440
  printInfo("iii binary", `missing at ${III_BINARY_PATH} \u2014 auto-fetching v0.11.2`);
33489
34441
  try {
33490
34442
  await autoEnsureIiiBinary(serviceDir);
@@ -33512,9 +34464,9 @@ async function runMemoryStart() {
33512
34464
  );
33513
34465
  return 1;
33514
34466
  }
33515
- mkdirSync43(OLAM_HOME2, { recursive: true });
33516
- mkdirSync43(MEMORY_DATA_DIR, { recursive: true });
33517
- const logFd = openSync6(MEMORY_LOG_PATH, "a");
34467
+ mkdirSync47(OLAM_HOME2, { recursive: true });
34468
+ mkdirSync47(MEMORY_DATA_DIR, { recursive: true });
34469
+ const logFd = openSync7(MEMORY_LOG_PATH, "a");
33518
34470
  const child = spawn10(agentmemoryBin, [], {
33519
34471
  cwd: OLAM_HOME2,
33520
34472
  env: {
@@ -33536,7 +34488,7 @@ async function runMemoryStart() {
33536
34488
  printError("spawn returned no pid (process failed to start)");
33537
34489
  return 1;
33538
34490
  }
33539
- writeFileSync34(MEMORY_PID_PATH, `${child.pid}
34491
+ writeFileSync39(MEMORY_PID_PATH, `${child.pid}
33540
34492
  `, { mode: 420 });
33541
34493
  printInfo("pid", `${child.pid}`);
33542
34494
  printInfo("readiness", `polling ${MEMORY_LIVEZ_URL}`);
@@ -33559,7 +34511,7 @@ function registerMemoryStart(cmd) {
33559
34511
 
33560
34512
  // src/commands/memory/stop.ts
33561
34513
  init_output();
33562
- import { existsSync as existsSync77, readFileSync as readFileSync56, unlinkSync as unlinkSync19 } from "node:fs";
34514
+ import { existsSync as existsSync81, readFileSync as readFileSync61, unlinkSync as unlinkSync21 } from "node:fs";
33563
34515
  var SIGTERM_GRACE_MS = 1e4;
33564
34516
  var POLL_MS = 250;
33565
34517
  function isAlive(pid) {
@@ -33572,19 +34524,19 @@ function isAlive(pid) {
33572
34524
  }
33573
34525
  async function runMemoryStop() {
33574
34526
  printHeader("olam memory stop");
33575
- if (!existsSync77(MEMORY_PID_PATH)) {
34527
+ if (!existsSync81(MEMORY_PID_PATH)) {
33576
34528
  printSuccess("no pidfile present (nothing to stop)");
33577
34529
  return 0;
33578
34530
  }
33579
- const pid = parseInt(readFileSync56(MEMORY_PID_PATH, "utf8").trim(), 10);
34531
+ const pid = parseInt(readFileSync61(MEMORY_PID_PATH, "utf8").trim(), 10);
33580
34532
  if (!Number.isFinite(pid) || pid <= 0) {
33581
34533
  printWarning(`pidfile contained invalid value; removing`);
33582
- unlinkSync19(MEMORY_PID_PATH);
34534
+ unlinkSync21(MEMORY_PID_PATH);
33583
34535
  return 0;
33584
34536
  }
33585
34537
  if (!isAlive(pid)) {
33586
34538
  printSuccess(`pid ${pid} is not running (stale pidfile); cleaned up`);
33587
- unlinkSync19(MEMORY_PID_PATH);
34539
+ unlinkSync21(MEMORY_PID_PATH);
33588
34540
  return 0;
33589
34541
  }
33590
34542
  printInfo("pid", `${pid}`);
@@ -33607,8 +34559,8 @@ async function runMemoryStop() {
33607
34559
  }
33608
34560
  await new Promise((r) => setTimeout(r, 500));
33609
34561
  }
33610
- if (existsSync77(MEMORY_PID_PATH)) {
33611
- unlinkSync19(MEMORY_PID_PATH);
34562
+ if (existsSync81(MEMORY_PID_PATH)) {
34563
+ unlinkSync21(MEMORY_PID_PATH);
33612
34564
  }
33613
34565
  printSuccess(`stopped (pid ${pid})`);
33614
34566
  return 0;
@@ -33622,7 +34574,7 @@ function registerMemoryStop(cmd) {
33622
34574
 
33623
34575
  // src/commands/memory/status.ts
33624
34576
  init_output();
33625
- import { existsSync as existsSync78, readFileSync as readFileSync57 } from "node:fs";
34577
+ import { existsSync as existsSync82, readFileSync as readFileSync62 } from "node:fs";
33626
34578
  function isAlive2(pid) {
33627
34579
  try {
33628
34580
  process.kill(pid, 0);
@@ -33646,8 +34598,8 @@ async function probe(secret) {
33646
34598
  }
33647
34599
  async function collectMemoryStatus() {
33648
34600
  let pid = null;
33649
- if (existsSync78(MEMORY_PID_PATH)) {
33650
- const raw = readFileSync57(MEMORY_PID_PATH, "utf8").trim();
34601
+ if (existsSync82(MEMORY_PID_PATH)) {
34602
+ const raw = readFileSync62(MEMORY_PID_PATH, "utf8").trim();
33651
34603
  const parsed = parseInt(raw, 10);
33652
34604
  pid = Number.isFinite(parsed) && parsed > 0 ? parsed : null;
33653
34605
  }
@@ -33659,7 +34611,7 @@ async function collectMemoryStatus() {
33659
34611
  alive,
33660
34612
  livez,
33661
34613
  secretSet: hasMemorySecret(),
33662
- iiiBinary: existsSync78(III_BINARY_PATH) ? III_BINARY_PATH : null,
34614
+ iiiBinary: existsSync82(III_BINARY_PATH) ? III_BINARY_PATH : null,
33663
34615
  port: MEMORY_REST_PORT
33664
34616
  };
33665
34617
  }
@@ -33702,10 +34654,10 @@ function registerMemoryStatus(cmd) {
33702
34654
 
33703
34655
  // src/commands/memory/logs.ts
33704
34656
  init_output();
33705
- import { existsSync as existsSync79 } from "node:fs";
34657
+ import { existsSync as existsSync83 } from "node:fs";
33706
34658
  import { spawn as spawn11 } from "node:child_process";
33707
34659
  async function runMemoryLogs(opts) {
33708
- if (!existsSync79(MEMORY_LOG_PATH)) {
34660
+ if (!existsSync83(MEMORY_LOG_PATH)) {
33709
34661
  printWarning(`no log at ${MEMORY_LOG_PATH} (start the service first via 'olam memory start')`);
33710
34662
  return 1;
33711
34663
  }
@@ -33719,8 +34671,8 @@ async function runMemoryLogs(opts) {
33719
34671
  args.push(MEMORY_LOG_PATH);
33720
34672
  printHeader(`olam memory logs (${opts.follow ? "follow" : `tail -n ${tailN}`})`);
33721
34673
  const child = spawn11("tail", args, { stdio: "inherit" });
33722
- return new Promise((resolve18) => {
33723
- child.on("exit", (code) => resolve18(code ?? 0));
34674
+ return new Promise((resolve19) => {
34675
+ child.on("exit", (code) => resolve19(code ?? 0));
33724
34676
  });
33725
34677
  }
33726
34678
  function registerMemoryLogs(cmd) {
@@ -33731,7 +34683,7 @@ function registerMemoryLogs(cmd) {
33731
34683
  }
33732
34684
 
33733
34685
  // src/commands/memory/secret.ts
33734
- import { existsSync as existsSync80 } from "node:fs";
34686
+ import { existsSync as existsSync84 } from "node:fs";
33735
34687
  init_output();
33736
34688
  async function runMemorySecretShow() {
33737
34689
  if (!hasMemorySecret()) {
@@ -33746,7 +34698,7 @@ async function runMemorySecretShow() {
33746
34698
  }
33747
34699
  async function runMemorySecretRotate() {
33748
34700
  printHeader("olam memory secret rotate");
33749
- const wasRunning = existsSync80(MEMORY_PID_PATH);
34701
+ const wasRunning = existsSync84(MEMORY_PID_PATH);
33750
34702
  if (wasRunning) {
33751
34703
  printInfo("current state", "service running; will restart with new secret");
33752
34704
  const stopRc = await runMemoryStop();
@@ -33928,14 +34880,14 @@ function registerMemoryUninstall(cmd) {
33928
34880
  // src/commands/memory/mode.ts
33929
34881
  init_schema2();
33930
34882
  init_output();
33931
- import { existsSync as existsSync81, readFileSync as readFileSync58, writeFileSync as writeFileSync35 } from "node:fs";
33932
- import { join as join72 } from "node:path";
34883
+ import { existsSync as existsSync85, readFileSync as readFileSync63, writeFileSync as writeFileSync40 } from "node:fs";
34884
+ import { join as join74 } from "node:path";
33933
34885
  import * as readline6 from "node:readline/promises";
33934
34886
  import { parse as parseYaml7, stringify as stringifyYaml6 } from "yaml";
33935
34887
  var CONFIG_REL = ".olam/config.yaml";
33936
34888
  function locateConfig(cwd) {
33937
- const absPath = join72(cwd, CONFIG_REL);
33938
- if (!existsSync81(absPath)) {
34889
+ const absPath = join74(cwd, CONFIG_REL);
34890
+ if (!existsSync85(absPath)) {
33939
34891
  throw new Error(
33940
34892
  `No ${CONFIG_REL} at ${cwd}. Run \`olam init\` in your workspace root first.`
33941
34893
  );
@@ -33943,7 +34895,7 @@ function locateConfig(cwd) {
33943
34895
  return { absPath };
33944
34896
  }
33945
34897
  function readConfigYaml(absPath) {
33946
- const raw = readFileSync58(absPath, "utf-8");
34898
+ const raw = readFileSync63(absPath, "utf-8");
33947
34899
  const parsed = parseYaml7(raw) ?? {};
33948
34900
  if (typeof parsed !== "object" || parsed === null) {
33949
34901
  throw new Error(`${absPath} is not a YAML object`);
@@ -33952,7 +34904,7 @@ function readConfigYaml(absPath) {
33952
34904
  }
33953
34905
  function writeConfigYaml(absPath, parsed) {
33954
34906
  const out = stringifyYaml6(parsed, { aliasDuplicateObjects: false });
33955
- writeFileSync35(absPath, out, "utf-8");
34907
+ writeFileSync40(absPath, out, "utf-8");
33956
34908
  }
33957
34909
  async function defaultPromptText(question) {
33958
34910
  const rl = readline6.createInterface({ input: process.stdin, output: process.stdout });
@@ -34071,25 +35023,25 @@ function registerMemoryMode(cmd) {
34071
35023
  // src/commands/memory/bridge.ts
34072
35024
  init_output();
34073
35025
  import { spawn as spawn12 } from "node:child_process";
34074
- import { existsSync as existsSync82 } from "node:fs";
34075
- import { join as join73 } from "node:path";
35026
+ import { existsSync as existsSync86 } from "node:fs";
35027
+ import { join as join75 } from "node:path";
34076
35028
  var DEFAULT_PORT2 = 8788;
34077
35029
  function resolveMemoryServiceDir2() {
34078
35030
  for (const c of MEMORY_SERVICE_CANDIDATES) {
34079
- if (existsSync82(c)) return c;
35031
+ if (existsSync86(c)) return c;
34080
35032
  }
34081
35033
  throw new Error(
34082
35034
  `Could not find packages/memory-service/. Searched: ${MEMORY_SERVICE_CANDIDATES.join(", ")}. If running from a published @pleri/olam-cli tarball, this is a packaging bug \u2014 please file an issue.`
34083
35035
  );
34084
35036
  }
34085
35037
  function resolveLocalBridgeScript(serviceDir) {
34086
- const path78 = join73(serviceDir, "scripts", "local-bridge-server.mjs");
34087
- if (!existsSync82(path78)) {
35038
+ const path82 = join75(serviceDir, "scripts", "local-bridge-server.mjs");
35039
+ if (!existsSync86(path82)) {
34088
35040
  throw new Error(
34089
- `Could not find local-bridge-server.mjs at ${path78}. Verify packages/memory-service ships the scripts/ directory.`
35041
+ `Could not find local-bridge-server.mjs at ${path82}. Verify packages/memory-service ships the scripts/ directory.`
34090
35042
  );
34091
35043
  }
34092
- return path78;
35044
+ return path82;
34093
35045
  }
34094
35046
  function validateBridgeOpts(opts) {
34095
35047
  const local = opts.local ?? false;
@@ -34137,12 +35089,12 @@ async function runBridgeServe(opts, deps = {}) {
34137
35089
  stdio: "inherit"
34138
35090
  }));
34139
35091
  const child = spawner(process.execPath, [scriptPath, ...args], env);
34140
- return new Promise((resolve18) => {
35092
+ return new Promise((resolve19) => {
34141
35093
  let resolved = false;
34142
35094
  const finish = (code) => {
34143
35095
  if (resolved) return;
34144
35096
  resolved = true;
34145
- resolve18(code);
35097
+ resolve19(code);
34146
35098
  };
34147
35099
  const forward = (signal) => () => {
34148
35100
  if (!child.killed) {
@@ -34450,9 +35402,9 @@ function registerMemory(program2) {
34450
35402
  // src/commands/kg-build.ts
34451
35403
  init_storage_paths();
34452
35404
  init_workspace_name();
34453
- import * as fs74 from "node:fs";
34454
- import * as os41 from "node:os";
34455
- import * as path75 from "node:path";
35405
+ import * as fs79 from "node:fs";
35406
+ import * as os43 from "node:os";
35407
+ import * as path79 from "node:path";
34456
35408
 
34457
35409
  // ../core/dist/kg/kg-service-client.js
34458
35410
  var KG_SERVICE_PORT_DEFAULT = 9997;
@@ -34463,8 +35415,8 @@ function port() {
34463
35415
  const n = Number.parseInt(env, 10);
34464
35416
  return Number.isFinite(n) && n > 0 ? n : KG_SERVICE_PORT_DEFAULT;
34465
35417
  }
34466
- function url(path78) {
34467
- return `http://127.0.0.1:${port()}${path78}`;
35418
+ function url(path82) {
35419
+ return `http://127.0.0.1:${port()}${path82}`;
34468
35420
  }
34469
35421
  function kgServiceHealthUrl() {
34470
35422
  return url("/health");
@@ -34489,8 +35441,8 @@ var KgServiceUnreachableError = class extends Error {
34489
35441
  this.name = "KgServiceUnreachableError";
34490
35442
  }
34491
35443
  };
34492
- var DEFAULT_TIMEOUT_MS4 = 5e3;
34493
- async function postJson(endpointUrl, body, timeoutMs = DEFAULT_TIMEOUT_MS4) {
35444
+ var DEFAULT_TIMEOUT_MS5 = 5e3;
35445
+ async function postJson(endpointUrl, body, timeoutMs = DEFAULT_TIMEOUT_MS5) {
34494
35446
  let res;
34495
35447
  try {
34496
35448
  res = await fetch(endpointUrl, {
@@ -34508,7 +35460,7 @@ async function postJson(endpointUrl, body, timeoutMs = DEFAULT_TIMEOUT_MS4) {
34508
35460
  }
34509
35461
  return await res.json();
34510
35462
  }
34511
- async function getJson(endpointUrl, timeoutMs = DEFAULT_TIMEOUT_MS4) {
35463
+ async function getJson(endpointUrl, timeoutMs = DEFAULT_TIMEOUT_MS5) {
34512
35464
  let res;
34513
35465
  try {
34514
35466
  res = await fetch(endpointUrl, { signal: AbortSignal.timeout(timeoutMs) });
@@ -34542,40 +35494,40 @@ init_output();
34542
35494
  // src/commands/kg-status.ts
34543
35495
  init_storage_paths();
34544
35496
  init_workspace_name();
34545
- import fs70 from "node:fs";
34546
- import { homedir as homedir40 } from "node:os";
34547
- import path71 from "node:path";
35497
+ import fs75 from "node:fs";
35498
+ import { homedir as homedir42 } from "node:os";
35499
+ import path75 from "node:path";
34548
35500
  init_output();
34549
35501
  function olamHome4() {
34550
- return process.env.OLAM_HOME ?? path71.join(homedir40(), ".olam");
35502
+ return process.env.OLAM_HOME ?? path75.join(homedir42(), ".olam");
34551
35503
  }
34552
35504
  function kgRoot2() {
34553
- return path71.join(olamHome4(), "kg");
35505
+ return path75.join(olamHome4(), "kg");
34554
35506
  }
34555
35507
  function worldsRoot2() {
34556
- return path71.join(olamHome4(), "worlds");
35508
+ return path75.join(olamHome4(), "worlds");
34557
35509
  }
34558
35510
  function dirSizeBytes2(dir) {
34559
- if (!fs70.existsSync(dir)) return 0;
35511
+ if (!fs75.existsSync(dir)) return 0;
34560
35512
  let total = 0;
34561
35513
  const stack = [dir];
34562
35514
  while (stack.length > 0) {
34563
35515
  const cur = stack.pop();
34564
35516
  let entries;
34565
35517
  try {
34566
- entries = fs70.readdirSync(cur, { withFileTypes: true });
35518
+ entries = fs75.readdirSync(cur, { withFileTypes: true });
34567
35519
  } catch {
34568
35520
  continue;
34569
35521
  }
34570
35522
  for (const entry of entries) {
34571
- const full = path71.join(cur, entry.name);
35523
+ const full = path75.join(cur, entry.name);
34572
35524
  if (entry.isSymbolicLink()) continue;
34573
35525
  if (entry.isDirectory()) {
34574
35526
  stack.push(full);
34575
35527
  continue;
34576
35528
  }
34577
35529
  try {
34578
- total += fs70.statSync(full).size;
35530
+ total += fs75.statSync(full).size;
34579
35531
  } catch {
34580
35532
  }
34581
35533
  }
@@ -34589,10 +35541,10 @@ function formatBytes5(n) {
34589
35541
  return `${(n / 1024 / 1024 / 1024).toFixed(2)} GB`;
34590
35542
  }
34591
35543
  function readFreshness(workspace) {
34592
- const file = path71.join(kgPristinePath(workspace), "freshness.json");
34593
- if (!fs70.existsSync(file)) return null;
35544
+ const file = path75.join(kgPristinePath(workspace), "freshness.json");
35545
+ if (!fs75.existsSync(file)) return null;
34594
35546
  try {
34595
- const raw = JSON.parse(fs70.readFileSync(file, "utf-8"));
35547
+ const raw = JSON.parse(fs75.readFileSync(file, "utf-8"));
34596
35548
  if (raw && typeof raw === "object") return raw;
34597
35549
  return null;
34598
35550
  } catch {
@@ -34600,10 +35552,10 @@ function readFreshness(workspace) {
34600
35552
  }
34601
35553
  }
34602
35554
  function readOverlayNodeCount(graphifyOutDir) {
34603
- const graphPath = path71.join(graphifyOutDir, "graph.json");
34604
- if (!fs70.existsSync(graphPath)) return null;
35555
+ const graphPath = path75.join(graphifyOutDir, "graph.json");
35556
+ if (!fs75.existsSync(graphPath)) return null;
34605
35557
  try {
34606
- const raw = JSON.parse(fs70.readFileSync(graphPath, "utf-8"));
35558
+ const raw = JSON.parse(fs75.readFileSync(graphPath, "utf-8"));
34607
35559
  if (raw && typeof raw === "object") {
34608
35560
  const nodes = raw.nodes;
34609
35561
  if (Array.isArray(nodes)) return nodes.length;
@@ -34615,28 +35567,28 @@ function readOverlayNodeCount(graphifyOutDir) {
34615
35567
  }
34616
35568
  function listOverlays() {
34617
35569
  const root = worldsRoot2();
34618
- if (!fs70.existsSync(root)) return [];
35570
+ if (!fs75.existsSync(root)) return [];
34619
35571
  const records = [];
34620
35572
  let worldDirs;
34621
35573
  try {
34622
- worldDirs = fs70.readdirSync(root, { withFileTypes: true });
35574
+ worldDirs = fs75.readdirSync(root, { withFileTypes: true });
34623
35575
  } catch {
34624
35576
  return [];
34625
35577
  }
34626
35578
  for (const worldEntry of worldDirs) {
34627
35579
  if (!worldEntry.isDirectory()) continue;
34628
35580
  const worldId = worldEntry.name;
34629
- const worldDir = path71.join(root, worldId);
35581
+ const worldDir = path75.join(root, worldId);
34630
35582
  let cloneDirs;
34631
35583
  try {
34632
- cloneDirs = fs70.readdirSync(worldDir, { withFileTypes: true });
35584
+ cloneDirs = fs75.readdirSync(worldDir, { withFileTypes: true });
34633
35585
  } catch {
34634
35586
  continue;
34635
35587
  }
34636
35588
  for (const cloneEntry of cloneDirs) {
34637
35589
  if (!cloneEntry.isDirectory()) continue;
34638
- const graphifyOut = path71.join(worldDir, cloneEntry.name, "graphify-out");
34639
- if (!fs70.existsSync(graphifyOut)) continue;
35590
+ const graphifyOut = path75.join(worldDir, cloneEntry.name, "graphify-out");
35591
+ if (!fs75.existsSync(graphifyOut)) continue;
34640
35592
  records.push({
34641
35593
  world_id: worldId,
34642
35594
  clone_dir: cloneEntry.name,
@@ -34650,11 +35602,11 @@ function listOverlays() {
34650
35602
  }
34651
35603
  function listPristines(overlays) {
34652
35604
  const root = kgRoot2();
34653
- if (!fs70.existsSync(root)) return [];
35605
+ if (!fs75.existsSync(root)) return [];
34654
35606
  const records = [];
34655
35607
  let entries;
34656
35608
  try {
34657
- entries = fs70.readdirSync(root, { withFileTypes: true });
35609
+ entries = fs75.readdirSync(root, { withFileTypes: true });
34658
35610
  } catch {
34659
35611
  return [];
34660
35612
  }
@@ -34667,7 +35619,7 @@ function listPristines(overlays) {
34667
35619
  continue;
34668
35620
  }
34669
35621
  const fresh = readFreshness(workspace);
34670
- const graphifyOut = path71.join(kgPristinePath(workspace), "graphify-out");
35622
+ const graphifyOut = path75.join(kgPristinePath(workspace), "graphify-out");
34671
35623
  const size = dirSizeBytes2(graphifyOut);
34672
35624
  const worldCount = overlays.filter((o) => o.clone_dir === workspace).length;
34673
35625
  records.push({
@@ -34803,10 +35755,10 @@ init_storage_paths();
34803
35755
  init_workspace_name();
34804
35756
  init_output();
34805
35757
  import { spawn as spawn13 } from "node:child_process";
34806
- import fs71 from "node:fs";
34807
- import path72 from "node:path";
35758
+ import fs76 from "node:fs";
35759
+ import path76 from "node:path";
34808
35760
  function pidFilePath2(workspace) {
34809
- return path72.join(kgPristinePath(workspace), ".watch.pid");
35761
+ return path76.join(kgPristinePath(workspace), ".watch.pid");
34810
35762
  }
34811
35763
  function isPidAlive3(pid) {
34812
35764
  if (!Number.isInteger(pid) || pid <= 0) return false;
@@ -34821,39 +35773,39 @@ function isPidAlive3(pid) {
34821
35773
  }
34822
35774
  function readAndClassifyPid(workspace) {
34823
35775
  const file = pidFilePath2(workspace);
34824
- if (!fs71.existsSync(file)) return { status: "no-pidfile", pid: null };
35776
+ if (!fs76.existsSync(file)) return { status: "no-pidfile", pid: null };
34825
35777
  let pid;
34826
35778
  try {
34827
- const raw = fs71.readFileSync(file, "utf-8").trim();
35779
+ const raw = fs76.readFileSync(file, "utf-8").trim();
34828
35780
  pid = Number.parseInt(raw, 10);
34829
35781
  } catch {
34830
- fs71.rmSync(file, { force: true });
35782
+ fs76.rmSync(file, { force: true });
34831
35783
  return { status: "stale-reclaimed", pid: null };
34832
35784
  }
34833
35785
  if (!Number.isInteger(pid) || pid <= 0) {
34834
- fs71.rmSync(file, { force: true });
35786
+ fs76.rmSync(file, { force: true });
34835
35787
  return { status: "stale-reclaimed", pid: null };
34836
35788
  }
34837
35789
  if (isPidAlive3(pid)) return { status: "active", pid };
34838
- fs71.rmSync(file, { force: true });
35790
+ fs76.rmSync(file, { force: true });
34839
35791
  return { status: "stale-reclaimed", pid: null };
34840
35792
  }
34841
35793
  function writePidFile2(workspace, pid) {
34842
35794
  const file = pidFilePath2(workspace);
34843
- const dir = path72.dirname(file);
34844
- fs71.mkdirSync(dir, { recursive: true });
34845
- fs71.writeFileSync(file, String(pid), { encoding: "utf-8" });
35795
+ const dir = path76.dirname(file);
35796
+ fs76.mkdirSync(dir, { recursive: true });
35797
+ fs76.writeFileSync(file, String(pid), { encoding: "utf-8" });
34846
35798
  }
34847
35799
  function removePidFile(workspace) {
34848
35800
  const file = pidFilePath2(workspace);
34849
35801
  try {
34850
- fs71.rmSync(file, { force: true });
35802
+ fs76.rmSync(file, { force: true });
34851
35803
  } catch {
34852
35804
  }
34853
35805
  }
34854
35806
  async function runKgWatch(workspaceArg, opts, deps = {}) {
34855
35807
  const cwd = deps.cwd ?? opts.cwd ?? process.cwd();
34856
- const name = workspaceArg ?? path72.basename(cwd).toLowerCase();
35808
+ const name = workspaceArg ?? path76.basename(cwd).toLowerCase();
34857
35809
  try {
34858
35810
  validateWorkspaceName(name);
34859
35811
  } catch (err) {
@@ -34861,7 +35813,7 @@ async function runKgWatch(workspaceArg, opts, deps = {}) {
34861
35813
  return { exitCode: 1, pidWritten: false };
34862
35814
  }
34863
35815
  const pristinePath = kgPristinePath(name);
34864
- const graphPath = path72.join(pristinePath, "graphify-out", "graph.json");
35816
+ const graphPath = path76.join(pristinePath, "graphify-out", "graph.json");
34865
35817
  const pidState = readAndClassifyPid(name);
34866
35818
  if (pidState.status === "active") {
34867
35819
  printError(
@@ -34901,16 +35853,16 @@ async function runKgWatch(workspaceArg, opts, deps = {}) {
34901
35853
  process.on("SIGINT", () => forward("SIGINT"));
34902
35854
  process.on("SIGTERM", () => forward("SIGTERM"));
34903
35855
  }
34904
- return new Promise((resolve18) => {
35856
+ return new Promise((resolve19) => {
34905
35857
  child.on("exit", (code, signal) => {
34906
35858
  removePidFile(name);
34907
35859
  const exitCode = typeof code === "number" ? code : signal === "SIGINT" || signal === "SIGTERM" ? 0 : 1;
34908
- resolve18({ exitCode, pidWritten: true });
35860
+ resolve19({ exitCode, pidWritten: true });
34909
35861
  });
34910
35862
  child.on("error", (err) => {
34911
35863
  removePidFile(name);
34912
35864
  printError(`graphify subprocess error: ${err.message}`);
34913
- resolve18({ exitCode: 1, pidWritten: true });
35865
+ resolve19({ exitCode: 1, pidWritten: true });
34914
35866
  });
34915
35867
  });
34916
35868
  }
@@ -34924,7 +35876,7 @@ function registerKgWatchCommand(kg) {
34924
35876
  }
34925
35877
 
34926
35878
  // src/commands/kg-classify.ts
34927
- import pc39 from "picocolors";
35879
+ import pc40 from "picocolors";
34928
35880
  init_output();
34929
35881
  function registerKgClassifyCommand(kg) {
34930
35882
  kg.command("classify <question>").description("Route a question to kg | grep | both via the 4-layer classifier (kg-service required)").option("--workspace <name>", "Scope the L2 probe gate to a specific workspace graph").option("--json", "Emit raw JSON instead of the formatted summary").action(async (question, opts) => {
@@ -34934,7 +35886,7 @@ function registerKgClassifyCommand(kg) {
34934
35886
  process.stdout.write(JSON.stringify(result, null, 2) + "\n");
34935
35887
  return;
34936
35888
  }
34937
- const routeStr = result.route === "kg" ? pc39.cyan("kg") : result.route === "grep" ? pc39.magenta("grep") : pc39.yellow("both");
35889
+ const routeStr = result.route === "kg" ? pc40.cyan("kg") : result.route === "grep" ? pc40.magenta("grep") : pc40.yellow("both");
34938
35890
  printInfo("route", `${routeStr} (layer ${result.layer}, took ${result.took_ms}ms)`);
34939
35891
  printInfo("confidence", String(result.confidence));
34940
35892
  printInfo("reason", result.reason);
@@ -34956,7 +35908,7 @@ function registerKgClassifyCommand(kg) {
34956
35908
  }
34957
35909
 
34958
35910
  // src/commands/kg-doctor.ts
34959
- import pc40 from "picocolors";
35911
+ import pc41 from "picocolors";
34960
35912
  init_output();
34961
35913
  async function runProbes() {
34962
35914
  const results = [];
@@ -35075,12 +36027,12 @@ function registerKgDoctorCommand(kg) {
35075
36027
  } else {
35076
36028
  printHeader("kg-service doctor");
35077
36029
  for (const p of probes) {
35078
- const badge = p.status === "ok" ? pc40.green("\u2713") : p.status === "warn" ? pc40.yellow("\u2298") : pc40.red("\u2717");
36030
+ const badge = p.status === "ok" ? pc41.green("\u2713") : p.status === "warn" ? pc41.yellow("\u2298") : pc41.red("\u2717");
35079
36031
  const label = `${badge} ${p.name}`;
35080
36032
  const detail = p.detail ?? "";
35081
36033
  printInfo(label, detail);
35082
36034
  if (p.remedy) {
35083
- process.stderr.write(` ${pc40.dim("remedy:")} ${p.remedy}
36035
+ process.stderr.write(` ${pc41.dim("remedy:")} ${p.remedy}
35084
36036
  `);
35085
36037
  }
35086
36038
  }
@@ -35098,9 +36050,9 @@ function registerKgDoctorCommand(kg) {
35098
36050
  }
35099
36051
 
35100
36052
  // src/commands/kg-install-hook.ts
35101
- import * as fs72 from "node:fs";
35102
- import * as path73 from "node:path";
35103
- import * as os39 from "node:os";
36053
+ import * as fs77 from "node:fs";
36054
+ import * as path77 from "node:path";
36055
+ import * as os41 from "node:os";
35104
36056
 
35105
36057
  // ../core/dist/kg/hook-template.js
35106
36058
  var KG_HOOK_SENTINEL = "kg-service-v2-classifier-hook";
@@ -35151,15 +36103,15 @@ function buildHookMatcherEntry(opts) {
35151
36103
  init_output();
35152
36104
  function settingsPathFor2(scope) {
35153
36105
  if (scope === "user") {
35154
- return path73.join(os39.homedir(), ".claude", "settings.json");
36106
+ return path77.join(os41.homedir(), ".claude", "settings.json");
35155
36107
  }
35156
- return path73.join(process.cwd(), ".claude", "settings.json");
36108
+ return path77.join(process.cwd(), ".claude", "settings.json");
35157
36109
  }
35158
36110
  function backup2(filePath) {
35159
- if (!fs72.existsSync(filePath)) return null;
36111
+ if (!fs77.existsSync(filePath)) return null;
35160
36112
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
35161
36113
  const backupPath = `${filePath}.olam-bak.${ts}`;
35162
- fs72.copyFileSync(filePath, backupPath);
36114
+ fs77.copyFileSync(filePath, backupPath);
35163
36115
  return backupPath;
35164
36116
  }
35165
36117
  function registerKgInstallHookCommand(kg) {
@@ -35167,9 +36119,9 @@ function registerKgInstallHookCommand(kg) {
35167
36119
  const scope = opts.scope === "user" ? "user" : "project";
35168
36120
  const filePath = settingsPathFor2(scope);
35169
36121
  try {
35170
- fs72.mkdirSync(path73.dirname(filePath), { recursive: true });
36122
+ fs77.mkdirSync(path77.dirname(filePath), { recursive: true });
35171
36123
  } catch (err) {
35172
- printError(`could not create ${path73.dirname(filePath)}: ${err instanceof Error ? err.message : String(err)}`);
36124
+ printError(`could not create ${path77.dirname(filePath)}: ${err instanceof Error ? err.message : String(err)}`);
35173
36125
  process.exitCode = 1;
35174
36126
  return;
35175
36127
  }
@@ -35193,7 +36145,7 @@ function registerKgInstallHookCommand(kg) {
35193
36145
  printInfo("kg-service hook", `already installed at ${filePath}`);
35194
36146
  if (backupPath) {
35195
36147
  try {
35196
- fs72.unlinkSync(backupPath);
36148
+ fs77.unlinkSync(backupPath);
35197
36149
  } catch {
35198
36150
  }
35199
36151
  }
@@ -35211,15 +36163,15 @@ function registerKgInstallHookCommand(kg) {
35211
36163
  }
35212
36164
 
35213
36165
  // src/commands/kg-uninstall-hook.ts
35214
- import * as fs73 from "node:fs";
35215
- import * as path74 from "node:path";
35216
- import * as os40 from "node:os";
36166
+ import * as fs78 from "node:fs";
36167
+ import * as path78 from "node:path";
36168
+ import * as os42 from "node:os";
35217
36169
  init_output();
35218
36170
  function settingsPathFor3(scope) {
35219
36171
  if (scope === "user") {
35220
- return path74.join(os40.homedir(), ".claude", "settings.json");
36172
+ return path78.join(os42.homedir(), ".claude", "settings.json");
35221
36173
  }
35222
- return path74.join(process.cwd(), ".claude", "settings.json");
36174
+ return path78.join(process.cwd(), ".claude", "settings.json");
35223
36175
  }
35224
36176
  function dropSentinel(matchers) {
35225
36177
  let changed = false;
@@ -35249,13 +36201,13 @@ function registerKgUninstallHookCommand(kg) {
35249
36201
  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) => {
35250
36202
  const scope = opts.scope === "user" ? "user" : "project";
35251
36203
  const filePath = settingsPathFor3(scope);
35252
- if (!fs73.existsSync(filePath)) {
36204
+ if (!fs78.existsSync(filePath)) {
35253
36205
  printInfo("kg-service hook", `no settings.json at ${filePath} \u2014 nothing to remove`);
35254
36206
  return;
35255
36207
  }
35256
36208
  let settings;
35257
36209
  try {
35258
- const raw = fs73.readFileSync(filePath, "utf-8");
36210
+ const raw = fs78.readFileSync(filePath, "utf-8");
35259
36211
  settings = raw.trim() ? JSON.parse(raw) : {};
35260
36212
  } catch (err) {
35261
36213
  printError(`could not parse ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
@@ -35275,7 +36227,7 @@ function registerKgUninstallHookCommand(kg) {
35275
36227
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
35276
36228
  const backupPath = `${filePath}.olam-bak.${ts}`;
35277
36229
  try {
35278
- fs73.copyFileSync(filePath, backupPath);
36230
+ fs78.copyFileSync(filePath, backupPath);
35279
36231
  } catch {
35280
36232
  }
35281
36233
  const next = {
@@ -35294,7 +36246,7 @@ function registerKgUninstallHookCommand(kg) {
35294
36246
  }
35295
36247
  }
35296
36248
  try {
35297
- fs73.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
36249
+ fs78.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
35298
36250
  printSuccess(`kg-service hook removed from ${filePath}`);
35299
36251
  printInfo("backup", backupPath);
35300
36252
  } catch (err) {
@@ -35368,20 +36320,20 @@ function registerKgSavingsCommand(kg) {
35368
36320
  // src/commands/kg-build.ts
35369
36321
  function resolveWorkspace(arg) {
35370
36322
  const cwd = process.cwd();
35371
- const name = arg ?? path75.basename(cwd).toLowerCase();
36323
+ const name = arg ?? path79.basename(cwd).toLowerCase();
35372
36324
  validateWorkspaceName(name);
35373
36325
  return { name, sourcePath: cwd };
35374
36326
  }
35375
36327
  function toContainerPath(hostPath) {
35376
- const home = os41.homedir();
35377
- const resolved = path75.resolve(hostPath);
35378
- if (!resolved.startsWith(home + path75.sep) && resolved !== home) {
36328
+ const home = os43.homedir();
36329
+ const resolved = path79.resolve(hostPath);
36330
+ if (!resolved.startsWith(home + path79.sep) && resolved !== home) {
35379
36331
  throw new Error(
35380
36332
  `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.`
35381
36333
  );
35382
36334
  }
35383
- const rel = path75.relative(home, resolved);
35384
- return rel === "" ? "/host-home" : path75.posix.join("/host-home", rel.split(path75.sep).join("/"));
36335
+ const rel = path79.relative(home, resolved);
36336
+ return rel === "" ? "/host-home" : path79.posix.join("/host-home", rel.split(path79.sep).join("/"));
35385
36337
  }
35386
36338
  async function runKgBuild(workspaceArg, options = {}) {
35387
36339
  let workspace;
@@ -35399,7 +36351,7 @@ async function runKgBuild(workspaceArg, options = {}) {
35399
36351
  return { exitCode: 2 };
35400
36352
  }
35401
36353
  const outDir = kgPristinePath(workspace.name);
35402
- fs74.mkdirSync(outDir, { recursive: true });
36354
+ fs79.mkdirSync(outDir, { recursive: true });
35403
36355
  const human = !options.json;
35404
36356
  if (human) {
35405
36357
  printInfo("kg build", `workspace=${workspace.name} source=${workspace.sourcePath}`);
@@ -35432,12 +36384,12 @@ async function runKgBuild(workspaceArg, options = {}) {
35432
36384
  workspace: workspace.name,
35433
36385
  graphify_path: "container"
35434
36386
  };
35435
- fs74.writeFileSync(
35436
- path75.join(outDir, "freshness.json"),
36387
+ fs79.writeFileSync(
36388
+ path79.join(outDir, "freshness.json"),
35437
36389
  JSON.stringify(freshness, null, 2) + "\n",
35438
36390
  "utf-8"
35439
36391
  );
35440
- const finalOut = path75.join(outDir, "graphify-out");
36392
+ const finalOut = path79.join(outDir, "graphify-out");
35441
36393
  if (options.json) {
35442
36394
  process.stdout.write(JSON.stringify(freshness) + "\n");
35443
36395
  } else {
@@ -35714,14 +36666,14 @@ init_manager();
35714
36666
  init_context();
35715
36667
  init_output();
35716
36668
  import { spawnSync as defaultSpawnSync } from "node:child_process";
35717
- import * as fs75 from "node:fs";
35718
- import * as os42 from "node:os";
35719
- import * as path76 from "node:path";
36669
+ import * as fs80 from "node:fs";
36670
+ import * as os44 from "node:os";
36671
+ import * as path80 from "node:path";
35720
36672
  function devboxContainerName(worldId) {
35721
36673
  return `olam-${worldId}-devbox`;
35722
36674
  }
35723
36675
  function olamHomeDir() {
35724
- return process.env["OLAM_HOME"] ?? path76.join(os42.homedir(), ".olam");
36676
+ return process.env["OLAM_HOME"] ?? path80.join(os44.homedir(), ".olam");
35725
36677
  }
35726
36678
  function defaultRestartContainer(name, spawn14 = defaultSpawnSync) {
35727
36679
  const r = spawn14("docker", ["restart", "--time", "30", name], {
@@ -35734,8 +36686,8 @@ function defaultRestartContainer(name, spawn14 = defaultSpawnSync) {
35734
36686
  };
35735
36687
  }
35736
36688
  function defaultAppendAuditLog(homeDir, line) {
35737
- fs75.mkdirSync(homeDir, { recursive: true });
35738
- fs75.appendFileSync(path76.join(homeDir, "usage.log"), line.endsWith("\n") ? line : line + "\n", {
36689
+ fs80.mkdirSync(homeDir, { recursive: true });
36690
+ fs80.appendFileSync(path80.join(homeDir, "usage.log"), line.endsWith("\n") ? line : line + "\n", {
35739
36691
  encoding: "utf-8"
35740
36692
  });
35741
36693
  }
@@ -35780,19 +36732,19 @@ async function doRekey(worldId, deps) {
35780
36732
  );
35781
36733
  const rotatedAt = deps.now().toISOString();
35782
36734
  const homeDir = deps.olamHomeDir();
35783
- const worldDir = path76.join(homeDir, "worlds", worldId);
35784
- fs75.mkdirSync(worldDir, { recursive: true });
35785
- const credentialsPath = path76.join(worldDir, "credentials.json");
36735
+ const worldDir = path80.join(homeDir, "worlds", worldId);
36736
+ fs80.mkdirSync(worldDir, { recursive: true });
36737
+ const credentialsPath = path80.join(worldDir, "credentials.json");
35786
36738
  const payload = {
35787
36739
  worldRoleName,
35788
36740
  password,
35789
36741
  rotatedAt
35790
36742
  };
35791
- fs75.writeFileSync(credentialsPath, JSON.stringify(payload, null, 2) + "\n", {
36743
+ fs80.writeFileSync(credentialsPath, JSON.stringify(payload, null, 2) + "\n", {
35792
36744
  encoding: "utf-8",
35793
36745
  mode: 384
35794
36746
  });
35795
- fs75.chmodSync(credentialsPath, 384);
36747
+ fs80.chmodSync(credentialsPath, 384);
35796
36748
  const restart = deps.restartContainer(devboxContainerName(worldId));
35797
36749
  deps.appendAuditLog(`${rotatedAt} ${worldId} rekey`);
35798
36750
  if (!restart.ok) {
@@ -35856,18 +36808,18 @@ function registerRekey(program2) {
35856
36808
  }
35857
36809
 
35858
36810
  // src/pleri-config.ts
35859
- import * as fs76 from "node:fs";
35860
- import * as path77 from "node:path";
36811
+ import * as fs81 from "node:fs";
36812
+ import * as path81 from "node:path";
35861
36813
  function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
35862
36814
  if (process.env.PLERI_BASE_URL) {
35863
36815
  return true;
35864
36816
  }
35865
- const configPath = path77.join(configDir, "config.yaml");
35866
- if (!fs76.existsSync(configPath)) {
36817
+ const configPath = path81.join(configDir, "config.yaml");
36818
+ if (!fs81.existsSync(configPath)) {
35867
36819
  return false;
35868
36820
  }
35869
36821
  try {
35870
- const contents = fs76.readFileSync(configPath, "utf8");
36822
+ const contents = fs81.readFileSync(configPath, "utf8");
35871
36823
  return /^[^#\n]*\bpleri:/m.test(contents);
35872
36824
  } catch {
35873
36825
  return false;
@@ -35939,6 +36891,8 @@ registerSkillsHook(program);
35939
36891
  registerSkillsOnboard(program);
35940
36892
  registerSkillsMigrate(program);
35941
36893
  registerSkillsMigrateBack(program);
36894
+ registerSkillsMigrateHooks(program);
36895
+ registerSkillsMigrateHooksBack(program);
35942
36896
  registerSkillsShadowBackups(program);
35943
36897
  registerSkillsDoctor(program);
35944
36898
  program.parse();