@pleri/olam-cli 0.1.143 → 0.1.145

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/commands/doctor.d.ts +53 -23
  2. package/dist/commands/doctor.d.ts.map +1 -1
  3. package/dist/commands/doctor.js +117 -46
  4. package/dist/commands/doctor.js.map +1 -1
  5. package/dist/commands/logs.d.ts +17 -3
  6. package/dist/commands/logs.d.ts.map +1 -1
  7. package/dist/commands/logs.js +38 -35
  8. package/dist/commands/logs.js.map +1 -1
  9. package/dist/commands/memory/bridge.d.ts +57 -0
  10. package/dist/commands/memory/bridge.d.ts.map +1 -0
  11. package/dist/commands/memory/bridge.js +156 -0
  12. package/dist/commands/memory/bridge.js.map +1 -0
  13. package/dist/commands/memory/index.d.ts +3 -0
  14. package/dist/commands/memory/index.d.ts.map +1 -1
  15. package/dist/commands/memory/index.js +10 -1
  16. package/dist/commands/memory/index.js.map +1 -1
  17. package/dist/commands/memory/reclassify.d.ts +56 -0
  18. package/dist/commands/memory/reclassify.d.ts.map +1 -0
  19. package/dist/commands/memory/reclassify.js +177 -0
  20. package/dist/commands/memory/reclassify.js.map +1 -0
  21. package/dist/commands/memory/stats.d.ts +69 -0
  22. package/dist/commands/memory/stats.d.ts.map +1 -0
  23. package/dist/commands/memory/stats.js +164 -0
  24. package/dist/commands/memory/stats.js.map +1 -0
  25. package/dist/commands/skills-source.d.ts +12 -0
  26. package/dist/commands/skills-source.d.ts.map +1 -0
  27. package/dist/commands/skills-source.js +133 -0
  28. package/dist/commands/skills-source.js.map +1 -0
  29. package/dist/commands/skills.d.ts +11 -0
  30. package/dist/commands/skills.d.ts.map +1 -0
  31. package/dist/commands/skills.js +163 -0
  32. package/dist/commands/skills.js.map +1 -0
  33. package/dist/commands/status.d.ts +27 -0
  34. package/dist/commands/status.d.ts.map +1 -1
  35. package/dist/commands/status.js +102 -1
  36. package/dist/commands/status.js.map +1 -1
  37. package/dist/commands/upgrade.d.ts +24 -0
  38. package/dist/commands/upgrade.d.ts.map +1 -1
  39. package/dist/commands/upgrade.js +73 -0
  40. package/dist/commands/upgrade.js.map +1 -1
  41. package/dist/image-digests.json +7 -7
  42. package/dist/index.js +2093 -538
  43. package/dist/index.js.map +1 -1
  44. package/dist/lib/health-probes.d.ts +72 -0
  45. package/dist/lib/health-probes.d.ts.map +1 -1
  46. package/dist/lib/health-probes.js +218 -0
  47. package/dist/lib/health-probes.js.map +1 -1
  48. package/dist/mcp-server.js +1248 -353
  49. package/host-cp/src/agent-runtime-trigger.mjs +262 -0
  50. package/host-cp/src/engine-identity.mjs +32 -0
  51. package/host-cp/src/server.mjs +246 -2
  52. package/package.json +1 -1
