@pleri/olam-cli 0.1.166 → 0.1.167

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 (49) hide show
  1. package/README.md +4 -2
  2. package/dist/commands/bootstrap.d.ts +6 -0
  3. package/dist/commands/bootstrap.d.ts.map +1 -1
  4. package/dist/commands/bootstrap.js +15 -0
  5. package/dist/commands/bootstrap.js.map +1 -1
  6. package/dist/commands/doctor.js +4 -4
  7. package/dist/commands/doctor.js.map +1 -1
  8. package/dist/commands/init.d.ts +4 -3
  9. package/dist/commands/init.d.ts.map +1 -1
  10. package/dist/commands/init.js +103 -81
  11. package/dist/commands/init.js.map +1 -1
  12. package/dist/commands/memory-service-container.d.ts +8 -0
  13. package/dist/commands/memory-service-container.d.ts.map +1 -1
  14. package/dist/commands/memory-service-container.js +16 -1
  15. package/dist/commands/memory-service-container.js.map +1 -1
  16. package/dist/commands/setup.d.ts +62 -14
  17. package/dist/commands/setup.d.ts.map +1 -1
  18. package/dist/commands/setup.js +373 -42
  19. package/dist/commands/setup.js.map +1 -1
  20. package/dist/commands/skills-source.d.ts.map +1 -1
  21. package/dist/commands/skills-source.js +89 -4
  22. package/dist/commands/skills-source.js.map +1 -1
  23. package/dist/image-digests.json +8 -7
  24. package/dist/index.js +672 -168
  25. package/dist/lib/bootstrap-kubernetes.d.ts.map +1 -1
  26. package/dist/lib/bootstrap-kubernetes.js +163 -106
  27. package/dist/lib/bootstrap-kubernetes.js.map +1 -1
  28. package/dist/lib/health-probes.d.ts +16 -0
  29. package/dist/lib/health-probes.d.ts.map +1 -1
  30. package/dist/lib/health-probes.js +49 -0
  31. package/dist/lib/health-probes.js.map +1 -1
  32. package/dist/lib/peripheral-registry.d.ts +9 -3
  33. package/dist/lib/peripheral-registry.d.ts.map +1 -1
  34. package/dist/lib/peripheral-registry.js +4 -4
  35. package/dist/lib/peripheral-registry.js.map +1 -1
  36. package/dist/lib/port-forward.js +1 -1
  37. package/dist/lib/port-forward.js.map +1 -1
  38. package/dist/lib/upgrade-kubernetes.d.ts +1 -1
  39. package/dist/lib/upgrade-kubernetes.d.ts.map +1 -1
  40. package/dist/lib/upgrade-kubernetes.js +35 -21
  41. package/dist/lib/upgrade-kubernetes.js.map +1 -1
  42. package/dist/mcp-server.js +990 -331
  43. package/hermes-bundle/version.json +1 -1
  44. package/host-cp/k8s/manifests/50-deployment.yaml +1 -1
  45. package/host-cp/k8s/manifests/auth-service/50-deployment.yaml +1 -1
  46. package/host-cp/k8s/manifests/kg-service/50-deployment.yaml +1 -1
  47. package/host-cp/k8s/manifests/mcp-auth-service/50-deployment.yaml +1 -1
  48. package/host-cp/k8s/manifests/memory-service/50-deployment.yaml +1 -1
  49. 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: path49, errorMaps, issueData } = params;