@@ -445,8 +445,8 @@ var init_parseUtil = __esm({
445
445
  init_errors();
446
446
  init_en();
447
447
  makeIssue = (params) => {
448
- const { data, path: path31, errorMaps, issueData } = params;
449
- const fullPath = [...path31, ...issueData.path || []];
448
+ const { data, path: path37, errorMaps, issueData } = params;
449
+ const fullPath = [...path37, ...issueData.path || []];
450
450
  const fullIssue = {
451
451
  ...issueData,
452
452
  path: fullPath
@@ -754,11 +754,11 @@ var init_types = __esm({
754
754
  init_parseUtil();
755
755
  init_util();
756
756
  ParseInputLazyPath = class {
757
- constructor(parent, value, path31, key) {
757
+ constructor(parent, value, path37, key) {
758
758
  this._cachedPath = [];
759
759
  this.parent = parent;
760
760
  this.data = value;
761
- this._path = path31;
761
+ this._path = path37;
762
762
  this._key = key;
763
763
  }
764
764
  get path() {
@@ -7332,8 +7332,8 @@ var require_utils = __commonJS({
7332
7332
  }
7333
7333
  return ind;
7334
7334
  }
7335
- function removeDotSegments(path31) {
7336
- let input = path31;
7335
+ function removeDotSegments(path37) {
7336
+ let input = path37;
7337
7337
  const output = [];
7338
7338
  let nextSlash = -1;
7339
7339
  let len = 0;
@@ -7532,8 +7532,8 @@ var require_schemes = __commonJS({
7532
7532
  wsComponent.secure = void 0;
7533
7533
  }
7534
7534
  if (wsComponent.resourceName) {
7535
- const [path31, query] = wsComponent.resourceName.split("?");
7536
- wsComponent.path = path31 && path31 !== "/" ? path31 : void 0;
7535
+ const [path37, query] = wsComponent.resourceName.split("?");
7536
+ wsComponent.path = path37 && path37 !== "/" ? path37 : void 0;
7537
7537
  wsComponent.query = query;
7538
7538
  wsComponent.resourceName = void 0;
7539
7539
  }
@@ -10895,12 +10895,12 @@ var require_dist = __commonJS({
10895
10895
  throw new Error(`Unknown format "${name}"`);
10896
10896
  return f;
10897
10897
  };
10898
- function addFormats(ajv, list, fs28, exportName) {
10898
+ function addFormats(ajv, list, fs34, exportName) {
10899
10899
  var _a3;
10900
10900
  var _b;
10901
10901
  (_a3 = (_b = ajv.opts.code).formats) !== null && _a3 !== void 0 ? _a3 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
10902
10902
  for (const f of list)
10903
- ajv.addFormat(f, fs28[f]);
10903
+ ajv.addFormat(f, fs34[f]);
10904
10904
  }
10905
10905
  module.exports = exports = formatsPlugin;
10906
10906
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -11008,7 +11008,7 @@ import YAML from "yaml";
11008
11008
  function bootstrapStepCmd(entry) {
11009
11009
  return typeof entry === "string" ? entry : entry.cmd;
11010
11010
  }
11011
- function refineForbiddenKeys(value, path31, ctx, rejectSource) {
11011
+ function refineForbiddenKeys(value, path37, ctx, rejectSource) {
11012
11012
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
11013
11013
  return;
11014
11014
  }
@@ -11016,12 +11016,12 @@ function refineForbiddenKeys(value, path31, ctx, rejectSource) {
11016
11016
  if (FORBIDDEN_KEYS.has(key)) {
11017
11017
  ctx.addIssue({
11018
11018
  code: external_exports.ZodIssueCode.custom,
11019
- path: [...path31, key],
11019
+ path: [...path37, key],
11020
11020
  message: `forbidden key "${key}" (prototype-pollution surface)`
11021
11021
  });
11022
11022
  continue;
11023
11023
  }
11024
- if (rejectSource && path31.length === 0 && key === "source") {
11024
+ if (rejectSource && path37.length === 0 && key === "source") {
11025
11025
  ctx.addIssue({
11026
11026
  code: external_exports.ZodIssueCode.custom,
11027
11027
  path: ["source"],
@@ -11029,21 +11029,21 @@ function refineForbiddenKeys(value, path31, ctx, rejectSource) {
11029
11029
  });
11030
11030
  continue;
11031
11031
  }
11032
- refineForbiddenKeys(value[key], [...path31, key], ctx, false);
11032
+ refineForbiddenKeys(value[key], [...path37, key], ctx, false);
11033
11033
  }
11034
11034
  }
11035
- function rejectForbiddenKeys(value, path31, rejectSource) {
11035
+ function rejectForbiddenKeys(value, path37, rejectSource) {
11036
11036
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
11037
11037
  return;
11038
11038
  }
11039
11039
  for (const key of Object.keys(value)) {
11040
11040
  if (FORBIDDEN_KEYS.has(key)) {
11041
- throw new Error(`[manifest] ${path31}: forbidden key "${key}" (prototype-pollution surface)`);
11041
+ throw new Error(`[manifest] ${path37}: forbidden key "${key}" (prototype-pollution surface)`);
11042
11042
  }
11043
11043
  if (rejectSource && key === "source") {
11044
- throw new Error(`[manifest] ${path31}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
11044
+ throw new Error(`[manifest] ${path37}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
11045
11045
  }
11046
- rejectForbiddenKeys(value[key], `${path31}.${key}`, false);
11046
+ rejectForbiddenKeys(value[key], `${path37}.${key}`, false);
11047
11047
  }
11048
11048
  }
11049
11049
  function unknownTopLevelKeys(parsed) {
@@ -12116,10 +12116,10 @@ function mergeDefs(...defs) {
12116
12116
  function cloneDef(schema) {
12117
12117
  return mergeDefs(schema._zod.def);
12118
12118
  }
12119
- function getElementAtPath(obj, path31) {
12120
- if (!path31)
12119
+ function getElementAtPath(obj, path37) {
12120
+ if (!path37)
12121
12121
  return obj;
12122
- return path31.reduce((acc, key) => acc?.[key], obj);
12122
+ return path37.reduce((acc, key) => acc?.[key], obj);
12123
12123
  }
12124
12124
  function promiseAllObject(promisesObj) {
12125
12125
  const keys = Object.keys(promisesObj);
@@ -12528,11 +12528,11 @@ function explicitlyAborted(x, startIndex = 0) {
12528
12528
  }
12529
12529
  return false;
12530
12530
  }
12531
- function prefixIssues(path31, issues) {
12531
+ function prefixIssues(path37, issues) {
12532
12532
  return issues.map((iss) => {
12533
12533
  var _a3;
12534
12534
  (_a3 = iss).path ?? (_a3.path = []);
12535
- iss.path.unshift(path31);
12535
+ iss.path.unshift(path37);
12536
12536
  return iss;
12537
12537
  });
12538
12538
  }
@@ -12679,16 +12679,16 @@ function flattenError(error2, mapper = (issue2) => issue2.message) {
12679
12679
  }
12680
12680
  function formatError(error2, mapper = (issue2) => issue2.message) {
12681
12681
  const fieldErrors = { _errors: [] };
12682
- const processError = (error3, path31 = []) => {
12682
+ const processError = (error3, path37 = []) => {
12683
12683
  for (const issue2 of error3.issues) {
12684
12684
  if (issue2.code === "invalid_union" && issue2.errors.length) {
12685
- issue2.errors.map((issues) => processError({ issues }, [...path31, ...issue2.path]));
12685
+ issue2.errors.map((issues) => processError({ issues }, [...path37, ...issue2.path]));
12686
12686
  } else if (issue2.code === "invalid_key") {
12687
- processError({ issues: issue2.issues }, [...path31, ...issue2.path]);
12687
+ processError({ issues: issue2.issues }, [...path37, ...issue2.path]);
12688
12688
  } else if (issue2.code === "invalid_element") {
12689
- processError({ issues: issue2.issues }, [...path31, ...issue2.path]);
12689
+ processError({ issues: issue2.issues }, [...path37, ...issue2.path]);
12690
12690
  } else {
12691
- const fullpath = [...path31, ...issue2.path];
12691
+ const fullpath = [...path37, ...issue2.path];
12692
12692
  if (fullpath.length === 0) {
12693
12693
  fieldErrors._errors.push(mapper(issue2));
12694
12694
  } else {
@@ -23327,8 +23327,8 @@ var AuthClient = class {
23327
23327
  throw new Error(`failed to report rate-limit for ${accountId} (HTTP ${res.status})`);
23328
23328
  }
23329
23329
  }
23330
- async request(method, path31, body, attempt = 0) {
23331
- const url2 = `${this.baseUrl}${path31}`;
23330
+ async request(method, path37, body, attempt = 0) {
23331
+ const url2 = `${this.baseUrl}${path37}`;
23332
23332
  const controller = new AbortController();
23333
23333
  const timer = setTimeout(() => controller.abort(), this.timeoutMs);
23334
23334
  const headers = {};
@@ -23346,7 +23346,7 @@ var AuthClient = class {
23346
23346
  } catch (err) {
23347
23347
  if (attempt < RETRY_COUNT && isTransient(err)) {
23348
23348
  await sleep(RETRY_BACKOFF_MS * (attempt + 1));
23349
- return this.request(method, path31, body, attempt + 1);
23349
+ return this.request(method, path37, body, attempt + 1);
23350
23350
  }
23351
23351
  throw err;
23352
23352
  } finally {
@@ -24197,12 +24197,12 @@ function register3(server, _ctx, _initError) {
24197
24197
  registry2.close();
24198
24198
  }
24199
24199
  try {
24200
- const { default: fs28 } = await import("node:fs");
24201
- const { default: os17 } = await import("node:os");
24202
- const { default: path31 } = await import("node:path");
24203
- const tokenPath = path31.join(os17.homedir(), ".olam", "host-cp.token");
24204
- if (fs28.existsSync(tokenPath)) {
24205
- const token = fs28.readFileSync(tokenPath, "utf-8").trim();
24200
+ const { default: fs34 } = await import("node:fs");
24201
+ const { default: os21 } = await import("node:os");
24202
+ const { default: path37 } = await import("node:path");
24203
+ const tokenPath = path37.join(os21.homedir(), ".olam", "host-cp.token");
24204
+ if (fs34.existsSync(tokenPath)) {
24205
+ const token = fs34.readFileSync(tokenPath, "utf-8").trim();
24206
24206
  await fetch("http://127.0.0.1:19000/api/admin/world-pr", {
24207
24207
  method: "POST",
24208
24208
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
@@ -24639,10 +24639,10 @@ function extractMcpConfig(claudeJsonPath) {
24639
24639
  }
24640
24640
  return { mcpServers, secrets };
24641
24641
  }
24642
- function readOptional(path31) {
24643
- if (!existsSync6(path31)) return null;
24642
+ function readOptional(path37) {
24643
+ if (!existsSync6(path37)) return null;
24644
24644
  try {
24645
- return readFileSync5(path31, "utf8");
24645
+ return readFileSync5(path37, "utf8");
24646
24646
  } catch {
24647
24647
  return null;
24648
24648
  }
@@ -26058,8 +26058,8 @@ var CloudflareProvider = class extends ComputeProvider {
26058
26058
  // -----------------------------------------------------------------------
26059
26059
  // Internal fetch helper
26060
26060
  // -----------------------------------------------------------------------
26061
- async request(path31, method, body) {
26062
- const url2 = `${this.config.workerUrl}${path31}`;
26061
+ async request(path37, method, body) {
26062
+ const url2 = `${this.config.workerUrl}${path37}`;
26063
26063
  const bearer = await this.config.mintToken();
26064
26064
  const headers = {
26065
26065
  Authorization: `Bearer ${bearer}`
@@ -28510,10 +28510,10 @@ async function writeManifest(args) {
28510
28510
  capturedAt: args.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
28511
28511
  shots: entries
28512
28512
  };
28513
- const path31 = join13(args.outDir, "manifest.json");
28514
- await writeFile(path31, `${JSON.stringify(manifest, null, 2)}
28513
+ const path37 = join13(args.outDir, "manifest.json");
28514
+ await writeFile(path37, `${JSON.stringify(manifest, null, 2)}
28515
28515
  `, "utf8");
28516
- return { path: path31, manifest };
28516
+ return { path: path37, manifest };
28517
28517
  }
28518
28518
 
28519
28519
  // ../mcp-server/src/tools/_capture/proxy.ts
@@ -28767,9 +28767,9 @@ async function startProxy(opts) {
28767
28767
  const liveCompiled = verified.allowedPaths.map(compileGlob);
28768
28768
  const target = parseRequestTarget(req);
28769
28769
  if (!target) return httpReject(400, "invalid_target");
28770
- const path31 = target.pathname;
28771
- if (!liveCompiled.some((re) => re.test(path31))) {
28772
- return httpReject(403, "outside_allow_list", { path: path31 });
28770
+ const path37 = target.pathname;
28771
+ if (!liveCompiled.some((re) => re.test(path37))) {
28772
+ return httpReject(403, "outside_allow_list", { path: path37 });
28773
28773
  }
28774
28774
  const headerWorld = req.headers[WORLD_ASSERT_HEADER];
28775
28775
  const headerWorldStr = typeof headerWorld === "string" ? headerWorld : Array.isArray(headerWorld) && headerWorld.length > 0 ? headerWorld[0] : void 0;
@@ -29548,14 +29548,14 @@ async function runShot(browser, shot, outDir, format, jpegQuality, allowEval, as
29548
29548
  await page.waitForTimeout(shot.afterLoadMs);
29549
29549
  }
29550
29550
  const ext = format === "jpeg" ? "jpg" : "png";
29551
- const path31 = join14(outDir, `${shot.name}.${ext}`);
29551
+ const path37 = join14(outDir, `${shot.name}.${ext}`);
29552
29552
  await page.screenshot({
29553
- path: path31,
29553
+ path: path37,
29554
29554
  type: format,
29555
29555
  ...format === "jpeg" ? { quality: jpegQuality } : {},
29556
29556
  fullPage: false
29557
29557
  });
29558
- return { name: shot.name, path: path31, urlRedacted: redactUrl(shot.url), viewport };
29558
+ return { name: shot.name, path: path37, urlRedacted: redactUrl(shot.url), viewport };
29559
29559
  } finally {
29560
29560
  await context.close();
29561
29561
  }
@@ -29999,12 +29999,12 @@ function openUrl(url2) {
29999
29999
  var HOST_CP_URL = "http://127.0.0.1:19000";
30000
30000
  async function readHostCpToken2() {
30001
30001
  try {
30002
- const { default: fs28 } = await import("node:fs");
30003
- const { default: os17 } = await import("node:os");
30004
- const { default: path31 } = await import("node:path");
30005
- const tp = path31.join(os17.homedir(), ".olam", "host-cp.token");
30006
- if (!fs28.existsSync(tp)) return { token: null };
30007
- return { token: fs28.readFileSync(tp, "utf-8").trim() };
30002
+ const { default: fs34 } = await import("node:fs");
30003
+ const { default: os21 } = await import("node:os");
30004
+ const { default: path37 } = await import("node:path");
30005
+ const tp = path37.join(os21.homedir(), ".olam", "host-cp.token");
30006
+ if (!fs34.existsSync(tp)) return { token: null };
30007
+ return { token: fs34.readFileSync(tp, "utf-8").trim() };
30008
30008
  } catch {
30009
30009
  return { token: null };
30010
30010
  }
@@ -30240,6 +30240,22 @@ init_v3();
30240
30240
  // ../core/dist/global-config/schema.js
30241
30241
  init_v3();
30242
30242
  init_schema();
30243
+
30244
+ // ../core/dist/skill-sources/schema.js
30245
+ init_v3();
30246
+ var SKILL_SOURCE_ID_LENGTH = 12;
30247
+ var NAME_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
30248
+ var URL_PATTERN = /^(?:https?:\/\/|git@|ssh:\/\/|file:\/\/|\/).+/;
30249
+ var SkillSourceSchema = external_exports.object({
30250
+ id: external_exports.string().length(SKILL_SOURCE_ID_LENGTH, `skill-source id must be exactly ${SKILL_SOURCE_ID_LENGTH} chars (sha256-of-url prefix)`).regex(/^[a-f0-9]+$/, "skill-source id must be lowercase hex"),
30251
+ name: external_exports.string().regex(NAME_PATTERN, "skill-source name must be ASCII lowercase + digits + dash (1-64 chars, no leading/trailing dash)"),
30252
+ gitUrl: external_exports.string().min(1, "gitUrl must not be empty").regex(URL_PATTERN, "gitUrl must look like a git URL (https://, git@, ssh://, file://, or absolute path)"),
30253
+ branch: external_exports.string().min(1, "branch must not be empty").default("main"),
30254
+ addedAt: external_exports.number().int().nonnegative(),
30255
+ lastPulledSha: external_exports.string().regex(/^[a-f0-9]{40}$/, "lastPulledSha must be a 40-char lowercase hex git SHA").optional()
30256
+ });
30257
+
30258
+ // ../core/dist/global-config/schema.js
30243
30259
  function isAbsoluteOrTilde(p) {
30244
30260
  return p.startsWith("/") || p === "~" || p.startsWith("~/");
30245
30261
  }
@@ -30292,7 +30308,8 @@ var RunbookSchema = external_exports.object({
30292
30308
  var GlobalConfigSchema = external_exports.object({
30293
30309
  schemaVersion: external_exports.literal(1),
30294
30310
  repos: external_exports.array(RepoEntrySchema).optional().default([]),
30295
- runbooks: external_exports.array(RunbookSchema).optional().default([])
30311
+ runbooks: external_exports.array(RunbookSchema).optional().default([]),
30312
+ skillSources: external_exports.array(SkillSourceSchema).optional().default([])
30296
30313
  }).strip().superRefine((val, ctx) => {
30297
30314
  const repoNames = val.repos.map((r) => r.name);
30298
30315
  const repoDupes = repoNames.filter((n, i) => repoNames.indexOf(n) !== i);
@@ -30304,11 +30321,22 @@ var GlobalConfigSchema = external_exports.object({
30304
30321
  for (const d of rbDupes) {
30305
30322
  ctx.addIssue({ code: external_exports.ZodIssueCode.custom, message: `duplicate runbook name: "${d}"`, path: ["runbooks"] });
30306
30323
  }
30324
+ const skillIds = val.skillSources.map((s) => s.id);
30325
+ const skillIdDupes = skillIds.filter((n, i) => skillIds.indexOf(n) !== i);
30326
+ for (const d of skillIdDupes) {
30327
+ ctx.addIssue({ code: external_exports.ZodIssueCode.custom, message: `duplicate skill-source id: "${d}"`, path: ["skillSources"] });
30328
+ }
30329
+ const skillNames = val.skillSources.map((s) => s.name);
30330
+ const skillNameDupes = skillNames.filter((n, i) => skillNames.indexOf(n) !== i);
30331
+ for (const d of skillNameDupes) {
30332
+ ctx.addIssue({ code: external_exports.ZodIssueCode.custom, message: `duplicate skill-source name: "${d}"`, path: ["skillSources"] });
30333
+ }
30307
30334
  });
30308
30335
  var DEFAULT_GLOBAL_CONFIG = {
30309
30336
  schemaVersion: 1,
30310
30337
  repos: [],
30311
- runbooks: []
30338
+ runbooks: [],
30339
+ skillSources: []
30312
30340
  };
30313
30341
 
30314
30342
  // ../core/dist/global-config/store.js
@@ -30622,6 +30650,627 @@ function repoEntryToRepoConfig(entry) {
30622
30650
  return config2;
30623
30651
  }
30624
30652
 
30653
+ // ../core/dist/skill-sources/store.js
30654
+ import * as crypto3 from "node:crypto";
30655
+ function deriveSkillSourceId(gitUrl) {
30656
+ return crypto3.createHash("sha256").update(gitUrl).digest("hex").slice(0, SKILL_SOURCE_ID_LENGTH);
30657
+ }
30658
+ function listSkillSources() {
30659
+ return readGlobalConfig().skillSources;
30660
+ }
30661
+ function getSkillSource(id) {
30662
+ return readGlobalConfig().skillSources.find((s) => s.id === id);
30663
+ }
30664
+ function addSkillSource(entry) {
30665
+ const config2 = readGlobalConfig();
30666
+ const id = deriveSkillSourceId(entry.gitUrl);
30667
+ if (config2.skillSources.some((s) => s.id === id)) {
30668
+ throw new Error(`skill-source "${entry.gitUrl}" already registered (id "${id}"). Use "olam skills source list" to inspect.`);
30669
+ }
30670
+ if (config2.skillSources.some((s) => s.name === entry.name)) {
30671
+ throw new Error(`skill-source name "${entry.name}" already in use. Pick a different display name.`);
30672
+ }
30673
+ const now = Date.now();
30674
+ const newEntry = {
30675
+ id,
30676
+ name: entry.name,
30677
+ gitUrl: entry.gitUrl,
30678
+ branch: entry.branch ?? "main",
30679
+ addedAt: now
30680
+ };
30681
+ writeGlobalConfig({ ...config2, skillSources: [...config2.skillSources, newEntry] });
30682
+ return newEntry;
30683
+ }
30684
+ function removeSkillSource(id) {
30685
+ const config2 = readGlobalConfig();
30686
+ if (!config2.skillSources.some((s) => s.id === id)) {
30687
+ throw new Error(`skill-source "${id}" is not registered. Run "olam skills source list" to see registered sources.`);
30688
+ }
30689
+ writeGlobalConfig({
30690
+ ...config2,
30691
+ skillSources: config2.skillSources.filter((s) => s.id !== id)
30692
+ });
30693
+ }
30694
+ function updateSkillSource(id, patch) {
30695
+ const config2 = readGlobalConfig();
30696
+ const idx = config2.skillSources.findIndex((s) => s.id === id);
30697
+ if (idx === -1) {
30698
+ throw new Error(`skill-source "${id}" is not registered. Run "olam skills source list" to see registered sources.`);
30699
+ }
30700
+ if (patch.name !== void 0) {
30701
+ const collision = config2.skillSources.find((s, i) => i !== idx && s.name === patch.name);
30702
+ if (collision !== void 0) {
30703
+ throw new Error(`skill-source name "${patch.name}" already in use by id "${collision.id}".`);
30704
+ }
30705
+ }
30706
+ const existing = config2.skillSources[idx];
30707
+ const updated = {
30708
+ ...existing,
30709
+ ...patch.name !== void 0 ? { name: patch.name } : {},
30710
+ ...patch.branch !== void 0 ? { branch: patch.branch } : {},
30711
+ ...patch.lastPulledSha !== void 0 ? { lastPulledSha: patch.lastPulledSha } : {}
30712
+ };
30713
+ const next = [...config2.skillSources];
30714
+ next[idx] = updated;
30715
+ writeGlobalConfig({ ...config2, skillSources: next });
30716
+ return updated;
30717
+ }
30718
+
30719
+ // ../core/dist/skill-sources/clone.js
30720
+ import { execFileSync as execFileSync2 } from "node:child_process";
30721
+ import * as fs13 from "node:fs";
30722
+ import * as os9 from "node:os";
30723
+ import * as path15 from "node:path";
30724
+ function skillSourcesRootDir() {
30725
+ const override = process.env["OLAM_SKILL_SOURCES_DIR"];
30726
+ if (override && override.length > 0)
30727
+ return override;
30728
+ return path15.join(os9.homedir(), ".olam", "state", "skill-sources");
30729
+ }
30730
+ function skillSourceClonePath(id) {
30731
+ return path15.join(skillSourcesRootDir(), id);
30732
+ }
30733
+ var SkillSourceGitError = class extends Error {
30734
+ op;
30735
+ gitUrl;
30736
+ constructor(op, gitUrl, cause) {
30737
+ const msg = cause instanceof Error ? cause.message : String(cause);
30738
+ super(`git ${op} failed for "${gitUrl}": ${msg}`);
30739
+ this.op = op;
30740
+ this.gitUrl = gitUrl;
30741
+ this.name = "SkillSourceGitError";
30742
+ this.cause = cause;
30743
+ }
30744
+ };
30745
+ function runGit(args, cwd) {
30746
+ try {
30747
+ return execFileSync2("git", args, {
30748
+ cwd,
30749
+ encoding: "utf-8",
30750
+ stdio: ["ignore", "pipe", "pipe"]
30751
+ });
30752
+ } catch (err) {
30753
+ throw err;
30754
+ }
30755
+ }
30756
+ function cloneSkillSource(opts) {
30757
+ const clonePath = skillSourceClonePath(opts.id);
30758
+ if (fs13.existsSync(clonePath)) {
30759
+ throw new Error(`clone path "${clonePath}" already exists. Remove the existing skill-source first.`);
30760
+ }
30761
+ fs13.mkdirSync(skillSourcesRootDir(), { recursive: true });
30762
+ try {
30763
+ runGit(["clone", "--depth", "1", "--branch", opts.branch, opts.gitUrl, clonePath]);
30764
+ } catch (err) {
30765
+ if (fs13.existsSync(clonePath)) {
30766
+ fs13.rmSync(clonePath, { recursive: true, force: true });
30767
+ }
30768
+ throw new SkillSourceGitError("clone", opts.gitUrl, err);
30769
+ }
30770
+ let headSha;
30771
+ try {
30772
+ headSha = runGit(["rev-parse", "HEAD"], clonePath).trim();
30773
+ } catch (err) {
30774
+ throw new SkillSourceGitError("rev-parse", opts.gitUrl, err);
30775
+ }
30776
+ return { clonePath, headSha };
30777
+ }
30778
+ function pullSkillSource(opts) {
30779
+ const clonePath = skillSourceClonePath(opts.id);
30780
+ if (!fs13.existsSync(clonePath)) {
30781
+ throw new Error(`clone path "${clonePath}" does not exist. Run "olam skills source add" first.`);
30782
+ }
30783
+ try {
30784
+ runGit(["fetch", "origin", opts.branch], clonePath);
30785
+ runGit(["reset", "--hard", `origin/${opts.branch}`], clonePath);
30786
+ } catch (err) {
30787
+ throw new SkillSourceGitError("fetch/reset", opts.gitUrl, err);
30788
+ }
30789
+ try {
30790
+ const headSha = runGit(["rev-parse", "HEAD"], clonePath).trim();
30791
+ return { headSha };
30792
+ } catch (err) {
30793
+ throw new SkillSourceGitError("rev-parse", opts.gitUrl, err);
30794
+ }
30795
+ }
30796
+ function removeSkillSourceClone(id) {
30797
+ const clonePath = skillSourceClonePath(id);
30798
+ if (fs13.existsSync(clonePath)) {
30799
+ fs13.rmSync(clonePath, { recursive: true, force: true });
30800
+ }
30801
+ }
30802
+
30803
+ // ../core/dist/skill-sync/artifact-resolver.js
30804
+ import * as fs14 from "node:fs";
30805
+ import * as path16 from "node:path";
30806
+ function resolveSubscriptions(opts) {
30807
+ const { clonePath, atlasUser } = opts;
30808
+ if (atlasUser) {
30809
+ const subsPath = path16.join(clonePath, "members", atlasUser, "subscriptions.json");
30810
+ if (fs14.existsSync(subsPath)) {
30811
+ try {
30812
+ const parsed = JSON.parse(fs14.readFileSync(subsPath, "utf-8"));
30813
+ if (Array.isArray(parsed?.categories)) {
30814
+ return {
30815
+ categories: parsed.categories.filter((c) => typeof c === "string"),
30816
+ fromSubscriptionsFile: true,
30817
+ atlasUser
30818
+ };
30819
+ }
30820
+ } catch {
30821
+ }
30822
+ }
30823
+ }
30824
+ const catsPath = path16.join(clonePath, "shared", "categories.json");
30825
+ if (fs14.existsSync(catsPath)) {
30826
+ try {
30827
+ const parsed = JSON.parse(fs14.readFileSync(catsPath, "utf-8"));
30828
+ if (Array.isArray(parsed?.categories)) {
30829
+ return {
30830
+ categories: parsed.categories.map((c) => c.id).filter((id) => typeof id === "string"),
30831
+ fromSubscriptionsFile: false,
30832
+ atlasUser
30833
+ };
30834
+ }
30835
+ } catch {
30836
+ }
30837
+ }
30838
+ const sharedDir = path16.join(clonePath, "shared");
30839
+ const cats = [];
30840
+ if (fs14.existsSync(sharedDir)) {
30841
+ for (const name of fs14.readdirSync(sharedDir)) {
30842
+ const dir = path16.join(sharedDir, name);
30843
+ if (!fs14.statSync(dir).isDirectory())
30844
+ continue;
30845
+ if (fs14.existsSync(path16.join(dir, "skills")) || fs14.existsSync(path16.join(dir, "agents"))) {
30846
+ cats.push(name);
30847
+ }
30848
+ }
30849
+ }
30850
+ return { categories: cats, fromSubscriptionsFile: false, atlasUser };
30851
+ }
30852
+ function listDirSafe(dir) {
30853
+ if (!fs14.existsSync(dir))
30854
+ return [];
30855
+ return fs14.readdirSync(dir);
30856
+ }
30857
+ function resolveSkillsDir(opts) {
30858
+ const { sourceId, baseDir } = opts;
30859
+ const out = [];
30860
+ for (const name of listDirSafe(baseDir)) {
30861
+ const subdir = path16.join(baseDir, name);
30862
+ if (!fs14.statSync(subdir).isDirectory())
30863
+ continue;
30864
+ if (!fs14.existsSync(path16.join(subdir, "SKILL.md")))
30865
+ continue;
30866
+ out.push({ kind: "skill", sourceId, sourcePath: subdir, deployBasename: name });
30867
+ const subagentsDir = path16.join(subdir, "references", "agents");
30868
+ if (fs14.existsSync(subagentsDir) && fs14.statSync(subagentsDir).isDirectory()) {
30869
+ for (const f of listDirSafe(subagentsDir)) {
30870
+ if (!f.endsWith(".md"))
30871
+ continue;
30872
+ out.push({
30873
+ kind: "subagent",
30874
+ sourceId,
30875
+ sourcePath: path16.join(subagentsDir, f),
30876
+ deployBasename: f,
30877
+ parentSkill: name
30878
+ });
30879
+ }
30880
+ }
30881
+ }
30882
+ return out;
30883
+ }
30884
+ function resolveAgentsDir(opts) {
30885
+ const { sourceId, baseDir } = opts;
30886
+ const out = [];
30887
+ for (const name of listDirSafe(baseDir)) {
30888
+ const full = path16.join(baseDir, name);
30889
+ const stat = fs14.statSync(full);
30890
+ if (stat.isFile() && name.endsWith(".md")) {
30891
+ out.push({ kind: "agent", sourceId, sourcePath: full, deployBasename: name });
30892
+ } else if (stat.isDirectory()) {
30893
+ for (const f of listDirSafe(full)) {
30894
+ if (!f.endsWith(".md"))
30895
+ continue;
30896
+ out.push({
30897
+ kind: "agent",
30898
+ sourceId,
30899
+ sourcePath: path16.join(full, f),
30900
+ deployBasename: `${name}-${f}`
30901
+ });
30902
+ }
30903
+ }
30904
+ }
30905
+ return out;
30906
+ }
30907
+ function resolveScriptsDir(opts) {
30908
+ const { sourceId, baseDir } = opts;
30909
+ const out = [];
30910
+ for (const name of listDirSafe(baseDir)) {
30911
+ const full = path16.join(baseDir, name);
30912
+ const stat = fs14.statSync(full);
30913
+ if (stat.isFile() && name.endsWith(".sh")) {
30914
+ out.push({ kind: "script", sourceId, sourcePath: full, deployBasename: name });
30915
+ } else if (stat.isDirectory()) {
30916
+ out.push({ kind: "script", sourceId, sourcePath: full, deployBasename: name });
30917
+ }
30918
+ }
30919
+ return out;
30920
+ }
30921
+ function resolveRulesDir(opts) {
30922
+ const { sourceId, baseDir } = opts;
30923
+ const out = [];
30924
+ for (const name of listDirSafe(baseDir)) {
30925
+ if (!name.endsWith(".md"))
30926
+ continue;
30927
+ const full = path16.join(baseDir, name);
30928
+ if (!fs14.statSync(full).isFile())
30929
+ continue;
30930
+ out.push({ kind: "rule", sourceId, sourcePath: full, deployBasename: name });
30931
+ }
30932
+ return out;
30933
+ }
30934
+ function resolveJsonDir(opts) {
30935
+ const { sourceId, baseDir, kind } = opts;
30936
+ const out = [];
30937
+ for (const name of listDirSafe(baseDir)) {
30938
+ if (!name.endsWith(".json"))
30939
+ continue;
30940
+ const full = path16.join(baseDir, name);
30941
+ if (!fs14.statSync(full).isFile())
30942
+ continue;
30943
+ out.push({ kind, sourceId, sourcePath: full, deployBasename: name });
30944
+ }
30945
+ return out;
30946
+ }
30947
+ function resolveSourceArtifacts(opts) {
30948
+ const { sourceId, clonePath, atlasUser } = opts;
30949
+ const subscription = resolveSubscriptions({ clonePath, atlasUser });
30950
+ const artifacts = [];
30951
+ for (const cat of subscription.categories) {
30952
+ const catDir = path16.join(clonePath, "shared", cat);
30953
+ if (!fs14.existsSync(catDir))
30954
+ continue;
30955
+ artifacts.push(...resolveSkillsDir({ sourceId, baseDir: path16.join(catDir, "skills") }));
30956
+ artifacts.push(...resolveAgentsDir({ sourceId, baseDir: path16.join(catDir, "agents") }));
30957
+ artifacts.push(...resolveScriptsDir({ sourceId, baseDir: path16.join(catDir, "scripts") }));
30958
+ artifacts.push(...resolveRulesDir({ sourceId, baseDir: path16.join(catDir, "rules") }));
30959
+ artifacts.push(...resolveJsonDir({ sourceId, baseDir: path16.join(catDir, "hooks"), kind: "hook" }));
30960
+ artifacts.push(...resolveJsonDir({ sourceId, baseDir: path16.join(catDir, "permissions"), kind: "permission" }));
30961
+ }
30962
+ if (atlasUser) {
30963
+ const memberRoot = path16.join(clonePath, "members", atlasUser);
30964
+ if (fs14.existsSync(memberRoot)) {
30965
+ artifacts.push(...resolveSkillsDir({ sourceId, baseDir: path16.join(memberRoot, "skills") }));
30966
+ artifacts.push(...resolveAgentsDir({ sourceId, baseDir: path16.join(memberRoot, "agents") }));
30967
+ artifacts.push(...resolveScriptsDir({ sourceId, baseDir: path16.join(memberRoot, "scripts") }));
30968
+ artifacts.push(...resolveRulesDir({ sourceId, baseDir: path16.join(memberRoot, "rules") }));
30969
+ artifacts.push(...resolveJsonDir({ sourceId, baseDir: path16.join(memberRoot, "hooks"), kind: "hook" }));
30970
+ artifacts.push(...resolveJsonDir({ sourceId, baseDir: path16.join(memberRoot, "permissions"), kind: "permission" }));
30971
+ }
30972
+ }
30973
+ return { subscription, artifacts };
30974
+ }
30975
+
30976
+ // ../core/dist/skill-sync/symlink-deployer.js
30977
+ import * as fs15 from "node:fs";
30978
+ import * as os10 from "node:os";
30979
+ import * as path17 from "node:path";
30980
+ function claudeDir() {
30981
+ const override = process.env["OLAM_CLAUDE_DIR"];
30982
+ if (override && override.length > 0)
30983
+ return override;
30984
+ return path17.join(os10.homedir(), ".claude");
30985
+ }
30986
+ var BUCKETS = ["commands", "agents", "skills", "scripts", "rules"];
30987
+ function bucketFor(kind) {
30988
+ switch (kind) {
30989
+ case "skill":
30990
+ return "skills";
30991
+ case "agent":
30992
+ return "agents";
30993
+ case "subagent":
30994
+ return "agents";
30995
+ case "script":
30996
+ return "scripts";
30997
+ case "rule":
30998
+ return "rules";
30999
+ case "hook":
31000
+ case "permission":
31001
+ return void 0;
31002
+ }
31003
+ }
31004
+ function cleanManagedSymlinks(claude) {
31005
+ for (const bucket of BUCKETS) {
31006
+ const dir = path17.join(claude, bucket);
31007
+ if (!fs15.existsSync(dir))
31008
+ continue;
31009
+ for (const name of fs15.readdirSync(dir)) {
31010
+ const p = path17.join(dir, name);
31011
+ try {
31012
+ const stat = fs15.lstatSync(p);
31013
+ if (stat.isSymbolicLink()) {
31014
+ fs15.unlinkSync(p);
31015
+ }
31016
+ } catch {
31017
+ }
31018
+ }
31019
+ }
31020
+ }
31021
+ function shadowBackup(link) {
31022
+ const epoch = Math.floor(Date.now() / 1e3);
31023
+ const backup = `${link}.shadow-backup-${epoch}`;
31024
+ fs15.renameSync(link, backup);
31025
+ return backup;
31026
+ }
31027
+ function linkIfNeeded(target, link) {
31028
+ try {
31029
+ const existing = fs15.readlinkSync(link);
31030
+ if (existing === target)
31031
+ return { created: false };
31032
+ } catch {
31033
+ }
31034
+ let isLink = false;
31035
+ try {
31036
+ isLink = fs15.lstatSync(link).isSymbolicLink();
31037
+ } catch {
31038
+ }
31039
+ let backup;
31040
+ if (isLink) {
31041
+ fs15.unlinkSync(link);
31042
+ } else if (fs15.existsSync(link)) {
31043
+ backup = shadowBackup(link);
31044
+ }
31045
+ fs15.symlinkSync(target, link);
31046
+ return { created: true, shadowBackup: backup };
31047
+ }
31048
+ function deployArtifacts(artifacts) {
31049
+ const claude = claudeDir();
31050
+ for (const bucket of BUCKETS) {
31051
+ fs15.mkdirSync(path17.join(claude, bucket), { recursive: true });
31052
+ }
31053
+ cleanManagedSymlinks(claude);
31054
+ const result = { linked: 0, shadowBackups: [], subagentCollisions: [] };
31055
+ const seenAgentBasenames = /* @__PURE__ */ new Map();
31056
+ const collisionLosers = /* @__PURE__ */ new Map();
31057
+ for (const artifact of artifacts) {
31058
+ const bucket = bucketFor(artifact.kind);
31059
+ if (!bucket)
31060
+ continue;
31061
+ if (artifact.kind === "agent" || artifact.kind === "subagent") {
31062
+ const prior = seenAgentBasenames.get(artifact.deployBasename);
31063
+ if (prior) {
31064
+ const losers = collisionLosers.get(artifact.deployBasename) ?? [];
31065
+ losers.push(artifact.sourcePath);
31066
+ collisionLosers.set(artifact.deployBasename, losers);
31067
+ continue;
31068
+ }
31069
+ seenAgentBasenames.set(artifact.deployBasename, artifact.sourcePath);
31070
+ }
31071
+ const linkPath = path17.join(claude, bucket, artifact.deployBasename);
31072
+ const { created, shadowBackup: backup } = linkIfNeeded(artifact.sourcePath, linkPath);
31073
+ if (created)
31074
+ result.linked += 1;
31075
+ if (backup)
31076
+ result.shadowBackups.push(backup);
31077
+ }
31078
+ for (const [name, losers] of collisionLosers.entries()) {
31079
+ const winner = seenAgentBasenames.get(name);
31080
+ result.subagentCollisions.push({ name, winner, losers });
31081
+ }
31082
+ return result;
31083
+ }
31084
+
31085
+ // ../core/dist/skill-sync/settings-merger.js
31086
+ import * as fs16 from "node:fs";
31087
+ import * as os11 from "node:os";
31088
+ import * as path18 from "node:path";
31089
+ var OLAM_SKILLS_MARKER = "_olamSkillsManaged";
31090
+ var BACKUP_RETENTION = 30;
31091
+ function claudeSettingsPath() {
31092
+ const override = process.env["OLAM_CLAUDE_SETTINGS_PATH"];
31093
+ if (override && override.length > 0)
31094
+ return override;
31095
+ return path18.join(claudeDirInternal(), "settings.json");
31096
+ }
31097
+ function claudeDirInternal() {
31098
+ const override = process.env["OLAM_CLAUDE_DIR"];
31099
+ if (override && override.length > 0)
31100
+ return override;
31101
+ return path18.join(os11.homedir(), ".claude");
31102
+ }
31103
+ function settingsBackupDir() {
31104
+ const override = process.env["OLAM_SETTINGS_BACKUP_DIR"];
31105
+ if (override && override.length > 0)
31106
+ return override;
31107
+ return path18.join(os11.homedir(), ".olam", "state", "settings-backups");
31108
+ }
31109
+ function dedupeByMatcher(entries) {
31110
+ const map = /* @__PURE__ */ new Map();
31111
+ for (const e of entries) {
31112
+ map.set(e.matcher ?? "", e);
31113
+ }
31114
+ return [...map.values()];
31115
+ }
31116
+ function tagOlam(entry) {
31117
+ return { ...entry, [OLAM_SKILLS_MARKER]: true };
31118
+ }
31119
+ function readJson(file) {
31120
+ return JSON.parse(fs16.readFileSync(file, "utf-8"));
31121
+ }
31122
+ function rotateBackups(backupDir) {
31123
+ if (!fs16.existsSync(backupDir))
31124
+ return;
31125
+ const files = fs16.readdirSync(backupDir).filter((f) => f.endsWith(".json")).map((f) => ({ name: f, full: path18.join(backupDir, f), mtime: fs16.statSync(path18.join(backupDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
31126
+ for (const f of files.slice(BACKUP_RETENTION)) {
31127
+ try {
31128
+ fs16.unlinkSync(f.full);
31129
+ } catch {
31130
+ }
31131
+ }
31132
+ }
31133
+ function backupSettings() {
31134
+ const src = claudeSettingsPath();
31135
+ if (!fs16.existsSync(src))
31136
+ return void 0;
31137
+ const dir = settingsBackupDir();
31138
+ fs16.mkdirSync(dir, { recursive: true });
31139
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
31140
+ const dest = path18.join(dir, `settings-${stamp}.json`);
31141
+ fs16.copyFileSync(src, dest);
31142
+ rotateBackups(dir);
31143
+ return dest;
31144
+ }
31145
+ function mergeSettings(input) {
31146
+ const settingsPath = claudeSettingsPath();
31147
+ const backupPath = backupSettings();
31148
+ let base = {};
31149
+ if (fs16.existsSync(settingsPath)) {
31150
+ try {
31151
+ base = readJson(settingsPath);
31152
+ } catch {
31153
+ base = {};
31154
+ }
31155
+ }
31156
+ const olamHooksByCategory = /* @__PURE__ */ new Map();
31157
+ for (const file of input.hookFiles) {
31158
+ let parsed;
31159
+ try {
31160
+ parsed = readJson(file);
31161
+ } catch {
31162
+ continue;
31163
+ }
31164
+ if (!parsed.hooks || typeof parsed.hooks !== "object")
31165
+ continue;
31166
+ for (const [category, entries] of Object.entries(parsed.hooks)) {
31167
+ if (!Array.isArray(entries))
31168
+ continue;
31169
+ const list = olamHooksByCategory.get(category) ?? [];
31170
+ list.push(...entries.map(tagOlam));
31171
+ olamHooksByCategory.set(category, list);
31172
+ }
31173
+ }
31174
+ const mergedHooks = {};
31175
+ const existingHooks = base.hooks && typeof base.hooks === "object" ? base.hooks : {};
31176
+ const categories = /* @__PURE__ */ new Set([
31177
+ ...Object.keys(existingHooks),
31178
+ ...olamHooksByCategory.keys()
31179
+ ]);
31180
+ let hooksAdded = 0;
31181
+ for (const cat of categories) {
31182
+ const existing = Array.isArray(existingHooks[cat]) ? existingHooks[cat] : [];
31183
+ const preserved = existing.filter((e) => !e[OLAM_SKILLS_MARKER]);
31184
+ const olam = olamHooksByCategory.get(cat) ?? [];
31185
+ const combined = [...preserved, ...olam];
31186
+ mergedHooks[cat] = dedupeByMatcher(combined);
31187
+ hooksAdded += olam.length;
31188
+ }
31189
+ const permSet = /* @__PURE__ */ new Set();
31190
+ for (const file of input.permissionFiles) {
31191
+ let parsed;
31192
+ try {
31193
+ parsed = readJson(file);
31194
+ } catch {
31195
+ continue;
31196
+ }
31197
+ const allow = parsed.permissions?.allow;
31198
+ if (Array.isArray(allow)) {
31199
+ for (const p of allow)
31200
+ if (typeof p === "string")
31201
+ permSet.add(p);
31202
+ }
31203
+ }
31204
+ const next = {
31205
+ ...base,
31206
+ hooks: mergedHooks,
31207
+ permissions: {
31208
+ ...base.permissions ?? {},
31209
+ ...input.permissionFiles.length > 0 ? { allow: [...permSet] } : {}
31210
+ }
31211
+ };
31212
+ fs16.mkdirSync(path18.dirname(settingsPath), { recursive: true });
31213
+ const tmp = `${settingsPath}.tmp-${process.pid}`;
31214
+ fs16.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n", { mode: 420 });
31215
+ fs16.renameSync(tmp, settingsPath);
31216
+ return { backupPath, hooksAdded, permissionsCount: permSet.size };
31217
+ }
31218
+
31219
+ // ../core/dist/skill-sync/engine.js
31220
+ import * as fs17 from "node:fs";
31221
+ import * as os12 from "node:os";
31222
+ import * as path19 from "node:path";
31223
+ function resolveAtlasUser(override) {
31224
+ if (override)
31225
+ return override;
31226
+ const claudeDir2 = process.env["OLAM_CLAUDE_DIR"] || path19.join(os12.homedir(), ".claude");
31227
+ const f = path19.join(claudeDir2, ".atlas-user");
31228
+ if (fs17.existsSync(f)) {
31229
+ return fs17.readFileSync(f, "utf-8").trim() || void 0;
31230
+ }
31231
+ return void 0;
31232
+ }
31233
+ async function syncSkills(opts = {}) {
31234
+ const atlasUser = resolveAtlasUser(opts.atlasUser);
31235
+ const sources = listSkillSources();
31236
+ const allArtifacts = [];
31237
+ const perSource = [];
31238
+ for (const source of sources) {
31239
+ const clonePath = skillSourceClonePath(source.id);
31240
+ if (!fs17.existsSync(clonePath))
31241
+ continue;
31242
+ const { artifacts, subscription } = resolveSourceArtifacts({
31243
+ sourceId: source.id,
31244
+ clonePath,
31245
+ atlasUser
31246
+ });
31247
+ allArtifacts.push(...artifacts);
31248
+ perSource.push({
31249
+ sourceId: source.id,
31250
+ name: source.name,
31251
+ artifactCount: artifacts.length,
31252
+ categories: subscription.categories,
31253
+ fromSubscriptionsFile: subscription.fromSubscriptionsFile
31254
+ });
31255
+ }
31256
+ const hookFiles = allArtifacts.filter((a) => a.kind === "hook").map((a) => a.sourcePath);
31257
+ const permissionFiles = allArtifacts.filter((a) => a.kind === "permission").map((a) => a.sourcePath);
31258
+ const summary = {
31259
+ sourceCount: sources.length,
31260
+ artifactCount: allArtifacts.length,
31261
+ hookFileCount: hookFiles.length,
31262
+ permissionFileCount: permissionFiles.length,
31263
+ deploy: void 0,
31264
+ merge: void 0,
31265
+ perSource
31266
+ };
31267
+ if (opts.dryRun)
31268
+ return summary;
31269
+ summary.deploy = deployArtifacts(allArtifacts);
31270
+ summary.merge = mergeSettings({ hookFiles, permissionFiles });
31271
+ return summary;
31272
+ }
31273
+
30625
31274
  // ../mcp-server/src/tools/repo.ts
30626
31275
  function asMessage4(err) {
30627
31276
  return err instanceof Error ? err.message : String(err);
@@ -30650,9 +31299,9 @@ function register22(server, _ctx, _initError) {
30650
31299
  description: external_exports.string().optional().describe("Optional human-readable description."),
30651
31300
  defaultBranch: external_exports.string().optional().describe("Default branch name (e.g. main).")
30652
31301
  },
30653
- async ({ name, path: path31, description, defaultBranch }) => {
31302
+ async ({ name, path: path37, description, defaultBranch }) => {
30654
31303
  try {
30655
- const entry = addRepo({ name, path: path31, description, defaultBranch });
31304
+ const entry = addRepo({ name, path: path37, description, defaultBranch });
30656
31305
  return {
30657
31306
  content: [{
30658
31307
  type: "text",
@@ -30693,9 +31342,9 @@ function register22(server, _ctx, _initError) {
30693
31342
  description: external_exports.string().optional().describe("New description."),
30694
31343
  defaultBranch: external_exports.string().optional().describe("New default branch.")
30695
31344
  },
30696
- async ({ name, path: path31, description, defaultBranch }) => {
31345
+ async ({ name, path: path37, description, defaultBranch }) => {
30697
31346
  try {
30698
- const entry = updateRepo(name, { path: path31, description, defaultBranch });
31347
+ const entry = updateRepo(name, { path: path37, description, defaultBranch });
30699
31348
  return {
30700
31349
  content: [{
30701
31350
  type: "text",
@@ -30716,15 +31365,15 @@ __export(process_port_exports, {
30716
31365
  resolveHostCpToken: () => resolveHostCpToken
30717
31366
  });
30718
31367
  init_v3();
30719
- import fs13 from "node:fs";
30720
- import os9 from "node:os";
30721
- import path15 from "node:path";
31368
+ import fs18 from "node:fs";
31369
+ import os13 from "node:os";
31370
+ import path20 from "node:path";
30722
31371
  var HOST_CP_BASE = "http://127.0.0.1:19000";
30723
31372
  function resolveHostCpToken() {
30724
31373
  const envToken = process.env["OLAM_HOST_CP_TOKEN"];
30725
31374
  if (envToken) return envToken;
30726
- const tokenPath = path15.join(os9.homedir(), ".olam", "host-cp.token");
30727
- if (fs13.existsSync(tokenPath)) return fs13.readFileSync(tokenPath, "utf-8").trim();
31375
+ const tokenPath = path20.join(os13.homedir(), ".olam", "host-cp.token");
31376
+ if (fs18.existsSync(tokenPath)) return fs18.readFileSync(tokenPath, "utf-8").trim();
30728
31377
  return null;
30729
31378
  }
30730
31379
  function tokenMissingError() {
@@ -31004,10 +31653,254 @@ ${conflicts.length} port conflict(s). Stop the conflicting processes or update p
31004
31653
  );
31005
31654
  }
31006
31655
 
31656
+ // ../mcp-server/src/tools/skill-source.ts
31657
+ var skill_source_exports = {};
31658
+ __export(skill_source_exports, {
31659
+ register: () => register25
31660
+ });
31661
+ init_v3();
31662
+ function asMessage7(err) {
31663
+ return err instanceof Error ? err.message : String(err);
31664
+ }
31665
+ function ok(data) {
31666
+ return {
31667
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
31668
+ };
31669
+ }
31670
+ function fail(err) {
31671
+ return {
31672
+ content: [{ type: "text", text: asMessage7(err) }],
31673
+ isError: true
31674
+ };
31675
+ }
31676
+ function register25(server, _ctx, _initError) {
31677
+ server.tool(
31678
+ "olam_skills_source_list",
31679
+ "List every registered skill source. Returns { skillSources: SkillSource[] }.",
31680
+ {},
31681
+ async () => {
31682
+ return ok({ skillSources: listSkillSources() });
31683
+ }
31684
+ );
31685
+ server.tool(
31686
+ "olam_skills_source_add",
31687
+ "Register and clone a skill source. Clones to ~/.olam/state/skill-sources/<id>/. Atomic: rolls back the state-store entry if the clone fails.",
31688
+ {
31689
+ name: external_exports.string().min(1).describe("Display name (lowercase, digits, dash; 1\u201364 chars)."),
31690
+ gitUrl: external_exports.string().min(1).describe("Git URL (https://, git@, ssh://, file://, or absolute path)."),
31691
+ branch: external_exports.string().min(1).optional().describe('Branch to track. Defaults to "main".')
31692
+ },
31693
+ async ({ name, gitUrl, branch }) => {
31694
+ let entry;
31695
+ try {
31696
+ entry = addSkillSource({ name, gitUrl, branch });
31697
+ } catch (err) {
31698
+ return fail(err);
31699
+ }
31700
+ try {
31701
+ const result = cloneSkillSource({
31702
+ gitUrl: entry.gitUrl,
31703
+ branch: entry.branch,
31704
+ id: entry.id
31705
+ });
31706
+ const updated = updateSkillSource(entry.id, { lastPulledSha: result.headSha });
31707
+ return ok({
31708
+ source: updated,
31709
+ clonePath: result.clonePath,
31710
+ message: `Registered skill source "${entry.name}" (${entry.id}) @ ${result.headSha.slice(0, 8)}.`
31711
+ });
31712
+ } catch (err) {
31713
+ try {
31714
+ removeSkillSource(entry.id);
31715
+ } catch {
31716
+ }
31717
+ return fail(err);
31718
+ }
31719
+ }
31720
+ );
31721
+ server.tool(
31722
+ "olam_skills_source_remove",
31723
+ "Remove a registered skill source. Deletes the clone directory and the state entry.",
31724
+ {
31725
+ id: external_exports.string().length(12).describe("Skill source id (from olam_skills_source_list).")
31726
+ },
31727
+ async ({ id }) => {
31728
+ try {
31729
+ removeSkillSourceClone(id);
31730
+ removeSkillSource(id);
31731
+ return ok({ id, message: `Removed skill source "${id}".` });
31732
+ } catch (err) {
31733
+ return fail(err);
31734
+ }
31735
+ }
31736
+ );
31737
+ server.tool(
31738
+ "olam_skills_source_pull",
31739
+ "Fetch + reset the clone to upstream HEAD. Updates lastPulledSha.",
31740
+ {
31741
+ id: external_exports.string().length(12).describe("Skill source id.")
31742
+ },
31743
+ async ({ id }) => {
31744
+ const entry = getSkillSource(id);
31745
+ if (!entry) {
31746
+ return fail(new Error(`skill source "${id}" is not registered`));
31747
+ }
31748
+ try {
31749
+ const result = pullSkillSource({
31750
+ gitUrl: entry.gitUrl,
31751
+ branch: entry.branch,
31752
+ id: entry.id
31753
+ });
31754
+ const updated = updateSkillSource(entry.id, { lastPulledSha: result.headSha });
31755
+ return ok({
31756
+ source: updated,
31757
+ message: `Pulled "${entry.name}" \u2192 ${result.headSha.slice(0, 8)}.`
31758
+ });
31759
+ } catch (err) {
31760
+ return fail(err);
31761
+ }
31762
+ }
31763
+ );
31764
+ server.tool(
31765
+ "olam_skills_source_show",
31766
+ "Show details for a single skill source (state-store entry + resolved clone path).",
31767
+ {
31768
+ id: external_exports.string().length(12).describe("Skill source id.")
31769
+ },
31770
+ async ({ id }) => {
31771
+ const entry = getSkillSource(id);
31772
+ if (!entry) {
31773
+ return fail(new Error(`skill source "${id}" is not registered`));
31774
+ }
31775
+ return ok({
31776
+ source: entry,
31777
+ clonePath: skillSourceClonePath(entry.id)
31778
+ });
31779
+ }
31780
+ );
31781
+ }
31782
+
31783
+ // ../mcp-server/src/tools/skills.ts
31784
+ var skills_exports = {};
31785
+ __export(skills_exports, {
31786
+ register: () => register26
31787
+ });
31788
+ init_v3();
31789
+ import * as fs19 from "node:fs";
31790
+ import * as path21 from "node:path";
31791
+ function asMessage8(err) {
31792
+ return err instanceof Error ? err.message : String(err);
31793
+ }
31794
+ function ok2(data) {
31795
+ return {
31796
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
31797
+ };
31798
+ }
31799
+ function fail2(err) {
31800
+ return {
31801
+ content: [{ type: "text", text: asMessage8(err) }],
31802
+ isError: true
31803
+ };
31804
+ }
31805
+ function listDeployed() {
31806
+ const dir = claudeDir();
31807
+ const sources = listSkillSources();
31808
+ const sourcePaths = new Map(
31809
+ sources.map((s) => [skillSourceClonePath(s.id), s.id])
31810
+ );
31811
+ const entries = [];
31812
+ for (const bucket of ["skills", "agents", "scripts", "rules", "commands"]) {
31813
+ const bucketDir = path21.join(dir, bucket);
31814
+ if (!fs19.existsSync(bucketDir)) continue;
31815
+ for (const name of fs19.readdirSync(bucketDir)) {
31816
+ const full = path21.join(bucketDir, name);
31817
+ try {
31818
+ const stat = fs19.lstatSync(full);
31819
+ if (!stat.isSymbolicLink()) continue;
31820
+ const target = fs19.readlinkSync(full);
31821
+ let sourceId;
31822
+ for (const [clonePath, id] of sourcePaths.entries()) {
31823
+ if (target.startsWith(clonePath)) {
31824
+ sourceId = id;
31825
+ break;
31826
+ }
31827
+ }
31828
+ entries.push({ bucket, name, target, sourceId });
31829
+ } catch {
31830
+ }
31831
+ }
31832
+ }
31833
+ return entries;
31834
+ }
31835
+ function register26(server, _ctx, _initError) {
31836
+ server.tool(
31837
+ "olam_skills_sync",
31838
+ "Sync all registered skill sources to ~/.claude/. Returns SyncSummary with per-source artifact breakdown, deploy result, and merge result.",
31839
+ {
31840
+ dryRun: external_exports.boolean().optional().describe("Resolve artifacts but do not deploy or merge. Returns the summary that sync would produce."),
31841
+ atlasUser: external_exports.string().optional().describe("Override atlas-user identifier (defaults to ~/.claude/.atlas-user).")
31842
+ },
31843
+ async ({ dryRun, atlasUser }) => {
31844
+ try {
31845
+ const summary = await syncSkills({ dryRun, atlasUser });
31846
+ return ok2(summary);
31847
+ } catch (err) {
31848
+ return fail2(err);
31849
+ }
31850
+ }
31851
+ );
31852
+ server.tool(
31853
+ "olam_skills_diff",
31854
+ "Show what `olam skills sync` would deploy without making on-disk changes. Equivalent to sync with dryRun=true.",
31855
+ {
31856
+ atlasUser: external_exports.string().optional().describe("Override atlas-user identifier.")
31857
+ },
31858
+ async ({ atlasUser }) => {
31859
+ try {
31860
+ const summary = await syncSkills({ dryRun: true, atlasUser });
31861
+ return ok2(summary);
31862
+ } catch (err) {
31863
+ return fail2(err);
31864
+ }
31865
+ }
31866
+ );
31867
+ server.tool(
31868
+ "olam_skills_list",
31869
+ "List artifacts currently deployed under ~/.claude/{skills,agents,scripts,rules,commands}/ along with their source-id (if from a registered olam source).",
31870
+ {},
31871
+ async () => {
31872
+ try {
31873
+ const entries = listDeployed();
31874
+ return ok2({ deployed: entries, count: entries.length });
31875
+ } catch (err) {
31876
+ return fail2(err);
31877
+ }
31878
+ }
31879
+ );
31880
+ server.tool(
31881
+ "olam_skills_show",
31882
+ 'Show details for a deployed artifact by name (e.g. "plan-hard" or "codex-second-opinion.md"). Returns one or more matches across buckets.',
31883
+ {
31884
+ name: external_exports.string().min(1).describe("Artifact name (basename under any of the managed buckets).")
31885
+ },
31886
+ async ({ name }) => {
31887
+ try {
31888
+ const entries = listDeployed().filter((e) => e.name === name);
31889
+ if (entries.length === 0) {
31890
+ return fail2(new Error(`no deployed artifact matches "${name}"`));
31891
+ }
31892
+ return ok2({ matches: entries });
31893
+ } catch (err) {
31894
+ return fail2(err);
31895
+ }
31896
+ }
31897
+ );
31898
+ }
31899
+
31007
31900
  // ../mcp-server/src/tools/kg-classify.ts
31008
31901
  var kg_classify_exports = {};
31009
31902
  __export(kg_classify_exports, {
31010
- register: () => register25
31903
+ register: () => register27
31011
31904
  });
31012
31905
  init_v3();
31013
31906
 
@@ -31020,8 +31913,8 @@ function port() {
31020
31913
  const n = Number.parseInt(env, 10);
31021
31914
  return Number.isFinite(n) && n > 0 ? n : KG_SERVICE_PORT_DEFAULT;
31022
31915
  }
31023
- function url(path31) {
31024
- return `http://127.0.0.1:${port()}${path31}`;
31916
+ function url(path37) {
31917
+ return `http://127.0.0.1:${port()}${path37}`;
31025
31918
  }
31026
31919
  function kgServiceHealthUrl() {
31027
31920
  return url("/health");
@@ -31082,7 +31975,7 @@ async function status(opts = {}) {
31082
31975
  }
31083
31976
 
31084
31977
  // ../mcp-server/src/tools/kg-classify.ts
31085
- function register25(server, _ctx, _initError) {
31978
+ function register27(server, _ctx, _initError) {
31086
31979
  server.tool(
31087
31980
  "olam_kg_classify",
31088
31981
  "Route a question to kg | grep | both via the 4-layer classifier (kg-service container). Returns route + layer + reason + matched exemplar. Requires olam-kg-service running (see `olam services up`).",
@@ -31130,7 +32023,7 @@ function register25(server, _ctx, _initError) {
31130
32023
  // ../mcp-server/src/tools/kg-doctor.ts
31131
32024
  var kg_doctor_exports = {};
31132
32025
  __export(kg_doctor_exports, {
31133
- register: () => register26
32026
+ register: () => register28
31134
32027
  });
31135
32028
  async function runProbes() {
31136
32029
  const results = [];
@@ -31180,7 +32073,7 @@ async function runProbes() {
31180
32073
  }
31181
32074
  return results;
31182
32075
  }
31183
- function register26(server, _ctx, _initError) {
32076
+ function register28(server, _ctx, _initError) {
31184
32077
  server.tool(
31185
32078
  "olam_kg_doctor",
31186
32079
  "Diagnostic report for olam-kg-service over HTTP: /health readiness, workspace inventory, and /classify round-trip. Returns a JSON `probes` array. If the container isn't running, all probes fail with a hint to run `olam services up`.",
@@ -31216,17 +32109,17 @@ function register26(server, _ctx, _initError) {
31216
32109
  // ../mcp-server/src/tools/kg-install-hook.ts
31217
32110
  var kg_install_hook_exports = {};
31218
32111
  __export(kg_install_hook_exports, {
31219
- register: () => register27
32112
+ register: () => register29
31220
32113
  });
31221
32114
  init_v3();
31222
- import * as fs15 from "node:fs";
31223
- import * as path17 from "node:path";
31224
- import * as os10 from "node:os";
32115
+ import * as fs21 from "node:fs";
32116
+ import * as path23 from "node:path";
32117
+ import * as os14 from "node:os";
31225
32118
 
31226
32119
  // ../core/dist/world/merge-settings.js
31227
- import * as fs14 from "node:fs";
31228
- import * as path16 from "node:path";
31229
- import * as crypto3 from "node:crypto";
32120
+ import * as fs20 from "node:fs";
32121
+ import * as path22 from "node:path";
32122
+ import * as crypto4 from "node:crypto";
31230
32123
  function mergeHomeSettingsJson(filePath, options) {
31231
32124
  let settings;
31232
32125
  try {
@@ -31285,10 +32178,10 @@ function mergeHomeSettingsJson(filePath, options) {
31285
32178
  return { status: "installed", message: `settings.json updated at ${filePath}` };
31286
32179
  }
31287
32180
  function readSettings(filePath) {
31288
- if (!fs14.existsSync(filePath)) {
32181
+ if (!fs20.existsSync(filePath)) {
31289
32182
  return {};
31290
32183
  }
31291
- const raw = fs14.readFileSync(filePath, "utf-8");
32184
+ const raw = fs20.readFileSync(filePath, "utf-8");
31292
32185
  if (!raw.trim())
31293
32186
  return {};
31294
32187
  return JSON.parse(raw);
@@ -31309,13 +32202,13 @@ function isHookSentinelPresent(matchers, sentinel) {
31309
32202
  return false;
31310
32203
  }
31311
32204
  function atomicWriteJson(filePath, data) {
31312
- const dir = path16.dirname(filePath);
31313
- fs14.mkdirSync(dir, { recursive: true });
31314
- const rand = crypto3.randomBytes(6).toString("hex");
32205
+ const dir = path22.dirname(filePath);
32206
+ fs20.mkdirSync(dir, { recursive: true });
32207
+ const rand = crypto4.randomBytes(6).toString("hex");
31315
32208
  const tmp = `${filePath}.tmp.${process.pid}.${rand}`;
31316
32209
  const json = JSON.stringify(data, null, 2) + "\n";
31317
- fs14.writeFileSync(tmp, json, { mode: 420 });
31318
- fs14.renameSync(tmp, filePath);
32210
+ fs20.writeFileSync(tmp, json, { mode: 420 });
32211
+ fs20.renameSync(tmp, filePath);
31319
32212
  }
31320
32213
 
31321
32214
  // ../core/dist/kg/hook-template.js
@@ -31342,11 +32235,11 @@ try:
31342
32235
  sys.stderr.write(f"\\x1b[32m\\u2713 KG hit\\x1b[0m \\"{q}\\" \\u2192 L{layer}/{route} \\u00b7 {nodes} nodes \\u00b7 ~{saved_k}k tokens saved\\n")
31343
32236
  print(json.dumps({"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":f"[kg-classifier L{layer}|{route}] {label[:160]}"}}))
31344
32237
  except Exception: pass' 2>/dev/null`;
32238
+ const curlPost = `RESP=$(curl -s --max-time 1 -X POST -H 'Content-Type: application/json' -d "{\\"q\\":\\"$(echo \\"$CMD\\" | head -c 200 | tr '\\"' ' ')\\"}" ${url2} 2>/dev/null)`;
31345
32239
  return [
31346
32240
  `KG_SENTINEL=${KG_HOOK_SENTINEL}`,
31347
32241
  `CMD=$(${extractCmd})`,
31348
- `case "$CMD" in *grep*|*rg\\ *|*ripgrep*|*find\\ *|*fd\\ *|*ack\\ *|*ag\\ *)`,
31349
- `RESP=$(curl -s --max-time 1 -X POST -H 'Content-Type: application/json' -d "{\\"q\\":\\"$(echo \\"$CMD\\" | head -c 200 | tr '\\"' ' ')\\"}" ${url2} 2>/dev/null)`,
32242
+ `case "$CMD" in *grep*|*rg\\ *|*ripgrep*|*find\\ *|*fd\\ *|*ack\\ *|*ag\\ *) ${curlPost}`,
31350
32243
  `KG_QUERY="$(echo \\"$CMD\\" | head -c 60 | tr '\\"' ' ')" echo "$RESP" | ${emitContext}`,
31351
32244
  `;; esac`
31352
32245
  ].join("; ");
@@ -31366,12 +32259,12 @@ function buildHookMatcherEntry(opts) {
31366
32259
  // ../mcp-server/src/tools/kg-install-hook.ts
31367
32260
  function settingsPathFor(scope, projectPath) {
31368
32261
  if (scope === "user") {
31369
- return path17.join(os10.homedir(), ".claude", "settings.json");
32262
+ return path23.join(os14.homedir(), ".claude", "settings.json");
31370
32263
  }
31371
32264
  const root = projectPath ?? process.cwd();
31372
- return path17.join(root, ".claude", "settings.json");
32265
+ return path23.join(root, ".claude", "settings.json");
31373
32266
  }
31374
- function register27(server, _ctx, _initError) {
32267
+ function register29(server, _ctx, _initError) {
31375
32268
  server.tool(
31376
32269
  "olam_kg_install_hook",
31377
32270
  "Install the kg-service PreToolUse hook into .claude/settings.json. Idempotent (sentinel-detected). Default scope=project (writes <cwd>/.claude/settings.json); scope=user writes ~/.claude/settings.json.",
@@ -31383,12 +32276,12 @@ function register27(server, _ctx, _initError) {
31383
32276
  const scope = params.scope === "user" ? "user" : "project";
31384
32277
  const filePath = settingsPathFor(scope, params.projectPath);
31385
32278
  try {
31386
- fs15.mkdirSync(path17.dirname(filePath), { recursive: true });
32279
+ fs21.mkdirSync(path23.dirname(filePath), { recursive: true });
31387
32280
  let backupPath = null;
31388
- if (fs15.existsSync(filePath)) {
32281
+ if (fs21.existsSync(filePath)) {
31389
32282
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
31390
32283
  backupPath = `${filePath}.olam-bak.${ts}`;
31391
- fs15.copyFileSync(filePath, backupPath);
32284
+ fs21.copyFileSync(filePath, backupPath);
31392
32285
  }
31393
32286
  const result = mergeHomeSettingsJson(filePath, {
31394
32287
  ensureHook: {
@@ -31399,7 +32292,7 @@ function register27(server, _ctx, _initError) {
31399
32292
  });
31400
32293
  if (result.status === "already-present" && backupPath) {
31401
32294
  try {
31402
- fs15.unlinkSync(backupPath);
32295
+ fs21.unlinkSync(backupPath);
31403
32296
  } catch {
31404
32297
  }
31405
32298
  }
@@ -31440,18 +32333,18 @@ function register27(server, _ctx, _initError) {
31440
32333
  // ../mcp-server/src/tools/kg-uninstall-hook.ts
31441
32334
  var kg_uninstall_hook_exports = {};
31442
32335
  __export(kg_uninstall_hook_exports, {
31443
- register: () => register28
32336
+ register: () => register30
31444
32337
  });
31445
32338
  init_v3();
31446
- import * as fs16 from "node:fs";
31447
- import * as path18 from "node:path";
31448
- import * as os11 from "node:os";
32339
+ import * as fs22 from "node:fs";
32340
+ import * as path24 from "node:path";
32341
+ import * as os15 from "node:os";
31449
32342
  function settingsPathFor2(scope, projectPath) {
31450
32343
  if (scope === "user") {
31451
- return path18.join(os11.homedir(), ".claude", "settings.json");
32344
+ return path24.join(os15.homedir(), ".claude", "settings.json");
31452
32345
  }
31453
32346
  const root = projectPath ?? process.cwd();
31454
- return path18.join(root, ".claude", "settings.json");
32347
+ return path24.join(root, ".claude", "settings.json");
31455
32348
  }
31456
32349
  function dropSentinel(matchers) {
31457
32350
  let changed = false;
@@ -31473,7 +32366,7 @@ function dropSentinel(matchers) {
31473
32366
  }
31474
32367
  return { matchers: out, changed };
31475
32368
  }
31476
- function register28(server, _ctx, _initError) {
32369
+ function register30(server, _ctx, _initError) {
31477
32370
  server.tool(
31478
32371
  "olam_kg_uninstall_hook",
31479
32372
  "Remove the kg-service PreToolUse hook from .claude/settings.json. Sentinel-matched: only the olam entry is removed; other PreToolUse hooks are preserved.",
@@ -31485,7 +32378,7 @@ function register28(server, _ctx, _initError) {
31485
32378
  const scope = params.scope === "user" ? "user" : "project";
31486
32379
  const filePath = settingsPathFor2(scope, params.projectPath);
31487
32380
  try {
31488
- if (!fs16.existsSync(filePath)) {
32381
+ if (!fs22.existsSync(filePath)) {
31489
32382
  return {
31490
32383
  content: [
31491
32384
  {
@@ -31499,7 +32392,7 @@ function register28(server, _ctx, _initError) {
31499
32392
  ]
31500
32393
  };
31501
32394
  }
31502
- const raw = fs16.readFileSync(filePath, "utf-8");
32395
+ const raw = fs22.readFileSync(filePath, "utf-8");
31503
32396
  const settings = raw.trim() ? JSON.parse(raw) : {};
31504
32397
  const preToolUse = settings.hooks?.PreToolUse;
31505
32398
  if (!Array.isArray(preToolUse) || preToolUse.length === 0) {
@@ -31534,7 +32427,7 @@ function register28(server, _ctx, _initError) {
31534
32427
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
31535
32428
  const backupPath = `${filePath}.olam-bak.${ts}`;
31536
32429
  try {
31537
- fs16.copyFileSync(filePath, backupPath);
32430
+ fs22.copyFileSync(filePath, backupPath);
31538
32431
  } catch {
31539
32432
  }
31540
32433
  const next = {
@@ -31546,7 +32439,7 @@ function register28(server, _ctx, _initError) {
31546
32439
  if (otherStages.length === 0) delete next.hooks;
31547
32440
  else delete next.hooks.PreToolUse;
31548
32441
  }
31549
- fs16.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
32442
+ fs22.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
31550
32443
  return {
31551
32444
  content: [
31552
32445
  {
@@ -31606,6 +32499,8 @@ var toolModules = [
31606
32499
  repo_exports,
31607
32500
  process_port_exports,
31608
32501
  runbook_exports,
32502
+ skill_source_exports,
32503
+ skills_exports,
31609
32504
  kg_classify_exports,
31610
32505
  kg_doctor_exports,
31611
32506
  kg_install_hook_exports,
@@ -31757,11 +32652,11 @@ function assertBetterSqlite3Loadable(deps = {}) {
31757
32652
  init_loader();
31758
32653
 
31759
32654
  // ../core/dist/world/manager.js
31760
- import * as crypto6 from "node:crypto";
32655
+ import * as crypto7 from "node:crypto";
31761
32656
  import { execSync as execSync5, spawnSync as spawnSync4 } from "node:child_process";
31762
- import * as fs25 from "node:fs";
31763
- import * as os15 from "node:os";
31764
- import * as path28 from "node:path";
32657
+ import * as fs31 from "node:fs";
32658
+ import * as os19 from "node:os";
32659
+ import * as path34 from "node:path";
31765
32660
 
31766
32661
  // ../core/dist/world/state.js
31767
32662
  var VALID_TRANSITIONS = {
@@ -31856,9 +32751,9 @@ function resolveDevboxImage(config2, tag) {
31856
32751
  }
31857
32752
 
31858
32753
  // ../core/dist/world/worktree.js
31859
- import { execFileSync as execFileSync2 } from "node:child_process";
31860
- import * as fs17 from "node:fs";
31861
- import * as path19 from "node:path";
32754
+ import { execFileSync as execFileSync3 } from "node:child_process";
32755
+ import * as fs23 from "node:fs";
32756
+ import * as path25 from "node:path";
31862
32757
  function resolveGitDir(repo) {
31863
32758
  if (repo.path) {
31864
32759
  return repo.path;
@@ -31868,18 +32763,18 @@ function resolveGitDir(repo) {
31868
32763
  async function createWorktrees(repos, worldId, workspacePath, branch) {
31869
32764
  const created = [];
31870
32765
  for (const repo of repos) {
31871
- const worktreePath = path19.join(workspacePath, repo.name);
32766
+ const worktreePath = path25.join(workspacePath, repo.name);
31872
32767
  const gitDir = resolveGitDir(repo);
31873
32768
  const branchName = branch || `olam/${worldId}`;
31874
32769
  try {
31875
- fs17.mkdirSync(path19.dirname(worktreePath), { recursive: true });
31876
- execFileSync2("git", ["worktree", "add", worktreePath, "-b", branchName], {
32770
+ fs23.mkdirSync(path25.dirname(worktreePath), { recursive: true });
32771
+ execFileSync3("git", ["worktree", "add", worktreePath, "-b", branchName], {
31877
32772
  cwd: gitDir,
31878
32773
  stdio: "pipe"
31879
32774
  });
31880
32775
  if (repo.submodules) {
31881
32776
  try {
31882
- execFileSync2("git", ["submodule", "update", "--init", "--recursive"], {
32777
+ execFileSync3("git", ["submodule", "update", "--init", "--recursive"], {
31883
32778
  cwd: worktreePath,
31884
32779
  stdio: "pipe"
31885
32780
  });
@@ -31891,7 +32786,7 @@ async function createWorktrees(repos, worldId, workspacePath, branch) {
31891
32786
  for (const entry of created) {
31892
32787
  try {
31893
32788
  const entryGitDir = resolveGitDir(entry.repo);
31894
- execFileSync2("git", ["worktree", "remove", entry.worktreePath, "--force"], {
32789
+ execFileSync3("git", ["worktree", "remove", entry.worktreePath, "--force"], {
31895
32790
  cwd: entryGitDir,
31896
32791
  stdio: "pipe"
31897
32792
  });
@@ -31905,7 +32800,7 @@ async function createWorktrees(repos, worldId, workspacePath, branch) {
31905
32800
  }
31906
32801
  async function removeWorktrees(repos, workspacePath) {
31907
32802
  for (const repo of repos) {
31908
- const worktreePath = path19.join(workspacePath, repo.name);
32803
+ const worktreePath = path25.join(workspacePath, repo.name);
31909
32804
  let gitDir;
31910
32805
  try {
31911
32806
  gitDir = resolveGitDir(repo);
@@ -31914,7 +32809,7 @@ async function removeWorktrees(repos, workspacePath) {
31914
32809
  }
31915
32810
  let removed = false;
31916
32811
  try {
31917
- execFileSync2("git", ["worktree", "remove", "--force", worktreePath], {
32812
+ execFileSync3("git", ["worktree", "remove", "--force", worktreePath], {
31918
32813
  cwd: gitDir,
31919
32814
  stdio: "pipe"
31920
32815
  });
@@ -31923,7 +32818,7 @@ async function removeWorktrees(repos, workspacePath) {
31923
32818
  }
31924
32819
  if (!removed) {
31925
32820
  try {
31926
- execFileSync2("git", ["worktree", "prune"], {
32821
+ execFileSync3("git", ["worktree", "prune"], {
31927
32822
  cwd: gitDir,
31928
32823
  stdio: "pipe"
31929
32824
  });
@@ -31940,7 +32835,7 @@ function removeBranch(repo, branch) {
31940
32835
  return { branch, action: "not-found" };
31941
32836
  }
31942
32837
  try {
31943
- execFileSync2("git", ["show-ref", "--quiet", `refs/heads/${branch}`], {
32838
+ execFileSync3("git", ["show-ref", "--quiet", `refs/heads/${branch}`], {
31944
32839
  cwd: gitDir,
31945
32840
  stdio: "pipe"
31946
32841
  });
@@ -31949,7 +32844,7 @@ function removeBranch(repo, branch) {
31949
32844
  }
31950
32845
  let hasUpstream = false;
31951
32846
  try {
31952
- execFileSync2("git", ["rev-parse", "--abbrev-ref", `${branch}@{upstream}`], { cwd: gitDir, stdio: "pipe" });
32847
+ execFileSync3("git", ["rev-parse", "--abbrev-ref", `${branch}@{upstream}`], { cwd: gitDir, stdio: "pipe" });
31953
32848
  hasUpstream = true;
31954
32849
  } catch {
31955
32850
  }
@@ -31958,14 +32853,14 @@ function removeBranch(repo, branch) {
31958
32853
  }
31959
32854
  let localCommitCount = 0;
31960
32855
  try {
31961
- const output = execFileSync2("git", ["rev-list", "--count", branch, "--not", "--remotes"], { cwd: gitDir, stdio: "pipe" }).toString().trim();
32856
+ const output = execFileSync3("git", ["rev-list", "--count", branch, "--not", "--remotes"], { cwd: gitDir, stdio: "pipe" }).toString().trim();
31962
32857
  localCommitCount = parseInt(output, 10) || 0;
31963
32858
  } catch {
31964
32859
  localCommitCount = 1;
31965
32860
  }
31966
32861
  if (localCommitCount === 0) {
31967
32862
  try {
31968
- execFileSync2("git", ["branch", "-D", branch], {
32863
+ execFileSync3("git", ["branch", "-D", branch], {
31969
32864
  cwd: gitDir,
31970
32865
  stdio: "pipe"
31971
32866
  });
@@ -31979,13 +32874,13 @@ function removeBranch(repo, branch) {
31979
32874
  }
31980
32875
 
31981
32876
  // ../core/dist/world/kg-overlay.js
31982
- import { execFileSync as execFileSync3 } from "node:child_process";
31983
- import * as fs18 from "node:fs";
31984
- import * as path20 from "node:path";
32877
+ import { execFileSync as execFileSync4 } from "node:child_process";
32878
+ import * as fs24 from "node:fs";
32879
+ import * as path26 from "node:path";
31985
32880
 
31986
32881
  // ../core/dist/kg/storage-paths.js
31987
- import { homedir as homedir12 } from "node:os";
31988
- import { join as join20, resolve as resolve5 } from "node:path";
32882
+ import { homedir as homedir16 } from "node:os";
32883
+ import { join as join26, resolve as resolve5 } from "node:path";
31989
32884
 
31990
32885
  // ../core/dist/world/workspace-name.js
31991
32886
  var InvalidWorkspaceNameError = class extends Error {
@@ -32006,25 +32901,25 @@ function validateWorkspaceName(name) {
32006
32901
 
32007
32902
  // ../core/dist/kg/storage-paths.js
32008
32903
  function olamHome() {
32009
- return process.env.OLAM_HOME ?? join20(homedir12(), ".olam");
32904
+ return process.env.OLAM_HOME ?? join26(homedir16(), ".olam");
32010
32905
  }
32011
32906
  function kgRoot() {
32012
- return join20(olamHome(), "kg");
32907
+ return join26(olamHome(), "kg");
32013
32908
  }
32014
32909
  function worldsRoot() {
32015
- return join20(olamHome(), "worlds");
32910
+ return join26(olamHome(), "worlds");
32016
32911
  }
32017
- function assertWithinPrefix(path31, prefix, label) {
32018
- if (!path31.startsWith(prefix + "/")) {
32019
- throw new Error(`${label} escape: ${path31} not under ${prefix}/`);
32912
+ function assertWithinPrefix(path37, prefix, label) {
32913
+ if (!path37.startsWith(prefix + "/")) {
32914
+ throw new Error(`${label} escape: ${path37} not under ${prefix}/`);
32020
32915
  }
32021
32916
  }
32022
32917
  function kgPristinePath(workspace) {
32023
32918
  validateWorkspaceName(workspace);
32024
32919
  const root = kgRoot();
32025
- const path31 = resolve5(join20(root, workspace));
32026
- assertWithinPrefix(path31, root, "kgPristinePath");
32027
- return path31;
32920
+ const path37 = resolve5(join26(root, workspace));
32921
+ assertWithinPrefix(path37, root, "kgPristinePath");
32922
+ return path37;
32028
32923
  }
32029
32924
  var KG_PATHS_INTERNALS = Object.freeze({
32030
32925
  olamHome,
@@ -32040,10 +32935,10 @@ var KgOverlayError = class extends Error {
32040
32935
  }
32041
32936
  };
32042
32937
  function ensureGitignoreEntry(worldClonePath) {
32043
- const gitignorePath = path20.join(worldClonePath, ".gitignore");
32044
- if (!fs18.existsSync(gitignorePath))
32938
+ const gitignorePath = path26.join(worldClonePath, ".gitignore");
32939
+ if (!fs24.existsSync(gitignorePath))
32045
32940
  return "no-gitignore";
32046
- const content = fs18.readFileSync(gitignorePath, "utf-8");
32941
+ const content = fs24.readFileSync(gitignorePath, "utf-8");
32047
32942
  const lines = content.split("\n").map((l) => l.trim());
32048
32943
  const recognised = /* @__PURE__ */ new Set([
32049
32944
  "graphify-out",
@@ -32058,31 +32953,31 @@ function ensureGitignoreEntry(worldClonePath) {
32058
32953
  const eol = content.includes("\r\n") ? "\r\n" : "\n";
32059
32954
  const needsLeadingNewline = content.length > 0 && !content.endsWith(eol);
32060
32955
  const block = `${needsLeadingNewline ? eol : ""}${eol}# olam-kg-service: per-world KG overlay (Phase B1)${eol}graphify-out/${eol}`;
32061
- fs18.appendFileSync(gitignorePath, block, "utf-8");
32956
+ fs24.appendFileSync(gitignorePath, block, "utf-8");
32062
32957
  return "appended";
32063
32958
  }
32064
32959
  function createWorldOverlay(opts) {
32065
32960
  const pristineRoot = kgPristinePath(opts.workspace);
32066
- const pristinePath = path20.join(pristineRoot, "graphify-out");
32067
- if (!fs18.existsSync(pristinePath)) {
32961
+ const pristinePath = path26.join(pristineRoot, "graphify-out");
32962
+ if (!fs24.existsSync(pristinePath)) {
32068
32963
  throw new KgOverlayError(`Pristine KG for workspace ${JSON.stringify(opts.workspace)} not found at ${pristinePath}. Run \`olam kg build ${opts.workspace}\` first.`);
32069
32964
  }
32070
- if (!path20.isAbsolute(opts.worldClonePath)) {
32965
+ if (!path26.isAbsolute(opts.worldClonePath)) {
32071
32966
  throw new KgOverlayError(`worldClonePath must be absolute (got ${opts.worldClonePath})`);
32072
32967
  }
32073
- if (!fs18.existsSync(opts.worldClonePath)) {
32968
+ if (!fs24.existsSync(opts.worldClonePath)) {
32074
32969
  throw new KgOverlayError(`worldClonePath does not exist: ${opts.worldClonePath}. Create the clone before reflinking.`);
32075
32970
  }
32076
- const overlayPath = path20.join(opts.worldClonePath, "graphify-out");
32077
- if (fs18.existsSync(overlayPath)) {
32078
- fs18.rmSync(overlayPath, { recursive: true, force: true });
32971
+ const overlayPath = path26.join(opts.worldClonePath, "graphify-out");
32972
+ if (fs24.existsSync(overlayPath)) {
32973
+ fs24.rmSync(overlayPath, { recursive: true, force: true });
32079
32974
  }
32080
32975
  const useReflink = process.platform === "darwin";
32081
32976
  let strategy;
32082
32977
  let reflinkError;
32083
32978
  if (useReflink) {
32084
32979
  try {
32085
- execFileSync3("cp", ["-c", "-r", pristinePath, opts.worldClonePath], {
32980
+ execFileSync4("cp", ["-c", "-r", pristinePath, opts.worldClonePath], {
32086
32981
  stdio: ["ignore", "ignore", "pipe"]
32087
32982
  });
32088
32983
  strategy = "cp-c-r-reflink";
@@ -32093,9 +32988,9 @@ function createWorldOverlay(opts) {
32093
32988
  } else {
32094
32989
  strategy = "cp-r";
32095
32990
  }
32096
- if (strategy === "cp-r" || !fs18.existsSync(overlayPath)) {
32991
+ if (strategy === "cp-r" || !fs24.existsSync(overlayPath)) {
32097
32992
  try {
32098
- execFileSync3("cp", ["-r", pristinePath, opts.worldClonePath], {
32993
+ execFileSync4("cp", ["-r", pristinePath, opts.worldClonePath], {
32099
32994
  stdio: ["ignore", "ignore", "pipe"]
32100
32995
  });
32101
32996
  strategy = "cp-r";
@@ -32105,7 +33000,7 @@ function createWorldOverlay(opts) {
32105
33000
  throw new KgOverlayError(`cp -r failed: ${msg}${reflinkMsg}`);
32106
33001
  }
32107
33002
  }
32108
- if (!fs18.existsSync(overlayPath)) {
33003
+ if (!fs24.existsSync(overlayPath)) {
32109
33004
  throw new KgOverlayError(`Overlay creation produced no ${overlayPath} after cp \u2014 filesystem returned without error?`);
32110
33005
  }
32111
33006
  const gitignoreAction = ensureGitignoreEntry(opts.worldClonePath);
@@ -32118,13 +33013,13 @@ function createWorldOverlay(opts) {
32118
33013
  }
32119
33014
 
32120
33015
  // ../core/dist/world/baseline-diff.js
32121
- import { execFileSync as execFileSync4 } from "node:child_process";
32122
- import * as fs19 from "node:fs";
32123
- import * as os12 from "node:os";
32124
- import * as path21 from "node:path";
33016
+ import { execFileSync as execFileSync5 } from "node:child_process";
33017
+ import * as fs25 from "node:fs";
33018
+ import * as os16 from "node:os";
33019
+ import * as path27 from "node:path";
32125
33020
  var DEFAULT_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
32126
- function expandHome2(p, homedir18) {
32127
- return p.replace(/^~(?=$|\/|\\)/, homedir18());
33021
+ function expandHome2(p, homedir22) {
33022
+ return p.replace(/^~(?=$|\/|\\)/, homedir22());
32128
33023
  }
32129
33024
  function sanitizeRepoFilename(name) {
32130
33025
  const sanitized = name.replace(/[^A-Za-z0-9._-]/g, "_");
@@ -32146,11 +33041,11 @@ ${stderr}`;
32146
33041
  return /unknown revision|bad revision|does not have any commits|HEAD'?: ambiguous|Needed a single revision/.test(blob);
32147
33042
  }
32148
33043
  function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
32149
- const exec = deps.exec ?? ((cmd, args, opts) => execFileSync4(cmd, args, opts));
32150
- const homedir18 = deps.homedir ?? (() => os12.homedir());
32151
- const baselineDir = path21.join(workspacePath, ".olam", "baseline");
33044
+ const exec = deps.exec ?? ((cmd, args, opts) => execFileSync5(cmd, args, opts));
33045
+ const homedir22 = deps.homedir ?? (() => os16.homedir());
33046
+ const baselineDir = path27.join(workspacePath, ".olam", "baseline");
32152
33047
  try {
32153
- fs19.mkdirSync(baselineDir, { recursive: true });
33048
+ fs25.mkdirSync(baselineDir, { recursive: true });
32154
33049
  } catch (err) {
32155
33050
  const msg = err instanceof Error ? err.message : String(err);
32156
33051
  console.warn(`[baseline-diff] mkdir ${baselineDir} failed: ${msg}; reaper will see no baseline at all`);
@@ -32162,9 +33057,9 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
32162
33057
  if (!repo.path)
32163
33058
  continue;
32164
33059
  const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
32165
- const outPath = path21.join(baselineDir, filename);
32166
- const repoPath = expandHome2(repo.path, homedir18);
32167
- if (!fs19.existsSync(repoPath)) {
33060
+ const outPath = path27.join(baselineDir, filename);
33061
+ const repoPath = expandHome2(repo.path, homedir22);
33062
+ if (!fs25.existsSync(repoPath)) {
32168
33063
  writeBaselineFile(outPath, `# repo: ${repo.name}
32169
33064
  # (skipped: path ${repoPath} does not exist)
32170
33065
  `);
@@ -32231,7 +33126,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
32231
33126
  }
32232
33127
  function writeBaselineFile(outPath, content) {
32233
33128
  try {
32234
- fs19.writeFileSync(outPath, content);
33129
+ fs25.writeFileSync(outPath, content);
32235
33130
  } catch (err) {
32236
33131
  const msg = err instanceof Error ? err.message : String(err);
32237
33132
  console.warn(`[baseline-diff] write to ${outPath} failed: ${msg}`);
@@ -32239,11 +33134,11 @@ function writeBaselineFile(outPath, content) {
32239
33134
  }
32240
33135
  function stripWorktreeEdits(repos, workspacePath) {
32241
33136
  for (const repo of repos) {
32242
- const worktreePath = path21.join(workspacePath, repo.name);
32243
- if (!fs19.existsSync(worktreePath))
33137
+ const worktreePath = path27.join(workspacePath, repo.name);
33138
+ if (!fs25.existsSync(worktreePath))
32244
33139
  continue;
32245
33140
  try {
32246
- execFileSync4("git", ["checkout", "--", "."], {
33141
+ execFileSync5("git", ["checkout", "--", "."], {
32247
33142
  cwd: worktreePath,
32248
33143
  stdio: "pipe"
32249
33144
  });
@@ -32270,7 +33165,7 @@ ${stderr.trim()}` : "";
32270
33165
  }
32271
33166
  };
32272
33167
  function captureOperatorDiff(repoPath, deps = {}) {
32273
- const exec = deps.exec ?? ((cmd, args, opts) => execFileSync4(cmd, args, opts));
33168
+ const exec = deps.exec ?? ((cmd, args, opts) => execFileSync5(cmd, args, opts));
32274
33169
  const unstaged = exec("git", ["diff"], {
32275
33170
  cwd: repoPath,
32276
33171
  encoding: "utf-8",
@@ -32298,22 +33193,22 @@ function extractStderr(err) {
32298
33193
  return typeof raw === "string" ? raw : raw.toString("utf-8");
32299
33194
  }
32300
33195
  function carryUncommittedEdits(repos, workspacePath, deps = {}) {
32301
- const exec = deps.exec ?? ((cmd, args, opts) => execFileSync4(cmd, args, opts));
32302
- const homedir18 = deps.homedir ?? (() => os12.homedir());
32303
- const existsSync27 = deps.existsSync ?? ((p) => fs19.existsSync(p));
32304
- const copyFileSync6 = deps.copyFileSync ?? ((src, dest) => fs19.copyFileSync(src, dest));
32305
- const mkdirSync18 = deps.mkdirSync ?? ((dirPath, opts) => {
32306
- fs19.mkdirSync(dirPath, opts);
33196
+ const exec = deps.exec ?? ((cmd, args, opts) => execFileSync5(cmd, args, opts));
33197
+ const homedir22 = deps.homedir ?? (() => os16.homedir());
33198
+ const existsSync33 = deps.existsSync ?? ((p) => fs25.existsSync(p));
33199
+ const copyFileSync7 = deps.copyFileSync ?? ((src, dest) => fs25.copyFileSync(src, dest));
33200
+ const mkdirSync21 = deps.mkdirSync ?? ((dirPath, opts) => {
33201
+ fs25.mkdirSync(dirPath, opts);
32307
33202
  });
32308
33203
  const plans = [];
32309
33204
  for (const repo of repos) {
32310
33205
  if (!repo.path)
32311
33206
  continue;
32312
- const repoPath = expandHome2(repo.path, homedir18);
32313
- const worktreePath = path21.join(workspacePath, repo.name);
32314
- if (!existsSync27(repoPath))
33207
+ const repoPath = expandHome2(repo.path, homedir22);
33208
+ const worktreePath = path27.join(workspacePath, repo.name);
33209
+ if (!existsSync33(repoPath))
32315
33210
  continue;
32316
- if (!existsSync27(worktreePath)) {
33211
+ if (!existsSync33(worktreePath)) {
32317
33212
  console.warn(`[carry] ${repo.name}: world worktree ${worktreePath} missing; skipping carry for this repo`);
32318
33213
  continue;
32319
33214
  }
@@ -32371,13 +33266,13 @@ function carryUncommittedEdits(repos, workspacePath, deps = {}) {
32371
33266
  }
32372
33267
  }
32373
33268
  for (const rel of plan.diff.untracked) {
32374
- const src = path21.join(plan.repoPath, rel);
32375
- const dest = path21.join(plan.worktreePath, rel);
32376
- if (!existsSync27(src))
33269
+ const src = path27.join(plan.repoPath, rel);
33270
+ const dest = path27.join(plan.worktreePath, rel);
33271
+ if (!existsSync33(src))
32377
33272
  continue;
32378
33273
  try {
32379
- mkdirSync18(path21.dirname(dest), { recursive: true });
32380
- copyFileSync6(src, dest);
33274
+ mkdirSync21(path27.dirname(dest), { recursive: true });
33275
+ copyFileSync7(src, dest);
32381
33276
  } catch (err) {
32382
33277
  const msg = err instanceof Error ? err.message : String(err);
32383
33278
  console.warn(`[carry] ${plan.name}: copy untracked ${rel} failed: ${msg}`);
@@ -32402,8 +33297,8 @@ function formatBaselineSummary(result) {
32402
33297
  }
32403
33298
 
32404
33299
  // ../core/dist/world/context-injection.js
32405
- import * as fs20 from "node:fs";
32406
- import * as path22 from "node:path";
33300
+ import * as fs26 from "node:fs";
33301
+ import * as path28 from "node:path";
32407
33302
 
32408
33303
  // ../core/dist/world/templates/_generated.js
32409
33304
  var GH_PR_CREATE = '# Creating PRs from inside an Olam world\n\n## The problem\n\nCalling `gh pr create` directly inside an Olam container **hangs forever** on a\nTTY confirmation prompt that the agent cannot answer. This is a known, reproduced issue.\n\n## The fix\n\nAlways use this exact pattern:\n\n```bash\necho y | timeout 30 gh pr create \\\n --base main \\\n --head <branch> \\\n --title "<title>" \\\n --body-file /tmp/pr-body.md\n```\n\n## Why each part matters\n\n- **`echo y |`** \u2014 answers the "Submit?" confirmation prompt up front so `gh` never pauses.\n- **`timeout 30`** \u2014 hard deadline. If `gh` hangs anyway, the command exits non-zero so the\n agent can react instead of stalling the world indefinitely.\n- **`--body-file /tmp/pr-body.md`** \u2014 write the PR body to a temp file first. Avoids\n shell-escaping bugs that occur with `--body "..."` for long or multi-line bodies.\n- **`--head` and `--base` explicitly** \u2014 removes all interactive prompts; `gh` has nothing to ask.\n\n## Troubleshooting\n\n**"no commits" or "branch not found" error:**\n\n```bash\ngit push -u origin <branch>\n# then retry:\necho y | timeout 30 gh pr create --base main --head <branch> --title "..." --body-file /tmp/pr-body.md\n```\n\n**Timeout exceeded (command exits 124):**\n\n- Check if the branch was pushed: `git log origin/<branch> --oneline -1`\n- Check GitHub CLI auth: `gh auth status`\n- Retry once; if it hangs again, open the PR via the GitHub web UI.\n';
@@ -32413,10 +33308,10 @@ var WORLD_CLAUDE_MD = '# Olam World: {{worldName}}\n\n{{taskBlock}}\n\n## Enviro
32413
33308
  // ../core/dist/world/context-injection.js
32414
33309
  function injectWorldContext(opts) {
32415
33310
  const { world } = opts;
32416
- const claudeDir = path22.join(world.workspacePath, ".claude");
32417
- fs20.mkdirSync(claudeDir, { recursive: true });
33311
+ const claudeDir2 = path28.join(world.workspacePath, ".claude");
33312
+ fs26.mkdirSync(claudeDir2, { recursive: true });
32418
33313
  const content = WORLD_CLAUDE_MD.replace("{{worldName}}", world.name).replace("{{worldId}}", world.id).replace("{{branch}}", world.branch).replace("{{taskBlock}}", buildTaskBlock(opts)).replace("{{reposList}}", buildReposList(world)).replace("{{servicesLine}}", buildServicesLine(opts.services)).replace("{{pleriPlaneLine}}", buildPleriPlaneLine(opts.pleriPlaneUrl)).replace("{{planFileBlock}}", buildPlanFileBlock(world)).replace("{{extraContextBlock}}", buildExtraContextBlock(opts.claudeMdExtra));
32419
- fs20.writeFileSync(path22.join(claudeDir, "CLAUDE.md"), content);
33314
+ fs26.writeFileSync(path28.join(claudeDir2, "CLAUDE.md"), content);
32420
33315
  writeOlamDocs(world.workspacePath);
32421
33316
  }
32422
33317
  function buildTaskBlock(opts) {
@@ -32490,10 +33385,10 @@ function buildExtraContextBlock(extra) {
32490
33385
  ${extra}`;
32491
33386
  }
32492
33387
  function writeOlamDocs(workspacePath) {
32493
- const docsDir = path22.join(workspacePath, ".olam", "docs");
32494
- fs20.mkdirSync(docsDir, { recursive: true });
32495
- fs20.writeFileSync(path22.join(docsDir, "gh-pr-create.md"), GH_PR_CREATE);
32496
- fs20.writeFileSync(path22.join(docsDir, "lane-orchestration.md"), LANE_ORCHESTRATION);
33388
+ const docsDir = path28.join(workspacePath, ".olam", "docs");
33389
+ fs26.mkdirSync(docsDir, { recursive: true });
33390
+ fs26.writeFileSync(path28.join(docsDir, "gh-pr-create.md"), GH_PR_CREATE);
33391
+ fs26.writeFileSync(path28.join(docsDir, "lane-orchestration.md"), LANE_ORCHESTRATION);
32497
33392
  }
32498
33393
  function formatTaskSource(ctx) {
32499
33394
  if (ctx.source === "linear" && ctx.ticketId) {
@@ -32507,9 +33402,9 @@ function formatTaskSource(ctx) {
32507
33402
  function hasPlanFile(world) {
32508
33403
  if (world.repos.length === 0)
32509
33404
  return false;
32510
- const plansDir = path22.join(world.workspacePath, world.repos[0], "docs", "plans");
33405
+ const plansDir = path28.join(world.workspacePath, world.repos[0], "docs", "plans");
32511
33406
  try {
32512
- return fs20.existsSync(plansDir) && fs20.readdirSync(plansDir).length > 0;
33407
+ return fs26.existsSync(plansDir) && fs26.readdirSync(plansDir).length > 0;
32513
33408
  } catch {
32514
33409
  return false;
32515
33410
  }
@@ -32737,7 +33632,7 @@ async function installStack(exec, repos, stacks) {
32737
33632
 
32738
33633
  // ../core/dist/world/stack-image.js
32739
33634
  import { execSync as execSync3 } from "node:child_process";
32740
- import * as crypto4 from "node:crypto";
33635
+ import * as crypto5 from "node:crypto";
32741
33636
  var BASE_IMAGE = "olam-devbox";
32742
33637
  var LABEL_PREFIX = "olam.stack-image";
32743
33638
  var MAX_TAG_LENGTH = 128;
@@ -32793,7 +33688,7 @@ function getImageDigest(imageRef) {
32793
33688
  cachedImageDigests.set(imageRef, short);
32794
33689
  return short;
32795
33690
  } catch {
32796
- const fallback = crypto4.createHash("sha256").update(imageRef).digest("hex").slice(0, 16);
33691
+ const fallback = crypto5.createHash("sha256").update(imageRef).digest("hex").slice(0, 16);
32797
33692
  cachedImageDigests.set(imageRef, fallback);
32798
33693
  return fallback;
32799
33694
  }
@@ -32804,7 +33699,7 @@ function getBaseImageDigest() {
32804
33699
  function sanitizeTag(raw) {
32805
33700
  let tag = raw.toLowerCase().replace(/[^a-z0-9._-]/g, "-");
32806
33701
  if (tag.length > MAX_TAG_LENGTH) {
32807
- const hash = crypto4.createHash("sha256").update(raw).digest("hex").slice(0, 12);
33702
+ const hash = crypto5.createHash("sha256").update(raw).digest("hex").slice(0, 12);
32808
33703
  tag = tag.slice(0, MAX_TAG_LENGTH - 13) + "_" + hash;
32809
33704
  }
32810
33705
  return tag;
@@ -33080,26 +33975,26 @@ function shellQuote(s) {
33080
33975
  init_repo_manifest();
33081
33976
 
33082
33977
  // ../core/dist/world/snapshot.js
33083
- import * as crypto5 from "node:crypto";
33084
- import * as fs21 from "node:fs";
33085
- import * as os13 from "node:os";
33086
- import * as path23 from "node:path";
33087
- import { execFileSync as execFileSync5, spawn as spawn2 } from "node:child_process";
33978
+ import * as crypto6 from "node:crypto";
33979
+ import * as fs27 from "node:fs";
33980
+ import * as os17 from "node:os";
33981
+ import * as path29 from "node:path";
33982
+ import { execFileSync as execFileSync6, spawn as spawn2 } from "node:child_process";
33088
33983
  import { gunzipSync } from "node:zlib";
33089
33984
  function snapshotsDir() {
33090
- return process.env["OLAM_SNAPSHOTS_DIR"] ?? path23.join(os13.homedir(), ".olam", "snapshots");
33985
+ return process.env["OLAM_SNAPSHOTS_DIR"] ?? path29.join(os17.homedir(), ".olam", "snapshots");
33091
33986
  }
33092
33987
  function snapshotKindDirByWorkspace(workspace, arch, kind) {
33093
- return path23.join(snapshotsDir(), "by-workspace", workspace, arch, kind);
33988
+ return path29.join(snapshotsDir(), "by-workspace", workspace, arch, kind);
33094
33989
  }
33095
33990
  function cleanupLegacyByWorldDir(worldId) {
33096
- const legacyDir = path23.join(snapshotsDir(), worldId);
33991
+ const legacyDir = path29.join(snapshotsDir(), worldId);
33097
33992
  if (worldId === "by-workspace")
33098
33993
  return;
33099
- if (!fs21.existsSync(legacyDir))
33994
+ if (!fs27.existsSync(legacyDir))
33100
33995
  return;
33101
33996
  try {
33102
- fs21.rmSync(legacyDir, { recursive: true, force: true });
33997
+ fs27.rmSync(legacyDir, { recursive: true, force: true });
33103
33998
  } catch {
33104
33999
  }
33105
34000
  }
@@ -33108,7 +34003,7 @@ function manifestPath(tarPath) {
33108
34003
  }
33109
34004
  function hashBuffers(entries) {
33110
34005
  const sorted = [...entries].sort((a, b) => a.path.localeCompare(b.path));
33111
- const hash = crypto5.createHash("sha256");
34006
+ const hash = crypto6.createHash("sha256");
33112
34007
  for (const entry of sorted) {
33113
34008
  hash.update(entry.path);
33114
34009
  hash.update("\0");
@@ -33118,11 +34013,11 @@ function hashBuffers(entries) {
33118
34013
  return hash.digest("hex").slice(0, 12);
33119
34014
  }
33120
34015
  function computeGemsFingerprint(repoDir, imageDigest) {
33121
- const lockfile = path23.join(repoDir, "Gemfile.lock");
33122
- if (!fs21.existsSync(lockfile))
34016
+ const lockfile = path29.join(repoDir, "Gemfile.lock");
34017
+ if (!fs27.existsSync(lockfile))
33123
34018
  return null;
33124
34019
  const entries = [
33125
- { path: "Gemfile.lock", content: fs21.readFileSync(lockfile) }
34020
+ { path: "Gemfile.lock", content: fs27.readFileSync(lockfile) }
33126
34021
  ];
33127
34022
  if (imageDigest) {
33128
34023
  entries.push({ path: "__image_digest__", content: Buffer.from(imageDigest, "utf-8") });
@@ -33132,10 +34027,10 @@ function computeGemsFingerprint(repoDir, imageDigest) {
33132
34027
  function computeNodeFingerprint(repoDir, imageDigest) {
33133
34028
  const candidates = ["yarn.lock", "pnpm-lock.yaml", "package-lock.json"];
33134
34029
  for (const name of candidates) {
33135
- const lockfile = path23.join(repoDir, name);
33136
- if (fs21.existsSync(lockfile)) {
34030
+ const lockfile = path29.join(repoDir, name);
34031
+ if (fs27.existsSync(lockfile)) {
33137
34032
  const entries = [
33138
- { path: name, content: fs21.readFileSync(lockfile) }
34033
+ { path: name, content: fs27.readFileSync(lockfile) }
33139
34034
  ];
33140
34035
  if (imageDigest) {
33141
34036
  entries.push({ path: "__image_digest__", content: Buffer.from(imageDigest, "utf-8") });
@@ -33154,18 +34049,18 @@ function unpackTarballAtomic(srcPath, destDir) {
33154
34049
  detail: validation.detail ?? `unsafe entry: ${validation.unsafePath}`
33155
34050
  };
33156
34051
  }
33157
- const parent = path23.dirname(destDir);
33158
- fs21.mkdirSync(parent, { recursive: true });
33159
- const tmpSuffix = `.tmp-${process.pid}-${crypto5.randomBytes(4).toString("hex")}`;
34052
+ const parent = path29.dirname(destDir);
34053
+ fs27.mkdirSync(parent, { recursive: true });
34054
+ const tmpSuffix = `.tmp-${process.pid}-${crypto6.randomBytes(4).toString("hex")}`;
33160
34055
  const tmpDir = `${destDir}${tmpSuffix}`;
33161
34056
  try {
33162
- fs21.mkdirSync(tmpDir, { recursive: true });
33163
- execFileSync5("tar", ["-xzf", srcPath, "-C", tmpDir], { stdio: "pipe" });
33164
- fs21.renameSync(tmpDir, destDir);
34057
+ fs27.mkdirSync(tmpDir, { recursive: true });
34058
+ execFileSync6("tar", ["-xzf", srcPath, "-C", tmpDir], { stdio: "pipe" });
34059
+ fs27.renameSync(tmpDir, destDir);
33165
34060
  return { ok: true, entryCount: validation.entries.length };
33166
34061
  } catch (err) {
33167
34062
  try {
33168
- fs21.rmSync(tmpDir, { recursive: true, force: true });
34063
+ fs27.rmSync(tmpDir, { recursive: true, force: true });
33169
34064
  } catch {
33170
34065
  }
33171
34066
  return {
@@ -33176,12 +34071,12 @@ function unpackTarballAtomic(srcPath, destDir) {
33176
34071
  }
33177
34072
  }
33178
34073
  function resolvesWithin(base, target) {
33179
- const resolved = path23.resolve(base, target);
33180
- const baseResolved = path23.resolve(base);
33181
- const rel = path23.relative(baseResolved, resolved);
34074
+ const resolved = path29.resolve(base, target);
34075
+ const baseResolved = path29.resolve(base);
34076
+ const rel = path29.relative(baseResolved, resolved);
33182
34077
  if (rel === "")
33183
34078
  return true;
33184
- return !rel.startsWith("..") && !path23.isAbsolute(rel);
34079
+ return !rel.startsWith("..") && !path29.isAbsolute(rel);
33185
34080
  }
33186
34081
  var TYPE_CHAR_TO_TYPE = {
33187
34082
  "-": "file",
@@ -33231,7 +34126,7 @@ function parseTarListLine(line) {
33231
34126
  function validateHardlinksBinary(tarPath, targetDir) {
33232
34127
  let raw;
33233
34128
  try {
33234
- raw = gunzipSync(fs21.readFileSync(tarPath));
34129
+ raw = gunzipSync(fs27.readFileSync(tarPath));
33235
34130
  } catch {
33236
34131
  return null;
33237
34132
  }
@@ -33246,7 +34141,7 @@ function validateHardlinksBinary(tarPath, targetDir) {
33246
34141
  const name = block.subarray(0, nameNull >= 0 && nameNull <= 99 ? nameNull : 100).toString("utf-8");
33247
34142
  const linkNull = block.indexOf(0, 157);
33248
34143
  const linkname = block.subarray(157, linkNull >= 157 && linkNull <= 256 ? linkNull : 257).toString("utf-8");
33249
- if (linkname && (path23.isAbsolute(linkname) || !resolvesWithin(targetDir, linkname))) {
34144
+ if (linkname && (path29.isAbsolute(linkname) || !resolvesWithin(targetDir, linkname))) {
33250
34145
  return {
33251
34146
  valid: false,
33252
34147
  reason: "hardlink-escape",
@@ -33264,7 +34159,7 @@ function validateHardlinksBinary(tarPath, targetDir) {
33264
34159
  function enumerateAndValidateTarballEntries(tarPath, targetDir) {
33265
34160
  let raw;
33266
34161
  try {
33267
- raw = execFileSync5("tar", ["-tvf", tarPath], {
34162
+ raw = execFileSync6("tar", ["-tvf", tarPath], {
33268
34163
  stdio: ["ignore", "pipe", "pipe"],
33269
34164
  env: { ...process.env, LC_ALL: "C", TZ: "UTC" },
33270
34165
  encoding: "utf-8",
@@ -33284,7 +34179,7 @@ function enumerateAndValidateTarballEntries(tarPath, targetDir) {
33284
34179
  const entry = parseTarListLine(line);
33285
34180
  if (!entry)
33286
34181
  continue;
33287
- if (path23.isAbsolute(entry.name) || !resolvesWithin(targetDir, entry.name)) {
34182
+ if (path29.isAbsolute(entry.name) || !resolvesWithin(targetDir, entry.name)) {
33288
34183
  return {
33289
34184
  valid: false,
33290
34185
  reason: "path-traversal",
@@ -33292,8 +34187,8 @@ function enumerateAndValidateTarballEntries(tarPath, targetDir) {
33292
34187
  };
33293
34188
  }
33294
34189
  if (entry.type === "symlink" && entry.linkname !== void 0) {
33295
- const symlinkParent = path23.join(targetDir, path23.dirname(entry.name));
33296
- if (path23.isAbsolute(entry.linkname) || !resolvesWithin(targetDir, path23.join(path23.dirname(entry.name), entry.linkname))) {
34190
+ const symlinkParent = path29.join(targetDir, path29.dirname(entry.name));
34191
+ if (path29.isAbsolute(entry.linkname) || !resolvesWithin(targetDir, path29.join(path29.dirname(entry.name), entry.linkname))) {
33297
34192
  return {
33298
34193
  valid: false,
33299
34194
  reason: "symlink-escape",
@@ -33303,7 +34198,7 @@ function enumerateAndValidateTarballEntries(tarPath, targetDir) {
33303
34198
  }
33304
34199
  }
33305
34200
  if (entry.type === "hardlink" && entry.linkname !== void 0) {
33306
- if (path23.isAbsolute(entry.linkname) || !resolvesWithin(targetDir, entry.linkname)) {
34201
+ if (path29.isAbsolute(entry.linkname) || !resolvesWithin(targetDir, entry.linkname)) {
33307
34202
  return {
33308
34203
  valid: false,
33309
34204
  reason: "hardlink-escape",
@@ -33336,8 +34231,8 @@ function restoreSnapshotsForRepos(input) {
33336
34231
  }
33337
34232
  const archDir = snapshotKindDirByWorkspace(input.workspace, input.arch, kind);
33338
34233
  const tarFilename = `${repo.name}-${input.arch}-${fingerprint}.tar.gz`;
33339
- const tarPath = path23.join(archDir, tarFilename);
33340
- if (!fs21.existsSync(tarPath)) {
34234
+ const tarPath = path29.join(archDir, tarFilename);
34235
+ if (!fs27.existsSync(tarPath)) {
33341
34236
  outcomes.push({ repo: repo.name, kind, outcome: "miss", reason: "no-tarball", fingerprint });
33342
34237
  continue;
33343
34238
  }
@@ -33352,9 +34247,9 @@ function restoreSnapshotsForRepos(input) {
33352
34247
  });
33353
34248
  continue;
33354
34249
  }
33355
- const targetDir = path23.join(repo.worktreeDir, targetSubpath);
34250
+ const targetDir = path29.join(repo.worktreeDir, targetSubpath);
33356
34251
  try {
33357
- fs21.rmSync(targetDir, { recursive: true, force: true });
34252
+ fs27.rmSync(targetDir, { recursive: true, force: true });
33358
34253
  } catch {
33359
34254
  }
33360
34255
  const result = unpackTarballAtomic(tarPath, targetDir);
@@ -33367,8 +34262,8 @@ function restoreSnapshotsForRepos(input) {
33367
34262
  fingerprint
33368
34263
  });
33369
34264
  try {
33370
- fs21.rmSync(tarPath, { force: true });
33371
- fs21.rmSync(manifestPath(tarPath), { force: true });
34265
+ fs27.rmSync(tarPath, { force: true });
34266
+ fs27.rmSync(manifestPath(tarPath), { force: true });
33372
34267
  } catch {
33373
34268
  }
33374
34269
  continue;
@@ -33384,10 +34279,10 @@ function restoreSnapshotsForRepos(input) {
33384
34279
  }
33385
34280
  function readManifest(tarPath) {
33386
34281
  const mPath = manifestPath(tarPath);
33387
- if (!fs21.existsSync(mPath))
34282
+ if (!fs27.existsSync(mPath))
33388
34283
  return null;
33389
34284
  try {
33390
- return JSON.parse(fs21.readFileSync(mPath, "utf-8"));
34285
+ return JSON.parse(fs27.readFileSync(mPath, "utf-8"));
33391
34286
  } catch {
33392
34287
  return null;
33393
34288
  }
@@ -33402,17 +34297,17 @@ function isPidAlive(pid) {
33402
34297
  }
33403
34298
  }
33404
34299
  function evictOldSnapshotsWithFlock(maxBytes, dir = snapshotsDir()) {
33405
- fs21.mkdirSync(dir, { recursive: true });
33406
- const lockPath = path23.join(dir, EVICT_LOCK_FILENAME);
34300
+ fs27.mkdirSync(dir, { recursive: true });
34301
+ const lockPath = path29.join(dir, EVICT_LOCK_FILENAME);
33407
34302
  let fd;
33408
34303
  try {
33409
- fd = fs21.openSync(lockPath, fs21.constants.O_WRONLY | fs21.constants.O_CREAT | fs21.constants.O_EXCL, 384);
34304
+ fd = fs27.openSync(lockPath, fs27.constants.O_WRONLY | fs27.constants.O_CREAT | fs27.constants.O_EXCL, 384);
33410
34305
  } catch (err) {
33411
34306
  if (err.code !== "EEXIST")
33412
34307
  return 0;
33413
34308
  let holderPid = null;
33414
34309
  try {
33415
- holderPid = parseInt(fs21.readFileSync(lockPath, "utf-8").trim(), 10);
34310
+ holderPid = parseInt(fs27.readFileSync(lockPath, "utf-8").trim(), 10);
33416
34311
  } catch {
33417
34312
  holderPid = null;
33418
34313
  }
@@ -33420,23 +34315,23 @@ function evictOldSnapshotsWithFlock(maxBytes, dir = snapshotsDir()) {
33420
34315
  return 0;
33421
34316
  }
33422
34317
  try {
33423
- fs21.unlinkSync(lockPath);
33424
- fd = fs21.openSync(lockPath, fs21.constants.O_WRONLY | fs21.constants.O_CREAT | fs21.constants.O_EXCL, 384);
34318
+ fs27.unlinkSync(lockPath);
34319
+ fd = fs27.openSync(lockPath, fs27.constants.O_WRONLY | fs27.constants.O_CREAT | fs27.constants.O_EXCL, 384);
33425
34320
  } catch {
33426
34321
  return 0;
33427
34322
  }
33428
34323
  }
33429
34324
  try {
33430
- fs21.writeSync(fd, `${process.pid}
34325
+ fs27.writeSync(fd, `${process.pid}
33431
34326
  `);
33432
34327
  } finally {
33433
- fs21.closeSync(fd);
34328
+ fs27.closeSync(fd);
33434
34329
  }
33435
34330
  try {
33436
34331
  return evictOldSnapshots(maxBytes, dir);
33437
34332
  } finally {
33438
34333
  try {
33439
- fs21.unlinkSync(lockPath);
34334
+ fs27.unlinkSync(lockPath);
33440
34335
  } catch {
33441
34336
  }
33442
34337
  }
@@ -33469,16 +34364,16 @@ function spawnAutoCapture(worldId, olamBin = "olam") {
33469
34364
  }
33470
34365
  }
33471
34366
  function evictOldSnapshots(maxBytes, dir = snapshotsDir()) {
33472
- if (!fs21.existsSync(dir))
34367
+ if (!fs27.existsSync(dir))
33473
34368
  return 0;
33474
34369
  const allTars = [];
33475
34370
  const walk = (d) => {
33476
- for (const entry of fs21.readdirSync(d, { withFileTypes: true })) {
33477
- const full = path23.join(d, entry.name);
34371
+ for (const entry of fs27.readdirSync(d, { withFileTypes: true })) {
34372
+ const full = path29.join(d, entry.name);
33478
34373
  if (entry.isDirectory()) {
33479
34374
  walk(full);
33480
34375
  } else if (entry.name.endsWith(".tar.gz")) {
33481
- const stat = fs21.statSync(full);
34376
+ const stat = fs27.statSync(full);
33482
34377
  allTars.push({ path: full, size: stat.size, mtime: stat.mtimeMs });
33483
34378
  }
33484
34379
  }
@@ -33493,8 +34388,8 @@ function evictOldSnapshots(maxBytes, dir = snapshotsDir()) {
33493
34388
  for (const tar of allTars) {
33494
34389
  if (remaining <= maxBytes)
33495
34390
  break;
33496
- fs21.rmSync(tar.path, { force: true });
33497
- fs21.rmSync(manifestPath(tar.path), { force: true });
34391
+ fs27.rmSync(tar.path, { force: true });
34392
+ fs27.rmSync(manifestPath(tar.path), { force: true });
33498
34393
  freed += tar.size;
33499
34394
  remaining -= tar.size;
33500
34395
  }
@@ -33611,14 +34506,14 @@ function gcloudAvailable(execFn = defaultExecFn) {
33611
34506
 
33612
34507
  // ../core/dist/world/olam-yaml.js
33613
34508
  init_repo_manifest();
33614
- import * as path24 from "node:path";
34509
+ import * as path30 from "node:path";
33615
34510
  import YAML2 from "yaml";
33616
34511
  function enrichReposWithManifests(repos, workspacePath) {
33617
34512
  return repos.map((repo) => {
33618
34513
  if (repo.manifest !== void 0 && repo.manifest !== null) {
33619
34514
  return repo;
33620
34515
  }
33621
- const repoDir = path24.join(workspacePath, repo.name);
34516
+ const repoDir = path30.join(workspacePath, repo.name);
33622
34517
  let manifest = null;
33623
34518
  try {
33624
34519
  manifest = loadRepoManifest(repoDir);
@@ -33633,8 +34528,8 @@ function enrichReposWithManifests(repos, workspacePath) {
33633
34528
  }
33634
34529
 
33635
34530
  // ../core/dist/policies/loader.js
33636
- import * as fs22 from "node:fs";
33637
- import * as path25 from "node:path";
34531
+ import * as fs28 from "node:fs";
34532
+ import * as path31 from "node:path";
33638
34533
  import { parse as parseYaml3 } from "yaml";
33639
34534
  function parseFrontmatter(content) {
33640
34535
  const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/m.exec(content);
@@ -33654,20 +34549,20 @@ function toStringArray(v) {
33654
34549
  return v.filter((x) => typeof x === "string");
33655
34550
  }
33656
34551
  function loadPolicies(workspaceRoot) {
33657
- const policiesDir = path25.join(workspaceRoot, ".olam", "policies");
33658
- if (!fs22.existsSync(policiesDir))
34552
+ const policiesDir = path31.join(workspaceRoot, ".olam", "policies");
34553
+ if (!fs28.existsSync(policiesDir))
33659
34554
  return [];
33660
34555
  let files;
33661
34556
  try {
33662
- files = fs22.readdirSync(policiesDir).filter((f) => f.endsWith(".md")).sort();
34557
+ files = fs28.readdirSync(policiesDir).filter((f) => f.endsWith(".md")).sort();
33663
34558
  } catch {
33664
34559
  return [];
33665
34560
  }
33666
34561
  const policies = [];
33667
34562
  for (const file of files) {
33668
- const filePath = path25.join(policiesDir, file);
34563
+ const filePath = path31.join(policiesDir, file);
33669
34564
  try {
33670
- const content = fs22.readFileSync(filePath, "utf8");
34565
+ const content = fs28.readFileSync(filePath, "utf8");
33671
34566
  const parsed = parseFrontmatter(content);
33672
34567
  if (!parsed) {
33673
34568
  console.warn(`[policies] skipping ${file}: no valid frontmatter block`);
@@ -33809,12 +34704,12 @@ async function autoDispatchTask(opts) {
33809
34704
  }
33810
34705
 
33811
34706
  // ../core/dist/global-config/runbook-resolver.js
33812
- import * as fs23 from "node:fs";
33813
- import * as os14 from "node:os";
33814
- import * as path26 from "node:path";
34707
+ import * as fs29 from "node:fs";
34708
+ import * as os18 from "node:os";
34709
+ import * as path32 from "node:path";
33815
34710
  function expandTilde(p) {
33816
34711
  if (p === "~" || p.startsWith("~/")) {
33817
- return path26.join(os14.homedir(), p.slice(1));
34712
+ return path32.join(os18.homedir(), p.slice(1));
33818
34713
  }
33819
34714
  return p;
33820
34715
  }
@@ -33826,7 +34721,7 @@ function resolveRunbookToWorldParams(runbook, repoRegistry) {
33826
34721
  throw new Error(`repo "${repoName}" is referenced by runbook "${runbook.name}" but is not in the registry. Run "olam repos add ${repoName} --path <path>" to register it.`);
33827
34722
  }
33828
34723
  const resolvedPath = expandTilde(entry.path);
33829
- if (!fs23.existsSync(resolvedPath)) {
34724
+ if (!fs29.existsSync(resolvedPath)) {
33830
34725
  throw new Error(`repo "${repoName}" path "${resolvedPath}" no longer exists. Run "olam repos update ${repoName} --path <new-path>" to fix.`);
33831
34726
  }
33832
34727
  }
@@ -33839,19 +34734,19 @@ function resolveRunbookToWorldParams(runbook, repoRegistry) {
33839
34734
  }
33840
34735
 
33841
34736
  // ../core/dist/world/bootstrap-hooks.js
33842
- import * as fs24 from "node:fs";
33843
- import * as path27 from "node:path";
34737
+ import * as fs30 from "node:fs";
34738
+ import * as path33 from "node:path";
33844
34739
  function runFixtureCopySeeds(seeds, workspacePath) {
33845
34740
  if (!seeds)
33846
34741
  return;
33847
34742
  for (const seed of seeds) {
33848
34743
  if (seed.type !== "fixture-copy")
33849
34744
  continue;
33850
- const srcAbs = path27.resolve(workspacePath, seed.repo, seed.src);
33851
- const destAbs = path27.resolve(workspacePath, seed.repo, seed.dest);
33852
- const destDir = path27.dirname(destAbs);
33853
- fs24.mkdirSync(destDir, { recursive: true });
33854
- fs24.cpSync(srcAbs, destAbs, { recursive: true, force: true });
34745
+ const srcAbs = path33.resolve(workspacePath, seed.repo, seed.src);
34746
+ const destAbs = path33.resolve(workspacePath, seed.repo, seed.dest);
34747
+ const destDir = path33.dirname(destAbs);
34748
+ fs30.mkdirSync(destDir, { recursive: true });
34749
+ fs30.cpSync(srcAbs, destAbs, { recursive: true, force: true });
33855
34750
  }
33856
34751
  }
33857
34752
  async function runSeedHooks(seeds, containerName, servicePortMap, exec) {
@@ -34487,7 +35382,7 @@ ${detail}`);
34487
35382
  runbookSeeds = resolved.seeds;
34488
35383
  }
34489
35384
  const worldId = generateWorldId();
34490
- const workspacePath = path28.join(os15.homedir(), ".olam", "worlds", worldId);
35385
+ const workspacePath = path34.join(os19.homedir(), ".olam", "worlds", worldId);
34491
35386
  const portOffset = this.registry.getNextPortOffset();
34492
35387
  const branch = opts.branchName ?? `olam/${worldId}`;
34493
35388
  const repos = this.resolveReposWithWorkspace(opts);
@@ -34568,38 +35463,38 @@ ${detail}`);
34568
35463
  for (const repo of repos) {
34569
35464
  if (!repo.path)
34570
35465
  continue;
34571
- const sourceRoot = repo.path.replace(/^~/, os15.homedir());
34572
- const worktreeRoot = path28.join(workspacePath, repo.name);
34573
- if (!fs25.existsSync(sourceRoot) || !fs25.existsSync(worktreeRoot))
35466
+ const sourceRoot = repo.path.replace(/^~/, os19.homedir());
35467
+ const worktreeRoot = path34.join(workspacePath, repo.name);
35468
+ if (!fs31.existsSync(sourceRoot) || !fs31.existsSync(worktreeRoot))
34574
35469
  continue;
34575
35470
  let copied = 0;
34576
35471
  for (const pattern of RUNTIME_FILE_PATTERNS) {
34577
35472
  const matches2 = [];
34578
35473
  if (pattern.includes("*")) {
34579
- const [dir, glob] = [path28.dirname(pattern), path28.basename(pattern)];
34580
- const sourceDir = path28.join(sourceRoot, dir);
34581
- if (fs25.existsSync(sourceDir)) {
35474
+ const [dir, glob] = [path34.dirname(pattern), path34.basename(pattern)];
35475
+ const sourceDir = path34.join(sourceRoot, dir);
35476
+ if (fs31.existsSync(sourceDir)) {
34582
35477
  const ext = glob.replace(/^\*+/, "");
34583
35478
  try {
34584
- for (const entry of fs25.readdirSync(sourceDir)) {
35479
+ for (const entry of fs31.readdirSync(sourceDir)) {
34585
35480
  if (ext === "" || entry.endsWith(ext))
34586
- matches2.push(path28.join(dir, entry));
35481
+ matches2.push(path34.join(dir, entry));
34587
35482
  }
34588
35483
  } catch {
34589
35484
  }
34590
35485
  }
34591
- } else if (fs25.existsSync(path28.join(sourceRoot, pattern))) {
35486
+ } else if (fs31.existsSync(path34.join(sourceRoot, pattern))) {
34592
35487
  matches2.push(pattern);
34593
35488
  }
34594
35489
  for (const rel of matches2) {
34595
- const src = path28.join(sourceRoot, rel);
34596
- const dst = path28.join(worktreeRoot, rel);
35490
+ const src = path34.join(sourceRoot, rel);
35491
+ const dst = path34.join(worktreeRoot, rel);
34597
35492
  try {
34598
- const st = fs25.statSync(src);
35493
+ const st = fs31.statSync(src);
34599
35494
  if (!st.isFile())
34600
35495
  continue;
34601
- fs25.mkdirSync(path28.dirname(dst), { recursive: true });
34602
- fs25.copyFileSync(src, dst);
35496
+ fs31.mkdirSync(path34.dirname(dst), { recursive: true });
35497
+ fs31.copyFileSync(src, dst);
34603
35498
  copied++;
34604
35499
  } catch {
34605
35500
  }
@@ -34685,7 +35580,7 @@ ${detail}`);
34685
35580
  }
34686
35581
  const overlayAttachments = [];
34687
35582
  for (const repo of repos) {
34688
- const worldClonePath = path28.join(workspacePath, repo.name);
35583
+ const worldClonePath = path34.join(workspacePath, repo.name);
34689
35584
  try {
34690
35585
  const result = createWorldOverlay({
34691
35586
  workspace: repo.name,
@@ -34740,7 +35635,7 @@ ${detail}`);
34740
35635
  try {
34741
35636
  const hostExec = makeHostExecFn();
34742
35637
  for (const repo of repos) {
34743
- const repoDir = path28.join(workspacePath, repo.name);
35638
+ const repoDir = path34.join(workspacePath, repo.name);
34744
35639
  if (repo.stack && Object.keys(repo.stack).length > 0) {
34745
35640
  preDetectedStacks.set(repo.name, { repoName: repo.name, versions: repo.stack });
34746
35641
  } else {
@@ -34784,10 +35679,10 @@ ${detail}`);
34784
35679
  const worldEnv = {};
34785
35680
  if (opts.task)
34786
35681
  worldEnv.OLAM_TASK = opts.task;
34787
- const r2CredsPath = path28.join(os15.homedir(), ".olam", "r2-credentials.json");
34788
- if (fs25.existsSync(r2CredsPath)) {
35682
+ const r2CredsPath = path34.join(os19.homedir(), ".olam", "r2-credentials.json");
35683
+ if (fs31.existsSync(r2CredsPath)) {
34789
35684
  try {
34790
- const r2Raw = fs25.readFileSync(r2CredsPath, "utf-8").trim();
35685
+ const r2Raw = fs31.readFileSync(r2CredsPath, "utf-8").trim();
34791
35686
  if (r2Raw.length > 0) {
34792
35687
  const r2 = JSON.parse(r2Raw);
34793
35688
  if (typeof r2.account_id === "string")
@@ -34804,10 +35699,10 @@ ${detail}`);
34804
35699
  } catch {
34805
35700
  }
34806
35701
  }
34807
- const keysYamlPath = path28.join(os15.homedir(), ".olam", "keys.yaml");
34808
- if (fs25.existsSync(keysYamlPath)) {
35702
+ const keysYamlPath = path34.join(os19.homedir(), ".olam", "keys.yaml");
35703
+ if (fs31.existsSync(keysYamlPath)) {
34809
35704
  try {
34810
- const keysRaw = fs25.readFileSync(keysYamlPath, "utf-8").trim();
35705
+ const keysRaw = fs31.readFileSync(keysYamlPath, "utf-8").trim();
34811
35706
  if (keysRaw.length > 0) {
34812
35707
  const parsed = YAML3.parse(keysRaw);
34813
35708
  if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
@@ -34866,10 +35761,10 @@ ${detail}`);
34866
35761
  worldEnv[k] = v;
34867
35762
  }
34868
35763
  for (const { repoName, relativePath, content } of fileWrites) {
34869
- const absPath = path28.join(workspacePath, repoName, relativePath);
35764
+ const absPath = path34.join(workspacePath, repoName, relativePath);
34870
35765
  try {
34871
- fs25.mkdirSync(path28.dirname(absPath), { recursive: true });
34872
- fs25.writeFileSync(absPath, content.endsWith("\n") ? content : content + "\n", {
35766
+ fs31.mkdirSync(path34.dirname(absPath), { recursive: true });
35767
+ fs31.writeFileSync(absPath, content.endsWith("\n") ? content : content + "\n", {
34873
35768
  mode: 384
34874
35769
  });
34875
35770
  console.log(`[secrets] ${repoName}: materialised ${relativePath} (${content.length} chars, mode 0600)`);
@@ -35040,7 +35935,7 @@ ${detail}`);
35040
35935
  imageDigest: void 0,
35041
35936
  repos: enrichedRepos.map((r) => ({
35042
35937
  name: r.name,
35043
- worktreeDir: path28.join(workspacePath, r.name)
35938
+ worktreeDir: path34.join(workspacePath, r.name)
35044
35939
  }))
35045
35940
  });
35046
35941
  for (const out of restoreResult.outcomes) {
@@ -35146,7 +36041,7 @@ ${detail}`);
35146
36041
  }
35147
36042
  if (opts.task) {
35148
36043
  const allPolicies = repos.flatMap((repo) => {
35149
- const repoWorktree = path28.join(workspacePath, repo.name);
36044
+ const repoWorktree = path34.join(workspacePath, repo.name);
35150
36045
  try {
35151
36046
  return loadPolicies(repoWorktree);
35152
36047
  } catch (err) {
@@ -35159,8 +36054,8 @@ ${detail}`);
35159
36054
  try {
35160
36055
  execSync5(`docker exec ${containerName} mkdir -p /home/olam/.olam/policies`, { stdio: "pipe", timeout: 1e4 });
35161
36056
  for (const repo of repos) {
35162
- const policiesDir = path28.join(workspacePath, repo.name, ".olam", "policies");
35163
- if (fs25.existsSync(policiesDir)) {
36057
+ const policiesDir = path34.join(workspacePath, repo.name, ".olam", "policies");
36058
+ if (fs31.existsSync(policiesDir)) {
35164
36059
  execSync5(`docker cp "${policiesDir}/." "${containerName}:/home/olam/.olam/policies/"`, { stdio: "pipe", timeout: 15e3 });
35165
36060
  }
35166
36061
  }
@@ -35268,8 +36163,8 @@ ${detail}`);
35268
36163
  } catch {
35269
36164
  }
35270
36165
  try {
35271
- fs25.rmSync(world.workspacePath, { recursive: true, force: true });
35272
- if (fs25.existsSync(world.workspacePath)) {
36166
+ fs31.rmSync(world.workspacePath, { recursive: true, force: true });
36167
+ if (fs31.existsSync(world.workspacePath)) {
35273
36168
  console.warn(`[WorldManager] destroyWorld(${worldId}): workspace dir ${world.workspacePath} still exists after rmSync. Run \`olam clean --apply\` to reap.`);
35274
36169
  }
35275
36170
  } catch (err) {
@@ -35378,14 +36273,14 @@ ${detail}`);
35378
36273
  }).filter((r) => r !== void 0);
35379
36274
  }
35380
36275
  transportPlanFile(planFilePath, workspacePath, repoNames) {
35381
- const planContent = fs25.readFileSync(planFilePath, "utf-8");
35382
- const planFileName = path28.basename(planFilePath);
36276
+ const planContent = fs31.readFileSync(planFilePath, "utf-8");
36277
+ const planFileName = path34.basename(planFilePath);
35383
36278
  const targetRepo = repoNames[0];
35384
36279
  if (!targetRepo)
35385
36280
  return;
35386
- const plansDir = path28.join(workspacePath, targetRepo, "docs", "plans");
35387
- fs25.mkdirSync(plansDir, { recursive: true });
35388
- fs25.writeFileSync(path28.join(plansDir, planFileName), planContent);
36281
+ const plansDir = path34.join(workspacePath, targetRepo, "docs", "plans");
36282
+ fs31.mkdirSync(plansDir, { recursive: true });
36283
+ fs31.writeFileSync(path34.join(plansDir, planFileName), planContent);
35389
36284
  }
35390
36285
  resolveServices(repos) {
35391
36286
  const services = [];
@@ -35688,7 +36583,7 @@ function applyPostgresWorldRole(worldId, worldDbNames, options = {}) {
35688
36583
  return { worldRoleName, password };
35689
36584
  }
35690
36585
  function defaultPasswordGenerator() {
35691
- return crypto6.randomBytes(24).toString("base64url");
36586
+ return crypto7.randomBytes(24).toString("base64url");
35692
36587
  }
35693
36588
  function escapeSqlLiteral(s) {
35694
36589
  return s.replace(/'/g, "''");
@@ -35819,8 +36714,8 @@ import * as http2 from "node:http";
35819
36714
 
35820
36715
  // ../core/dist/dashboard/server.js
35821
36716
  import * as http from "node:http";
35822
- import * as fs26 from "node:fs";
35823
- import * as path29 from "node:path";
36717
+ import * as fs32 from "node:fs";
36718
+ import * as path35 from "node:path";
35824
36719
  import { fileURLToPath as fileURLToPath2 } from "node:url";
35825
36720
 
35826
36721
  // ../core/dist/dashboard/serialize.js
@@ -36155,7 +37050,7 @@ function notFound(res) {
36155
37050
  }
36156
37051
  function openThoughtStore(workspacePath) {
36157
37052
  const dbPath = getWorldDbPath(workspacePath);
36158
- if (!fs26.existsSync(dbPath))
37053
+ if (!fs32.existsSync(dbPath))
36159
37054
  return null;
36160
37055
  return new ThoughtLocalStore(dbPath);
36161
37056
  }
@@ -36326,13 +37221,13 @@ function findSessionInWorld(registry2, sessionId) {
36326
37221
  }
36327
37222
  function createDashboardServer(opts) {
36328
37223
  const { port: port2, registry: registry2 } = opts;
36329
- const thisDir = path29.dirname(fileURLToPath2(import.meta.url));
36330
- const defaultPublicDir = path29.resolve(thisDir, "../../../control-plane/public");
37224
+ const thisDir = path35.dirname(fileURLToPath2(import.meta.url));
37225
+ const defaultPublicDir = path35.resolve(thisDir, "../../../control-plane/public");
36331
37226
  const publicDir = opts.publicDir ?? defaultPublicDir;
36332
- let hasPublicDir = fs26.existsSync(publicDir);
37227
+ let hasPublicDir = fs32.existsSync(publicDir);
36333
37228
  const server = http.createServer((req, res) => {
36334
37229
  if (!hasPublicDir) {
36335
- hasPublicDir = fs26.existsSync(publicDir);
37230
+ hasPublicDir = fs32.existsSync(publicDir);
36336
37231
  }
36337
37232
  const host = req.headers.host ?? `localhost:${port2}`;
36338
37233
  const url2 = new URL(req.url ?? "/", `http://${host}`);
@@ -36606,22 +37501,22 @@ function createDashboardServer(opts) {
36606
37501
  res.end(`<html><body style="font-family:system-ui;padding:2rem"><h1>Olam Dashboard</h1><p>The React app has not been built yet.</p><p>Run <code>npm run build:app</code> in <code>packages/control-plane</code> to build it.</p><p>API routes are available at <code>/api/*</code>.</p></body></html>`);
36607
37502
  return;
36608
37503
  }
36609
- let filePath = path29.join(publicDir, pathname === "/" ? "index.html" : pathname);
37504
+ let filePath = path35.join(publicDir, pathname === "/" ? "index.html" : pathname);
36610
37505
  if (!filePath.startsWith(publicDir)) {
36611
37506
  notFound(res);
36612
37507
  return;
36613
37508
  }
36614
- if (fs26.existsSync(filePath) && fs26.statSync(filePath).isFile()) {
36615
- const ext = path29.extname(filePath);
37509
+ if (fs32.existsSync(filePath) && fs32.statSync(filePath).isFile()) {
37510
+ const ext = path35.extname(filePath);
36616
37511
  const contentType = MIME[ext] ?? "application/octet-stream";
36617
37512
  res.writeHead(200, { "Content-Type": contentType });
36618
- fs26.createReadStream(filePath).pipe(res);
37513
+ fs32.createReadStream(filePath).pipe(res);
36619
37514
  return;
36620
37515
  }
36621
- filePath = path29.join(publicDir, "index.html");
36622
- if (fs26.existsSync(filePath)) {
37516
+ filePath = path35.join(publicDir, "index.html");
37517
+ if (fs32.existsSync(filePath)) {
36623
37518
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
36624
- fs26.createReadStream(filePath).pipe(res);
37519
+ fs32.createReadStream(filePath).pipe(res);
36625
37520
  return;
36626
37521
  }
36627
37522
  notFound(res);
@@ -36631,17 +37526,17 @@ function createDashboardServer(opts) {
36631
37526
  }
36632
37527
 
36633
37528
  // ../core/dist/dashboard/state.js
36634
- import * as fs27 from "node:fs";
36635
- import * as os16 from "node:os";
36636
- import * as path30 from "node:path";
36637
- var STATE_PATH = path30.join(os16.homedir(), ".olam", "dashboard.json");
37529
+ import * as fs33 from "node:fs";
37530
+ import * as os20 from "node:os";
37531
+ import * as path36 from "node:path";
37532
+ var STATE_PATH = path36.join(os20.homedir(), ".olam", "dashboard.json");
36638
37533
  function saveDashboardState(state) {
36639
- fs27.mkdirSync(path30.dirname(STATE_PATH), { recursive: true });
36640
- fs27.writeFileSync(STATE_PATH, JSON.stringify(state, null, 2));
37534
+ fs33.mkdirSync(path36.dirname(STATE_PATH), { recursive: true });
37535
+ fs33.writeFileSync(STATE_PATH, JSON.stringify(state, null, 2));
36641
37536
  }
36642
37537
  function loadDashboardState() {
36643
37538
  try {
36644
- const raw = fs27.readFileSync(STATE_PATH, "utf-8");
37539
+ const raw = fs33.readFileSync(STATE_PATH, "utf-8");
36645
37540
  return JSON.parse(raw);
36646
37541
  } catch {
36647
37542
  return null;
@@ -36649,7 +37544,7 @@ function loadDashboardState() {
36649
37544
  }
36650
37545
  function clearDashboardState() {
36651
37546
  try {
36652
- fs27.unlinkSync(STATE_PATH);
37547
+ fs33.unlinkSync(STATE_PATH);
36653
37548
  } catch {
36654
37549
  }
36655
37550
  }
@@ -36929,8 +37824,8 @@ var PleriClient = class {
36929
37824
  };
36930
37825
 
36931
37826
  // ../mcp-server/src/env-loader.ts
36932
- import { readFileSync as readFileSync19, existsSync as existsSync26, statSync as statSync7 } from "node:fs";
36933
- import { join as join31, dirname as dirname18, resolve as resolve9 } from "node:path";
37827
+ import { readFileSync as readFileSync22, existsSync as existsSync32, statSync as statSync9 } from "node:fs";
37828
+ import { join as join37, dirname as dirname19, resolve as resolve9 } from "node:path";
36934
37829
  var PROJECT_MARKERS = [
36935
37830
  ".olam/config.yaml",
36936
37831
  ".olam/config.yml",
@@ -36942,26 +37837,26 @@ function findProjectRoot2(startDir) {
36942
37837
  const root = resolve9("/");
36943
37838
  while (true) {
36944
37839
  for (const marker of PROJECT_MARKERS) {
36945
- if (existsSync26(join31(dir, marker))) return dir;
37840
+ if (existsSync32(join37(dir, marker))) return dir;
36946
37841
  }
36947
- const pkg = join31(dir, "package.json");
36948
- if (existsSync26(pkg)) {
37842
+ const pkg = join37(dir, "package.json");
37843
+ if (existsSync32(pkg)) {
36949
37844
  try {
36950
- const json = JSON.parse(readFileSync19(pkg, "utf8"));
37845
+ const json = JSON.parse(readFileSync22(pkg, "utf8"));
36951
37846
  const isOlamWorkspace = typeof json.name === "string" && json.name.startsWith("@olam/");
36952
37847
  const hasOlamDep = json.dependencies && Object.keys(json.dependencies).some((k) => k.startsWith("@olam/")) || json.devDependencies && Object.keys(json.devDependencies).some((k) => k.startsWith("@olam/"));
36953
37848
  if (isOlamWorkspace || hasOlamDep) return dir;
36954
37849
  } catch {
36955
37850
  }
36956
37851
  }
36957
- const parent = dirname18(dir);
37852
+ const parent = dirname19(dir);
36958
37853
  if (parent === dir || parent === root) return null;
36959
37854
  dir = parent;
36960
37855
  }
36961
37856
  }
36962
- function parseEnvFile(path31) {
37857
+ function parseEnvFile(path37) {
36963
37858
  const out = {};
36964
- const raw = readFileSync19(path31, "utf8");
37859
+ const raw = readFileSync22(path37, "utf8");
36965
37860
  for (const line of raw.split(/\r?\n/)) {
36966
37861
  const trimmed = line.trim();
36967
37862
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -36984,8 +37879,8 @@ function loadProjectEnv(startDir = process.cwd()) {
36984
37879
  const filesRead = [];
36985
37880
  const merged = {};
36986
37881
  for (const name of [".env", ".env.local"]) {
36987
- const p = join31(root, name);
36988
- if (existsSync26(p) && statSync7(p).isFile()) {
37882
+ const p = join37(root, name);
37883
+ if (existsSync32(p) && statSync9(p).isFile()) {
36989
37884
  Object.assign(merged, parseEnvFile(p));
36990
37885
  filesRead.push(p);
36991
37886
  }