449
- const fullPath = [...path49, ...issueData.path || []];
448
+ const { data, path: path52, errorMaps, issueData } = params;
449
+ const fullPath = [...path52, ...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, path49, key) {
757
+ constructor(parent, value, path52, key) {
758
758
  this._cachedPath = [];
759
759
  this.parent = parent;
760
760
  this.data = value;
761
- this._path = path49;
761
+ this._path = path52;
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(path49) {
7336
- let input = path49;
7335
+ function removeDotSegments(path52) {
7336
+ let input = path52;
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 [path49, query] = wsComponent.resourceName.split("?");
7536
- wsComponent.path = path49 && path49 !== "/" ? path49 : void 0;
7535
+ const [path52, query] = wsComponent.resourceName.split("?");
7536
+ wsComponent.path = path52 && path52 !== "/" ? path52 : 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, fs49, exportName) {
10898
+ function addFormats(ajv, list, fs51, 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, fs49[f]);
10903
+ ajv.addFormat(f, fs51[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, path49, ctx, rejectSource) {
11011
+ function refineForbiddenKeys(value, path52, 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, path49, ctx, rejectSource) {
11016
11016
  if (FORBIDDEN_KEYS.has(key)) {
11017
11017
  ctx.addIssue({
11018
11018
  code: external_exports.ZodIssueCode.custom,
11019
- path: [...path49, key],
11019
+ path: [...path52, key],
11020
11020
  message: `forbidden key "${key}" (prototype-pollution surface)`
11021
11021
  });
11022
11022
  continue;
11023
11023
  }
11024
- if (rejectSource && path49.length === 0 && key === "source") {
11024
+ if (rejectSource && path52.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, path49, ctx, rejectSource) {
11029
11029
  });
11030
11030
  continue;
11031
11031
  }
11032
- refineForbiddenKeys(value[key], [...path49, key], ctx, false);
11032
+ refineForbiddenKeys(value[key], [...path52, key], ctx, false);
11033
11033
  }
11034
11034
  }
11035
- function rejectForbiddenKeys(value, path49, rejectSource) {
11035
+ function rejectForbiddenKeys(value, path52, 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] ${path49}: forbidden key "${key}" (prototype-pollution surface)`);
11041
+ throw new Error(`[manifest] ${path52}: forbidden key "${key}" (prototype-pollution surface)`);
11042
11042
  }
11043
11043
  if (rejectSource && key === "source") {
11044
- throw new Error(`[manifest] ${path49}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
11044
+ throw new Error(`[manifest] ${path52}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
11045
11045
  }
11046
- rejectForbiddenKeys(value[key], `${path49}.${key}`, false);
11046
+ rejectForbiddenKeys(value[key], `${path52}.${key}`, false);
11047
11047
  }
11048
11048
  }
11049
11049
  function unknownTopLevelKeys(parsed) {
@@ -11920,7 +11920,19 @@ var init_schema3 = __esm({
11920
11920
  * use canonical names; `olam flywheel migrate-overlays --push` enforces
11921
11921
  * this via the reverse validator.
11922
11922
  */
11923
- prefix: external_exports.string().regex(PREFIX_PATTERN, "skill-source prefix must be ASCII lowercase + digits + dash/underscore (1-39 chars, no leading/trailing dash)").optional()
11923
+ prefix: external_exports.string().regex(PREFIX_PATTERN, "skill-source prefix must be ASCII lowercase + digits + dash/underscore (1-39 chars, no leading/trailing dash)").optional(),
11924
+ /**
11925
+ * Which artifact kinds get renamed when `prefix` is set. Optional; defaults
11926
+ * to `['skill', 'agent']` for back-compat with the original Phase A semantic
11927
+ * (Decision 6 in docs/decisions/019-skill-prefix-rules.md). Operators who
11928
+ * want to rebrand ONLY skills (keeping `@architect` etc. canonical) set
11929
+ * `['skill']`; ones who want only agents set `['agent']`.
11930
+ *
11931
+ * Empty array `[]` = same as omitting `prefix` entirely (no renaming).
11932
+ *
11933
+ * NOT applicable when `prefix` is undefined.
11934
+ */
11935
+ prefixScope: external_exports.array(external_exports.enum(["skill", "agent"])).optional()
11924
11936
  });
11925
11937
  }
11926
11938
  });
@@ -12568,29 +12580,26 @@ function updateSkillSource(id, patch) {
12568
12580
  }
12569
12581
  }
12570
12582
  const existing = config2.skillSources[idx];
12571
- let prefixUpdate = {};
12583
+ let working = { ...existing };
12572
12584
  if (patch.prefix === null) {
12573
- const { prefix: _dropped, ...rest } = existing;
12574
- void _dropped;
12575
- const updated2 = {
12576
- ...rest,
12577
- ...patch.name !== void 0 ? { name: patch.name } : {},
12578
- ...patch.branch !== void 0 ? { branch: patch.branch } : {},
12579
- ...patch.lastPulledSha !== void 0 ? { lastPulledSha: patch.lastPulledSha } : {}
12580
- };
12581
- const next2 = [...config2.skillSources];
12582
- next2[idx] = updated2;
12583
- writeGlobalConfig({ ...config2, skillSources: next2 });
12584
- return updated2;
12585
+ const { prefix: _p, ...rest } = working;
12586
+ void _p;
12587
+ working = rest;
12585
12588
  } else if (patch.prefix !== void 0) {
12586
- prefixUpdate = { prefix: patch.prefix };
12589
+ working = { ...working, prefix: patch.prefix };
12590
+ }
12591
+ if (patch.prefixScope === null) {
12592
+ const { prefixScope: _s, ...rest } = working;
12593
+ void _s;
12594
+ working = rest;
12595
+ } else if (patch.prefixScope !== void 0) {
12596
+ working = { ...working, prefixScope: [...patch.prefixScope] };
12587
12597
  }
12588
12598
  const updated = {
12589
- ...existing,
12599
+ ...working,
12590
12600
  ...patch.name !== void 0 ? { name: patch.name } : {},
12591
12601
  ...patch.branch !== void 0 ? { branch: patch.branch } : {},
12592
- ...patch.lastPulledSha !== void 0 ? { lastPulledSha: patch.lastPulledSha } : {},
12593
- ...prefixUpdate
12602
+ ...patch.lastPulledSha !== void 0 ? { lastPulledSha: patch.lastPulledSha } : {}
12594
12603
  };
12595
12604
  const next = [...config2.skillSources];
12596
12605
  next[idx] = updated;
@@ -13404,7 +13413,7 @@ function detectCollisions(artifacts) {
13404
13413
  }
13405
13414
  return { winners, collisions };
13406
13415
  }
13407
- function cleanManagedSymlinks(claude, installedOlamVersion, overlayReferences) {
13416
+ function cleanManagedSymlinks(claude, installedOlamVersion, overlayReferences, expectedAgentWinnerNames) {
13408
13417
  const shadowBackups = [];
13409
13418
  for (const bucket of BUCKETS) {
13410
13419
  const dir = path21.join(claude, bucket);
@@ -13438,8 +13447,11 @@ function cleanManagedSymlinks(claude, installedOlamVersion, overlayReferences) {
13438
13447
  }
13439
13448
  fs20.unlinkSync(p);
13440
13449
  } else if (bucket === "agents" && stat.isFile() && !name.includes(".shadow-backup-")) {
13441
- const backup = shadowBackup(p);
13442
- shadowBackups.push(backup);
13450
+ const hasWinner = expectedAgentWinnerNames !== void 0 ? expectedAgentWinnerNames.has(name) : true;
13451
+ if (hasWinner) {
13452
+ const backup = shadowBackup(p);
13453
+ shadowBackups.push(backup);
13454
+ }
13443
13455
  }
13444
13456
  } catch {
13445
13457
  }
@@ -13479,8 +13491,9 @@ function deployArtifacts(artifacts, opts) {
13479
13491
  for (const bucket of BUCKETS) {
13480
13492
  fs20.mkdirSync(path21.join(claude, bucket), { recursive: true });
13481
13493
  }
13482
- const sweepShadowBackups = cleanManagedSymlinks(claude, opts?.installedOlamVersion, opts?.overlayReferences);
13483
13494
  const { winners, collisions } = detectCollisions(artifacts);
13495
+ const expectedAgentWinnerNames = new Set(winners.filter((a) => a.kind === "agent").map((a) => a.deployBasename));
13496
+ const sweepShadowBackups = cleanManagedSymlinks(claude, opts?.installedOlamVersion, opts?.overlayReferences, expectedAgentWinnerNames);
13484
13497
  const result = { linked: 0, shadowBackups: [...sweepShadowBackups], collisions };
13485
13498
  for (const artifact of winners) {
13486
13499
  const bucket = bucketFor(artifact.kind);
@@ -14945,15 +14958,18 @@ import * as fs30 from "node:fs";
14945
14958
  import * as path29 from "node:path";
14946
14959
  function buildSourcePrefixMap(sources) {
14947
14960
  const byId = /* @__PURE__ */ new Map();
14961
+ const scopeById = /* @__PURE__ */ new Map();
14948
14962
  const prefixes = /* @__PURE__ */ new Set();
14949
14963
  for (const s of sources) {
14950
14964
  if (s.prefix !== void 0 && s.prefix.length > 0) {
14951
14965
  byId.set(s.id, s.prefix);
14966
+ scopeById.set(s.id, s.prefixScope ?? DEFAULT_SCOPE);
14952
14967
  prefixes.add(s.prefix);
14953
14968
  }
14954
14969
  }
14955
14970
  return {
14956
14971
  get: (sourceId) => byId.get(sourceId),
14972
+ getScope: (sourceId) => scopeById.get(sourceId) ?? DEFAULT_SCOPE,
14957
14973
  registeredPrefixes: Array.from(prefixes)
14958
14974
  };
14959
14975
  }
@@ -14965,6 +14981,9 @@ function applyPrefixRewrites(baseArtifacts, sourceMap, claudeDir2, dryRun) {
14965
14981
  const prefix = sourceMap.get(artifact.sourceId);
14966
14982
  if (prefix === void 0)
14967
14983
  continue;
14984
+ const scope = sourceMap.getScope(artifact.sourceId);
14985
+ if (!scope.includes(artifact.kind))
14986
+ continue;
14968
14987
  const canonical = artifact.deployBasename;
14969
14988
  const otherPrefixes = sourceMap.registeredPrefixes.filter((p) => p !== prefix);
14970
14989
  const renamed = applyPrefix(canonical, prefix, otherPrefixes);
@@ -15031,11 +15050,13 @@ function detectPrefixCollisions(sources) {
15031
15050
  }
15032
15051
  return collisions;
15033
15052
  }
15053
+ var DEFAULT_SCOPE;
15034
15054
  var init_prefix_deploy = __esm({
15035
15055
  "../core/dist/skill-sync/prefix-deploy.js"() {
15036
15056
  "use strict";
15037
15057
  init_prefix_rules();
15038
15058
  init_managed_merge();
15059
+ DEFAULT_SCOPE = ["skill", "agent"];
15039
15060
  }
15040
15061
  });
15041
15062
 
@@ -15917,6 +15938,9 @@ var init_global_config = __esm({
15917
15938
  }
15918
15939
  });
15919
15940
 
15941
+ // ../mcp-server/src/redirect-stdout-to-stderr.ts
15942
+ console.log = console.error;
15943
+
15920
15944
  // ../../node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
15921
15945
  import process3 from "node:process";
15922
15946
 
@@ -16160,10 +16184,10 @@ function mergeDefs(...defs) {
16160
16184
  function cloneDef(schema) {
16161
16185
  return mergeDefs(schema._zod.def);
16162
16186
  }
16163
- function getElementAtPath(obj, path49) {
16164
- if (!path49)
16187
+ function getElementAtPath(obj, path52) {
16188
+ if (!path52)
16165
16189
  return obj;
16166
- return path49.reduce((acc, key) => acc?.[key], obj);
16190
+ return path52.reduce((acc, key) => acc?.[key], obj);
16167
16191
  }
16168
16192
  function promiseAllObject(promisesObj) {
16169
16193
  const keys = Object.keys(promisesObj);
@@ -16572,11 +16596,11 @@ function explicitlyAborted(x, startIndex = 0) {
16572
16596
  }
16573
16597
  return false;
16574
16598
  }
16575
- function prefixIssues(path49, issues) {
16599
+ function prefixIssues(path52, issues) {
16576
16600
  return issues.map((iss) => {
16577
16601
  var _a3;
16578
16602
  (_a3 = iss).path ?? (_a3.path = []);
16579
- iss.path.unshift(path49);
16603
+ iss.path.unshift(path52);
16580
16604
  return iss;
16581
16605
  });
16582
16606
  }
@@ -16723,16 +16747,16 @@ function flattenError(error2, mapper = (issue2) => issue2.message) {
16723
16747
  }
16724
16748
  function formatError(error2, mapper = (issue2) => issue2.message) {
16725
16749
  const fieldErrors = { _errors: [] };
16726
- const processError = (error3, path49 = []) => {
16750
+ const processError = (error3, path52 = []) => {
16727
16751
  for (const issue2 of error3.issues) {
16728
16752
  if (issue2.code === "invalid_union" && issue2.errors.length) {
16729
- issue2.errors.map((issues) => processError({ issues }, [...path49, ...issue2.path]));
16753
+ issue2.errors.map((issues) => processError({ issues }, [...path52, ...issue2.path]));
16730
16754
  } else if (issue2.code === "invalid_key") {
16731
- processError({ issues: issue2.issues }, [...path49, ...issue2.path]);
16755
+ processError({ issues: issue2.issues }, [...path52, ...issue2.path]);
16732
16756
  } else if (issue2.code === "invalid_element") {
16733
- processError({ issues: issue2.issues }, [...path49, ...issue2.path]);
16757
+ processError({ issues: issue2.issues }, [...path52, ...issue2.path]);
16734
16758
  } else {
16735
- const fullpath = [...path49, ...issue2.path];
16759
+ const fullpath = [...path52, ...issue2.path];
16736
16760
  if (fullpath.length === 0) {
16737
16761
  fieldErrors._errors.push(mapper(issue2));
16738
16762
  } else {
@@ -26155,6 +26179,228 @@ var McpZodTypeKind;
26155
26179
  McpZodTypeKind2["Completable"] = "McpCompletable";
26156
26180
  })(McpZodTypeKind || (McpZodTypeKind = {}));
26157
26181
 
26182
+ // ../../node_modules/@modelcontextprotocol/sdk/dist/esm/shared/uriTemplate.js
26183
+ var MAX_TEMPLATE_LENGTH = 1e6;
26184
+ var MAX_VARIABLE_LENGTH = 1e6;
26185
+ var MAX_TEMPLATE_EXPRESSIONS = 1e4;
26186
+ var MAX_REGEX_LENGTH = 1e6;
26187
+ var UriTemplate = class _UriTemplate {
26188
+ /**
26189
+ * Returns true if the given string contains any URI template expressions.
26190
+ * A template expression is a sequence of characters enclosed in curly braces,
26191
+ * like {foo} or {?bar}.
26192
+ */
26193
+ static isTemplate(str) {
26194
+ return /\{[^}\s]+\}/.test(str);
26195
+ }
26196
+ static validateLength(str, max, context) {
26197
+ if (str.length > max) {
26198
+ throw new Error(`${context} exceeds maximum length of ${max} characters (got ${str.length})`);
26199
+ }
26200
+ }
26201
+ get variableNames() {
26202
+ return this.parts.flatMap((part) => typeof part === "string" ? [] : part.names);
26203
+ }
26204
+ constructor(template) {
26205
+ _UriTemplate.validateLength(template, MAX_TEMPLATE_LENGTH, "Template");
26206
+ this.template = template;
26207
+ this.parts = this.parse(template);
26208
+ }
26209
+ toString() {
26210
+ return this.template;
26211
+ }
26212
+ parse(template) {
26213
+ const parts = [];
26214
+ let currentText = "";
26215
+ let i = 0;
26216
+ let expressionCount = 0;
26217
+ while (i < template.length) {
26218
+ if (template[i] === "{") {
26219
+ if (currentText) {
26220
+ parts.push(currentText);
26221
+ currentText = "";
26222
+ }
26223
+ const end = template.indexOf("}", i);
26224
+ if (end === -1)
26225
+ throw new Error("Unclosed template expression");
26226
+ expressionCount++;
26227
+ if (expressionCount > MAX_TEMPLATE_EXPRESSIONS) {
26228
+ throw new Error(`Template contains too many expressions (max ${MAX_TEMPLATE_EXPRESSIONS})`);
26229
+ }
26230
+ const expr = template.slice(i + 1, end);
26231
+ const operator = this.getOperator(expr);
26232
+ const exploded = expr.includes("*");
26233
+ const names = this.getNames(expr);
26234
+ const name = names[0];
26235
+ for (const name2 of names) {
26236
+ _UriTemplate.validateLength(name2, MAX_VARIABLE_LENGTH, "Variable name");
26237
+ }
26238
+ parts.push({ name, operator, names, exploded });
26239
+ i = end + 1;
26240
+ } else {
26241
+ currentText += template[i];
26242
+ i++;
26243
+ }
26244
+ }
26245
+ if (currentText) {
26246
+ parts.push(currentText);
26247
+ }
26248
+ return parts;
26249
+ }
26250
+ getOperator(expr) {
26251
+ const operators = ["+", "#", ".", "/", "?", "&"];
26252
+ return operators.find((op) => expr.startsWith(op)) || "";
26253
+ }
26254
+ getNames(expr) {
26255
+ const operator = this.getOperator(expr);
26256
+ return expr.slice(operator.length).split(",").map((name) => name.replace("*", "").trim()).filter((name) => name.length > 0);
26257
+ }
26258
+ encodeValue(value, operator) {
26259
+ _UriTemplate.validateLength(value, MAX_VARIABLE_LENGTH, "Variable value");
26260
+ if (operator === "+" || operator === "#") {
26261
+ return encodeURI(value);
26262
+ }
26263
+ return encodeURIComponent(value);
26264
+ }
26265
+ expandPart(part, variables) {
26266
+ if (part.operator === "?" || part.operator === "&") {
26267
+ const pairs = part.names.map((name) => {
26268
+ const value2 = variables[name];
26269
+ if (value2 === void 0)
26270
+ return "";
26271
+ const encoded2 = Array.isArray(value2) ? value2.map((v) => this.encodeValue(v, part.operator)).join(",") : this.encodeValue(value2.toString(), part.operator);
26272
+ return `${name}=${encoded2}`;
26273
+ }).filter((pair) => pair.length > 0);
26274
+ if (pairs.length === 0)
26275
+ return "";
26276
+ const separator = part.operator === "?" ? "?" : "&";
26277
+ return separator + pairs.join("&");
26278
+ }
26279
+ if (part.names.length > 1) {
26280
+ const values2 = part.names.map((name) => variables[name]).filter((v) => v !== void 0);
26281
+ if (values2.length === 0)
26282
+ return "";
26283
+ return values2.map((v) => Array.isArray(v) ? v[0] : v).join(",");
26284
+ }
26285
+ const value = variables[part.name];
26286
+ if (value === void 0)
26287
+ return "";
26288
+ const values = Array.isArray(value) ? value : [value];
26289
+ const encoded = values.map((v) => this.encodeValue(v, part.operator));
26290
+ switch (part.operator) {
26291
+ case "":
26292
+ return encoded.join(",");
26293
+ case "+":
26294
+ return encoded.join(",");
26295
+ case "#":
26296
+ return "#" + encoded.join(",");
26297
+ case ".":
26298
+ return "." + encoded.join(".");
26299
+ case "/":
26300
+ return "/" + encoded.join("/");
26301
+ default:
26302
+ return encoded.join(",");
26303
+ }
26304
+ }
26305
+ expand(variables) {
26306
+ let result = "";
26307
+ let hasQueryParam = false;
26308
+ for (const part of this.parts) {
26309
+ if (typeof part === "string") {
26310
+ result += part;
26311
+ continue;
26312
+ }
26313
+ const expanded = this.expandPart(part, variables);
26314
+ if (!expanded)
26315
+ continue;
26316
+ if ((part.operator === "?" || part.operator === "&") && hasQueryParam) {
26317
+ result += expanded.replace("?", "&");
26318
+ } else {
26319
+ result += expanded;
26320
+ }
26321
+ if (part.operator === "?" || part.operator === "&") {
26322
+ hasQueryParam = true;
26323
+ }
26324
+ }
26325
+ return result;
26326
+ }
26327
+ escapeRegExp(str) {
26328
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
26329
+ }
26330
+ partToRegExp(part) {
26331
+ const patterns = [];
26332
+ for (const name2 of part.names) {
26333
+ _UriTemplate.validateLength(name2, MAX_VARIABLE_LENGTH, "Variable name");
26334
+ }
26335
+ if (part.operator === "?" || part.operator === "&") {
26336
+ for (let i = 0; i < part.names.length; i++) {
26337
+ const name2 = part.names[i];
26338
+ const prefix = i === 0 ? "\\" + part.operator : "&";
26339
+ patterns.push({
26340
+ pattern: prefix + this.escapeRegExp(name2) + "=([^&]+)",
26341
+ name: name2
26342
+ });
26343
+ }
26344
+ return patterns;
26345
+ }
26346
+ let pattern;
26347
+ const name = part.name;
26348
+ switch (part.operator) {
26349
+ case "":
26350
+ pattern = part.exploded ? "([^/,]+(?:,[^/,]+)*)" : "([^/,]+)";
26351
+ break;
26352
+ case "+":
26353
+ case "#":
26354
+ pattern = "(.+)";
26355
+ break;
26356
+ case ".":
26357
+ pattern = "\\.([^/,]+)";
26358
+ break;
26359
+ case "/":
26360
+ pattern = "/" + (part.exploded ? "([^/,]+(?:,[^/,]+)*)" : "([^/,]+)");
26361
+ break;
26362
+ default:
26363
+ pattern = "([^/]+)";
26364
+ }
26365
+ patterns.push({ pattern, name });
26366
+ return patterns;
26367
+ }
26368
+ match(uri) {
26369
+ _UriTemplate.validateLength(uri, MAX_TEMPLATE_LENGTH, "URI");
26370
+ let pattern = "^";
26371
+ const names = [];
26372
+ for (const part of this.parts) {
26373
+ if (typeof part === "string") {
26374
+ pattern += this.escapeRegExp(part);
26375
+ } else {
26376
+ const patterns = this.partToRegExp(part);
26377
+ for (const { pattern: partPattern, name } of patterns) {
26378
+ pattern += partPattern;
26379
+ names.push({ name, exploded: part.exploded });
26380
+ }
26381
+ }
26382
+ }
26383
+ pattern += "$";
26384
+ _UriTemplate.validateLength(pattern, MAX_REGEX_LENGTH, "Generated regex pattern");
26385
+ const regex = new RegExp(pattern);
26386
+ const match = uri.match(regex);
26387
+ if (!match)
26388
+ return null;
26389
+ const result = {};
26390
+ for (let i = 0; i < names.length; i++) {
26391
+ const { name, exploded } = names[i];
26392
+ const value = match[i + 1];
26393
+ const cleanName = name.replace("*", "");
26394
+ if (exploded && value.includes(",")) {
26395
+ result[cleanName] = value.split(",");
26396
+ } else {
26397
+ result[cleanName] = value;
26398
+ }
26399
+ }
26400
+ return result;
26401
+ }
26402
+ };
26403
+
26158
26404
  // ../../node_modules/@modelcontextprotocol/sdk/dist/esm/shared/toolNameValidation.js
26159
26405
  var TOOL_NAME_REGEX = /^[A-Za-z0-9._-]{1,128}$/;
26160
26406
  function validateToolName(name) {
@@ -26944,6 +27190,30 @@ var McpServer = class {
26944
27190
  }
26945
27191
  }
26946
27192
  };
27193
+ var ResourceTemplate = class {
27194
+ constructor(uriTemplate, _callbacks) {
27195
+ this._callbacks = _callbacks;
27196
+ this._uriTemplate = typeof uriTemplate === "string" ? new UriTemplate(uriTemplate) : uriTemplate;
27197
+ }
27198
+ /**
27199
+ * Gets the URI template pattern.
27200
+ */
27201
+ get uriTemplate() {
27202
+ return this._uriTemplate;
27203
+ }
27204
+ /**
27205
+ * Gets the list callback, if one was provided.
27206
+ */
27207
+ get listCallback() {
27208
+ return this._callbacks.list;
27209
+ }
27210
+ /**
27211
+ * Gets the callback for completing a specific URI template variable, if one was provided.
27212
+ */
27213
+ completeCallback(variable) {
27214
+ return this._callbacks.complete?.[variable];
27215
+ }
27216
+ };
26947
27217
  var EMPTY_OBJECT_JSON_SCHEMA = {
26948
27218
  type: "object",
26949
27219
  properties: {}
@@ -27268,7 +27538,7 @@ function readSecretIfExists() {
27268
27538
 
27269
27539
  // ../core/dist/auth/client.js
27270
27540
  var DEFAULT_BASE_URL = "http://127.0.0.1:9999";
27271
- var DEFAULT_TIMEOUT_MS = 3e3;
27541
+ var DEFAULT_TIMEOUT_MS = 1e4;
27272
27542
  var RETRY_COUNT = 2;
27273
27543
  var RETRY_BACKOFF_MS = 250;
27274
27544
  var AuthClient = class {
@@ -27371,8 +27641,8 @@ var AuthClient = class {
27371
27641
  throw new Error(`failed to report rate-limit for ${accountId} (HTTP ${res.status})`);
27372
27642
  }
27373
27643
  }
27374
- async request(method, path49, body, attempt = 0) {
27375
- const url2 = `${this.baseUrl}${path49}`;
27644
+ async request(method, path52, body, attempt = 0) {
27645
+ const url2 = `${this.baseUrl}${path52}`;
27376
27646
  const controller = new AbortController();
27377
27647
  const timer = setTimeout(() => controller.abort(), this.timeoutMs);
27378
27648
  const headers = {};
@@ -27390,7 +27660,7 @@ var AuthClient = class {
27390
27660
  } catch (err) {
27391
27661
  if (attempt < RETRY_COUNT && isTransient(err)) {
27392
27662
  await sleep(RETRY_BACKOFF_MS * (attempt + 1));
27393
- return this.request(method, path49, body, attempt + 1);
27663
+ return this.request(method, path52, body, attempt + 1);
27394
27664
  }
27395
27665
  throw err;
27396
27666
  } finally {
@@ -28244,12 +28514,12 @@ function register3(server, _ctx, _initError) {
28244
28514
  registry2.close();
28245
28515
  }
28246
28516
  try {
28247
- const { default: fs49 } = await import("node:fs");
28248
- const { default: os28 } = await import("node:os");
28249
- const { default: path49 } = await import("node:path");
28250
- const tokenPath = path49.join(os28.homedir(), ".olam", "host-cp.token");
28251
- if (fs49.existsSync(tokenPath)) {
28252
- const token = fs49.readFileSync(tokenPath, "utf-8").trim();
28517
+ const { default: fs51 } = await import("node:fs");
28518
+ const { default: os31 } = await import("node:os");
28519
+ const { default: path52 } = await import("node:path");
28520
+ const tokenPath = path52.join(os31.homedir(), ".olam", "host-cp.token");
28521
+ if (fs51.existsSync(tokenPath)) {
28522
+ const token = fs51.readFileSync(tokenPath, "utf-8").trim();
28253
28523
  await fetch("http://127.0.0.1:19000/api/admin/world-pr", {
28254
28524
  method: "POST",
28255
28525
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
@@ -28669,10 +28939,10 @@ function extractMcpConfig(claudeJsonPath) {
28669
28939
  }
28670
28940
  return { mcpServers, secrets };
28671
28941
  }
28672
- function readOptional(path49) {
28673
- if (!existsSync6(path49)) return null;
28942
+ function readOptional(path52) {
28943
+ if (!existsSync6(path52)) return null;
28674
28944
  try {
28675
- return readFileSync5(path49, "utf8");
28945
+ return readFileSync5(path52, "utf8");
28676
28946
  } catch {
28677
28947
  return null;
28678
28948
  }
@@ -30118,8 +30388,8 @@ var CloudflareProvider = class extends ComputeProvider {
30118
30388
  // -----------------------------------------------------------------------
30119
30389
  // Internal fetch helper
30120
30390
  // -----------------------------------------------------------------------
30121
- async request(path49, method, body) {
30122
- const url2 = `${this.config.workerUrl}${path49}`;
30391
+ async request(path52, method, body) {
30392
+ const url2 = `${this.config.workerUrl}${path52}`;
30123
30393
  const bearer = await this.config.mintToken();
30124
30394
  const headers = {
30125
30395
  Authorization: `Bearer ${bearer}`
@@ -32570,10 +32840,10 @@ async function writeManifest(args) {
32570
32840
  capturedAt: args.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
32571
32841
  shots: entries
32572
32842
  };
32573
- const path49 = join13(args.outDir, "manifest.json");
32574
- await writeFile(path49, `${JSON.stringify(manifest, null, 2)}
32843
+ const path52 = join13(args.outDir, "manifest.json");
32844
+ await writeFile(path52, `${JSON.stringify(manifest, null, 2)}
32575
32845
  `, "utf8");
32576
- return { path: path49, manifest };
32846
+ return { path: path52, manifest };
32577
32847
  }
32578
32848
 
32579
32849
  // ../mcp-server/src/tools/_capture/proxy.ts
@@ -32827,9 +33097,9 @@ async function startProxy(opts) {
32827
33097
  const liveCompiled = verified.allowedPaths.map(compileGlob);
32828
33098
  const target = parseRequestTarget(req);
32829
33099
  if (!target) return httpReject(400, "invalid_target");
32830
- const path49 = target.pathname;
32831
- if (!liveCompiled.some((re) => re.test(path49))) {
32832
- return httpReject(403, "outside_allow_list", { path: path49 });
33100
+ const path52 = target.pathname;
33101
+ if (!liveCompiled.some((re) => re.test(path52))) {
33102
+ return httpReject(403, "outside_allow_list", { path: path52 });
32833
33103
  }
32834
33104
  const headerWorld = req.headers[WORLD_ASSERT_HEADER];
32835
33105
  const headerWorldStr = typeof headerWorld === "string" ? headerWorld : Array.isArray(headerWorld) && headerWorld.length > 0 ? headerWorld[0] : void 0;
@@ -33608,14 +33878,14 @@ async function runShot(browser, shot, outDir, format, jpegQuality, allowEval, as
33608
33878
  await page.waitForTimeout(shot.afterLoadMs);
33609
33879
  }
33610
33880
  const ext = format === "jpeg" ? "jpg" : "png";
33611
- const path49 = join14(outDir, `${shot.name}.${ext}`);
33881
+ const path52 = join14(outDir, `${shot.name}.${ext}`);
33612
33882
  await page.screenshot({
33613
- path: path49,
33883
+ path: path52,
33614
33884
  type: format,
33615
33885
  ...format === "jpeg" ? { quality: jpegQuality } : {},
33616
33886
  fullPage: false
33617
33887
  });
33618
- return { name: shot.name, path: path49, urlRedacted: redactUrl(shot.url), viewport };
33888
+ return { name: shot.name, path: path52, urlRedacted: redactUrl(shot.url), viewport };
33619
33889
  } finally {
33620
33890
  await context.close();
33621
33891
  }
@@ -34059,12 +34329,12 @@ function openUrl(url2) {
34059
34329
  var HOST_CP_URL = "http://127.0.0.1:19000";
34060
34330
  async function readHostCpToken2() {
34061
34331
  try {
34062
- const { default: fs49 } = await import("node:fs");
34063
- const { default: os28 } = await import("node:os");
34064
- const { default: path49 } = await import("node:path");
34065
- const tp = path49.join(os28.homedir(), ".olam", "host-cp.token");
34066
- if (!fs49.existsSync(tp)) return { token: null };
34067
- return { token: fs49.readFileSync(tp, "utf-8").trim() };
34332
+ const { default: fs51 } = await import("node:fs");
34333
+ const { default: os31 } = await import("node:os");
34334
+ const { default: path52 } = await import("node:path");
34335
+ const tp = path52.join(os31.homedir(), ".olam", "host-cp.token");
34336
+ if (!fs51.existsSync(tp)) return { token: null };
34337
+ return { token: fs51.readFileSync(tp, "utf-8").trim() };
34068
34338
  } catch {
34069
34339
  return { token: null };
34070
34340
  }
@@ -34324,9 +34594,9 @@ function register22(server, _ctx, _initError) {
34324
34594
  description: external_exports.string().optional().describe("Optional human-readable description."),
34325
34595
  defaultBranch: external_exports.string().optional().describe("Default branch name (e.g. main).")
34326
34596
  },
34327
- async ({ name, path: path49, description, defaultBranch }) => {
34597
+ async ({ name, path: path52, description, defaultBranch }) => {
34328
34598
  try {
34329
- const entry = addRepo({ name, path: path49, description, defaultBranch });
34599
+ const entry = addRepo({ name, path: path52, description, defaultBranch });
34330
34600
  return {
34331
34601
  content: [{
34332
34602
  type: "text",
@@ -34367,9 +34637,9 @@ function register22(server, _ctx, _initError) {
34367
34637
  description: external_exports.string().optional().describe("New description."),
34368
34638
  defaultBranch: external_exports.string().optional().describe("New default branch.")
34369
34639
  },
34370
- async ({ name, path: path49, description, defaultBranch }) => {
34640
+ async ({ name, path: path52, description, defaultBranch }) => {
34371
34641
  try {
34372
- const entry = updateRepo(name, { path: path49, description, defaultBranch });
34642
+ const entry = updateRepo(name, { path: path52, description, defaultBranch });
34373
34643
  return {
34374
34644
  content: [{
34375
34645
  type: "text",
@@ -34941,10 +35211,196 @@ function register26(server, _ctx, _initError) {
34941
35211
  );
34942
35212
  }
34943
35213
 
35214
+ // ../mcp-server/src/tools/skills-search.ts
35215
+ var skills_search_exports = {};
35216
+ __export(skills_search_exports, {
35217
+ register: () => register27
35218
+ });
35219
+ init_v3();
35220
+ import * as path36 from "node:path";
35221
+ import * as os22 from "node:os";
35222
+
35223
+ // ../mcp-server/src/lib/skills-index.mjs
35224
+ import { createRequire as createRequire4 } from "node:module";
35225
+ import * as fs36 from "node:fs";
35226
+ import * as path35 from "node:path";
35227
+ import * as os21 from "node:os";
35228
+ var VECTOR_DIM = 256;
35229
+ var SCHEMA_VERSION3 = "1";
35230
+ var SCHEMA_KEY = "skills_index_schema_version";
35231
+ var _require4 = createRequire4(import.meta.url);
35232
+ var _Database3 = null;
35233
+ function getDatabase3() {
35234
+ if (_Database3 === null) {
35235
+ _Database3 = _require4("better-sqlite3");
35236
+ }
35237
+ return _Database3;
35238
+ }
35239
+ var STOPWORDS = /* @__PURE__ */ new Set([
35240
+ "a",
35241
+ "an",
35242
+ "and",
35243
+ "the",
35244
+ "of",
35245
+ "to",
35246
+ "in",
35247
+ "on",
35248
+ "for",
35249
+ "with",
35250
+ "by",
35251
+ "is",
35252
+ "are",
35253
+ "be",
35254
+ "or",
35255
+ "as",
35256
+ "at",
35257
+ "it",
35258
+ "this",
35259
+ "that",
35260
+ "from",
35261
+ "use",
35262
+ "used",
35263
+ "when",
35264
+ "if",
35265
+ "via"
35266
+ ]);
35267
+ function fnv1a32(str) {
35268
+ let h = 2166136261;
35269
+ for (let i = 0; i < str.length; i++) {
35270
+ h ^= str.charCodeAt(i);
35271
+ h = Math.imul(h, 16777619);
35272
+ }
35273
+ return h >>> 0;
35274
+ }
35275
+ function tokenize(text) {
35276
+ if (!text) return [];
35277
+ const tokens = [];
35278
+ for (const raw of text.toLowerCase().split(/[^a-z0-9]+/)) {
35279
+ if (raw.length < 2) continue;
35280
+ if (STOPWORDS.has(raw)) continue;
35281
+ tokens.push(raw);
35282
+ }
35283
+ return tokens;
35284
+ }
35285
+ function embed(text) {
35286
+ const vec = new Float32Array(VECTOR_DIM);
35287
+ const tokens = tokenize(text);
35288
+ if (tokens.length === 0) return vec;
35289
+ for (const tok of tokens) {
35290
+ const bucket = fnv1a32(tok) % VECTOR_DIM;
35291
+ vec[bucket] += 1;
35292
+ }
35293
+ let mag = 0;
35294
+ for (let i = 0; i < VECTOR_DIM; i++) mag += vec[i] * vec[i];
35295
+ mag = Math.sqrt(mag);
35296
+ if (mag > 0) {
35297
+ for (let i = 0; i < VECTOR_DIM; i++) vec[i] /= mag;
35298
+ }
35299
+ return vec;
35300
+ }
35301
+ function cosine(a, b) {
35302
+ let dot = 0;
35303
+ for (let i = 0; i < VECTOR_DIM; i++) dot += a[i] * b[i];
35304
+ return dot;
35305
+ }
35306
+ function bufferToVector(buf) {
35307
+ const ab = new ArrayBuffer(buf.byteLength);
35308
+ Buffer.from(ab).set(buf);
35309
+ const vec = new Float32Array(ab);
35310
+ if (vec.length !== VECTOR_DIM) {
35311
+ throw new Error(`vector length mismatch: expected ${VECTOR_DIM}, got ${vec.length}`);
35312
+ }
35313
+ return vec;
35314
+ }
35315
+ function openIndex(dbPath) {
35316
+ if (!fs36.existsSync(dbPath)) {
35317
+ throw new Error(
35318
+ `skills index not found at ${dbPath}. Run \`node scripts/skills-index-build.mjs --out ${dbPath}\` first.`
35319
+ );
35320
+ }
35321
+ const Database = getDatabase3();
35322
+ const db = new Database(dbPath, { readonly: true, fileMustExist: true });
35323
+ let row;
35324
+ try {
35325
+ row = db.prepare("SELECT value FROM meta WHERE key = ?").get(SCHEMA_KEY);
35326
+ } catch (e) {
35327
+ db.close();
35328
+ throw new Error(`skills index at ${dbPath} is not a valid skills DB: ${e.message}`);
35329
+ }
35330
+ if (!row || row.value !== SCHEMA_VERSION3) {
35331
+ db.close();
35332
+ throw new Error(
35333
+ `skills index at ${dbPath} has schema version ${row ? row.value : "(none)"}, expected ${SCHEMA_VERSION3}. Rebuild it.`
35334
+ );
35335
+ }
35336
+ return db;
35337
+ }
35338
+ function searchIndex(dbPath, query, k = 5) {
35339
+ const db = openIndex(dbPath);
35340
+ try {
35341
+ const qvec = embed(query);
35342
+ let qmag = 0;
35343
+ for (let i = 0; i < VECTOR_DIM; i++) qmag += qvec[i] * qvec[i];
35344
+ if (qmag === 0) return [];
35345
+ const rows = db.prepare("SELECT name, description, vector FROM skills").all();
35346
+ const scored = rows.map((r) => {
35347
+ const v = bufferToVector(r.vector);
35348
+ const score = cosine(qvec, v);
35349
+ const snippet = (r.description || "").slice(0, 200);
35350
+ return { name: r.name, score, snippet };
35351
+ });
35352
+ scored.sort((a, b) => b.score - a.score);
35353
+ return scored.slice(0, Math.max(1, k));
35354
+ } finally {
35355
+ db.close();
35356
+ }
35357
+ }
35358
+ var DEFAULT_DB_PATH = path35.join(os21.homedir(), ".olam", "skills.vec.db");
35359
+ var DEFAULT_SOURCE_DIR = path35.join(os21.homedir(), ".claude", "skills");
35360
+
35361
+ // ../mcp-server/src/tools/skills-search.ts
35362
+ function defaultDbPath() {
35363
+ const override = process.env["SKILLS_INDEX_PATH"];
35364
+ if (override) return override;
35365
+ return path36.join(os22.homedir(), ".olam", "skills.vec.db");
35366
+ }
35367
+ function asMessage9(err) {
35368
+ return err instanceof Error ? err.message : String(err);
35369
+ }
35370
+ function ok3(data) {
35371
+ return {
35372
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
35373
+ };
35374
+ }
35375
+ function fail3(err) {
35376
+ return {
35377
+ content: [{ type: "text", text: asMessage9(err) }],
35378
+ isError: true
35379
+ };
35380
+ }
35381
+ function register27(server, _ctx, _initError) {
35382
+ server.tool(
35383
+ "olam_skills_search",
35384
+ "Semantic search over the local Claude skills index. Returns top-k skills ranked by cosine similarity against a deterministic bag-of-words embedding. Requires `scripts/skills-index-build.mjs` to have been run; set `SKILLS_INDEX_PATH` to override the index location (defaults to ~/.olam/skills.vec.db).",
35385
+ {
35386
+ query: external_exports.string().min(1).describe('Natural-language description of the kind of skill you want (e.g. "stage and commit my changes" or "roll out a new release").'),
35387
+ k: external_exports.number().int().min(1).max(50).optional().describe("Number of hits to return (default 5, max 50).")
35388
+ },
35389
+ async ({ query, k }) => {
35390
+ try {
35391
+ const hits = searchIndex(defaultDbPath(), query, k ?? 5);
35392
+ return ok3({ query, k: k ?? 5, count: hits.length, hits });
35393
+ } catch (err) {
35394
+ return fail3(err);
35395
+ }
35396
+ }
35397
+ );
35398
+ }
35399
+
34944
35400
  // ../mcp-server/src/tools/kg-classify.ts
34945
35401
  var kg_classify_exports = {};
34946
35402
  __export(kg_classify_exports, {
34947
- register: () => register27
35403
+ register: () => register28
34948
35404
  });
34949
35405
  init_v3();
34950
35406
 
@@ -34957,8 +35413,8 @@ function port() {
34957
35413
  const n = Number.parseInt(env, 10);
34958
35414
  return Number.isFinite(n) && n > 0 ? n : KG_SERVICE_PORT_DEFAULT;
34959
35415
  }
34960
- function url(path49) {
34961
- return `http://127.0.0.1:${port()}${path49}`;
35416
+ function url(path52) {
35417
+ return `http://127.0.0.1:${port()}${path52}`;
34962
35418
  }
34963
35419
  function kgServiceHealthUrl() {
34964
35420
  return url("/health");
@@ -35019,7 +35475,7 @@ async function status(opts = {}) {
35019
35475
  }
35020
35476
 
35021
35477
  // ../mcp-server/src/tools/kg-classify.ts
35022
- function register27(server, _ctx, _initError) {
35478
+ function register28(server, _ctx, _initError) {
35023
35479
  server.tool(
35024
35480
  "olam_kg_classify",
35025
35481
  "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`).",
@@ -35067,7 +35523,7 @@ function register27(server, _ctx, _initError) {
35067
35523
  // ../mcp-server/src/tools/kg-doctor.ts
35068
35524
  var kg_doctor_exports = {};
35069
35525
  __export(kg_doctor_exports, {
35070
- register: () => register28
35526
+ register: () => register29
35071
35527
  });
35072
35528
  async function runProbes() {
35073
35529
  const results = [];
@@ -35117,7 +35573,7 @@ async function runProbes() {
35117
35573
  }
35118
35574
  return results;
35119
35575
  }
35120
- function register28(server, _ctx, _initError) {
35576
+ function register29(server, _ctx, _initError) {
35121
35577
  server.tool(
35122
35578
  "olam_kg_doctor",
35123
35579
  "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`.",
@@ -35153,13 +35609,13 @@ function register28(server, _ctx, _initError) {
35153
35609
  // ../mcp-server/src/tools/kg-install-hook.ts
35154
35610
  var kg_install_hook_exports = {};
35155
35611
  __export(kg_install_hook_exports, {
35156
- register: () => register29
35612
+ register: () => register30
35157
35613
  });
35158
35614
  init_v3();
35159
35615
  init_merge_settings();
35160
- import * as fs36 from "node:fs";
35161
- import * as path35 from "node:path";
35162
- import * as os21 from "node:os";
35616
+ import * as fs37 from "node:fs";
35617
+ import * as path37 from "node:path";
35618
+ import * as os23 from "node:os";
35163
35619
 
35164
35620
  // ../core/dist/kg/hook-template.js
35165
35621
  var KG_HOOK_SENTINEL = "kg-service-v2-classifier-hook";
@@ -35209,12 +35665,12 @@ function buildHookMatcherEntry(opts) {
35209
35665
  // ../mcp-server/src/tools/kg-install-hook.ts
35210
35666
  function settingsPathFor2(scope, projectPath) {
35211
35667
  if (scope === "user") {
35212
- return path35.join(os21.homedir(), ".claude", "settings.json");
35668
+ return path37.join(os23.homedir(), ".claude", "settings.json");
35213
35669
  }
35214
35670
  const root = projectPath ?? process.cwd();
35215
- return path35.join(root, ".claude", "settings.json");
35671
+ return path37.join(root, ".claude", "settings.json");
35216
35672
  }
35217
- function register29(server, _ctx, _initError) {
35673
+ function register30(server, _ctx, _initError) {
35218
35674
  server.tool(
35219
35675
  "olam_kg_install_hook",
35220
35676
  "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.",
@@ -35226,12 +35682,12 @@ function register29(server, _ctx, _initError) {
35226
35682
  const scope = params.scope === "user" ? "user" : "project";
35227
35683
  const filePath = settingsPathFor2(scope, params.projectPath);
35228
35684
  try {
35229
- fs36.mkdirSync(path35.dirname(filePath), { recursive: true });
35685
+ fs37.mkdirSync(path37.dirname(filePath), { recursive: true });
35230
35686
  let backupPath = null;
35231
- if (fs36.existsSync(filePath)) {
35687
+ if (fs37.existsSync(filePath)) {
35232
35688
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
35233
35689
  backupPath = `${filePath}.olam-bak.${ts}`;
35234
- fs36.copyFileSync(filePath, backupPath);
35690
+ fs37.copyFileSync(filePath, backupPath);
35235
35691
  }
35236
35692
  const result = mergeHomeSettingsJson(filePath, {
35237
35693
  ensureHook: {
@@ -35242,7 +35698,7 @@ function register29(server, _ctx, _initError) {
35242
35698
  });
35243
35699
  if (result.status === "already-present" && backupPath) {
35244
35700
  try {
35245
- fs36.unlinkSync(backupPath);
35701
+ fs37.unlinkSync(backupPath);
35246
35702
  } catch {
35247
35703
  }
35248
35704
  }
@@ -35283,18 +35739,18 @@ function register29(server, _ctx, _initError) {
35283
35739
  // ../mcp-server/src/tools/kg-uninstall-hook.ts
35284
35740
  var kg_uninstall_hook_exports = {};
35285
35741
  __export(kg_uninstall_hook_exports, {
35286
- register: () => register30
35742
+ register: () => register31
35287
35743
  });
35288
35744
  init_v3();
35289
- import * as fs37 from "node:fs";
35290
- import * as path36 from "node:path";
35291
- import * as os22 from "node:os";
35745
+ import * as fs38 from "node:fs";
35746
+ import * as path38 from "node:path";
35747
+ import * as os24 from "node:os";
35292
35748
  function settingsPathFor3(scope, projectPath) {
35293
35749
  if (scope === "user") {
35294
- return path36.join(os22.homedir(), ".claude", "settings.json");
35750
+ return path38.join(os24.homedir(), ".claude", "settings.json");
35295
35751
  }
35296
35752
  const root = projectPath ?? process.cwd();
35297
- return path36.join(root, ".claude", "settings.json");
35753
+ return path38.join(root, ".claude", "settings.json");
35298
35754
  }
35299
35755
  function dropSentinel(matchers) {
35300
35756
  let changed = false;
@@ -35316,7 +35772,7 @@ function dropSentinel(matchers) {
35316
35772
  }
35317
35773
  return { matchers: out, changed };
35318
35774
  }
35319
- function register30(server, _ctx, _initError) {
35775
+ function register31(server, _ctx, _initError) {
35320
35776
  server.tool(
35321
35777
  "olam_kg_uninstall_hook",
35322
35778
  "Remove the kg-service PreToolUse hook from .claude/settings.json. Sentinel-matched: only the olam entry is removed; other PreToolUse hooks are preserved.",
@@ -35328,7 +35784,7 @@ function register30(server, _ctx, _initError) {
35328
35784
  const scope = params.scope === "user" ? "user" : "project";
35329
35785
  const filePath = settingsPathFor3(scope, params.projectPath);
35330
35786
  try {
35331
- if (!fs37.existsSync(filePath)) {
35787
+ if (!fs38.existsSync(filePath)) {
35332
35788
  return {
35333
35789
  content: [
35334
35790
  {
@@ -35342,7 +35798,7 @@ function register30(server, _ctx, _initError) {
35342
35798
  ]
35343
35799
  };
35344
35800
  }
35345
- const raw = fs37.readFileSync(filePath, "utf-8");
35801
+ const raw = fs38.readFileSync(filePath, "utf-8");
35346
35802
  const settings = raw.trim() ? JSON.parse(raw) : {};
35347
35803
  const preToolUse = settings.hooks?.PreToolUse;
35348
35804
  if (!Array.isArray(preToolUse) || preToolUse.length === 0) {
@@ -35377,7 +35833,7 @@ function register30(server, _ctx, _initError) {
35377
35833
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
35378
35834
  const backupPath = `${filePath}.olam-bak.${ts}`;
35379
35835
  try {
35380
- fs37.copyFileSync(filePath, backupPath);
35836
+ fs38.copyFileSync(filePath, backupPath);
35381
35837
  } catch {
35382
35838
  }
35383
35839
  const next = {
@@ -35389,7 +35845,7 @@ function register30(server, _ctx, _initError) {
35389
35845
  if (otherStages.length === 0) delete next.hooks;
35390
35846
  else delete next.hooks.PreToolUse;
35391
35847
  }
35392
- fs37.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
35848
+ fs38.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
35393
35849
  return {
35394
35850
  content: [
35395
35851
  {
@@ -35451,6 +35907,7 @@ var toolModules = [
35451
35907
  runbook_exports,
35452
35908
  skill_source_exports,
35453
35909
  skills_exports,
35910
+ skills_search_exports,
35454
35911
  kg_classify_exports,
35455
35912
  kg_doctor_exports,
35456
35913
  kg_install_hook_exports,
@@ -35462,6 +35919,207 @@ function registerAllTools(server, ctx, initError) {
35462
35919
  }
35463
35920
  }
35464
35921
 
35922
+ // ../mcp-server/src/resources/chunks.ts
35923
+ import fs39 from "node:fs";
35924
+ import os25 from "node:os";
35925
+ import path39 from "node:path";
35926
+ var DEFAULT_HOST_CP_URL = "http://127.0.0.1:19000";
35927
+ var DEFAULT_PLAN_CHAT_SECRET_PATH = path39.join(
35928
+ os25.homedir(),
35929
+ ".olam",
35930
+ "plan-chat-secret"
35931
+ );
35932
+ var URI_SCHEME = "olam:";
35933
+ var URI_HOST = "worlds";
35934
+ var WORLD_ID_RE2 = /^[a-z0-9][a-z0-9-_.]{0,62}$/i;
35935
+ var SESSION_ID_RE = /^[a-zA-Z0-9_\-.]{1,128}$/;
35936
+ var LIMIT_RE = /^[1-9][0-9]{0,5}$/;
35937
+ function loadBearer(bearerOpt, secretPath) {
35938
+ if (typeof bearerOpt === "string" && bearerOpt.length > 0) return bearerOpt;
35939
+ const envBearer = process.env.OLAM_PLAN_CHAT_BEARER?.trim();
35940
+ if (envBearer && envBearer.length > 0) return envBearer;
35941
+ try {
35942
+ const onDisk = fs39.readFileSync(secretPath, "utf8").trim();
35943
+ return onDisk.length > 0 ? onDisk : null;
35944
+ } catch (err) {
35945
+ if (err && typeof err === "object" && "code" in err && err.code === "ENOENT") {
35946
+ return null;
35947
+ }
35948
+ return null;
35949
+ }
35950
+ }
35951
+ function parseChunksUri(uri) {
35952
+ let parsed;
35953
+ try {
35954
+ parsed = new URL(uri);
35955
+ } catch {
35956
+ return null;
35957
+ }
35958
+ if (parsed.protocol !== URI_SCHEME) return null;
35959
+ if (parsed.host !== URI_HOST) return null;
35960
+ const segments = parsed.pathname.split("/").filter((s) => s.length > 0);
35961
+ if (segments.length !== 2) return null;
35962
+ const [rawWorldId, kind] = segments;
35963
+ if (rawWorldId === void 0 || kind !== "chunks") return null;
35964
+ const worldId = decodeURIComponent(rawWorldId);
35965
+ if (!WORLD_ID_RE2.test(worldId)) return null;
35966
+ const sessionIdRaw = parsed.searchParams.get("sessionId");
35967
+ const limitRaw = parsed.searchParams.get("limit");
35968
+ let sessionId;
35969
+ if (sessionIdRaw !== null) {
35970
+ if (!SESSION_ID_RE.test(sessionIdRaw)) return null;
35971
+ sessionId = sessionIdRaw;
35972
+ }
35973
+ let limit;
35974
+ if (limitRaw !== null) {
35975
+ if (!LIMIT_RE.test(limitRaw)) return null;
35976
+ limit = Number.parseInt(limitRaw, 10);
35977
+ }
35978
+ return { worldId, sessionId, limit };
35979
+ }
35980
+ function buildUpstreamUrl(hostCpUrl, parts) {
35981
+ const upstream = new URL(hostCpUrl);
35982
+ upstream.pathname = "/api/plan-chat/v1/shape";
35983
+ upstream.searchParams.set("table", "chunks");
35984
+ upstream.searchParams.set("world_id", parts.worldId);
35985
+ if (parts.sessionId) {
35986
+ upstream.searchParams.set("session_id", parts.sessionId);
35987
+ }
35988
+ if (typeof parts.limit === "number") {
35989
+ upstream.searchParams.set("limit", String(parts.limit));
35990
+ }
35991
+ upstream.searchParams.set("offset", "-1");
35992
+ return upstream;
35993
+ }
35994
+ function createChunksResource(deps = {}) {
35995
+ const hostCpUrl = deps.hostCpUrl ?? process.env.OLAM_HOST_CP_URL?.trim() ?? DEFAULT_HOST_CP_URL;
35996
+ const fetchImpl = deps.fetchImpl ?? fetch;
35997
+ const secretPath = deps.secretPath ?? DEFAULT_PLAN_CHAT_SECRET_PATH;
35998
+ const resolveBearer = () => loadBearer(deps.bearer, secretPath);
35999
+ return {
36000
+ name: "olam-world-chunks",
36001
+ // RFC 6570 form with required `sessionId` in the template (the SDK's
36002
+ // matcher treats every listed var as required, so listing both
36003
+ // `sessionId` AND `limit` would reject URIs that only pass sessionId).
36004
+ // The optional `limit` param is parsed by `parseChunksUri` from the
36005
+ // concrete URL instead — clients pass `?sessionId=...&limit=...` and
36006
+ // both fields land in `ChunksUriParts`.
36007
+ uriTemplate: "olam://worlds/{worldId}/chunks{?sessionId}",
36008
+ description: "Per-world agent reasoning chunks (the chunks substrate). Append `?sessionId=<id>` to scope to a single planning session \u2014 Electric SQL requires it server-side. Optional `&limit=<n>` caps the returned row count. Returns the Electric shape snapshot as JSON.",
36009
+ mimeType: "application/json",
36010
+ parseUri: parseChunksUri,
36011
+ async read(uri) {
36012
+ const parts = parseChunksUri(uri);
36013
+ if (!parts) {
36014
+ return {
36015
+ ok: false,
36016
+ code: "invalid_uri",
36017
+ message: `Invalid chunks URI: ${uri}. Expected \`olam://worlds/{worldId}/chunks?sessionId=<id>\`.`
36018
+ };
36019
+ }
36020
+ if (!parts.sessionId) {
36021
+ return {
36022
+ ok: false,
36023
+ code: "missing_session_id",
36024
+ message: "sessionId query param is required. Electric SQL enforces per-(world_id,session_id) scope at the proxy layer."
36025
+ };
36026
+ }
36027
+ const bearer = resolveBearer();
36028
+ if (!bearer) {
36029
+ return {
36030
+ ok: false,
36031
+ code: "missing_bearer",
36032
+ message: "No plan-chat bearer available. Set OLAM_PLAN_CHAT_BEARER or ensure ~/.olam/plan-chat-secret exists."
36033
+ };
36034
+ }
36035
+ const upstream = buildUpstreamUrl(hostCpUrl, parts);
36036
+ let res;
36037
+ try {
36038
+ res = await fetchImpl(upstream.toString(), {
36039
+ method: "GET",
36040
+ headers: {
36041
+ authorization: `Bearer ${bearer}`,
36042
+ accept: "application/json"
36043
+ }
36044
+ });
36045
+ } catch (err) {
36046
+ return {
36047
+ ok: false,
36048
+ code: "upstream_unavailable",
36049
+ message: `host-cp /api/plan-chat/v1/shape unreachable: ${err instanceof Error ? err.message : String(err)}`,
36050
+ detail: { upstream: upstream.toString() }
36051
+ };
36052
+ }
36053
+ if (!res.ok) {
36054
+ let body = "";
36055
+ try {
36056
+ body = await res.text();
36057
+ } catch {
36058
+ }
36059
+ return {
36060
+ ok: false,
36061
+ code: "upstream_error",
36062
+ message: `host-cp returned ${res.status} ${res.statusText} for chunks fetch`,
36063
+ detail: { upstream: upstream.toString(), body: body.slice(0, 512) }
36064
+ };
36065
+ }
36066
+ let payload;
36067
+ try {
36068
+ payload = await res.json();
36069
+ } catch (err) {
36070
+ return {
36071
+ ok: false,
36072
+ code: "upstream_error",
36073
+ message: `host-cp returned non-JSON body for chunks fetch: ${err instanceof Error ? err.message : String(err)}`,
36074
+ detail: { upstream: upstream.toString() }
36075
+ };
36076
+ }
36077
+ return {
36078
+ ok: true,
36079
+ uri,
36080
+ mimeType: "application/json",
36081
+ payload
36082
+ };
36083
+ }
36084
+ };
36085
+ }
36086
+
36087
+ // ../mcp-server/src/resources/index.ts
36088
+ function registerAllResources(server, deps = {}) {
36089
+ const chunks = deps.chunks ?? createChunksResource();
36090
+ server.registerResource(
36091
+ chunks.name,
36092
+ new ResourceTemplate(chunks.uriTemplate, {
36093
+ list: void 0
36094
+ }),
36095
+ {
36096
+ description: chunks.description,
36097
+ mimeType: chunks.mimeType
36098
+ },
36099
+ async (uri) => {
36100
+ const result = await chunks.read(uri.toString());
36101
+ if (!result.ok) {
36102
+ const err = new Error(result.message);
36103
+ err.code = result.code;
36104
+ throw err;
36105
+ }
36106
+ return {
36107
+ contents: [
36108
+ {
36109
+ uri: result.uri,
36110
+ mimeType: result.mimeType,
36111
+ text: JSON.stringify(result.payload)
36112
+ }
36113
+ ]
36114
+ };
36115
+ }
36116
+ );
36117
+ logger.info("Olam MCP resources registered", {
36118
+ resources: [chunks.name],
36119
+ uriTemplate: chunks.uriTemplate
36120
+ });
36121
+ }
36122
+
35465
36123
  // ../mcp-server/src/server.ts
35466
36124
  var SERVER_NAME = "olam";
35467
36125
  var SERVER_VERSION = "0.1.0";
@@ -35477,6 +36135,7 @@ function createServer4(ctx, initError) {
35477
36135
  { instructions: SERVER_INSTRUCTIONS }
35478
36136
  );
35479
36137
  registerAllTools(server, ctx, initError);
36138
+ registerAllResources(server);
35480
36139
  logger.info("Olam MCP server created", {
35481
36140
  name: SERVER_NAME,
35482
36141
  version: SERVER_VERSION,
@@ -35486,8 +36145,8 @@ function createServer4(ctx, initError) {
35486
36145
  }
35487
36146
 
35488
36147
  // ../mcp-server/src/utils/native-probe.ts
35489
- import { createRequire as createRequire4 } from "node:module";
35490
- var PROBE_REQUIRE = createRequire4(import.meta.url);
36148
+ import { createRequire as createRequire5 } from "node:module";
36149
+ var PROBE_REQUIRE = createRequire5(import.meta.url);
35491
36150
  function runtimeModuleVersion() {
35492
36151
  return Number.parseInt(process.versions.modules, 10);
35493
36152
  }
@@ -35604,9 +36263,9 @@ init_loader();
35604
36263
  // ../core/dist/world/manager.js
35605
36264
  import * as crypto8 from "node:crypto";
35606
36265
  import { execSync as execSync5, spawnSync as spawnSync4 } from "node:child_process";
35607
- import * as fs46 from "node:fs";
35608
- import * as os26 from "node:os";
35609
- import * as path46 from "node:path";
36266
+ import * as fs48 from "node:fs";
36267
+ import * as os29 from "node:os";
36268
+ import * as path49 from "node:path";
35610
36269
 
35611
36270
  // ../core/dist/world/state.js
35612
36271
  var VALID_TRANSITIONS = {
@@ -35702,8 +36361,8 @@ function resolveDevboxImage(config2, tag) {
35702
36361
 
35703
36362
  // ../core/dist/world/worktree.js
35704
36363
  import { execFileSync as execFileSync4 } from "node:child_process";
35705
- import * as fs38 from "node:fs";
35706
- import * as path37 from "node:path";
36364
+ import * as fs40 from "node:fs";
36365
+ import * as path40 from "node:path";
35707
36366
  function resolveGitDir(repo) {
35708
36367
  if (repo.path) {
35709
36368
  return repo.path;
@@ -35713,11 +36372,11 @@ function resolveGitDir(repo) {
35713
36372
  async function createWorktrees(repos, worldId, workspacePath, branch) {
35714
36373
  const created = [];
35715
36374
  for (const repo of repos) {
35716
- const worktreePath = path37.join(workspacePath, repo.name);
36375
+ const worktreePath = path40.join(workspacePath, repo.name);
35717
36376
  const gitDir = resolveGitDir(repo);
35718
36377
  const branchName = branch || `olam/${worldId}`;
35719
36378
  try {
35720
- fs38.mkdirSync(path37.dirname(worktreePath), { recursive: true });
36379
+ fs40.mkdirSync(path40.dirname(worktreePath), { recursive: true });
35721
36380
  execFileSync4("git", ["worktree", "add", worktreePath, "-b", branchName], {
35722
36381
  cwd: gitDir,
35723
36382
  stdio: "pipe"
@@ -35750,7 +36409,7 @@ async function createWorktrees(repos, worldId, workspacePath, branch) {
35750
36409
  }
35751
36410
  async function removeWorktrees(repos, workspacePath) {
35752
36411
  for (const repo of repos) {
35753
- const worktreePath = path37.join(workspacePath, repo.name);
36412
+ const worktreePath = path40.join(workspacePath, repo.name);
35754
36413
  let gitDir;
35755
36414
  try {
35756
36415
  gitDir = resolveGitDir(repo);
@@ -35825,12 +36484,12 @@ function removeBranch(repo, branch) {
35825
36484
 
35826
36485
  // ../core/dist/world/kg-overlay.js
35827
36486
  import { execFileSync as execFileSync5 } from "node:child_process";
35828
- import * as fs39 from "node:fs";
35829
- import * as path38 from "node:path";
36487
+ import * as fs41 from "node:fs";
36488
+ import * as path41 from "node:path";
35830
36489
 
35831
36490
  // ../core/dist/kg/storage-paths.js
35832
- import { homedir as homedir22 } from "node:os";
35833
- import { join as join38, resolve as resolve9 } from "node:path";
36491
+ import { homedir as homedir24 } from "node:os";
36492
+ import { join as join40, resolve as resolve9 } from "node:path";
35834
36493
 
35835
36494
  // ../core/dist/world/workspace-name.js
35836
36495
  var InvalidWorkspaceNameError = class extends Error {
@@ -35851,25 +36510,25 @@ function validateWorkspaceName(name) {
35851
36510
 
35852
36511
  // ../core/dist/kg/storage-paths.js
35853
36512
  function olamHome() {
35854
- return process.env.OLAM_HOME ?? join38(homedir22(), ".olam");
36513
+ return process.env.OLAM_HOME ?? join40(homedir24(), ".olam");
35855
36514
  }
35856
36515
  function kgRoot() {
35857
- return join38(olamHome(), "kg");
36516
+ return join40(olamHome(), "kg");
35858
36517
  }
35859
36518
  function worldsRoot() {
35860
- return join38(olamHome(), "worlds");
36519
+ return join40(olamHome(), "worlds");
35861
36520
  }
35862
- function assertWithinPrefix(path49, prefix, label) {
35863
- if (!path49.startsWith(prefix + "/")) {
35864
- throw new Error(`${label} escape: ${path49} not under ${prefix}/`);
36521
+ function assertWithinPrefix(path52, prefix, label) {
36522
+ if (!path52.startsWith(prefix + "/")) {
36523
+ throw new Error(`${label} escape: ${path52} not under ${prefix}/`);
35865
36524
  }
35866
36525
  }
35867
36526
  function kgPristinePath(workspace) {
35868
36527
  validateWorkspaceName(workspace);
35869
36528
  const root = kgRoot();
35870
- const path49 = resolve9(join38(root, workspace));
35871
- assertWithinPrefix(path49, root, "kgPristinePath");
35872
- return path49;
36529
+ const path52 = resolve9(join40(root, workspace));
36530
+ assertWithinPrefix(path52, root, "kgPristinePath");
36531
+ return path52;
35873
36532
  }
35874
36533
  var KG_PATHS_INTERNALS = Object.freeze({
35875
36534
  olamHome,
@@ -35885,10 +36544,10 @@ var KgOverlayError = class extends Error {
35885
36544
  }
35886
36545
  };
35887
36546
  function ensureGitignoreEntry(worldClonePath) {
35888
- const gitignorePath = path38.join(worldClonePath, ".gitignore");
35889
- if (!fs39.existsSync(gitignorePath))
36547
+ const gitignorePath = path41.join(worldClonePath, ".gitignore");
36548
+ if (!fs41.existsSync(gitignorePath))
35890
36549
  return "no-gitignore";
35891
- const content = fs39.readFileSync(gitignorePath, "utf-8");
36550
+ const content = fs41.readFileSync(gitignorePath, "utf-8");
35892
36551
  const lines = content.split("\n").map((l) => l.trim());
35893
36552
  const recognised = /* @__PURE__ */ new Set([
35894
36553
  "graphify-out",
@@ -35903,24 +36562,24 @@ function ensureGitignoreEntry(worldClonePath) {
35903
36562
  const eol = content.includes("\r\n") ? "\r\n" : "\n";
35904
36563
  const needsLeadingNewline = content.length > 0 && !content.endsWith(eol);
35905
36564
  const block = `${needsLeadingNewline ? eol : ""}${eol}# olam-kg-service: per-world KG overlay (Phase B1)${eol}graphify-out/${eol}`;
35906
- fs39.appendFileSync(gitignorePath, block, "utf-8");
36565
+ fs41.appendFileSync(gitignorePath, block, "utf-8");
35907
36566
  return "appended";
35908
36567
  }
35909
36568
  function createWorldOverlay(opts) {
35910
36569
  const pristineRoot = kgPristinePath(opts.workspace);
35911
- const pristinePath = path38.join(pristineRoot, "graphify-out");
35912
- if (!fs39.existsSync(pristinePath)) {
36570
+ const pristinePath = path41.join(pristineRoot, "graphify-out");
36571
+ if (!fs41.existsSync(pristinePath)) {
35913
36572
  throw new KgOverlayError(`Pristine KG for workspace ${JSON.stringify(opts.workspace)} not found at ${pristinePath}. Run \`olam kg build ${opts.workspace}\` first.`);
35914
36573
  }
35915
- if (!path38.isAbsolute(opts.worldClonePath)) {
36574
+ if (!path41.isAbsolute(opts.worldClonePath)) {
35916
36575
  throw new KgOverlayError(`worldClonePath must be absolute (got ${opts.worldClonePath})`);
35917
36576
  }
35918
- if (!fs39.existsSync(opts.worldClonePath)) {
36577
+ if (!fs41.existsSync(opts.worldClonePath)) {
35919
36578
  throw new KgOverlayError(`worldClonePath does not exist: ${opts.worldClonePath}. Create the clone before reflinking.`);
35920
36579
  }
35921
- const overlayPath = path38.join(opts.worldClonePath, "graphify-out");
35922
- if (fs39.existsSync(overlayPath)) {
35923
- fs39.rmSync(overlayPath, { recursive: true, force: true });
36580
+ const overlayPath = path41.join(opts.worldClonePath, "graphify-out");
36581
+ if (fs41.existsSync(overlayPath)) {
36582
+ fs41.rmSync(overlayPath, { recursive: true, force: true });
35924
36583
  }
35925
36584
  const useReflink = process.platform === "darwin";
35926
36585
  let strategy;
@@ -35938,7 +36597,7 @@ function createWorldOverlay(opts) {
35938
36597
  } else {
35939
36598
  strategy = "cp-r";
35940
36599
  }
35941
- if (strategy === "cp-r" || !fs39.existsSync(overlayPath)) {
36600
+ if (strategy === "cp-r" || !fs41.existsSync(overlayPath)) {
35942
36601
  try {
35943
36602
  execFileSync5("cp", ["-r", pristinePath, opts.worldClonePath], {
35944
36603
  stdio: ["ignore", "ignore", "pipe"]
@@ -35950,7 +36609,7 @@ function createWorldOverlay(opts) {
35950
36609
  throw new KgOverlayError(`cp -r failed: ${msg}${reflinkMsg}`);
35951
36610
  }
35952
36611
  }
35953
- if (!fs39.existsSync(overlayPath)) {
36612
+ if (!fs41.existsSync(overlayPath)) {
35954
36613
  throw new KgOverlayError(`Overlay creation produced no ${overlayPath} after cp \u2014 filesystem returned without error?`);
35955
36614
  }
35956
36615
  const gitignoreAction = ensureGitignoreEntry(opts.worldClonePath);
@@ -35964,12 +36623,12 @@ function createWorldOverlay(opts) {
35964
36623
 
35965
36624
  // ../core/dist/world/baseline-diff.js
35966
36625
  import { execFileSync as execFileSync6 } from "node:child_process";
35967
- import * as fs40 from "node:fs";
35968
- import * as os23 from "node:os";
35969
- import * as path39 from "node:path";
36626
+ import * as fs42 from "node:fs";
36627
+ import * as os26 from "node:os";
36628
+ import * as path42 from "node:path";
35970
36629
  var DEFAULT_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
35971
- function expandHome2(p, homedir28) {
35972
- return p.replace(/^~(?=$|\/|\\)/, homedir28());
36630
+ function expandHome2(p, homedir30) {
36631
+ return p.replace(/^~(?=$|\/|\\)/, homedir30());
35973
36632
  }
35974
36633
  function sanitizeRepoFilename(name) {
35975
36634
  const sanitized = name.replace(/[^A-Za-z0-9._-]/g, "_");
@@ -35992,10 +36651,10 @@ ${stderr}`;
35992
36651
  }
35993
36652
  function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
35994
36653
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync6(cmd, args, opts));
35995
- const homedir28 = deps.homedir ?? (() => os23.homedir());
35996
- const baselineDir = path39.join(workspacePath, ".olam", "baseline");
36654
+ const homedir30 = deps.homedir ?? (() => os26.homedir());
36655
+ const baselineDir = path42.join(workspacePath, ".olam", "baseline");
35997
36656
  try {
35998
- fs40.mkdirSync(baselineDir, { recursive: true });
36657
+ fs42.mkdirSync(baselineDir, { recursive: true });
35999
36658
  } catch (err) {
36000
36659
  const msg = err instanceof Error ? err.message : String(err);
36001
36660
  console.warn(`[baseline-diff] mkdir ${baselineDir} failed: ${msg}; reaper will see no baseline at all`);
@@ -36007,9 +36666,9 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
36007
36666
  if (!repo.path)
36008
36667
  continue;
36009
36668
  const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
36010
- const outPath = path39.join(baselineDir, filename);
36011
- const repoPath = expandHome2(repo.path, homedir28);
36012
- if (!fs40.existsSync(repoPath)) {
36669
+ const outPath = path42.join(baselineDir, filename);
36670
+ const repoPath = expandHome2(repo.path, homedir30);
36671
+ if (!fs42.existsSync(repoPath)) {
36013
36672
  writeBaselineFile(outPath, `# repo: ${repo.name}
36014
36673
  # (skipped: path ${repoPath} does not exist)
36015
36674
  `);
@@ -36076,7 +36735,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
36076
36735
  }
36077
36736
  function writeBaselineFile(outPath, content) {
36078
36737
  try {
36079
- fs40.writeFileSync(outPath, content);
36738
+ fs42.writeFileSync(outPath, content);
36080
36739
  } catch (err) {
36081
36740
  const msg = err instanceof Error ? err.message : String(err);
36082
36741
  console.warn(`[baseline-diff] write to ${outPath} failed: ${msg}`);
@@ -36084,8 +36743,8 @@ function writeBaselineFile(outPath, content) {
36084
36743
  }
36085
36744
  function stripWorktreeEdits(repos, workspacePath) {
36086
36745
  for (const repo of repos) {
36087
- const worktreePath = path39.join(workspacePath, repo.name);
36088
- if (!fs40.existsSync(worktreePath))
36746
+ const worktreePath = path42.join(workspacePath, repo.name);
36747
+ if (!fs42.existsSync(worktreePath))
36089
36748
  continue;
36090
36749
  try {
36091
36750
  execFileSync6("git", ["checkout", "--", "."], {
@@ -36144,21 +36803,21 @@ function extractStderr(err) {
36144
36803
  }
36145
36804
  function carryUncommittedEdits(repos, workspacePath, deps = {}) {
36146
36805
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync6(cmd, args, opts));
36147
- const homedir28 = deps.homedir ?? (() => os23.homedir());
36148
- const existsSync46 = deps.existsSync ?? ((p) => fs40.existsSync(p));
36149
- const copyFileSync9 = deps.copyFileSync ?? ((src, dest) => fs40.copyFileSync(src, dest));
36150
- const mkdirSync29 = deps.mkdirSync ?? ((dirPath, opts) => {
36151
- fs40.mkdirSync(dirPath, opts);
36806
+ const homedir30 = deps.homedir ?? (() => os26.homedir());
36807
+ const existsSync47 = deps.existsSync ?? ((p) => fs42.existsSync(p));
36808
+ const copyFileSync9 = deps.copyFileSync ?? ((src, dest) => fs42.copyFileSync(src, dest));
36809
+ const mkdirSync30 = deps.mkdirSync ?? ((dirPath, opts) => {
36810
+ fs42.mkdirSync(dirPath, opts);
36152
36811
  });
36153
36812
  const plans = [];
36154
36813
  for (const repo of repos) {
36155
36814
  if (!repo.path)
36156
36815
  continue;
36157
- const repoPath = expandHome2(repo.path, homedir28);
36158
- const worktreePath = path39.join(workspacePath, repo.name);
36159
- if (!existsSync46(repoPath))
36816
+ const repoPath = expandHome2(repo.path, homedir30);
36817
+ const worktreePath = path42.join(workspacePath, repo.name);
36818
+ if (!existsSync47(repoPath))
36160
36819
  continue;
36161
- if (!existsSync46(worktreePath)) {
36820
+ if (!existsSync47(worktreePath)) {
36162
36821
  console.warn(`[carry] ${repo.name}: world worktree ${worktreePath} missing; skipping carry for this repo`);
36163
36822
  continue;
36164
36823
  }
@@ -36216,12 +36875,12 @@ function carryUncommittedEdits(repos, workspacePath, deps = {}) {
36216
36875
  }
36217
36876
  }
36218
36877
  for (const rel of plan.diff.untracked) {
36219
- const src = path39.join(plan.repoPath, rel);
36220
- const dest = path39.join(plan.worktreePath, rel);
36221
- if (!existsSync46(src))
36878
+ const src = path42.join(plan.repoPath, rel);
36879
+ const dest = path42.join(plan.worktreePath, rel);
36880
+ if (!existsSync47(src))
36222
36881
  continue;
36223
36882
  try {
36224
- mkdirSync29(path39.dirname(dest), { recursive: true });
36883
+ mkdirSync30(path42.dirname(dest), { recursive: true });
36225
36884
  copyFileSync9(src, dest);
36226
36885
  } catch (err) {
36227
36886
  const msg = err instanceof Error ? err.message : String(err);
@@ -36247,8 +36906,8 @@ function formatBaselineSummary(result) {
36247
36906
  }
36248
36907
 
36249
36908
  // ../core/dist/world/context-injection.js
36250
- import * as fs41 from "node:fs";
36251
- import * as path40 from "node:path";
36909
+ import * as fs43 from "node:fs";
36910
+ import * as path43 from "node:path";
36252
36911
 
36253
36912
  // ../core/dist/world/templates/_generated.js
36254
36913
  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';
@@ -36258,10 +36917,10 @@ var WORLD_CLAUDE_MD = '# Olam World: {{worldName}}\n\n{{taskBlock}}\n\n## Enviro
36258
36917
  // ../core/dist/world/context-injection.js
36259
36918
  function injectWorldContext(opts) {
36260
36919
  const { world } = opts;
36261
- const claudeDir2 = path40.join(world.workspacePath, ".claude");
36262
- fs41.mkdirSync(claudeDir2, { recursive: true });
36920
+ const claudeDir2 = path43.join(world.workspacePath, ".claude");
36921
+ fs43.mkdirSync(claudeDir2, { recursive: true });
36263
36922
  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));
36264
- fs41.writeFileSync(path40.join(claudeDir2, "CLAUDE.md"), content);
36923
+ fs43.writeFileSync(path43.join(claudeDir2, "CLAUDE.md"), content);
36265
36924
  writeOlamDocs(world.workspacePath);
36266
36925
  }
36267
36926
  function buildTaskBlock(opts) {
@@ -36335,10 +36994,10 @@ function buildExtraContextBlock(extra) {
36335
36994
  ${extra}`;
36336
36995
  }
36337
36996
  function writeOlamDocs(workspacePath) {
36338
- const docsDir = path40.join(workspacePath, ".olam", "docs");
36339
- fs41.mkdirSync(docsDir, { recursive: true });
36340
- fs41.writeFileSync(path40.join(docsDir, "gh-pr-create.md"), GH_PR_CREATE);
36341
- fs41.writeFileSync(path40.join(docsDir, "lane-orchestration.md"), LANE_ORCHESTRATION);
36997
+ const docsDir = path43.join(workspacePath, ".olam", "docs");
36998
+ fs43.mkdirSync(docsDir, { recursive: true });
36999
+ fs43.writeFileSync(path43.join(docsDir, "gh-pr-create.md"), GH_PR_CREATE);
37000
+ fs43.writeFileSync(path43.join(docsDir, "lane-orchestration.md"), LANE_ORCHESTRATION);
36342
37001
  }
36343
37002
  function formatTaskSource(ctx) {
36344
37003
  if (ctx.source === "linear" && ctx.ticketId) {
@@ -36352,9 +37011,9 @@ function formatTaskSource(ctx) {
36352
37011
  function hasPlanFile(world) {
36353
37012
  if (world.repos.length === 0)
36354
37013
  return false;
36355
- const plansDir = path40.join(world.workspacePath, world.repos[0], "docs", "plans");
37014
+ const plansDir = path43.join(world.workspacePath, world.repos[0], "docs", "plans");
36356
37015
  try {
36357
- return fs41.existsSync(plansDir) && fs41.readdirSync(plansDir).length > 0;
37016
+ return fs43.existsSync(plansDir) && fs43.readdirSync(plansDir).length > 0;
36358
37017
  } catch {
36359
37018
  return false;
36360
37019
  }
@@ -36926,25 +37585,25 @@ init_repo_manifest();
36926
37585
 
36927
37586
  // ../core/dist/world/snapshot.js
36928
37587
  import * as crypto7 from "node:crypto";
36929
- import * as fs42 from "node:fs";
36930
- import * as os24 from "node:os";
36931
- import * as path41 from "node:path";
37588
+ import * as fs44 from "node:fs";
37589
+ import * as os27 from "node:os";
37590
+ import * as path44 from "node:path";
36932
37591
  import { execFileSync as execFileSync7, spawn as spawn2 } from "node:child_process";
36933
37592
  import { gunzipSync } from "node:zlib";
36934
37593
  function snapshotsDir() {
36935
- return process.env["OLAM_SNAPSHOTS_DIR"] ?? path41.join(os24.homedir(), ".olam", "snapshots");
37594
+ return process.env["OLAM_SNAPSHOTS_DIR"] ?? path44.join(os27.homedir(), ".olam", "snapshots");
36936
37595
  }
36937
37596
  function snapshotKindDirByWorkspace(workspace, arch, kind) {
36938
- return path41.join(snapshotsDir(), "by-workspace", workspace, arch, kind);
37597
+ return path44.join(snapshotsDir(), "by-workspace", workspace, arch, kind);
36939
37598
  }
36940
37599
  function cleanupLegacyByWorldDir(worldId) {
36941
- const legacyDir = path41.join(snapshotsDir(), worldId);
37600
+ const legacyDir = path44.join(snapshotsDir(), worldId);
36942
37601
  if (worldId === "by-workspace")
36943
37602
  return;
36944
- if (!fs42.existsSync(legacyDir))
37603
+ if (!fs44.existsSync(legacyDir))
36945
37604
  return;
36946
37605
  try {
36947
- fs42.rmSync(legacyDir, { recursive: true, force: true });
37606
+ fs44.rmSync(legacyDir, { recursive: true, force: true });
36948
37607
  } catch {
36949
37608
  }
36950
37609
  }
@@ -36963,11 +37622,11 @@ function hashBuffers(entries) {
36963
37622
  return hash.digest("hex").slice(0, 12);
36964
37623
  }
36965
37624
  function computeGemsFingerprint(repoDir, imageDigest) {
36966
- const lockfile = path41.join(repoDir, "Gemfile.lock");
36967
- if (!fs42.existsSync(lockfile))
37625
+ const lockfile = path44.join(repoDir, "Gemfile.lock");
37626
+ if (!fs44.existsSync(lockfile))
36968
37627
  return null;
36969
37628
  const entries = [
36970
- { path: "Gemfile.lock", content: fs42.readFileSync(lockfile) }
37629
+ { path: "Gemfile.lock", content: fs44.readFileSync(lockfile) }
36971
37630
  ];
36972
37631
  if (imageDigest) {
36973
37632
  entries.push({ path: "__image_digest__", content: Buffer.from(imageDigest, "utf-8") });
@@ -36977,10 +37636,10 @@ function computeGemsFingerprint(repoDir, imageDigest) {
36977
37636
  function computeNodeFingerprint(repoDir, imageDigest) {
36978
37637
  const candidates = ["yarn.lock", "pnpm-lock.yaml", "package-lock.json"];
36979
37638
  for (const name of candidates) {
36980
- const lockfile = path41.join(repoDir, name);
36981
- if (fs42.existsSync(lockfile)) {
37639
+ const lockfile = path44.join(repoDir, name);
37640
+ if (fs44.existsSync(lockfile)) {
36982
37641
  const entries = [
36983
- { path: name, content: fs42.readFileSync(lockfile) }
37642
+ { path: name, content: fs44.readFileSync(lockfile) }
36984
37643
  ];
36985
37644
  if (imageDigest) {
36986
37645
  entries.push({ path: "__image_digest__", content: Buffer.from(imageDigest, "utf-8") });
@@ -36999,18 +37658,18 @@ function unpackTarballAtomic(srcPath, destDir) {
36999
37658
  detail: validation.detail ?? `unsafe entry: ${validation.unsafePath}`
37000
37659
  };
37001
37660
  }
37002
- const parent = path41.dirname(destDir);
37003
- fs42.mkdirSync(parent, { recursive: true });
37661
+ const parent = path44.dirname(destDir);
37662
+ fs44.mkdirSync(parent, { recursive: true });
37004
37663
  const tmpSuffix = `.tmp-${process.pid}-${crypto7.randomBytes(4).toString("hex")}`;
37005
37664
  const tmpDir = `${destDir}${tmpSuffix}`;
37006
37665
  try {
37007
- fs42.mkdirSync(tmpDir, { recursive: true });
37666
+ fs44.mkdirSync(tmpDir, { recursive: true });
37008
37667
  execFileSync7("tar", ["-xzf", srcPath, "-C", tmpDir], { stdio: "pipe" });
37009
- fs42.renameSync(tmpDir, destDir);
37668
+ fs44.renameSync(tmpDir, destDir);
37010
37669
  return { ok: true, entryCount: validation.entries.length };
37011
37670
  } catch (err) {
37012
37671
  try {
37013
- fs42.rmSync(tmpDir, { recursive: true, force: true });
37672
+ fs44.rmSync(tmpDir, { recursive: true, force: true });
37014
37673
  } catch {
37015
37674
  }
37016
37675
  return {
@@ -37021,12 +37680,12 @@ function unpackTarballAtomic(srcPath, destDir) {
37021
37680
  }
37022
37681
  }
37023
37682
  function resolvesWithin(base, target) {
37024
- const resolved = path41.resolve(base, target);
37025
- const baseResolved = path41.resolve(base);
37026
- const rel = path41.relative(baseResolved, resolved);
37683
+ const resolved = path44.resolve(base, target);
37684
+ const baseResolved = path44.resolve(base);
37685
+ const rel = path44.relative(baseResolved, resolved);
37027
37686
  if (rel === "")
37028
37687
  return true;
37029
- return !rel.startsWith("..") && !path41.isAbsolute(rel);
37688
+ return !rel.startsWith("..") && !path44.isAbsolute(rel);
37030
37689
  }
37031
37690
  var TYPE_CHAR_TO_TYPE = {
37032
37691
  "-": "file",
@@ -37076,7 +37735,7 @@ function parseTarListLine(line) {
37076
37735
  function validateHardlinksBinary(tarPath, targetDir) {
37077
37736
  let raw;
37078
37737
  try {
37079
- raw = gunzipSync(fs42.readFileSync(tarPath));
37738
+ raw = gunzipSync(fs44.readFileSync(tarPath));
37080
37739
  } catch {
37081
37740
  return null;
37082
37741
  }
@@ -37091,7 +37750,7 @@ function validateHardlinksBinary(tarPath, targetDir) {
37091
37750
  const name = block.subarray(0, nameNull >= 0 && nameNull <= 99 ? nameNull : 100).toString("utf-8");
37092
37751
  const linkNull = block.indexOf(0, 157);
37093
37752
  const linkname = block.subarray(157, linkNull >= 157 && linkNull <= 256 ? linkNull : 257).toString("utf-8");
37094
- if (linkname && (path41.isAbsolute(linkname) || !resolvesWithin(targetDir, linkname))) {
37753
+ if (linkname && (path44.isAbsolute(linkname) || !resolvesWithin(targetDir, linkname))) {
37095
37754
  return {
37096
37755
  valid: false,
37097
37756
  reason: "hardlink-escape",
@@ -37129,7 +37788,7 @@ function enumerateAndValidateTarballEntries(tarPath, targetDir) {
37129
37788
  const entry = parseTarListLine(line);
37130
37789
  if (!entry)
37131
37790
  continue;
37132
- if (path41.isAbsolute(entry.name) || !resolvesWithin(targetDir, entry.name)) {
37791
+ if (path44.isAbsolute(entry.name) || !resolvesWithin(targetDir, entry.name)) {
37133
37792
  return {
37134
37793
  valid: false,
37135
37794
  reason: "path-traversal",
@@ -37137,8 +37796,8 @@ function enumerateAndValidateTarballEntries(tarPath, targetDir) {
37137
37796
  };
37138
37797
  }
37139
37798
  if (entry.type === "symlink" && entry.linkname !== void 0) {
37140
- const symlinkParent = path41.join(targetDir, path41.dirname(entry.name));
37141
- if (path41.isAbsolute(entry.linkname) || !resolvesWithin(targetDir, path41.join(path41.dirname(entry.name), entry.linkname))) {
37799
+ const symlinkParent = path44.join(targetDir, path44.dirname(entry.name));
37800
+ if (path44.isAbsolute(entry.linkname) || !resolvesWithin(targetDir, path44.join(path44.dirname(entry.name), entry.linkname))) {
37142
37801
  return {
37143
37802
  valid: false,
37144
37803
  reason: "symlink-escape",
@@ -37148,7 +37807,7 @@ function enumerateAndValidateTarballEntries(tarPath, targetDir) {
37148
37807
  }
37149
37808
  }
37150
37809
  if (entry.type === "hardlink" && entry.linkname !== void 0) {
37151
- if (path41.isAbsolute(entry.linkname) || !resolvesWithin(targetDir, entry.linkname)) {
37810
+ if (path44.isAbsolute(entry.linkname) || !resolvesWithin(targetDir, entry.linkname)) {
37152
37811
  return {
37153
37812
  valid: false,
37154
37813
  reason: "hardlink-escape",
@@ -37181,8 +37840,8 @@ function restoreSnapshotsForRepos(input) {
37181
37840
  }
37182
37841
  const archDir = snapshotKindDirByWorkspace(input.workspace, input.arch, kind);
37183
37842
  const tarFilename = `${repo.name}-${input.arch}-${fingerprint}.tar.gz`;
37184
- const tarPath = path41.join(archDir, tarFilename);
37185
- if (!fs42.existsSync(tarPath)) {
37843
+ const tarPath = path44.join(archDir, tarFilename);
37844
+ if (!fs44.existsSync(tarPath)) {
37186
37845
  outcomes.push({ repo: repo.name, kind, outcome: "miss", reason: "no-tarball", fingerprint });
37187
37846
  continue;
37188
37847
  }
@@ -37197,9 +37856,9 @@ function restoreSnapshotsForRepos(input) {
37197
37856
  });
37198
37857
  continue;
37199
37858
  }
37200
- const targetDir = path41.join(repo.worktreeDir, targetSubpath);
37859
+ const targetDir = path44.join(repo.worktreeDir, targetSubpath);
37201
37860
  try {
37202
- fs42.rmSync(targetDir, { recursive: true, force: true });
37861
+ fs44.rmSync(targetDir, { recursive: true, force: true });
37203
37862
  } catch {
37204
37863
  }
37205
37864
  const result = unpackTarballAtomic(tarPath, targetDir);
@@ -37212,8 +37871,8 @@ function restoreSnapshotsForRepos(input) {
37212
37871
  fingerprint
37213
37872
  });
37214
37873
  try {
37215
- fs42.rmSync(tarPath, { force: true });
37216
- fs42.rmSync(manifestPath(tarPath), { force: true });
37874
+ fs44.rmSync(tarPath, { force: true });
37875
+ fs44.rmSync(manifestPath(tarPath), { force: true });
37217
37876
  } catch {
37218
37877
  }
37219
37878
  continue;
@@ -37229,10 +37888,10 @@ function restoreSnapshotsForRepos(input) {
37229
37888
  }
37230
37889
  function readManifest(tarPath) {
37231
37890
  const mPath = manifestPath(tarPath);
37232
- if (!fs42.existsSync(mPath))
37891
+ if (!fs44.existsSync(mPath))
37233
37892
  return null;
37234
37893
  try {
37235
- return JSON.parse(fs42.readFileSync(mPath, "utf-8"));
37894
+ return JSON.parse(fs44.readFileSync(mPath, "utf-8"));
37236
37895
  } catch {
37237
37896
  return null;
37238
37897
  }
@@ -37247,17 +37906,17 @@ function isPidAlive(pid) {
37247
37906
  }
37248
37907
  }
37249
37908
  function evictOldSnapshotsWithFlock(maxBytes, dir = snapshotsDir()) {
37250
- fs42.mkdirSync(dir, { recursive: true });
37251
- const lockPath = path41.join(dir, EVICT_LOCK_FILENAME);
37909
+ fs44.mkdirSync(dir, { recursive: true });
37910
+ const lockPath = path44.join(dir, EVICT_LOCK_FILENAME);
37252
37911
  let fd;
37253
37912
  try {
37254
- fd = fs42.openSync(lockPath, fs42.constants.O_WRONLY | fs42.constants.O_CREAT | fs42.constants.O_EXCL, 384);
37913
+ fd = fs44.openSync(lockPath, fs44.constants.O_WRONLY | fs44.constants.O_CREAT | fs44.constants.O_EXCL, 384);
37255
37914
  } catch (err) {
37256
37915
  if (err.code !== "EEXIST")
37257
37916
  return 0;
37258
37917
  let holderPid = null;
37259
37918
  try {
37260
- holderPid = parseInt(fs42.readFileSync(lockPath, "utf-8").trim(), 10);
37919
+ holderPid = parseInt(fs44.readFileSync(lockPath, "utf-8").trim(), 10);
37261
37920
  } catch {
37262
37921
  holderPid = null;
37263
37922
  }
@@ -37265,23 +37924,23 @@ function evictOldSnapshotsWithFlock(maxBytes, dir = snapshotsDir()) {
37265
37924
  return 0;
37266
37925
  }
37267
37926
  try {
37268
- fs42.unlinkSync(lockPath);
37269
- fd = fs42.openSync(lockPath, fs42.constants.O_WRONLY | fs42.constants.O_CREAT | fs42.constants.O_EXCL, 384);
37927
+ fs44.unlinkSync(lockPath);
37928
+ fd = fs44.openSync(lockPath, fs44.constants.O_WRONLY | fs44.constants.O_CREAT | fs44.constants.O_EXCL, 384);
37270
37929
  } catch {
37271
37930
  return 0;
37272
37931
  }
37273
37932
  }
37274
37933
  try {
37275
- fs42.writeSync(fd, `${process.pid}
37934
+ fs44.writeSync(fd, `${process.pid}
37276
37935
  `);
37277
37936
  } finally {
37278
- fs42.closeSync(fd);
37937
+ fs44.closeSync(fd);
37279
37938
  }
37280
37939
  try {
37281
37940
  return evictOldSnapshots(maxBytes, dir);
37282
37941
  } finally {
37283
37942
  try {
37284
- fs42.unlinkSync(lockPath);
37943
+ fs44.unlinkSync(lockPath);
37285
37944
  } catch {
37286
37945
  }
37287
37946
  }
@@ -37314,16 +37973,16 @@ function spawnAutoCapture(worldId, olamBin = "olam") {
37314
37973
  }
37315
37974
  }
37316
37975
  function evictOldSnapshots(maxBytes, dir = snapshotsDir()) {
37317
- if (!fs42.existsSync(dir))
37976
+ if (!fs44.existsSync(dir))
37318
37977
  return 0;
37319
37978
  const allTars = [];
37320
37979
  const walk = (d) => {
37321
- for (const entry of fs42.readdirSync(d, { withFileTypes: true })) {
37322
- const full = path41.join(d, entry.name);
37980
+ for (const entry of fs44.readdirSync(d, { withFileTypes: true })) {
37981
+ const full = path44.join(d, entry.name);
37323
37982
  if (entry.isDirectory()) {
37324
37983
  walk(full);
37325
37984
  } else if (entry.name.endsWith(".tar.gz")) {
37326
- const stat = fs42.statSync(full);
37985
+ const stat = fs44.statSync(full);
37327
37986
  allTars.push({ path: full, size: stat.size, mtime: stat.mtimeMs });
37328
37987
  }
37329
37988
  }
@@ -37338,8 +37997,8 @@ function evictOldSnapshots(maxBytes, dir = snapshotsDir()) {
37338
37997
  for (const tar of allTars) {
37339
37998
  if (remaining <= maxBytes)
37340
37999
  break;
37341
- fs42.rmSync(tar.path, { force: true });
37342
- fs42.rmSync(manifestPath(tar.path), { force: true });
38000
+ fs44.rmSync(tar.path, { force: true });
38001
+ fs44.rmSync(manifestPath(tar.path), { force: true });
37343
38002
  freed += tar.size;
37344
38003
  remaining -= tar.size;
37345
38004
  }
@@ -37456,14 +38115,14 @@ function gcloudAvailable(execFn = defaultExecFn) {
37456
38115
 
37457
38116
  // ../core/dist/world/olam-yaml.js
37458
38117
  init_repo_manifest();
37459
- import * as path42 from "node:path";
38118
+ import * as path45 from "node:path";
37460
38119
  import YAML2 from "yaml";
37461
38120
  function enrichReposWithManifests(repos, workspacePath) {
37462
38121
  return repos.map((repo) => {
37463
38122
  if (repo.manifest !== void 0 && repo.manifest !== null) {
37464
38123
  return repo;
37465
38124
  }
37466
- const repoDir = path42.join(workspacePath, repo.name);
38125
+ const repoDir = path45.join(workspacePath, repo.name);
37467
38126
  let manifest = null;
37468
38127
  try {
37469
38128
  manifest = loadRepoManifest(repoDir);
@@ -37478,8 +38137,8 @@ function enrichReposWithManifests(repos, workspacePath) {
37478
38137
  }
37479
38138
 
37480
38139
  // ../core/dist/policies/loader.js
37481
- import * as fs43 from "node:fs";
37482
- import * as path43 from "node:path";
38140
+ import * as fs45 from "node:fs";
38141
+ import * as path46 from "node:path";
37483
38142
  import { parse as parseYaml4 } from "yaml";
37484
38143
  function parseFrontmatter2(content) {
37485
38144
  const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/m.exec(content);
@@ -37499,20 +38158,20 @@ function toStringArray(v) {
37499
38158
  return v.filter((x) => typeof x === "string");
37500
38159
  }
37501
38160
  function loadPolicies(workspaceRoot) {
37502
- const policiesDir = path43.join(workspaceRoot, ".olam", "policies");
37503
- if (!fs43.existsSync(policiesDir))
38161
+ const policiesDir = path46.join(workspaceRoot, ".olam", "policies");
38162
+ if (!fs45.existsSync(policiesDir))
37504
38163
  return [];
37505
38164
  let files;
37506
38165
  try {
37507
- files = fs43.readdirSync(policiesDir).filter((f) => f.endsWith(".md")).sort();
38166
+ files = fs45.readdirSync(policiesDir).filter((f) => f.endsWith(".md")).sort();
37508
38167
  } catch {
37509
38168
  return [];
37510
38169
  }
37511
38170
  const policies = [];
37512
38171
  for (const file of files) {
37513
- const filePath = path43.join(policiesDir, file);
38172
+ const filePath = path46.join(policiesDir, file);
37514
38173
  try {
37515
- const content = fs43.readFileSync(filePath, "utf8");
38174
+ const content = fs45.readFileSync(filePath, "utf8");
37516
38175
  const parsed = parseFrontmatter2(content);
37517
38176
  if (!parsed) {
37518
38177
  console.warn(`[policies] skipping ${file}: no valid frontmatter block`);
@@ -37659,12 +38318,12 @@ init_store();
37659
38318
  init_bridge();
37660
38319
 
37661
38320
  // ../core/dist/global-config/runbook-resolver.js
37662
- import * as fs44 from "node:fs";
37663
- import * as os25 from "node:os";
37664
- import * as path44 from "node:path";
38321
+ import * as fs46 from "node:fs";
38322
+ import * as os28 from "node:os";
38323
+ import * as path47 from "node:path";
37665
38324
  function expandTilde(p) {
37666
38325
  if (p === "~" || p.startsWith("~/")) {
37667
- return path44.join(os25.homedir(), p.slice(1));
38326
+ return path47.join(os28.homedir(), p.slice(1));
37668
38327
  }
37669
38328
  return p;
37670
38329
  }
@@ -37676,7 +38335,7 @@ function resolveRunbookToWorldParams(runbook, repoRegistry) {
37676
38335
  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.`);
37677
38336
  }
37678
38337
  const resolvedPath = expandTilde(entry.path);
37679
- if (!fs44.existsSync(resolvedPath)) {
38338
+ if (!fs46.existsSync(resolvedPath)) {
37680
38339
  throw new Error(`repo "${repoName}" path "${resolvedPath}" no longer exists. Run "olam repos update ${repoName} --path <new-path>" to fix.`);
37681
38340
  }
37682
38341
  }
@@ -37692,19 +38351,19 @@ function resolveRunbookToWorldParams(runbook, repoRegistry) {
37692
38351
  init_port_validator();
37693
38352
 
37694
38353
  // ../core/dist/world/bootstrap-hooks.js
37695
- import * as fs45 from "node:fs";
37696
- import * as path45 from "node:path";
38354
+ import * as fs47 from "node:fs";
38355
+ import * as path48 from "node:path";
37697
38356
  function runFixtureCopySeeds(seeds, workspacePath) {
37698
38357
  if (!seeds)
37699
38358
  return;
37700
38359
  for (const seed of seeds) {
37701
38360
  if (seed.type !== "fixture-copy")
37702
38361
  continue;
37703
- const srcAbs = path45.resolve(workspacePath, seed.repo, seed.src);
37704
- const destAbs = path45.resolve(workspacePath, seed.repo, seed.dest);
37705
- const destDir = path45.dirname(destAbs);
37706
- fs45.mkdirSync(destDir, { recursive: true });
37707
- fs45.cpSync(srcAbs, destAbs, { recursive: true, force: true });
38362
+ const srcAbs = path48.resolve(workspacePath, seed.repo, seed.src);
38363
+ const destAbs = path48.resolve(workspacePath, seed.repo, seed.dest);
38364
+ const destDir = path48.dirname(destAbs);
38365
+ fs47.mkdirSync(destDir, { recursive: true });
38366
+ fs47.cpSync(srcAbs, destAbs, { recursive: true, force: true });
37708
38367
  }
37709
38368
  }
37710
38369
  async function runSeedHooks(seeds, containerName, servicePortMap, exec) {
@@ -38340,7 +38999,7 @@ ${detail}`);
38340
38999
  runbookSeeds = resolved.seeds;
38341
39000
  }
38342
39001
  const worldId = generateWorldId();
38343
- const workspacePath = path46.join(os26.homedir(), ".olam", "worlds", worldId);
39002
+ const workspacePath = path49.join(os29.homedir(), ".olam", "worlds", worldId);
38344
39003
  const portOffset = this.registry.getNextPortOffset();
38345
39004
  const branch = opts.branchName ?? `olam/${worldId}`;
38346
39005
  const repos = this.resolveReposWithWorkspace(opts);
@@ -38421,38 +39080,38 @@ ${detail}`);
38421
39080
  for (const repo of repos) {
38422
39081
  if (!repo.path)
38423
39082
  continue;
38424
- const sourceRoot = repo.path.replace(/^~/, os26.homedir());
38425
- const worktreeRoot = path46.join(workspacePath, repo.name);
38426
- if (!fs46.existsSync(sourceRoot) || !fs46.existsSync(worktreeRoot))
39083
+ const sourceRoot = repo.path.replace(/^~/, os29.homedir());
39084
+ const worktreeRoot = path49.join(workspacePath, repo.name);
39085
+ if (!fs48.existsSync(sourceRoot) || !fs48.existsSync(worktreeRoot))
38427
39086
  continue;
38428
39087
  let copied = 0;
38429
39088
  for (const pattern of RUNTIME_FILE_PATTERNS) {
38430
39089
  const matches2 = [];
38431
39090
  if (pattern.includes("*")) {
38432
- const [dir, glob] = [path46.dirname(pattern), path46.basename(pattern)];
38433
- const sourceDir = path46.join(sourceRoot, dir);
38434
- if (fs46.existsSync(sourceDir)) {
39091
+ const [dir, glob] = [path49.dirname(pattern), path49.basename(pattern)];
39092
+ const sourceDir = path49.join(sourceRoot, dir);
39093
+ if (fs48.existsSync(sourceDir)) {
38435
39094
  const ext = glob.replace(/^\*+/, "");
38436
39095
  try {
38437
- for (const entry of fs46.readdirSync(sourceDir)) {
39096
+ for (const entry of fs48.readdirSync(sourceDir)) {
38438
39097
  if (ext === "" || entry.endsWith(ext))
38439
- matches2.push(path46.join(dir, entry));
39098
+ matches2.push(path49.join(dir, entry));
38440
39099
  }
38441
39100
  } catch {
38442
39101
  }
38443
39102
  }
38444
- } else if (fs46.existsSync(path46.join(sourceRoot, pattern))) {
39103
+ } else if (fs48.existsSync(path49.join(sourceRoot, pattern))) {
38445
39104
  matches2.push(pattern);
38446
39105
  }
38447
39106
  for (const rel of matches2) {
38448
- const src = path46.join(sourceRoot, rel);
38449
- const dst = path46.join(worktreeRoot, rel);
39107
+ const src = path49.join(sourceRoot, rel);
39108
+ const dst = path49.join(worktreeRoot, rel);
38450
39109
  try {
38451
- const st = fs46.statSync(src);
39110
+ const st = fs48.statSync(src);
38452
39111
  if (!st.isFile())
38453
39112
  continue;
38454
- fs46.mkdirSync(path46.dirname(dst), { recursive: true });
38455
- fs46.copyFileSync(src, dst);
39113
+ fs48.mkdirSync(path49.dirname(dst), { recursive: true });
39114
+ fs48.copyFileSync(src, dst);
38456
39115
  copied++;
38457
39116
  } catch {
38458
39117
  }
@@ -38538,7 +39197,7 @@ ${detail}`);
38538
39197
  }
38539
39198
  const overlayAttachments = [];
38540
39199
  for (const repo of repos) {
38541
- const worldClonePath = path46.join(workspacePath, repo.name);
39200
+ const worldClonePath = path49.join(workspacePath, repo.name);
38542
39201
  try {
38543
39202
  const result = createWorldOverlay({
38544
39203
  workspace: repo.name,
@@ -38593,7 +39252,7 @@ ${detail}`);
38593
39252
  try {
38594
39253
  const hostExec = makeHostExecFn();
38595
39254
  for (const repo of repos) {
38596
- const repoDir = path46.join(workspacePath, repo.name);
39255
+ const repoDir = path49.join(workspacePath, repo.name);
38597
39256
  if (repo.stack && Object.keys(repo.stack).length > 0) {
38598
39257
  preDetectedStacks.set(repo.name, { repoName: repo.name, versions: repo.stack });
38599
39258
  } else {
@@ -38637,10 +39296,10 @@ ${detail}`);
38637
39296
  const worldEnv = {};
38638
39297
  if (opts.task)
38639
39298
  worldEnv.OLAM_TASK = opts.task;
38640
- const r2CredsPath = path46.join(os26.homedir(), ".olam", "r2-credentials.json");
38641
- if (fs46.existsSync(r2CredsPath)) {
39299
+ const r2CredsPath = path49.join(os29.homedir(), ".olam", "r2-credentials.json");
39300
+ if (fs48.existsSync(r2CredsPath)) {
38642
39301
  try {
38643
- const r2Raw = fs46.readFileSync(r2CredsPath, "utf-8").trim();
39302
+ const r2Raw = fs48.readFileSync(r2CredsPath, "utf-8").trim();
38644
39303
  if (r2Raw.length > 0) {
38645
39304
  const r2 = JSON.parse(r2Raw);
38646
39305
  if (typeof r2.account_id === "string")
@@ -38657,10 +39316,10 @@ ${detail}`);
38657
39316
  } catch {
38658
39317
  }
38659
39318
  }
38660
- const keysYamlPath = path46.join(os26.homedir(), ".olam", "keys.yaml");
38661
- if (fs46.existsSync(keysYamlPath)) {
39319
+ const keysYamlPath = path49.join(os29.homedir(), ".olam", "keys.yaml");
39320
+ if (fs48.existsSync(keysYamlPath)) {
38662
39321
  try {
38663
- const keysRaw = fs46.readFileSync(keysYamlPath, "utf-8").trim();
39322
+ const keysRaw = fs48.readFileSync(keysYamlPath, "utf-8").trim();
38664
39323
  if (keysRaw.length > 0) {
38665
39324
  const parsed = YAML3.parse(keysRaw);
38666
39325
  if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
@@ -38719,10 +39378,10 @@ ${detail}`);
38719
39378
  worldEnv[k] = v;
38720
39379
  }
38721
39380
  for (const { repoName, relativePath, content } of fileWrites) {
38722
- const absPath = path46.join(workspacePath, repoName, relativePath);
39381
+ const absPath = path49.join(workspacePath, repoName, relativePath);
38723
39382
  try {
38724
- fs46.mkdirSync(path46.dirname(absPath), { recursive: true });
38725
- fs46.writeFileSync(absPath, content.endsWith("\n") ? content : content + "\n", {
39383
+ fs48.mkdirSync(path49.dirname(absPath), { recursive: true });
39384
+ fs48.writeFileSync(absPath, content.endsWith("\n") ? content : content + "\n", {
38726
39385
  mode: 384
38727
39386
  });
38728
39387
  console.log(`[secrets] ${repoName}: materialised ${relativePath} (${content.length} chars, mode 0600)`);
@@ -38899,7 +39558,7 @@ ${detail}`);
38899
39558
  imageDigest: void 0,
38900
39559
  repos: enrichedRepos.map((r) => ({
38901
39560
  name: r.name,
38902
- worktreeDir: path46.join(workspacePath, r.name)
39561
+ worktreeDir: path49.join(workspacePath, r.name)
38903
39562
  }))
38904
39563
  });
38905
39564
  for (const out of restoreResult.outcomes) {
@@ -39005,7 +39664,7 @@ ${detail}`);
39005
39664
  }
39006
39665
  if (opts.task) {
39007
39666
  const allPolicies = repos.flatMap((repo) => {
39008
- const repoWorktree = path46.join(workspacePath, repo.name);
39667
+ const repoWorktree = path49.join(workspacePath, repo.name);
39009
39668
  try {
39010
39669
  return loadPolicies(repoWorktree);
39011
39670
  } catch (err) {
@@ -39018,8 +39677,8 @@ ${detail}`);
39018
39677
  try {
39019
39678
  execSync5(`docker exec ${containerName} mkdir -p /home/olam/.olam/policies`, { stdio: "pipe", timeout: 1e4 });
39020
39679
  for (const repo of repos) {
39021
- const policiesDir = path46.join(workspacePath, repo.name, ".olam", "policies");
39022
- if (fs46.existsSync(policiesDir)) {
39680
+ const policiesDir = path49.join(workspacePath, repo.name, ".olam", "policies");
39681
+ if (fs48.existsSync(policiesDir)) {
39023
39682
  execSync5(`docker cp "${policiesDir}/." "${containerName}:/home/olam/.olam/policies/"`, { stdio: "pipe", timeout: 15e3 });
39024
39683
  }
39025
39684
  }
@@ -39127,8 +39786,8 @@ ${detail}`);
39127
39786
  } catch {
39128
39787
  }
39129
39788
  try {
39130
- fs46.rmSync(world.workspacePath, { recursive: true, force: true });
39131
- if (fs46.existsSync(world.workspacePath)) {
39789
+ fs48.rmSync(world.workspacePath, { recursive: true, force: true });
39790
+ if (fs48.existsSync(world.workspacePath)) {
39132
39791
  console.warn(`[WorldManager] destroyWorld(${worldId}): workspace dir ${world.workspacePath} still exists after rmSync. Run \`olam clean --apply\` to reap.`);
39133
39792
  }
39134
39793
  } catch (err) {
@@ -39237,14 +39896,14 @@ ${detail}`);
39237
39896
  }).filter((r) => r !== void 0);
39238
39897
  }
39239
39898
  transportPlanFile(planFilePath, workspacePath, repoNames) {
39240
- const planContent = fs46.readFileSync(planFilePath, "utf-8");
39241
- const planFileName = path46.basename(planFilePath);
39899
+ const planContent = fs48.readFileSync(planFilePath, "utf-8");
39900
+ const planFileName = path49.basename(planFilePath);
39242
39901
  const targetRepo = repoNames[0];
39243
39902
  if (!targetRepo)
39244
39903
  return;
39245
- const plansDir = path46.join(workspacePath, targetRepo, "docs", "plans");
39246
- fs46.mkdirSync(plansDir, { recursive: true });
39247
- fs46.writeFileSync(path46.join(plansDir, planFileName), planContent);
39904
+ const plansDir = path49.join(workspacePath, targetRepo, "docs", "plans");
39905
+ fs48.mkdirSync(plansDir, { recursive: true });
39906
+ fs48.writeFileSync(path49.join(plansDir, planFileName), planContent);
39248
39907
  }
39249
39908
  resolveServices(repos) {
39250
39909
  const services = [];
@@ -39678,8 +40337,8 @@ import * as http2 from "node:http";
39678
40337
 
39679
40338
  // ../core/dist/dashboard/server.js
39680
40339
  import * as http from "node:http";
39681
- import * as fs47 from "node:fs";
39682
- import * as path47 from "node:path";
40340
+ import * as fs49 from "node:fs";
40341
+ import * as path50 from "node:path";
39683
40342
  import { fileURLToPath as fileURLToPath3 } from "node:url";
39684
40343
 
39685
40344
  // ../core/dist/dashboard/serialize.js
@@ -40014,7 +40673,7 @@ function notFound(res) {
40014
40673
  }
40015
40674
  function openThoughtStore(workspacePath) {
40016
40675
  const dbPath = getWorldDbPath(workspacePath);
40017
- if (!fs47.existsSync(dbPath))
40676
+ if (!fs49.existsSync(dbPath))
40018
40677
  return null;
40019
40678
  return new ThoughtLocalStore(dbPath);
40020
40679
  }
@@ -40185,13 +40844,13 @@ function findSessionInWorld(registry2, sessionId) {
40185
40844
  }
40186
40845
  function createDashboardServer(opts) {
40187
40846
  const { port: port2, registry: registry2 } = opts;
40188
- const thisDir = path47.dirname(fileURLToPath3(import.meta.url));
40189
- const defaultPublicDir = path47.resolve(thisDir, "../../../control-plane/public");
40847
+ const thisDir = path50.dirname(fileURLToPath3(import.meta.url));
40848
+ const defaultPublicDir = path50.resolve(thisDir, "../../../control-plane/public");
40190
40849
  const publicDir = opts.publicDir ?? defaultPublicDir;
40191
- let hasPublicDir = fs47.existsSync(publicDir);
40850
+ let hasPublicDir = fs49.existsSync(publicDir);
40192
40851
  const server = http.createServer((req, res) => {
40193
40852
  if (!hasPublicDir) {
40194
- hasPublicDir = fs47.existsSync(publicDir);
40853
+ hasPublicDir = fs49.existsSync(publicDir);
40195
40854
  }
40196
40855
  const host = req.headers.host ?? `localhost:${port2}`;
40197
40856
  const url2 = new URL(req.url ?? "/", `http://${host}`);
@@ -40465,22 +41124,22 @@ function createDashboardServer(opts) {
40465
41124
  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>`);
40466
41125
  return;
40467
41126
  }
40468
- let filePath = path47.join(publicDir, pathname === "/" ? "index.html" : pathname);
41127
+ let filePath = path50.join(publicDir, pathname === "/" ? "index.html" : pathname);
40469
41128
  if (!filePath.startsWith(publicDir)) {
40470
41129
  notFound(res);
40471
41130
  return;
40472
41131
  }
40473
- if (fs47.existsSync(filePath) && fs47.statSync(filePath).isFile()) {
40474
- const ext = path47.extname(filePath);
41132
+ if (fs49.existsSync(filePath) && fs49.statSync(filePath).isFile()) {
41133
+ const ext = path50.extname(filePath);
40475
41134
  const contentType = MIME[ext] ?? "application/octet-stream";
40476
41135
  res.writeHead(200, { "Content-Type": contentType });
40477
- fs47.createReadStream(filePath).pipe(res);
41136
+ fs49.createReadStream(filePath).pipe(res);
40478
41137
  return;
40479
41138
  }
40480
- filePath = path47.join(publicDir, "index.html");
40481
- if (fs47.existsSync(filePath)) {
41139
+ filePath = path50.join(publicDir, "index.html");
41140
+ if (fs49.existsSync(filePath)) {
40482
41141
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
40483
- fs47.createReadStream(filePath).pipe(res);
41142
+ fs49.createReadStream(filePath).pipe(res);
40484
41143
  return;
40485
41144
  }
40486
41145
  notFound(res);
@@ -40490,17 +41149,17 @@ function createDashboardServer(opts) {
40490
41149
  }
40491
41150
 
40492
41151
  // ../core/dist/dashboard/state.js
40493
- import * as fs48 from "node:fs";
40494
- import * as os27 from "node:os";
40495
- import * as path48 from "node:path";
40496
- var STATE_PATH = path48.join(os27.homedir(), ".olam", "dashboard.json");
41152
+ import * as fs50 from "node:fs";
41153
+ import * as os30 from "node:os";
41154
+ import * as path51 from "node:path";
41155
+ var STATE_PATH = path51.join(os30.homedir(), ".olam", "dashboard.json");
40497
41156
  function saveDashboardState(state) {
40498
- fs48.mkdirSync(path48.dirname(STATE_PATH), { recursive: true });
40499
- fs48.writeFileSync(STATE_PATH, JSON.stringify(state, null, 2));
41157
+ fs50.mkdirSync(path51.dirname(STATE_PATH), { recursive: true });
41158
+ fs50.writeFileSync(STATE_PATH, JSON.stringify(state, null, 2));
40500
41159
  }
40501
41160
  function loadDashboardState() {
40502
41161
  try {
40503
- const raw = fs48.readFileSync(STATE_PATH, "utf-8");
41162
+ const raw = fs50.readFileSync(STATE_PATH, "utf-8");
40504
41163
  return JSON.parse(raw);
40505
41164
  } catch {
40506
41165
  return null;
@@ -40508,7 +41167,7 @@ function loadDashboardState() {
40508
41167
  }
40509
41168
  function clearDashboardState() {
40510
41169
  try {
40511
- fs48.unlinkSync(STATE_PATH);
41170
+ fs50.unlinkSync(STATE_PATH);
40512
41171
  } catch {
40513
41172
  }
40514
41173
  }
@@ -40788,8 +41447,8 @@ var PleriClient = class {
40788
41447
  };
40789
41448
 
40790
41449
  // ../mcp-server/src/env-loader.ts
40791
- import { readFileSync as readFileSync37, existsSync as existsSync45, statSync as statSync14 } from "node:fs";
40792
- import { join as join49, dirname as dirname28, resolve as resolve13 } from "node:path";
41450
+ import { readFileSync as readFileSync38, existsSync as existsSync46, statSync as statSync14 } from "node:fs";
41451
+ import { join as join51, dirname as dirname29, resolve as resolve13 } from "node:path";
40793
41452
  var PROJECT_MARKERS = [
40794
41453
  ".olam/config.yaml",
40795
41454
  ".olam/config.yml",
@@ -40801,26 +41460,26 @@ function findProjectRoot2(startDir) {
40801
41460
  const root = resolve13("/");
40802
41461
  while (true) {
40803
41462
  for (const marker of PROJECT_MARKERS) {
40804
- if (existsSync45(join49(dir, marker))) return dir;
41463
+ if (existsSync46(join51(dir, marker))) return dir;
40805
41464
  }
40806
- const pkg = join49(dir, "package.json");
40807
- if (existsSync45(pkg)) {
41465
+ const pkg = join51(dir, "package.json");
41466
+ if (existsSync46(pkg)) {
40808
41467
  try {
40809
- const json = JSON.parse(readFileSync37(pkg, "utf8"));
41468
+ const json = JSON.parse(readFileSync38(pkg, "utf8"));
40810
41469
  const isOlamWorkspace = typeof json.name === "string" && json.name.startsWith("@olam/");
40811
41470
  const hasOlamDep = json.dependencies && Object.keys(json.dependencies).some((k) => k.startsWith("@olam/")) || json.devDependencies && Object.keys(json.devDependencies).some((k) => k.startsWith("@olam/"));
40812
41471
  if (isOlamWorkspace || hasOlamDep) return dir;
40813
41472
  } catch {
40814
41473
  }
40815
41474
  }
40816
- const parent = dirname28(dir);
41475
+ const parent = dirname29(dir);
40817
41476
  if (parent === dir || parent === root) return null;
40818
41477
  dir = parent;
40819
41478
  }
40820
41479
  }
40821
- function parseEnvFile(path49) {
41480
+ function parseEnvFile(path52) {
40822
41481
  const out = {};
40823
- const raw = readFileSync37(path49, "utf8");
41482
+ const raw = readFileSync38(path52, "utf8");
40824
41483
  for (const line of raw.split(/\r?\n/)) {
40825
41484
  const trimmed = line.trim();
40826
41485
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -40843,8 +41502,8 @@ function loadProjectEnv(startDir = process.cwd()) {
40843
41502
  const filesRead = [];
40844
41503
  const merged = {};
40845
41504
  for (const name of [".env", ".env.local"]) {
40846
- const p = join49(root, name);
40847
- if (existsSync45(p) && statSync14(p).isFile()) {
41505
+ const p = join51(root, name);
41506
+ if (existsSync46(p) && statSync14(p).isFile()) {
40848
41507
  Object.assign(merged, parseEnvFile(p));
40849
41508
  filesRead.push(p);
40850
41509
  }
@@ -40880,12 +41539,12 @@ async function main() {
40880
41539
  maxDailyUsd: config2.cost.max_daily_usd,
40881
41540
  warningThreshold: config2.cost.warning_threshold
40882
41541
  });
40883
- const WORLD_ID_RE2 = /^[a-z0-9-]+$/;
41542
+ const WORLD_ID_RE3 = /^[a-z0-9-]+$/;
40884
41543
  const callerWorldIdRaw = (process.env.OLAM_CALLER_WORLD_ID ?? "").trim();
40885
41544
  let callerWorldId;
40886
41545
  if (callerWorldIdRaw.length === 0) {
40887
41546
  callerWorldId = void 0;
40888
- } else if (WORLD_ID_RE2.test(callerWorldIdRaw)) {
41547
+ } else if (WORLD_ID_RE3.test(callerWorldIdRaw)) {
40889
41548
  callerWorldId = callerWorldIdRaw;
40890
41549
  } else {
40891
41550
  logger.warn(