@pleri/olam-cli 0.1.55 → 0.1.57

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 (45) hide show
  1. package/dist/__tests__/services.test.d.ts +8 -0
  2. package/dist/__tests__/services.test.d.ts.map +1 -0
  3. package/dist/__tests__/services.test.js +185 -0
  4. package/dist/__tests__/services.test.js.map +1 -0
  5. package/dist/commands/__tests__/__fixtures__/upgrade-helpers.d.ts +6 -0
  6. package/dist/commands/__tests__/__fixtures__/upgrade-helpers.d.ts.map +1 -0
  7. package/dist/commands/__tests__/__fixtures__/upgrade-helpers.js +26 -0
  8. package/dist/commands/__tests__/__fixtures__/upgrade-helpers.js.map +1 -0
  9. package/dist/commands/__tests__/upgrade.all-three.test.js +1 -13
  10. package/dist/commands/__tests__/upgrade.all-three.test.js.map +1 -1
  11. package/dist/commands/__tests__/upgrade.compose-path.test.js +1 -13
  12. package/dist/commands/__tests__/upgrade.compose-path.test.js.map +1 -1
  13. package/dist/commands/__tests__/upgrade.olam-tag.test.js +1 -14
  14. package/dist/commands/__tests__/upgrade.olam-tag.test.js.map +1 -1
  15. package/dist/commands/__tests__/upgrade.recreate.test.js +1 -13
  16. package/dist/commands/__tests__/upgrade.recreate.test.js.map +1 -1
  17. package/dist/commands/__tests__/upgrade.rollback.test.js +1 -21
  18. package/dist/commands/__tests__/upgrade.rollback.test.js.map +1 -1
  19. package/dist/commands/__tests__/upgrade.smoke.test.js +9 -23
  20. package/dist/commands/__tests__/upgrade.smoke.test.js.map +1 -1
  21. package/dist/commands/__tests__/upgrade.swap.test.js +1 -22
  22. package/dist/commands/__tests__/upgrade.swap.test.js.map +1 -1
  23. package/dist/commands/auth.d.ts.map +1 -1
  24. package/dist/commands/auth.js +15 -38
  25. package/dist/commands/auth.js.map +1 -1
  26. package/dist/commands/bootstrap.d.ts +2 -0
  27. package/dist/commands/bootstrap.d.ts.map +1 -1
  28. package/dist/commands/bootstrap.js +3 -3
  29. package/dist/commands/bootstrap.js.map +1 -1
  30. package/dist/commands/create.d.ts.map +1 -1
  31. package/dist/commands/create.js +1 -9
  32. package/dist/commands/create.js.map +1 -1
  33. package/dist/commands/services.d.ts +39 -0
  34. package/dist/commands/services.d.ts.map +1 -0
  35. package/dist/commands/services.js +220 -0
  36. package/dist/commands/services.js.map +1 -0
  37. package/dist/commands/upgrade.d.ts +11 -12
  38. package/dist/commands/upgrade.d.ts.map +1 -1
  39. package/dist/commands/upgrade.js +81 -6
  40. package/dist/commands/upgrade.js.map +1 -1
  41. package/dist/image-digests.json +4 -3
  42. package/dist/index.js +1013 -1029
  43. package/dist/index.js.map +1 -1
  44. package/dist/mcp-server.js +310 -372
  45. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -460,8 +460,8 @@ var init_parseUtil = __esm({
460
460
  init_errors();
461
461
  init_en();
462
462
  makeIssue = (params) => {
463
- const { data, path: path45, errorMaps, issueData } = params;
464
- const fullPath = [...path45, ...issueData.path || []];
463
+ const { data, path: path44, errorMaps, issueData } = params;
464
+ const fullPath = [...path44, ...issueData.path || []];
465
465
  const fullIssue = {
466
466
  ...issueData,
467
467
  path: fullPath
@@ -769,11 +769,11 @@ var init_types = __esm({
769
769
  init_parseUtil();
770
770
  init_util();
771
771
  ParseInputLazyPath = class {
772
- constructor(parent, value, path45, key) {
772
+ constructor(parent, value, path44, key) {
773
773
  this._cachedPath = [];
774
774
  this.parent = parent;
775
775
  this.data = value;
776
- this._path = path45;
776
+ this._path = path44;
777
777
  this._key = key;
778
778
  }
779
779
  get path() {
@@ -4254,7 +4254,7 @@ import YAML from "yaml";
4254
4254
  function bootstrapStepCmd(entry) {
4255
4255
  return typeof entry === "string" ? entry : entry.cmd;
4256
4256
  }
4257
- function refineForbiddenKeys(value, path45, ctx, rejectSource) {
4257
+ function refineForbiddenKeys(value, path44, ctx, rejectSource) {
4258
4258
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
4259
4259
  return;
4260
4260
  }
@@ -4262,12 +4262,12 @@ function refineForbiddenKeys(value, path45, ctx, rejectSource) {
4262
4262
  if (FORBIDDEN_KEYS.has(key)) {
4263
4263
  ctx.addIssue({
4264
4264
  code: external_exports.ZodIssueCode.custom,
4265
- path: [...path45, key],
4265
+ path: [...path44, key],
4266
4266
  message: `forbidden key "${key}" (prototype-pollution surface)`
4267
4267
  });
4268
4268
  continue;
4269
4269
  }
4270
- if (rejectSource && path45.length === 0 && key === "source") {
4270
+ if (rejectSource && path44.length === 0 && key === "source") {
4271
4271
  ctx.addIssue({
4272
4272
  code: external_exports.ZodIssueCode.custom,
4273
4273
  path: ["source"],
@@ -4275,21 +4275,21 @@ function refineForbiddenKeys(value, path45, ctx, rejectSource) {
4275
4275
  });
4276
4276
  continue;
4277
4277
  }
4278
- refineForbiddenKeys(value[key], [...path45, key], ctx, false);
4278
+ refineForbiddenKeys(value[key], [...path44, key], ctx, false);
4279
4279
  }
4280
4280
  }
4281
- function rejectForbiddenKeys(value, path45, rejectSource) {
4281
+ function rejectForbiddenKeys(value, path44, rejectSource) {
4282
4282
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
4283
4283
  return;
4284
4284
  }
4285
4285
  for (const key of Object.keys(value)) {
4286
4286
  if (FORBIDDEN_KEYS.has(key)) {
4287
- throw new Error(`[manifest] ${path45}: forbidden key "${key}" (prototype-pollution surface)`);
4287
+ throw new Error(`[manifest] ${path44}: forbidden key "${key}" (prototype-pollution surface)`);
4288
4288
  }
4289
4289
  if (rejectSource && key === "source") {
4290
- throw new Error(`[manifest] ${path45}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
4290
+ throw new Error(`[manifest] ${path44}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
4291
4291
  }
4292
- rejectForbiddenKeys(value[key], `${path45}.${key}`, false);
4292
+ rejectForbiddenKeys(value[key], `${path44}.${key}`, false);
4293
4293
  }
4294
4294
  }
4295
4295
  function unknownTopLevelKeys(parsed) {
@@ -4604,7 +4604,22 @@ function isSecureOrLocalhost(value) {
4604
4604
  return false;
4605
4605
  return parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1" || parsed.hostname === "[::1]" || parsed.hostname === "::1";
4606
4606
  }
4607
- var repoTypeSchema, envSetupSchema, EntitledMcpsSchema, RepoConfigSchema, ServiceConfigSchema, sshHostSchema, computeProviderType, stackImageSchema, computeProvidersSchema, ComputeConfigSchema, CostConfigSchema, DashboardConfigSchema, PleriConfigSchema, authModeSchema, AuthConfigSchema, DevboxRegistrySchema, DevboxImageSelectorSchema, DevboxConfigSchema, WorldsDefaultSchema, OlamConfigSchema;
4607
+ function inferRegistryProvider(prefix) {
4608
+ if (!prefix)
4609
+ return void 0;
4610
+ const head = prefix.split("/")[0] ?? "";
4611
+ if (!head.includes(".") && !head.includes(":"))
4612
+ return "dockerhub";
4613
+ if (head === "ghcr.io")
4614
+ return "ghcr";
4615
+ if (head === "docker.io")
4616
+ return "dockerhub";
4617
+ if (head === "gcr.io" || head.endsWith("-docker.pkg.dev") || head.endsWith(".pkg.dev")) {
4618
+ return "gar";
4619
+ }
4620
+ return void 0;
4621
+ }
4622
+ var repoTypeSchema, envSetupSchema, EntitledMcpsSchema, RepoConfigSchema, ServiceConfigSchema, sshHostSchema, computeProviderType, stackImageSchema, computeProvidersSchema, ComputeConfigSchema, CostConfigSchema, DashboardConfigSchema, PleriConfigSchema, authModeSchema, AuthConfigSchema, DevboxRegistryProviderSchema, DevboxRegistrySchema, DevboxImageSelectorSchema, DevboxConfigSchema, WorldsDefaultSchema, OlamConfigSchema;
4608
4623
  var init_schema2 = __esm({
4609
4624
  "../core/dist/config/schema.js"() {
4610
4625
  "use strict";
@@ -4740,19 +4755,54 @@ var init_schema2 = __esm({
4740
4755
  mode: authModeSchema.default("oauth"),
4741
4756
  autoInject: external_exports.boolean().default(true).describe("Copy host credentials into world at creation. Set false to use browser OAuth instead.")
4742
4757
  });
4758
+ DevboxRegistryProviderSchema = external_exports.enum(["ghcr", "gar", "dockerhub"]);
4743
4759
  DevboxRegistrySchema = external_exports.object({
4744
4760
  /**
4745
4761
  * Fully-qualified registry prefix (no trailing slash), e.g.
4746
- * "ghcr.io/<org>/olam-devbox". When set without per-tag overrides, ALL
4747
- * `olam-devbox:*` lookups are rewritten to `<prefix>:<tag>`.
4762
+ * "ghcr.io/<org>/olam-devbox" or
4763
+ * "us-central1-docker.pkg.dev/<gcp-project>/<repo>/olam-devbox".
4764
+ * When set without per-tag overrides, ALL `olam-devbox:*` lookups are
4765
+ * rewritten to `<prefix>:<tag>`.
4748
4766
  */
4749
4767
  prefix: external_exports.string().optional(),
4768
+ /**
4769
+ * Registry provider. Optional — inferred from `prefix` hostname when
4770
+ * omitted. Set explicitly to assert which provider the consumer intends
4771
+ * (a mismatch with `prefix` is a config error, not silent acceptance).
4772
+ */
4773
+ provider: DevboxRegistryProviderSchema.optional(),
4750
4774
  /**
4751
4775
  * Per-tag overrides. Wins over `prefix` when both are set. Use this when
4752
4776
  * different image tags live in different registries, or when a few tags
4753
4777
  * are local-only.
4754
4778
  */
4755
4779
  tags: external_exports.record(external_exports.string(), external_exports.string()).optional().default({})
4780
+ }).superRefine((reg, ctx) => {
4781
+ if (reg.provider && !reg.prefix) {
4782
+ ctx.addIssue({
4783
+ code: external_exports.ZodIssueCode.custom,
4784
+ path: ["prefix"],
4785
+ message: `devbox.registry.provider was set to "${reg.provider}" but no prefix was declared. Either drop the provider field or add a prefix like "<host>/<owner>/olam-devbox".`
4786
+ });
4787
+ return;
4788
+ }
4789
+ if (!reg.prefix)
4790
+ return;
4791
+ const inferred = inferRegistryProvider(reg.prefix);
4792
+ if (reg.provider && inferred && reg.provider !== inferred) {
4793
+ ctx.addIssue({
4794
+ code: external_exports.ZodIssueCode.custom,
4795
+ path: ["provider"],
4796
+ message: `devbox.registry.provider "${reg.provider}" does not match prefix "${reg.prefix}" (inferred "${inferred}" from hostname). Fix the prefix host or drop the provider field.`
4797
+ });
4798
+ }
4799
+ if (reg.provider && !inferred) {
4800
+ ctx.addIssue({
4801
+ code: external_exports.ZodIssueCode.custom,
4802
+ path: ["prefix"],
4803
+ message: `devbox.registry.prefix "${reg.prefix}" hostname is not recognised \u2014 provider "${reg.provider}" cannot be cross-checked. Recognised hosts: ghcr.io, *-docker.pkg.dev, gcr.io, docker.io, or a bare "owner/repo" (Docker Hub default).`
4804
+ });
4805
+ }
4756
4806
  });
4757
4807
  DevboxImageSelectorSchema = external_exports.object({
4758
4808
  /** Bare tag the resolver feeds to the registry (e.g. "rails-monorepo"). */
@@ -5230,8 +5280,8 @@ var init_client = __esm({
5230
5280
  throw new Error(`failed to report rate-limit for ${accountId} (HTTP ${res.status})`);
5231
5281
  }
5232
5282
  }
5233
- async request(method, path45, body, attempt = 0) {
5234
- const url = `${this.baseUrl}${path45}`;
5283
+ async request(method, path44, body, attempt = 0) {
5284
+ const url = `${this.baseUrl}${path44}`;
5235
5285
  const controller = new AbortController();
5236
5286
  const timer = setTimeout(() => controller.abort(), this.timeoutMs);
5237
5287
  const headers = {};
@@ -5249,7 +5299,7 @@ var init_client = __esm({
5249
5299
  } catch (err) {
5250
5300
  if (attempt < RETRY_COUNT && isTransient(err)) {
5251
5301
  await sleep(RETRY_BACKOFF_MS * (attempt + 1));
5252
- return this.request(method, path45, body, attempt + 1);
5302
+ return this.request(method, path44, body, attempt + 1);
5253
5303
  }
5254
5304
  throw err;
5255
5305
  } finally {
@@ -6728,8 +6778,8 @@ var init_provider3 = __esm({
6728
6778
  // -----------------------------------------------------------------------
6729
6779
  // Internal fetch helper
6730
6780
  // -----------------------------------------------------------------------
6731
- async request(path45, method, body) {
6732
- const url = `${this.config.workerUrl}${path45}`;
6781
+ async request(path44, method, body) {
6782
+ const url = `${this.config.workerUrl}${path44}`;
6733
6783
  const bearer = await this.config.mintToken();
6734
6784
  const headers = {
6735
6785
  Authorization: `Bearer ${bearer}`
@@ -7519,192 +7569,87 @@ var init_hooks_config = __esm({
7519
7569
  }
7520
7570
  });
7521
7571
 
7522
- // ../core/dist/world/merge-settings.js
7523
- import * as fs12 from "node:fs";
7524
- import * as path13 from "node:path";
7525
- import * as crypto2 from "node:crypto";
7526
- function mergeHomeSettingsJson(filePath, options) {
7527
- let settings;
7528
- try {
7529
- settings = readSettings(filePath);
7530
- } catch (err) {
7531
- throw new Error(`merge-settings: failed to parse existing settings.json: ${err?.message ?? err}`);
7532
- }
7533
- let changed = false;
7534
- if (options.ensureHook) {
7535
- const { stage, sentinel, entry } = options.ensureHook;
7536
- if (!settings.hooks || typeof settings.hooks !== "object") {
7537
- settings = { ...settings, hooks: {} };
7538
- changed = true;
7539
- }
7540
- const hooks = settings.hooks;
7541
- if (!Array.isArray(hooks[stage])) {
7542
- settings = {
7543
- ...settings,
7544
- hooks: { ...hooks, [stage]: [] }
7545
- };
7546
- changed = true;
7547
- }
7548
- const stageArr = settings.hooks[stage];
7549
- if (isHookSentinelPresent(stageArr, sentinel)) {
7550
- if (!changed) {
7551
- return { status: "already-present", message: `hook already present at ${filePath}` };
7552
- }
7553
- } else {
7554
- settings = {
7555
- ...settings,
7556
- hooks: {
7557
- ...settings.hooks,
7558
- [stage]: [...stageArr, entry]
7559
- }
7560
- };
7561
- changed = true;
7562
- }
7563
- }
7564
- if (options.env) {
7565
- const existingEnv = settings.env && typeof settings.env === "object" ? settings.env : {};
7566
- const mergedEnv = { ...existingEnv, ...options.env };
7567
- const sameKeys = Object.keys(mergedEnv).length === Object.keys(existingEnv).length && Object.keys(mergedEnv).every((k) => existingEnv[k] === mergedEnv[k]);
7568
- if (!sameKeys) {
7569
- settings = { ...settings, env: mergedEnv };
7570
- changed = true;
7571
- }
7572
- }
7573
- if (!changed) {
7574
- return { status: "no-op", message: `no change needed at ${filePath}` };
7575
- }
7576
- try {
7577
- atomicWriteJson(filePath, settings);
7578
- } catch (err) {
7579
- throw new Error(`merge-settings: failed to write settings.json: ${err?.message ?? err}`);
7580
- }
7581
- return { status: "installed", message: `settings.json updated at ${filePath}` };
7582
- }
7583
- function readSettings(filePath) {
7584
- if (!fs12.existsSync(filePath)) {
7585
- return {};
7586
- }
7587
- const raw = fs12.readFileSync(filePath, "utf-8");
7588
- if (!raw.trim())
7589
- return {};
7590
- return JSON.parse(raw);
7591
- }
7592
- function isHookSentinelPresent(matchers, sentinel) {
7593
- for (const matcher of matchers) {
7594
- if (typeof matcher?.command === "string" && matcher.command.includes(sentinel)) {
7595
- return true;
7596
- }
7597
- if (Array.isArray(matcher?.hooks)) {
7598
- for (const h of matcher.hooks) {
7599
- if (typeof h?.command === "string" && h.command.includes(sentinel)) {
7600
- return true;
7601
- }
7602
- }
7603
- }
7604
- }
7605
- return false;
7606
- }
7607
- function atomicWriteJson(filePath, data) {
7608
- const dir = path13.dirname(filePath);
7609
- fs12.mkdirSync(dir, { recursive: true });
7610
- const rand = crypto2.randomBytes(6).toString("hex");
7611
- const tmp = `${filePath}.tmp.${process.pid}.${rand}`;
7612
- const json = JSON.stringify(data, null, 2) + "\n";
7613
- fs12.writeFileSync(tmp, json, { mode: 420 });
7614
- fs12.renameSync(tmp, filePath);
7615
- }
7616
- var init_merge_settings = __esm({
7617
- "../core/dist/world/merge-settings.js"() {
7618
- "use strict";
7619
- }
7620
- });
7621
-
7622
7572
  // ../core/dist/world/env-setup.js
7623
- import * as crypto3 from "node:crypto";
7624
- import * as fs13 from "node:fs";
7573
+ import * as crypto2 from "node:crypto";
7574
+ import * as fs12 from "node:fs";
7625
7575
  import * as os8 from "node:os";
7626
- import * as path14 from "node:path";
7576
+ import * as path13 from "node:path";
7627
7577
  import { globSync } from "node:fs";
7628
7578
  function copyClaudeConfig(workspacePath, homeDir, configCtx) {
7629
- const sourceClaudeDir = path14.join(homeDir ?? os8.homedir(), ".claude");
7630
- const destClaudeDir = path14.join(workspacePath, ".claude-host-config");
7579
+ const sourceClaudeDir = path13.join(homeDir ?? os8.homedir(), ".claude");
7580
+ const destClaudeDir = path13.join(workspacePath, ".claude-host-config");
7631
7581
  void configCtx;
7632
- if (!fs13.existsSync(sourceClaudeDir))
7582
+ if (!fs12.existsSync(sourceClaudeDir))
7633
7583
  return;
7634
- fs13.mkdirSync(destClaudeDir, { recursive: true });
7635
- const settingsPath = path14.join(sourceClaudeDir, "settings.json");
7584
+ fs12.mkdirSync(destClaudeDir, { recursive: true });
7585
+ const settingsPath = path13.join(sourceClaudeDir, "settings.json");
7636
7586
  let settings = {};
7637
- if (fs13.existsSync(settingsPath)) {
7587
+ if (fs12.existsSync(settingsPath)) {
7638
7588
  try {
7639
- settings = JSON.parse(fs13.readFileSync(settingsPath, "utf-8"));
7589
+ settings = JSON.parse(fs12.readFileSync(settingsPath, "utf-8"));
7640
7590
  delete settings["hooks"];
7641
7591
  } catch {
7642
7592
  }
7643
7593
  }
7644
7594
  const hooksConfig = generateHooksConfig(DEFAULT_HOOK_SERVER_URL);
7645
7595
  settings["hooks"] = hooksConfig["hooks"];
7646
- fs13.writeFileSync(path14.join(destClaudeDir, "settings.json"), JSON.stringify(settings, null, 2));
7647
- const claudeMdPath = path14.join(sourceClaudeDir, "CLAUDE.md");
7648
- if (fs13.existsSync(claudeMdPath)) {
7649
- fs13.copyFileSync(claudeMdPath, path14.join(destClaudeDir, "CLAUDE.md"));
7596
+ fs12.writeFileSync(path13.join(destClaudeDir, "settings.json"), JSON.stringify(settings, null, 2));
7597
+ const claudeMdPath = path13.join(sourceClaudeDir, "CLAUDE.md");
7598
+ if (fs12.existsSync(claudeMdPath)) {
7599
+ fs12.copyFileSync(claudeMdPath, path13.join(destClaudeDir, "CLAUDE.md"));
7650
7600
  }
7651
- const rulesDir = path14.join(sourceClaudeDir, "rules");
7652
- if (fs13.existsSync(rulesDir)) {
7653
- copyDirRecursive(rulesDir, path14.join(destClaudeDir, "rules"));
7601
+ const rulesDir = path13.join(sourceClaudeDir, "rules");
7602
+ if (fs12.existsSync(rulesDir)) {
7603
+ copyDirRecursive(rulesDir, path13.join(destClaudeDir, "rules"));
7654
7604
  }
7655
- const agentsDir = path14.join(sourceClaudeDir, "agents");
7656
- if (fs13.existsSync(agentsDir)) {
7657
- copyDirRecursive(agentsDir, path14.join(destClaudeDir, "agents"));
7605
+ const agentsDir = path13.join(sourceClaudeDir, "agents");
7606
+ if (fs12.existsSync(agentsDir)) {
7607
+ copyDirRecursive(agentsDir, path13.join(destClaudeDir, "agents"));
7658
7608
  }
7659
- const pluginsDir = path14.join(sourceClaudeDir, "plugins");
7660
- if (fs13.existsSync(pluginsDir)) {
7661
- copyDirRecursive(pluginsDir, path14.join(destClaudeDir, "plugins"), 0, SKIP_FILES);
7609
+ const pluginsDir = path13.join(sourceClaudeDir, "plugins");
7610
+ if (fs12.existsSync(pluginsDir)) {
7611
+ copyDirRecursive(pluginsDir, path13.join(destClaudeDir, "plugins"), 0, SKIP_FILES);
7662
7612
  }
7663
- const skillsDir = path14.join(sourceClaudeDir, "skills");
7664
- if (fs13.existsSync(skillsDir)) {
7665
- copyDirRecursive(skillsDir, path14.join(destClaudeDir, "skills"));
7613
+ const skillsDir = path13.join(sourceClaudeDir, "skills");
7614
+ if (fs12.existsSync(skillsDir)) {
7615
+ copyDirRecursive(skillsDir, path13.join(destClaudeDir, "skills"));
7666
7616
  }
7667
- const scriptsDir = path14.join(sourceClaudeDir, "scripts");
7668
- if (fs13.existsSync(scriptsDir)) {
7669
- copyDirRecursive(scriptsDir, path14.join(destClaudeDir, "scripts"));
7617
+ const scriptsDir = path13.join(sourceClaudeDir, "scripts");
7618
+ if (fs12.existsSync(scriptsDir)) {
7619
+ copyDirRecursive(scriptsDir, path13.join(destClaudeDir, "scripts"));
7670
7620
  }
7671
7621
  applyProjectClaudeOverlay(workspacePath, destClaudeDir);
7672
7622
  writeStrippedMcpServersSnapshot(homeDir ?? os8.homedir(), workspacePath, destClaudeDir);
7673
- if (configCtx != null && configCtx.worlds_default?.agent_teams_enabled !== false) {
7674
- mergeHomeSettingsJson(path14.join(destClaudeDir, "settings.json"), {
7675
- env: { CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: "1" }
7676
- });
7677
- }
7678
7623
  }
7679
7624
  function applyProjectClaudeOverlay(workspacePath, destClaudeDir) {
7680
- const projectClaudeDir = path14.join(workspacePath, ".claude");
7681
- if (!fs13.existsSync(projectClaudeDir))
7625
+ const projectClaudeDir = path13.join(workspacePath, ".claude");
7626
+ if (!fs12.existsSync(projectClaudeDir))
7682
7627
  return;
7683
- const projectSettingsPath = path14.join(projectClaudeDir, "settings.json");
7684
- const destSettingsPath = path14.join(destClaudeDir, "settings.json");
7685
- if (fs13.existsSync(projectSettingsPath)) {
7628
+ const projectSettingsPath = path13.join(projectClaudeDir, "settings.json");
7629
+ const destSettingsPath = path13.join(destClaudeDir, "settings.json");
7630
+ if (fs12.existsSync(projectSettingsPath)) {
7686
7631
  try {
7687
- const projectSettings = JSON.parse(fs13.readFileSync(projectSettingsPath, "utf-8"));
7632
+ const projectSettings = JSON.parse(fs12.readFileSync(projectSettingsPath, "utf-8"));
7688
7633
  delete projectSettings["hooks"];
7689
- const existing = fs13.existsSync(destSettingsPath) ? JSON.parse(fs13.readFileSync(destSettingsPath, "utf-8")) : {};
7634
+ const existing = fs12.existsSync(destSettingsPath) ? JSON.parse(fs12.readFileSync(destSettingsPath, "utf-8")) : {};
7690
7635
  const merged = { ...existing, ...projectSettings, hooks: existing["hooks"] };
7691
- fs13.writeFileSync(destSettingsPath, JSON.stringify(merged, null, 2));
7636
+ fs12.writeFileSync(destSettingsPath, JSON.stringify(merged, null, 2));
7692
7637
  } catch {
7693
7638
  }
7694
7639
  }
7695
- const projectClaudeMd = path14.join(projectClaudeDir, "CLAUDE.md");
7696
- if (fs13.existsSync(projectClaudeMd)) {
7697
- fs13.copyFileSync(projectClaudeMd, path14.join(destClaudeDir, "CLAUDE.md"));
7640
+ const projectClaudeMd = path13.join(projectClaudeDir, "CLAUDE.md");
7641
+ if (fs12.existsSync(projectClaudeMd)) {
7642
+ fs12.copyFileSync(projectClaudeMd, path13.join(destClaudeDir, "CLAUDE.md"));
7698
7643
  }
7699
- const projectAgentsMd = path14.join(projectClaudeDir, "AGENTS.md");
7700
- if (fs13.existsSync(projectAgentsMd)) {
7701
- fs13.copyFileSync(projectAgentsMd, path14.join(destClaudeDir, "AGENTS.md"));
7644
+ const projectAgentsMd = path13.join(projectClaudeDir, "AGENTS.md");
7645
+ if (fs12.existsSync(projectAgentsMd)) {
7646
+ fs12.copyFileSync(projectAgentsMd, path13.join(destClaudeDir, "AGENTS.md"));
7702
7647
  }
7703
7648
  for (const subdir of ["rules", "agents", "plugins", "skills", "scripts"]) {
7704
- const projectSubdir = path14.join(projectClaudeDir, subdir);
7705
- if (fs13.existsSync(projectSubdir)) {
7649
+ const projectSubdir = path13.join(projectClaudeDir, subdir);
7650
+ if (fs12.existsSync(projectSubdir)) {
7706
7651
  const skip = subdir === "plugins" ? SKIP_FILES : /* @__PURE__ */ new Set();
7707
- copyDirRecursive(projectSubdir, path14.join(destClaudeDir, subdir), 0, skip);
7652
+ copyDirRecursive(projectSubdir, path13.join(destClaudeDir, subdir), 0, skip);
7708
7653
  }
7709
7654
  }
7710
7655
  }
@@ -7734,8 +7679,8 @@ function stripMcpServers(mcpServers) {
7734
7679
  return out;
7735
7680
  }
7736
7681
  function writeStrippedMcpServersSnapshot(homeDir, workspacePath, destClaudeDir) {
7737
- const hostMcpServers = readMcpServersFromFile(path14.join(homeDir, ".claude.json"));
7738
- const projectMcpServers = readMcpServersFromFile(path14.join(workspacePath, ".mcp.json"));
7682
+ const hostMcpServers = readMcpServersFromFile(path13.join(homeDir, ".claude.json"));
7683
+ const projectMcpServers = readMcpServersFromFile(path13.join(workspacePath, ".mcp.json"));
7739
7684
  if (Object.keys(hostMcpServers).length === 0 && Object.keys(projectMcpServers).length === 0) {
7740
7685
  return;
7741
7686
  }
@@ -7744,11 +7689,11 @@ function writeStrippedMcpServersSnapshot(homeDir, workspacePath, destClaudeDir)
7744
7689
  ...stripMcpServers(projectMcpServers)
7745
7690
  };
7746
7691
  const output = { mcpServers: stripped };
7747
- fs13.writeFileSync(path14.join(destClaudeDir, ".claude.json"), JSON.stringify(output, null, 2), { mode: 384 });
7692
+ fs12.writeFileSync(path13.join(destClaudeDir, ".claude.json"), JSON.stringify(output, null, 2), { mode: 384 });
7748
7693
  }
7749
7694
  function writeWorldEntitlementsJson(workspacePath, configCtx) {
7750
- const olamDir = path14.join(workspacePath, ".olam");
7751
- fs13.mkdirSync(olamDir, { recursive: true });
7695
+ const olamDir = path13.join(workspacePath, ".olam");
7696
+ fs12.mkdirSync(olamDir, { recursive: true });
7752
7697
  const resolvedRepos = configCtx.repos.map((repo) => {
7753
7698
  const repoEntitlement = repo;
7754
7699
  return {
@@ -7762,14 +7707,14 @@ function writeWorldEntitlementsJson(workspacePath, configCtx) {
7762
7707
  worlds_default: configCtx.worlds_default,
7763
7708
  repos: resolvedRepos
7764
7709
  };
7765
- const filePath = path14.join(olamDir, "world-entitlements.json");
7766
- fs13.writeFileSync(filePath, JSON.stringify(resolved, null, 2), { mode: 420 });
7710
+ const filePath = path13.join(olamDir, "world-entitlements.json");
7711
+ fs12.writeFileSync(filePath, JSON.stringify(resolved, null, 2), { mode: 420 });
7767
7712
  }
7768
7713
  function readMcpServersFromFile(filePath) {
7769
- if (!fs13.existsSync(filePath))
7714
+ if (!fs12.existsSync(filePath))
7770
7715
  return {};
7771
7716
  try {
7772
- const raw = fs13.readFileSync(filePath, "utf-8");
7717
+ const raw = fs12.readFileSync(filePath, "utf-8");
7773
7718
  if (!raw.trim())
7774
7719
  return {};
7775
7720
  const parsed = JSON.parse(raw);
@@ -7784,8 +7729,8 @@ function readMcpServersFromFile(filePath) {
7784
7729
  function copyDirRecursive(src, dest, depth = 0, skipFiles = /* @__PURE__ */ new Set()) {
7785
7730
  if (depth > 10)
7786
7731
  return;
7787
- fs13.mkdirSync(dest, { recursive: true });
7788
- for (const entry of fs13.readdirSync(src, { withFileTypes: true })) {
7732
+ fs12.mkdirSync(dest, { recursive: true });
7733
+ for (const entry of fs12.readdirSync(src, { withFileTypes: true })) {
7789
7734
  const { name } = entry;
7790
7735
  if (skipFiles.has(name))
7791
7736
  continue;
@@ -7795,12 +7740,12 @@ function copyDirRecursive(src, dest, depth = 0, skipFiles = /* @__PURE__ */ new
7795
7740
  continue;
7796
7741
  if (entry.isDirectory() && SKIP_DIRS.has(name))
7797
7742
  continue;
7798
- const srcPath = path14.join(src, name);
7799
- const destPath = path14.join(dest, name);
7743
+ const srcPath = path13.join(src, name);
7744
+ const destPath = path13.join(dest, name);
7800
7745
  if (entry.isSymbolicLink()) {
7801
7746
  let stat;
7802
7747
  try {
7803
- stat = fs13.statSync(srcPath);
7748
+ stat = fs12.statSync(srcPath);
7804
7749
  } catch {
7805
7750
  continue;
7806
7751
  }
@@ -7809,12 +7754,12 @@ function copyDirRecursive(src, dest, depth = 0, skipFiles = /* @__PURE__ */ new
7809
7754
  continue;
7810
7755
  copyDirRecursive(srcPath, destPath, depth + 1, skipFiles);
7811
7756
  } else if (stat.isFile()) {
7812
- fs13.copyFileSync(srcPath, destPath);
7757
+ fs12.copyFileSync(srcPath, destPath);
7813
7758
  }
7814
7759
  } else if (entry.isDirectory()) {
7815
7760
  copyDirRecursive(srcPath, destPath, depth + 1, skipFiles);
7816
7761
  } else {
7817
- fs13.copyFileSync(srcPath, destPath);
7762
+ fs12.copyFileSync(srcPath, destPath);
7818
7763
  }
7819
7764
  }
7820
7765
  }
@@ -7952,9 +7897,9 @@ function setupWorldEnv(repos, workspacePath, serviceEnv, crossRepoEnv = {}, conf
7952
7897
  }
7953
7898
  }
7954
7899
  for (const repo of repos) {
7955
- const worktreePath = path14.join(workspacePath, repo.name);
7900
+ const worktreePath = path13.join(workspacePath, repo.name);
7956
7901
  const sourcePath = repo.path;
7957
- if (!sourcePath || !fs13.existsSync(worktreePath))
7902
+ if (!sourcePath || !fs12.existsSync(worktreePath))
7958
7903
  continue;
7959
7904
  const envSetup = repo.env_setup;
7960
7905
  if (!envSetup)
@@ -7973,23 +7918,23 @@ function setupWorldEnv(repos, workspacePath, serviceEnv, crossRepoEnv = {}, conf
7973
7918
  }
7974
7919
  }
7975
7920
  function copyMatchingFiles(sourcePath, destPath, pattern) {
7976
- const fullPattern = path14.join(sourcePath, pattern);
7921
+ const fullPattern = path13.join(sourcePath, pattern);
7977
7922
  if (!pattern.includes("*")) {
7978
- const sourceFile = path14.join(sourcePath, pattern);
7979
- const destFile = path14.join(destPath, pattern);
7980
- if (fs13.existsSync(sourceFile)) {
7981
- fs13.mkdirSync(path14.dirname(destFile), { recursive: true });
7982
- fs13.copyFileSync(sourceFile, destFile);
7923
+ const sourceFile = path13.join(sourcePath, pattern);
7924
+ const destFile = path13.join(destPath, pattern);
7925
+ if (fs12.existsSync(sourceFile)) {
7926
+ fs12.mkdirSync(path13.dirname(destFile), { recursive: true });
7927
+ fs12.copyFileSync(sourceFile, destFile);
7983
7928
  }
7984
7929
  return;
7985
7930
  }
7986
7931
  try {
7987
7932
  const matches2 = globSync(fullPattern);
7988
7933
  for (const match2 of matches2) {
7989
- const relative2 = path14.relative(sourcePath, match2);
7990
- const dest = path14.join(destPath, relative2);
7991
- fs13.mkdirSync(path14.dirname(dest), { recursive: true });
7992
- fs13.copyFileSync(match2, dest);
7934
+ const relative2 = path13.relative(sourcePath, match2);
7935
+ const dest = path13.join(destPath, relative2);
7936
+ fs12.mkdirSync(path13.dirname(dest), { recursive: true });
7937
+ fs12.copyFileSync(match2, dest);
7993
7938
  }
7994
7939
  } catch {
7995
7940
  }
@@ -7997,14 +7942,14 @@ function copyMatchingFiles(sourcePath, destPath, pattern) {
7997
7942
  function generateEnvFromExample(repoPath, overrides) {
7998
7943
  const exampleFiles = [".env.example", ".env.sample", ".env.local.example"];
7999
7944
  for (const exampleName of exampleFiles) {
8000
- const examplePath = path14.join(repoPath, exampleName);
8001
- if (!fs13.existsSync(examplePath))
7945
+ const examplePath = path13.join(repoPath, exampleName);
7946
+ if (!fs12.existsSync(examplePath))
8002
7947
  continue;
8003
7948
  const targetName = exampleName.replace(".example", "").replace(".sample", "");
8004
- const targetPath = path14.join(repoPath, targetName);
8005
- if (fs13.existsSync(targetPath))
7949
+ const targetPath = path13.join(repoPath, targetName);
7950
+ if (fs12.existsSync(targetPath))
8006
7951
  continue;
8007
- const template = fs13.readFileSync(examplePath, "utf-8");
7952
+ const template = fs12.readFileSync(examplePath, "utf-8");
8008
7953
  const generated = template.split("\n").map((line) => {
8009
7954
  const match2 = /^([A-Z_][A-Z0-9_]*)=(.*)$/.exec(line);
8010
7955
  if (match2) {
@@ -8015,13 +7960,13 @@ function generateEnvFromExample(repoPath, overrides) {
8015
7960
  }
8016
7961
  return line;
8017
7962
  }).join("\n");
8018
- fs13.writeFileSync(targetPath, generated);
7963
+ fs12.writeFileSync(targetPath, generated);
8019
7964
  }
8020
7965
  }
8021
7966
  function applyEnvOverrides(repoPath, overrides) {
8022
- const envPath = path14.join(repoPath, ".env");
8023
- if (fs13.existsSync(envPath)) {
8024
- const existing = fs13.readFileSync(envPath, "utf-8");
7967
+ const envPath = path13.join(repoPath, ".env");
7968
+ if (fs12.existsSync(envPath)) {
7969
+ const existing = fs12.readFileSync(envPath, "utf-8");
8025
7970
  const existingKeys = new Set(existing.split("\n").map((l) => l.split("=")[0]?.trim()).filter(Boolean));
8026
7971
  const additions = [];
8027
7972
  for (const [key, value] of Object.entries(overrides)) {
@@ -8030,7 +7975,7 @@ function applyEnvOverrides(repoPath, overrides) {
8030
7975
  }
8031
7976
  }
8032
7977
  if (additions.length > 0) {
8033
- fs13.appendFileSync(envPath, "\n# Olam injected\n" + additions.join("\n") + "\n");
7978
+ fs12.appendFileSync(envPath, "\n# Olam injected\n" + additions.join("\n") + "\n");
8034
7979
  }
8035
7980
  }
8036
7981
  }
@@ -8039,7 +7984,6 @@ var init_env_setup = __esm({
8039
7984
  "../core/dist/world/env-setup.js"() {
8040
7985
  "use strict";
8041
7986
  init_hooks_config();
8042
- init_merge_settings();
8043
7987
  MCP_SERVER_ALLOWLIST = /* @__PURE__ */ new Set([
8044
7988
  "command",
8045
7989
  "args",
@@ -8103,9 +8047,9 @@ var init_env_setup = __esm({
8103
8047
 
8104
8048
  // ../core/dist/world/baseline-diff.js
8105
8049
  import { execFileSync as execFileSync3 } from "node:child_process";
8106
- import * as fs14 from "node:fs";
8050
+ import * as fs13 from "node:fs";
8107
8051
  import * as os9 from "node:os";
8108
- import * as path15 from "node:path";
8052
+ import * as path14 from "node:path";
8109
8053
  function expandHome(p, homedir22) {
8110
8054
  return p.replace(/^~(?=$|\/|\\)/, homedir22());
8111
8055
  }
@@ -8131,9 +8075,9 @@ ${stderr}`;
8131
8075
  function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
8132
8076
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync3(cmd, args, opts));
8133
8077
  const homedir22 = deps.homedir ?? (() => os9.homedir());
8134
- const baselineDir = path15.join(workspacePath, ".olam", "baseline");
8078
+ const baselineDir = path14.join(workspacePath, ".olam", "baseline");
8135
8079
  try {
8136
- fs14.mkdirSync(baselineDir, { recursive: true });
8080
+ fs13.mkdirSync(baselineDir, { recursive: true });
8137
8081
  } catch (err) {
8138
8082
  const msg = err instanceof Error ? err.message : String(err);
8139
8083
  console.warn(`[baseline-diff] mkdir ${baselineDir} failed: ${msg}; reaper will see no baseline at all`);
@@ -8145,9 +8089,9 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
8145
8089
  if (!repo.path)
8146
8090
  continue;
8147
8091
  const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
8148
- const outPath = path15.join(baselineDir, filename);
8092
+ const outPath = path14.join(baselineDir, filename);
8149
8093
  const repoPath = expandHome(repo.path, homedir22);
8150
- if (!fs14.existsSync(repoPath)) {
8094
+ if (!fs13.existsSync(repoPath)) {
8151
8095
  writeBaselineFile(outPath, `# repo: ${repo.name}
8152
8096
  # (skipped: path ${repoPath} does not exist)
8153
8097
  `);
@@ -8214,7 +8158,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
8214
8158
  }
8215
8159
  function writeBaselineFile(outPath, content) {
8216
8160
  try {
8217
- fs14.writeFileSync(outPath, content);
8161
+ fs13.writeFileSync(outPath, content);
8218
8162
  } catch (err) {
8219
8163
  const msg = err instanceof Error ? err.message : String(err);
8220
8164
  console.warn(`[baseline-diff] write to ${outPath} failed: ${msg}`);
@@ -8222,8 +8166,8 @@ function writeBaselineFile(outPath, content) {
8222
8166
  }
8223
8167
  function stripWorktreeEdits(repos, workspacePath) {
8224
8168
  for (const repo of repos) {
8225
- const worktreePath = path15.join(workspacePath, repo.name);
8226
- if (!fs14.existsSync(worktreePath))
8169
+ const worktreePath = path14.join(workspacePath, repo.name);
8170
+ if (!fs13.existsSync(worktreePath))
8227
8171
  continue;
8228
8172
  try {
8229
8173
  execFileSync3("git", ["checkout", "--", "."], {
@@ -8260,12 +8204,12 @@ var init_baseline_diff = __esm({
8260
8204
  });
8261
8205
 
8262
8206
  // ../core/dist/world/context-injection.js
8263
- import * as fs15 from "node:fs";
8264
- import * as path16 from "node:path";
8207
+ import * as fs14 from "node:fs";
8208
+ import * as path15 from "node:path";
8265
8209
  function injectWorldContext(opts) {
8266
8210
  const { world, task, linearTicketId, claudeMdExtra, taskContext, services, pleriPlaneUrl } = opts;
8267
- const claudeDir = path16.join(world.workspacePath, ".claude");
8268
- fs15.mkdirSync(claudeDir, { recursive: true });
8211
+ const claudeDir = path15.join(world.workspacePath, ".claude");
8212
+ fs14.mkdirSync(claudeDir, { recursive: true });
8269
8213
  const sections = [];
8270
8214
  sections.push(`# Olam World: ${world.name}`);
8271
8215
  sections.push("");
@@ -8426,7 +8370,7 @@ function injectWorldContext(opts) {
8426
8370
  sections.push("");
8427
8371
  }
8428
8372
  const content = sections.join("\n");
8429
- fs15.writeFileSync(path16.join(claudeDir, "CLAUDE.md"), content);
8373
+ fs14.writeFileSync(path15.join(claudeDir, "CLAUDE.md"), content);
8430
8374
  }
8431
8375
  function formatTaskSource(ctx) {
8432
8376
  if (ctx.source === "linear" && ctx.ticketId) {
@@ -8440,9 +8384,9 @@ function formatTaskSource(ctx) {
8440
8384
  function hasPlanFile(world) {
8441
8385
  if (world.repos.length === 0)
8442
8386
  return false;
8443
- const plansDir = path16.join(world.workspacePath, world.repos[0], "docs", "plans");
8387
+ const plansDir = path15.join(world.workspacePath, world.repos[0], "docs", "plans");
8444
8388
  try {
8445
- return fs15.existsSync(plansDir) && fs15.readdirSync(plansDir).length > 0;
8389
+ return fs14.existsSync(plansDir) && fs14.readdirSync(plansDir).length > 0;
8446
8390
  } catch {
8447
8391
  return false;
8448
8392
  }
@@ -8687,7 +8631,7 @@ var init_stack_install = __esm({
8687
8631
 
8688
8632
  // ../core/dist/world/stack-image.js
8689
8633
  import { execSync as execSync2 } from "node:child_process";
8690
- import * as crypto4 from "node:crypto";
8634
+ import * as crypto3 from "node:crypto";
8691
8635
  function computeFingerprint(runtimes) {
8692
8636
  const parts = [];
8693
8637
  for (const [runtime, versions] of runtimes) {
@@ -8737,14 +8681,14 @@ function getBaseImageDigest() {
8737
8681
  cachedBaseDigest = digest.replace("sha256:", "").slice(0, 16);
8738
8682
  return cachedBaseDigest;
8739
8683
  } catch {
8740
- cachedBaseDigest = crypto4.createHash("sha256").update("unknown").digest("hex").slice(0, 16);
8684
+ cachedBaseDigest = crypto3.createHash("sha256").update("unknown").digest("hex").slice(0, 16);
8741
8685
  return cachedBaseDigest;
8742
8686
  }
8743
8687
  }
8744
8688
  function sanitizeTag(raw) {
8745
8689
  let tag = raw.toLowerCase().replace(/[^a-z0-9._-]/g, "-");
8746
8690
  if (tag.length > MAX_TAG_LENGTH) {
8747
- const hash = crypto4.createHash("sha256").update(raw).digest("hex").slice(0, 12);
8691
+ const hash = crypto3.createHash("sha256").update(raw).digest("hex").slice(0, 12);
8748
8692
  tag = tag.slice(0, MAX_TAG_LENGTH - 13) + "_" + hash;
8749
8693
  }
8750
8694
  return tag;
@@ -9146,14 +9090,14 @@ var init_secrets_fetcher = __esm({
9146
9090
  });
9147
9091
 
9148
9092
  // ../core/dist/world/olam-yaml.js
9149
- import * as path17 from "node:path";
9093
+ import * as path16 from "node:path";
9150
9094
  import YAML2 from "yaml";
9151
9095
  function enrichReposWithManifests(repos, workspacePath) {
9152
9096
  return repos.map((repo) => {
9153
9097
  if (repo.manifest !== void 0 && repo.manifest !== null) {
9154
9098
  return repo;
9155
9099
  }
9156
- const repoDir = path17.join(workspacePath, repo.name);
9100
+ const repoDir = path16.join(workspacePath, repo.name);
9157
9101
  let manifest = null;
9158
9102
  try {
9159
9103
  manifest = loadRepoManifest(repoDir);
@@ -9174,8 +9118,8 @@ var init_olam_yaml = __esm({
9174
9118
  });
9175
9119
 
9176
9120
  // ../core/dist/policies/loader.js
9177
- import * as fs16 from "node:fs";
9178
- import * as path18 from "node:path";
9121
+ import * as fs15 from "node:fs";
9122
+ import * as path17 from "node:path";
9179
9123
  import { parse as parseYaml3 } from "yaml";
9180
9124
  function parseFrontmatter(content) {
9181
9125
  const match2 = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/m.exec(content);
@@ -9195,20 +9139,20 @@ function toStringArray(v) {
9195
9139
  return v.filter((x) => typeof x === "string");
9196
9140
  }
9197
9141
  function loadPolicies(workspaceRoot) {
9198
- const policiesDir = path18.join(workspaceRoot, ".olam", "policies");
9199
- if (!fs16.existsSync(policiesDir))
9142
+ const policiesDir = path17.join(workspaceRoot, ".olam", "policies");
9143
+ if (!fs15.existsSync(policiesDir))
9200
9144
  return [];
9201
9145
  let files;
9202
9146
  try {
9203
- files = fs16.readdirSync(policiesDir).filter((f) => f.endsWith(".md")).sort();
9147
+ files = fs15.readdirSync(policiesDir).filter((f) => f.endsWith(".md")).sort();
9204
9148
  } catch {
9205
9149
  return [];
9206
9150
  }
9207
9151
  const policies = [];
9208
9152
  for (const file of files) {
9209
- const filePath = path18.join(policiesDir, file);
9153
+ const filePath = path17.join(policiesDir, file);
9210
9154
  try {
9211
- const content = fs16.readFileSync(filePath, "utf8");
9155
+ const content = fs15.readFileSync(filePath, "utf8");
9212
9156
  const parsed = parseFrontmatter(content);
9213
9157
  if (!parsed) {
9214
9158
  console.warn(`[policies] skipping ${file}: no valid frontmatter block`);
@@ -9283,7 +9227,7 @@ async function startSupervisedApps(containerName, worldId, repos, exec, options
9283
9227
  const probeTimeoutMs = options.probeTimeoutMs ?? 3e4;
9284
9228
  const probeIntervalMs = options.probeIntervalMs ?? 1e3;
9285
9229
  const clock = options.clock ?? Date.now;
9286
- const sleep3 = options.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
9230
+ const sleep4 = options.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
9287
9231
  for (const repo of repos) {
9288
9232
  if (isPortBound(exec, containerName, repo.hostPort)) {
9289
9233
  throw new PortInUseError(repo.hostPort, repo.name, repo.manifestPath);
@@ -9308,7 +9252,7 @@ async function startSupervisedApps(containerName, worldId, repos, exec, options
9308
9252
  probeTimeoutMs,
9309
9253
  probeIntervalMs,
9310
9254
  clock,
9311
- sleep: sleep3
9255
+ sleep: sleep4
9312
9256
  })));
9313
9257
  return {
9314
9258
  sessionName,
@@ -9372,7 +9316,6 @@ var manager_exports = {};
9372
9316
  __export(manager_exports, {
9373
9317
  AuthPreflightError: () => AuthPreflightError,
9374
9318
  BotIdentityError: () => BotIdentityError,
9375
- RepoSelectionRequiredError: () => RepoSelectionRequiredError,
9376
9319
  WorkspaceNotFoundError: () => WorkspaceNotFoundError,
9377
9320
  WorldManager: () => WorldManager,
9378
9321
  buildManifestRuntimeForTest: () => buildManifestRuntime,
@@ -9381,11 +9324,11 @@ __export(manager_exports, {
9381
9324
  planManifestPipeline: () => planManifestPipeline,
9382
9325
  runManifestRuntime: () => runManifestRuntime
9383
9326
  });
9384
- import * as crypto5 from "node:crypto";
9327
+ import * as crypto4 from "node:crypto";
9385
9328
  import { execSync as execSync4 } from "node:child_process";
9386
- import * as fs17 from "node:fs";
9329
+ import * as fs16 from "node:fs";
9387
9330
  import * as os10 from "node:os";
9388
- import * as path19 from "node:path";
9331
+ import * as path18 from "node:path";
9389
9332
  import YAML3 from "yaml";
9390
9333
  function getTokenScopes(ghToken, _exec = execSync4) {
9391
9334
  try {
@@ -9724,7 +9667,7 @@ function buildManifestRuntime(worldId, repos) {
9724
9667
  }
9725
9668
  return { worldId, repos: runtimeRepos };
9726
9669
  }
9727
- var BotIdentityError, ADJECTIVES, NOUNS, AuthPreflightError, WorkspaceNotFoundError, RepoSelectionRequiredError, WorldManager;
9670
+ var BotIdentityError, ADJECTIVES, NOUNS, AuthPreflightError, WorkspaceNotFoundError, WorldManager;
9728
9671
  var init_manager = __esm({
9729
9672
  "../core/dist/world/manager.js"() {
9730
9673
  "use strict";
@@ -9773,15 +9716,6 @@ var init_manager = __esm({
9773
9716
  this.name = "WorkspaceNotFoundError";
9774
9717
  }
9775
9718
  };
9776
- RepoSelectionRequiredError = class extends Error {
9777
- availableRepos;
9778
- constructor(availableRepos) {
9779
- const list = availableRepos.length > 0 ? availableRepos.join(", ") : "(none configured)";
9780
- super(`--repos or --workspace is required. Available repos: ${list}. Pick the subset you actually want \u2014 implicit "all repos" was removed to prevent accidental multi-repo bootstraps.`);
9781
- this.availableRepos = availableRepos;
9782
- this.name = "RepoSelectionRequiredError";
9783
- }
9784
- };
9785
9719
  WorldManager = class {
9786
9720
  config;
9787
9721
  provider;
@@ -9809,7 +9743,7 @@ var init_manager = __esm({
9809
9743
  }
9810
9744
  }
9811
9745
  const worldId = generateWorldId();
9812
- const workspacePath = path19.join(os10.homedir(), ".olam", "worlds", worldId);
9746
+ const workspacePath = path18.join(os10.homedir(), ".olam", "worlds", worldId);
9813
9747
  const portOffset = this.registry.getNextPortOffset();
9814
9748
  const branch = opts.branchName ?? `olam/${worldId}`;
9815
9749
  const repos = this.resolveReposWithWorkspace(opts);
@@ -9866,37 +9800,37 @@ var init_manager = __esm({
9866
9800
  if (!repo.path)
9867
9801
  continue;
9868
9802
  const sourceRoot = repo.path.replace(/^~/, os10.homedir());
9869
- const worktreeRoot = path19.join(workspacePath, repo.name);
9870
- if (!fs17.existsSync(sourceRoot) || !fs17.existsSync(worktreeRoot))
9803
+ const worktreeRoot = path18.join(workspacePath, repo.name);
9804
+ if (!fs16.existsSync(sourceRoot) || !fs16.existsSync(worktreeRoot))
9871
9805
  continue;
9872
9806
  let copied = 0;
9873
9807
  for (const pattern of RUNTIME_FILE_PATTERNS) {
9874
9808
  const matches2 = [];
9875
9809
  if (pattern.includes("*")) {
9876
- const [dir, glob] = [path19.dirname(pattern), path19.basename(pattern)];
9877
- const sourceDir = path19.join(sourceRoot, dir);
9878
- if (fs17.existsSync(sourceDir)) {
9810
+ const [dir, glob] = [path18.dirname(pattern), path18.basename(pattern)];
9811
+ const sourceDir = path18.join(sourceRoot, dir);
9812
+ if (fs16.existsSync(sourceDir)) {
9879
9813
  const ext2 = glob.replace(/^\*+/, "");
9880
9814
  try {
9881
- for (const entry of fs17.readdirSync(sourceDir)) {
9815
+ for (const entry of fs16.readdirSync(sourceDir)) {
9882
9816
  if (ext2 === "" || entry.endsWith(ext2))
9883
- matches2.push(path19.join(dir, entry));
9817
+ matches2.push(path18.join(dir, entry));
9884
9818
  }
9885
9819
  } catch {
9886
9820
  }
9887
9821
  }
9888
- } else if (fs17.existsSync(path19.join(sourceRoot, pattern))) {
9822
+ } else if (fs16.existsSync(path18.join(sourceRoot, pattern))) {
9889
9823
  matches2.push(pattern);
9890
9824
  }
9891
9825
  for (const rel of matches2) {
9892
- const src = path19.join(sourceRoot, rel);
9893
- const dst = path19.join(worktreeRoot, rel);
9826
+ const src = path18.join(sourceRoot, rel);
9827
+ const dst = path18.join(worktreeRoot, rel);
9894
9828
  try {
9895
- const st = fs17.statSync(src);
9829
+ const st = fs16.statSync(src);
9896
9830
  if (!st.isFile())
9897
9831
  continue;
9898
- fs17.mkdirSync(path19.dirname(dst), { recursive: true });
9899
- fs17.copyFileSync(src, dst);
9832
+ fs16.mkdirSync(path18.dirname(dst), { recursive: true });
9833
+ fs16.copyFileSync(src, dst);
9900
9834
  copied++;
9901
9835
  } catch {
9902
9836
  }
@@ -9996,7 +9930,7 @@ var init_manager = __esm({
9996
9930
  try {
9997
9931
  const hostExec = makeHostExecFn();
9998
9932
  for (const repo of repos) {
9999
- const repoDir = path19.join(workspacePath, repo.name);
9933
+ const repoDir = path18.join(workspacePath, repo.name);
10000
9934
  if (repo.stack && Object.keys(repo.stack).length > 0) {
10001
9935
  preDetectedStacks.set(repo.name, { repoName: repo.name, versions: repo.stack });
10002
9936
  } else {
@@ -10053,10 +9987,10 @@ var init_manager = __esm({
10053
9987
  const worldEnv = {};
10054
9988
  if (opts.task)
10055
9989
  worldEnv.OLAM_TASK = opts.task;
10056
- const r2CredsPath = path19.join(os10.homedir(), ".olam", "r2-credentials.json");
10057
- if (fs17.existsSync(r2CredsPath)) {
9990
+ const r2CredsPath = path18.join(os10.homedir(), ".olam", "r2-credentials.json");
9991
+ if (fs16.existsSync(r2CredsPath)) {
10058
9992
  try {
10059
- const r2Raw = fs17.readFileSync(r2CredsPath, "utf-8").trim();
9993
+ const r2Raw = fs16.readFileSync(r2CredsPath, "utf-8").trim();
10060
9994
  if (r2Raw.length > 0) {
10061
9995
  const r2 = JSON.parse(r2Raw);
10062
9996
  if (typeof r2.account_id === "string")
@@ -10073,10 +10007,10 @@ var init_manager = __esm({
10073
10007
  } catch {
10074
10008
  }
10075
10009
  }
10076
- const keysYamlPath = path19.join(os10.homedir(), ".olam", "keys.yaml");
10077
- if (fs17.existsSync(keysYamlPath)) {
10010
+ const keysYamlPath = path18.join(os10.homedir(), ".olam", "keys.yaml");
10011
+ if (fs16.existsSync(keysYamlPath)) {
10078
10012
  try {
10079
- const keysRaw = fs17.readFileSync(keysYamlPath, "utf-8").trim();
10013
+ const keysRaw = fs16.readFileSync(keysYamlPath, "utf-8").trim();
10080
10014
  if (keysRaw.length > 0) {
10081
10015
  const parsed = YAML3.parse(keysRaw);
10082
10016
  if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
@@ -10123,10 +10057,10 @@ var init_manager = __esm({
10123
10057
  worldEnv[k] = v;
10124
10058
  }
10125
10059
  for (const { repoName, relativePath, content } of fileWrites) {
10126
- const absPath = path19.join(workspacePath, repoName, relativePath);
10060
+ const absPath = path18.join(workspacePath, repoName, relativePath);
10127
10061
  try {
10128
- fs17.mkdirSync(path19.dirname(absPath), { recursive: true });
10129
- fs17.writeFileSync(absPath, content.endsWith("\n") ? content : content + "\n", {
10062
+ fs16.mkdirSync(path18.dirname(absPath), { recursive: true });
10063
+ fs16.writeFileSync(absPath, content.endsWith("\n") ? content : content + "\n", {
10130
10064
  mode: 384
10131
10065
  });
10132
10066
  console.log(`[secrets] ${repoName}: materialised ${relativePath} (${content.length} chars, mode 0600)`);
@@ -10278,7 +10212,7 @@ var init_manager = __esm({
10278
10212
  let taskWithPolicies = opts.task;
10279
10213
  try {
10280
10214
  const allPolicies = repos.flatMap((repo) => {
10281
- const repoWorktree = path19.join(workspacePath, repo.name);
10215
+ const repoWorktree = path18.join(workspacePath, repo.name);
10282
10216
  return loadPolicies(repoWorktree);
10283
10217
  });
10284
10218
  const seen = /* @__PURE__ */ new Set();
@@ -10294,8 +10228,8 @@ var init_manager = __esm({
10294
10228
  ${opts.task}`;
10295
10229
  execSync4(`docker exec ${containerName} mkdir -p /home/olam/.olam/policies`, { stdio: "pipe", timeout: 1e4 });
10296
10230
  for (const repo of repos) {
10297
- const policiesDir = path19.join(workspacePath, repo.name, ".olam", "policies");
10298
- if (fs17.existsSync(policiesDir)) {
10231
+ const policiesDir = path18.join(workspacePath, repo.name, ".olam", "policies");
10232
+ if (fs16.existsSync(policiesDir)) {
10299
10233
  execSync4(`docker cp "${policiesDir}/." "${containerName}:/home/olam/.olam/policies/"`, { stdio: "pipe", timeout: 15e3 });
10300
10234
  }
10301
10235
  }
@@ -10374,8 +10308,8 @@ ${opts.task}`;
10374
10308
  } catch {
10375
10309
  }
10376
10310
  try {
10377
- fs17.rmSync(world.workspacePath, { recursive: true, force: true });
10378
- if (fs17.existsSync(world.workspacePath)) {
10311
+ fs16.rmSync(world.workspacePath, { recursive: true, force: true });
10312
+ if (fs16.existsSync(world.workspacePath)) {
10379
10313
  console.warn(`[WorldManager] destroyWorld(${worldId}): workspace dir ${world.workspacePath} still exists after rmSync. Run \`olam clean --apply\` to reap.`);
10380
10314
  }
10381
10315
  } catch (err) {
@@ -10430,10 +10364,7 @@ ${opts.task}`;
10430
10364
  * Resolution precedence (matches the CF worker exactly):
10431
10365
  * 1. inline `opts.repos` names → look up in `config.repos`
10432
10366
  * 2. named `opts.workspace` → load catalog YAML, map via workspaceToRepoConfigs
10433
- * 3. neitherthrow `RepoSelectionRequiredError`. The historical
10434
- * "include every repo in config.yaml" fallback silently fanned a
10435
- * single-repo audit into 7-repo bootstraps and steered
10436
- * `image_selectors` to a wider tag than intended.
10367
+ * 3. fallbackevery repo declared in the project's config.yaml
10437
10368
  */
10438
10369
  resolveReposWithWorkspace(opts) {
10439
10370
  if (opts.repos && opts.repos.length > 0) {
@@ -10445,7 +10376,7 @@ ${opts.task}`;
10445
10376
  throw new WorkspaceNotFoundError(opts.workspace);
10446
10377
  return workspaceToRepoConfigs(ws);
10447
10378
  }
10448
- throw new RepoSelectionRequiredError(this.config.repos.map((r) => r.name));
10379
+ return this.resolveRepos(void 0);
10449
10380
  }
10450
10381
  resolveRepos(repoNames) {
10451
10382
  if (!repoNames || repoNames.length === 0) {
@@ -10463,14 +10394,14 @@ ${opts.task}`;
10463
10394
  return names.map((name) => this.config.repos.find((r) => r.name === name)).filter((r) => r !== void 0);
10464
10395
  }
10465
10396
  transportPlanFile(planFilePath, workspacePath, repoNames) {
10466
- const planContent = fs17.readFileSync(planFilePath, "utf-8");
10467
- const planFileName = path19.basename(planFilePath);
10397
+ const planContent = fs16.readFileSync(planFilePath, "utf-8");
10398
+ const planFileName = path18.basename(planFilePath);
10468
10399
  const targetRepo = repoNames[0];
10469
10400
  if (!targetRepo)
10470
10401
  return;
10471
- const plansDir = path19.join(workspacePath, targetRepo, "docs", "plans");
10472
- fs17.mkdirSync(plansDir, { recursive: true });
10473
- fs17.writeFileSync(path19.join(plansDir, planFileName), planContent);
10402
+ const plansDir = path18.join(workspacePath, targetRepo, "docs", "plans");
10403
+ fs16.mkdirSync(plansDir, { recursive: true });
10404
+ fs16.writeFileSync(path18.join(plansDir, planFileName), planContent);
10474
10405
  }
10475
10406
  resolveServices(repos) {
10476
10407
  const services = [];
@@ -10563,9 +10494,9 @@ var init_tracker = __esm({
10563
10494
  });
10564
10495
 
10565
10496
  // ../core/dist/world-paths.js
10566
- import * as path20 from "node:path";
10497
+ import * as path19 from "node:path";
10567
10498
  function getWorldDbPath(workspacePath) {
10568
- return path20.join(workspacePath, WORLD_DB_FILENAME);
10499
+ return path19.join(workspacePath, WORLD_DB_FILENAME);
10569
10500
  }
10570
10501
  var WORLD_DB_FILENAME;
10571
10502
  var init_world_paths = __esm({
@@ -11183,8 +11114,8 @@ var init_session_aggregator = __esm({
11183
11114
 
11184
11115
  // ../core/dist/dashboard/server.js
11185
11116
  import * as http from "node:http";
11186
- import * as fs18 from "node:fs";
11187
- import * as path21 from "node:path";
11117
+ import * as fs17 from "node:fs";
11118
+ import * as path20 from "node:path";
11188
11119
  import { fileURLToPath as fileURLToPath2 } from "node:url";
11189
11120
  function jsonResponse(res, data, status = 200) {
11190
11121
  res.writeHead(status, { "Content-Type": "application/json; charset=utf-8" });
@@ -11195,7 +11126,7 @@ function notFound(res) {
11195
11126
  }
11196
11127
  function openThoughtStore(workspacePath) {
11197
11128
  const dbPath = getWorldDbPath(workspacePath);
11198
- if (!fs18.existsSync(dbPath))
11129
+ if (!fs17.existsSync(dbPath))
11199
11130
  return null;
11200
11131
  return new ThoughtLocalStore(dbPath);
11201
11132
  }
@@ -11366,13 +11297,13 @@ function findSessionInWorld(registry, sessionId) {
11366
11297
  }
11367
11298
  function createDashboardServer(opts) {
11368
11299
  const { port, registry } = opts;
11369
- const thisDir = path21.dirname(fileURLToPath2(import.meta.url));
11370
- const defaultPublicDir = path21.resolve(thisDir, "../../../control-plane/public");
11300
+ const thisDir = path20.dirname(fileURLToPath2(import.meta.url));
11301
+ const defaultPublicDir = path20.resolve(thisDir, "../../../control-plane/public");
11371
11302
  const publicDir = opts.publicDir ?? defaultPublicDir;
11372
- let hasPublicDir = fs18.existsSync(publicDir);
11303
+ let hasPublicDir = fs17.existsSync(publicDir);
11373
11304
  const server = http.createServer((req, res) => {
11374
11305
  if (!hasPublicDir) {
11375
- hasPublicDir = fs18.existsSync(publicDir);
11306
+ hasPublicDir = fs17.existsSync(publicDir);
11376
11307
  }
11377
11308
  const host = req.headers.host ?? `localhost:${port}`;
11378
11309
  const url = new URL(req.url ?? "/", `http://${host}`);
@@ -11646,22 +11577,22 @@ function createDashboardServer(opts) {
11646
11577
  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>`);
11647
11578
  return;
11648
11579
  }
11649
- let filePath = path21.join(publicDir, pathname === "/" ? "index.html" : pathname);
11580
+ let filePath = path20.join(publicDir, pathname === "/" ? "index.html" : pathname);
11650
11581
  if (!filePath.startsWith(publicDir)) {
11651
11582
  notFound(res);
11652
11583
  return;
11653
11584
  }
11654
- if (fs18.existsSync(filePath) && fs18.statSync(filePath).isFile()) {
11655
- const ext2 = path21.extname(filePath);
11585
+ if (fs17.existsSync(filePath) && fs17.statSync(filePath).isFile()) {
11586
+ const ext2 = path20.extname(filePath);
11656
11587
  const contentType = MIME[ext2] ?? "application/octet-stream";
11657
11588
  res.writeHead(200, { "Content-Type": contentType });
11658
- fs18.createReadStream(filePath).pipe(res);
11589
+ fs17.createReadStream(filePath).pipe(res);
11659
11590
  return;
11660
11591
  }
11661
- filePath = path21.join(publicDir, "index.html");
11662
- if (fs18.existsSync(filePath)) {
11592
+ filePath = path20.join(publicDir, "index.html");
11593
+ if (fs17.existsSync(filePath)) {
11663
11594
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
11664
- fs18.createReadStream(filePath).pipe(res);
11595
+ fs17.createReadStream(filePath).pipe(res);
11665
11596
  return;
11666
11597
  }
11667
11598
  notFound(res);
@@ -11692,16 +11623,16 @@ var init_server = __esm({
11692
11623
  });
11693
11624
 
11694
11625
  // ../core/dist/dashboard/state.js
11695
- import * as fs19 from "node:fs";
11626
+ import * as fs18 from "node:fs";
11696
11627
  import * as os11 from "node:os";
11697
- import * as path22 from "node:path";
11628
+ import * as path21 from "node:path";
11698
11629
  function saveDashboardState(state) {
11699
- fs19.mkdirSync(path22.dirname(STATE_PATH), { recursive: true });
11700
- fs19.writeFileSync(STATE_PATH, JSON.stringify(state, null, 2));
11630
+ fs18.mkdirSync(path21.dirname(STATE_PATH), { recursive: true });
11631
+ fs18.writeFileSync(STATE_PATH, JSON.stringify(state, null, 2));
11701
11632
  }
11702
11633
  function loadDashboardState() {
11703
11634
  try {
11704
- const raw = fs19.readFileSync(STATE_PATH, "utf-8");
11635
+ const raw = fs18.readFileSync(STATE_PATH, "utf-8");
11705
11636
  return JSON.parse(raw);
11706
11637
  } catch {
11707
11638
  return null;
@@ -11709,7 +11640,7 @@ function loadDashboardState() {
11709
11640
  }
11710
11641
  function clearDashboardState() {
11711
11642
  try {
11712
- fs19.unlinkSync(STATE_PATH);
11643
+ fs18.unlinkSync(STATE_PATH);
11713
11644
  } catch {
11714
11645
  }
11715
11646
  }
@@ -11729,7 +11660,7 @@ var STATE_PATH;
11729
11660
  var init_state2 = __esm({
11730
11661
  "../core/dist/dashboard/state.js"() {
11731
11662
  "use strict";
11732
- STATE_PATH = path22.join(os11.homedir(), ".olam", "dashboard.json");
11663
+ STATE_PATH = path21.join(os11.homedir(), ".olam", "dashboard.json");
11733
11664
  }
11734
11665
  });
11735
11666
 
@@ -12123,51 +12054,51 @@ __export(host_cp_exports, {
12123
12054
  writePid: () => writePid,
12124
12055
  writeToken: () => writeToken
12125
12056
  });
12126
- import * as crypto6 from "node:crypto";
12127
- import * as fs20 from "node:fs";
12057
+ import * as crypto5 from "node:crypto";
12058
+ import * as fs19 from "node:fs";
12128
12059
  import * as os12 from "node:os";
12129
- import * as path23 from "node:path";
12060
+ import * as path22 from "node:path";
12130
12061
  import { spawnSync as spawnSync4 } from "node:child_process";
12131
12062
  import Dockerode2 from "dockerode";
12132
12063
  function findComposeFile() {
12133
12064
  const candidates = [
12134
12065
  // Bundled path: dist/index.js lives at <pkg>/dist/; host-cp/ is a sibling of dist/
12135
- path23.resolve(path23.dirname(new URL(import.meta.url).pathname), "../host-cp/compose.yaml"),
12066
+ path22.resolve(path22.dirname(new URL(import.meta.url).pathname), "../host-cp/compose.yaml"),
12136
12067
  // Source-mode: cwd is monorepo root
12137
- path23.resolve(process.cwd(), "packages/host-cp/compose.yaml"),
12068
+ path22.resolve(process.cwd(), "packages/host-cp/compose.yaml"),
12138
12069
  // Source-mode: cwd is one level inside the monorepo
12139
- path23.resolve(process.cwd(), "../packages/host-cp/compose.yaml")
12070
+ path22.resolve(process.cwd(), "../packages/host-cp/compose.yaml")
12140
12071
  ];
12141
12072
  for (const c of candidates) {
12142
- if (fs20.existsSync(c)) return c;
12073
+ if (fs19.existsSync(c)) return c;
12143
12074
  }
12144
- return path23.resolve(process.cwd(), "packages/host-cp/compose.yaml");
12075
+ return path22.resolve(process.cwd(), "packages/host-cp/compose.yaml");
12145
12076
  }
12146
12077
  function olamHome() {
12147
- return process.env.OLAM_HOME ?? path23.join(os12.homedir(), ".olam");
12078
+ return process.env.OLAM_HOME ?? path22.join(os12.homedir(), ".olam");
12148
12079
  }
12149
12080
  function tokenPath() {
12150
- return path23.join(olamHome(), "host-cp.token");
12081
+ return path22.join(olamHome(), "host-cp.token");
12151
12082
  }
12152
12083
  function pidPath() {
12153
- return path23.join(olamHome(), "host-cp.pid");
12084
+ return path22.join(olamHome(), "host-cp.pid");
12154
12085
  }
12155
12086
  function authSecretPath() {
12156
- return path23.join(olamHome(), "auth-secret");
12087
+ return path22.join(olamHome(), "auth-secret");
12157
12088
  }
12158
12089
  function readAuthSecret2() {
12159
12090
  const filePath = authSecretPath();
12160
- if (!fs20.existsSync(filePath)) return null;
12161
- const raw = fs20.readFileSync(filePath, "utf-8").trim();
12091
+ if (!fs19.existsSync(filePath)) return null;
12092
+ const raw = fs19.readFileSync(filePath, "utf-8").trim();
12162
12093
  return raw.length > 0 ? raw : null;
12163
12094
  }
12164
12095
  function r2CredentialsPath() {
12165
- return path23.join(olamHome(), "r2-credentials.json");
12096
+ return path22.join(olamHome(), "r2-credentials.json");
12166
12097
  }
12167
12098
  function readR2Credentials() {
12168
12099
  const filePath = r2CredentialsPath();
12169
- if (!fs20.existsSync(filePath)) return null;
12170
- const raw = fs20.readFileSync(filePath, "utf-8").trim();
12100
+ if (!fs19.existsSync(filePath)) return null;
12101
+ const raw = fs19.readFileSync(filePath, "utf-8").trim();
12171
12102
  if (raw.length === 0) return null;
12172
12103
  try {
12173
12104
  const parsed = JSON.parse(raw);
@@ -12188,39 +12119,39 @@ function readR2Credentials() {
12188
12119
  }
12189
12120
  }
12190
12121
  function writeToken() {
12191
- const token = crypto6.randomBytes(32).toString("hex");
12122
+ const token = crypto5.randomBytes(32).toString("hex");
12192
12123
  const filePath = tokenPath();
12193
- fs20.mkdirSync(path23.dirname(filePath), { recursive: true });
12194
- fs20.writeFileSync(filePath, token, { mode: 384 });
12124
+ fs19.mkdirSync(path22.dirname(filePath), { recursive: true });
12125
+ fs19.writeFileSync(filePath, token, { mode: 384 });
12195
12126
  return token;
12196
12127
  }
12197
12128
  function readToken() {
12198
12129
  const filePath = tokenPath();
12199
- if (!fs20.existsSync(filePath)) return null;
12200
- return fs20.readFileSync(filePath, "utf-8").trim();
12130
+ if (!fs19.existsSync(filePath)) return null;
12131
+ return fs19.readFileSync(filePath, "utf-8").trim();
12201
12132
  }
12202
12133
  function removeToken() {
12203
12134
  const filePath = tokenPath();
12204
- if (!fs20.existsSync(filePath)) return false;
12205
- fs20.unlinkSync(filePath);
12135
+ if (!fs19.existsSync(filePath)) return false;
12136
+ fs19.unlinkSync(filePath);
12206
12137
  return true;
12207
12138
  }
12208
12139
  function writePid(pid) {
12209
12140
  const filePath = pidPath();
12210
- fs20.mkdirSync(path23.dirname(filePath), { recursive: true });
12211
- fs20.writeFileSync(filePath, String(pid), { mode: 420 });
12141
+ fs19.mkdirSync(path22.dirname(filePath), { recursive: true });
12142
+ fs19.writeFileSync(filePath, String(pid), { mode: 420 });
12212
12143
  }
12213
12144
  function readPid() {
12214
12145
  const filePath = pidPath();
12215
- if (!fs20.existsSync(filePath)) return null;
12216
- const raw = fs20.readFileSync(filePath, "utf-8").trim();
12146
+ if (!fs19.existsSync(filePath)) return null;
12147
+ const raw = fs19.readFileSync(filePath, "utf-8").trim();
12217
12148
  const n = parseInt(raw, 10);
12218
12149
  return Number.isFinite(n) ? n : null;
12219
12150
  }
12220
12151
  function removePid() {
12221
12152
  const filePath = pidPath();
12222
- if (!fs20.existsSync(filePath)) return false;
12223
- fs20.unlinkSync(filePath);
12153
+ if (!fs19.existsSync(filePath)) return false;
12154
+ fs19.unlinkSync(filePath);
12224
12155
  return true;
12225
12156
  }
12226
12157
  async function findHostCpContainer() {
@@ -12379,7 +12310,7 @@ async function handleStart(opts) {
12379
12310
  }
12380
12311
  const token = writeToken();
12381
12312
  const composeFile = findComposeFile();
12382
- if (!fs20.existsSync(composeFile)) {
12313
+ if (!fs19.existsSync(composeFile)) {
12383
12314
  printError(`compose.yaml not found at ${composeFile}. Run from the olam project root.`);
12384
12315
  removeToken();
12385
12316
  process.exitCode = 1;
@@ -12461,7 +12392,7 @@ async function stopHostCp() {
12461
12392
  }
12462
12393
  async function handleStop() {
12463
12394
  const composeFile = findComposeFile();
12464
- if (!fs20.existsSync(composeFile)) {
12395
+ if (!fs19.existsSync(composeFile)) {
12465
12396
  printWarning(`compose.yaml not found at ${composeFile}. Cleaning up token + PID anyway.`);
12466
12397
  removeToken();
12467
12398
  removePid();
@@ -12489,13 +12420,13 @@ async function buildStatusReport() {
12489
12420
  const container = await findHostCpContainer();
12490
12421
  const health = await probeHealth();
12491
12422
  const tokenFile = tokenPath();
12492
- const tokenPresent = fs20.existsSync(tokenFile);
12423
+ const tokenPresent = fs19.existsSync(tokenFile);
12493
12424
  let tokenModeOk = false;
12494
12425
  if (tokenPresent) {
12495
- const mode = fs20.statSync(tokenFile).mode & 511;
12426
+ const mode = fs19.statSync(tokenFile).mode & 511;
12496
12427
  tokenModeOk = mode === 384;
12497
12428
  }
12498
- const pidPresent = fs20.existsSync(pidPath());
12429
+ const pidPresent = fs19.existsSync(pidPath());
12499
12430
  let stack;
12500
12431
  if (!container) {
12501
12432
  stack = "not_started";
@@ -12583,13 +12514,13 @@ async function discoverWorldPort(worldId) {
12583
12514
  }
12584
12515
  async function readHostCpToken2() {
12585
12516
  const tp = tokenPath();
12586
- if (!fs20.existsSync(tp)) return null;
12587
- return fs20.readFileSync(tp, "utf-8").trim();
12517
+ if (!fs19.existsSync(tp)) return null;
12518
+ return fs19.readFileSync(tp, "utf-8").trim();
12588
12519
  }
12589
- async function callHostCpProxy(method, worldId, path45, body) {
12520
+ async function callHostCpProxy(method, worldId, path44, body) {
12590
12521
  const token = await readHostCpToken2();
12591
12522
  if (!token) return { ok: false, status: 0, error: "no token (host CP not started)" };
12592
- const url = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path45}`;
12523
+ const url = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path44}`;
12593
12524
  try {
12594
12525
  const headers = {
12595
12526
  Authorization: `Bearer ${token}`
@@ -12714,17 +12645,17 @@ __export(install_root_exports, {
12714
12645
  isDevMode: () => isDevMode,
12715
12646
  resolveBuildScript: () => resolveBuildScript
12716
12647
  });
12717
- import { existsSync as existsSync19 } from "node:fs";
12718
- import { dirname as dirname14, join as join24, resolve as resolve6 } from "node:path";
12648
+ import { existsSync as existsSync18 } from "node:fs";
12649
+ import { dirname as dirname13, join as join24, resolve as resolve6 } from "node:path";
12719
12650
  import { fileURLToPath as fileURLToPath3 } from "node:url";
12720
12651
  function installRoot(metaUrl = import.meta.url) {
12721
12652
  const here = fileURLToPath3(metaUrl);
12722
- return resolve6(dirname14(here), "..");
12653
+ return resolve6(dirname13(here), "..");
12723
12654
  }
12724
12655
  function isDevMode(env = process.env, installRootDir = installRoot()) {
12725
12656
  if (env.OLAM_DEV !== "1") return false;
12726
12657
  const repoRoot = resolve6(installRootDir, "..", "..");
12727
- return existsSync19(join24(repoRoot, "packages")) && existsSync19(join24(repoRoot, "package.json"));
12658
+ return existsSync18(join24(repoRoot, "packages")) && existsSync18(join24(repoRoot, "package.json"));
12728
12659
  }
12729
12660
  function resolveBuildScript(input) {
12730
12661
  const { scriptRelPath, env = process.env, installRootDir = installRoot() } = input;
@@ -12903,20 +12834,20 @@ var init_registry_allowlist = __esm({
12903
12834
  });
12904
12835
 
12905
12836
  // ../core/dist/world/world-yaml.js
12906
- import * as fs22 from "node:fs";
12907
- import * as path25 from "node:path";
12837
+ import * as fs21 from "node:fs";
12838
+ import * as path24 from "node:path";
12908
12839
  import { parse as parseYaml4, stringify as stringifyYaml4 } from "yaml";
12909
12840
  function writeWorldYaml(worldPath, data) {
12910
- const olamDir = path25.join(worldPath, ".olam");
12911
- fs22.mkdirSync(olamDir, { recursive: true });
12912
- fs22.writeFileSync(path25.join(olamDir, "world.yaml"), stringifyYaml4(data), "utf-8");
12841
+ const olamDir = path24.join(worldPath, ".olam");
12842
+ fs21.mkdirSync(olamDir, { recursive: true });
12843
+ fs21.writeFileSync(path24.join(olamDir, "world.yaml"), stringifyYaml4(data), "utf-8");
12913
12844
  }
12914
12845
  function readWorldYaml(worldPath) {
12915
- const yamlPath = path25.join(worldPath, ".olam", "world.yaml");
12916
- if (!fs22.existsSync(yamlPath))
12846
+ const yamlPath = path24.join(worldPath, ".olam", "world.yaml");
12847
+ if (!fs21.existsSync(yamlPath))
12917
12848
  return null;
12918
12849
  try {
12919
- const raw = fs22.readFileSync(yamlPath, "utf-8");
12850
+ const raw = fs21.readFileSync(yamlPath, "utf-8");
12920
12851
  const parsed = parseYaml4(raw);
12921
12852
  return WorldYamlSchema.parse(parsed);
12922
12853
  } catch {
@@ -13047,16 +12978,16 @@ __export(machine_schema_exports, {
13047
12978
  readMachineConfig: () => readMachineConfig,
13048
12979
  writeMachineConfig: () => writeMachineConfig
13049
12980
  });
13050
- import * as fs36 from "node:fs";
13051
- import * as path40 from "node:path";
12981
+ import * as fs35 from "node:fs";
12982
+ import * as path39 from "node:path";
13052
12983
  import * as os21 from "node:os";
13053
12984
  import { parse as parseYaml5, stringify as stringifyYaml5 } from "yaml";
13054
12985
  function readMachineConfig(configPath) {
13055
12986
  const p = configPath ?? DEFAULT_CONFIG_PATH;
13056
- if (!fs36.existsSync(p))
12987
+ if (!fs35.existsSync(p))
13057
12988
  return null;
13058
12989
  try {
13059
- const raw = fs36.readFileSync(p, "utf-8");
12990
+ const raw = fs35.readFileSync(p, "utf-8");
13060
12991
  const parsed = parseYaml5(raw);
13061
12992
  return MachineConfigSchema.parse(parsed);
13062
12993
  } catch {
@@ -13065,8 +12996,8 @@ function readMachineConfig(configPath) {
13065
12996
  }
13066
12997
  function writeMachineConfig(config, configPath) {
13067
12998
  const p = configPath ?? DEFAULT_CONFIG_PATH;
13068
- fs36.mkdirSync(path40.dirname(p), { recursive: true });
13069
- fs36.writeFileSync(p, stringifyYaml5({ ...config }), { mode: 420 });
12999
+ fs35.mkdirSync(path39.dirname(p), { recursive: true });
13000
+ fs35.writeFileSync(p, stringifyYaml5({ ...config }), { mode: 420 });
13070
13001
  }
13071
13002
  function initMachineConfig(opts = {}) {
13072
13003
  const configPath = opts.configPath ?? DEFAULT_CONFIG_PATH;
@@ -13089,16 +13020,16 @@ var init_machine_schema = __esm({
13089
13020
  channel: external_exports.enum(["stable", "beta", "edge"]).default("stable"),
13090
13021
  auto_update: external_exports.boolean().default(true),
13091
13022
  telemetry: external_exports.boolean().default(true),
13092
- worlds_dir: external_exports.string().default(() => path40.join(os21.homedir(), ".olam", "worlds"))
13023
+ worlds_dir: external_exports.string().default(() => path39.join(os21.homedir(), ".olam", "worlds"))
13093
13024
  });
13094
- DEFAULT_CONFIG_PATH = path40.join(os21.homedir(), ".olam", "config.yaml");
13025
+ DEFAULT_CONFIG_PATH = path39.join(os21.homedir(), ".olam", "config.yaml");
13095
13026
  }
13096
13027
  });
13097
13028
 
13098
13029
  // src/index.ts
13099
13030
  import { Command } from "commander";
13100
- import * as fs40 from "node:fs";
13101
- import * as path44 from "node:path";
13031
+ import * as fs39 from "node:fs";
13032
+ import * as path43 from "node:path";
13102
13033
  import { fileURLToPath as fileURLToPath4 } from "node:url";
13103
13034
 
13104
13035
  // src/commands/init.ts
@@ -13475,9 +13406,9 @@ var UnknownArchetypeError = class extends Error {
13475
13406
  };
13476
13407
  var ArchetypeCycleError = class extends Error {
13477
13408
  path;
13478
- constructor(path45) {
13479
- super(`Archetype inheritance cycle detected: ${path45.join(" \u2192 ")} \u2192 ${path45[0] ?? "?"}`);
13480
- this.path = path45;
13409
+ constructor(path44) {
13410
+ super(`Archetype inheritance cycle detected: ${path44.join(" \u2192 ")} \u2192 ${path44[0] ?? "?"}`);
13411
+ this.path = path44;
13481
13412
  this.name = "ArchetypeCycleError";
13482
13413
  }
13483
13414
  };
@@ -13671,7 +13602,7 @@ function registerInstall(program2) {
13671
13602
  // src/commands/auth.ts
13672
13603
  init_auth();
13673
13604
  init_output();
13674
- import pc8 from "picocolors";
13605
+ import pc9 from "picocolors";
13675
13606
  import * as readline from "node:readline/promises";
13676
13607
  import { spawn as spawn3 } from "node:child_process";
13677
13608
 
@@ -13680,174 +13611,17 @@ import * as fs8 from "node:fs";
13680
13611
  import * as os5 from "node:os";
13681
13612
  import * as path9 from "node:path";
13682
13613
  import pc5 from "picocolors";
13683
-
13684
- // ../auth-logic/dist/effective-state.js
13685
- function effectiveState(account, now = Date.now()) {
13686
- const persisted = account.state ?? (account.rateLimited ? "cooldown" : "active");
13687
- if (persisted === "disabled")
13688
- return "disabled";
13689
- if (account.expiresAt != null && account.expiresAt <= now)
13690
- return "expired";
13691
- if (persisted === "cooldown" || persisted === "usage-capped") {
13692
- const reset = account.rateLimitResetsAt ? new Date(account.rateLimitResetsAt).getTime() : 0;
13693
- if (reset > 0 && reset <= now)
13694
- return "active";
13695
- return persisted;
13696
- }
13697
- return "active";
13698
- }
13699
-
13700
- // ../auth-logic/dist/pick-credential.js
13701
- function pickCredential(accounts, now = Date.now()) {
13702
- const active = accounts.filter((a) => effectiveState(a, now) === "active");
13703
- if (active.length === 0)
13704
- return null;
13705
- return [...active].sort((a, b) => {
13706
- const aCount = a.usage?.requestCount5h ?? 0;
13707
- const bCount = b.usage?.requestCount5h ?? 0;
13708
- if (aCount !== bCount)
13709
- return aCount - bCount;
13710
- const aLast = a.lastUsed ? new Date(a.lastUsed).getTime() : 0;
13711
- const bLast = b.lastUsed ? new Date(b.lastUsed).getTime() : 0;
13712
- return aLast - bLast;
13713
- })[0] ?? null;
13714
- }
13715
-
13716
- // ../auth-logic/dist/next-cooldown-reset.js
13717
- function nextCooldownReset(accounts, now = Date.now()) {
13718
- const upcoming = accounts.filter((a) => effectiveState(a, now) === "cooldown").map((a) => a.rateLimitResetsAt ? new Date(a.rateLimitResetsAt).getTime() : 0).filter((ts) => ts > now).sort((a, b) => a - b);
13719
- return upcoming.length > 0 ? new Date(upcoming[0]).toISOString() : null;
13720
- }
13721
-
13722
- // src/commands/auth-status.ts
13723
13614
  init_auth();
13724
13615
  init_output();
13725
13616
  init_exit_codes();
13726
13617
  var LOCAL_DATA_DIR = path9.join(os5.homedir(), ".olam", "auth-data");
13727
- function localHHMM(isoStr) {
13728
- const d = new Date(isoStr);
13729
- return d.toLocaleTimeString(void 0, {
13730
- hour: "2-digit",
13731
- minute: "2-digit",
13732
- hour12: false
13733
- });
13734
- }
13735
- function daysAgoStr(expiresAt, now) {
13736
- const diffDays = Math.floor((now - expiresAt) / (1e3 * 60 * 60 * 24));
13737
- if (diffDays <= 0) return "expired today";
13738
- return `expired ${diffDays} day${diffDays === 1 ? "" : "s"} ago`;
13739
- }
13740
- function trunc(s, maxLen) {
13741
- return s.length > maxLen ? s.slice(0, maxLen) : s;
13742
- }
13743
- var STATE_PRIORITY = {
13744
- active: 0,
13745
- cooldown: 1,
13746
- "usage-capped": 2,
13747
- disabled: 3,
13748
- expired: 4
13749
- };
13750
- function formatAuthStatus(accounts, now = Date.now()) {
13751
- const picked = pickCredential(accounts, now);
13752
- const rows = accounts.map((account) => {
13753
- const state = effectiveState(account, now);
13754
- const isPicked = picked != null && account.id === picked.id;
13755
- const req5h = account.usage?.requestCount5h ?? 0;
13756
- const last429 = account.usage?.last429At ? localHHMM(account.usage.last429At) : "never";
13757
- let reason;
13758
- if (isPicked) {
13759
- reason = "\u2190 selected";
13760
- } else if (state === "active") {
13761
- reason = `req5h=${req5h} (higher than candidate)`;
13762
- } else if (state === "cooldown") {
13763
- const resetTime = account.rateLimitResetsAt ? localHHMM(account.rateLimitResetsAt) : "?";
13764
- reason = `cooldown until ${resetTime}`;
13765
- } else if (state === "expired") {
13766
- reason = daysAgoStr(account.expiresAt ?? 0, now);
13767
- } else {
13768
- reason = "disabled";
13769
- }
13770
- return { id: account.id, label: account.accountLabel ?? account.id, state, reason, req5h, last429, isPicked };
13771
- });
13772
- rows.sort((a, b) => {
13773
- if (a.isPicked !== b.isPicked) return a.isPicked ? -1 : 1;
13774
- return STATE_PRIORITY[a.state] - STATE_PRIORITY[b.state];
13775
- });
13776
- const COL = { id: 17, label: 17, state: 11, reason: 28, req5h: 7 };
13777
- const lines = [];
13778
- const hdr = "id".padEnd(COL.id) + "label".padEnd(COL.label) + "state".padEnd(COL.state) + "reason".padEnd(COL.reason) + "req5h".padEnd(COL.req5h) + "last429";
13779
- lines.push(pc5.dim(hdr));
13780
- lines.push(pc5.dim("-".repeat(hdr.length)));
13781
- for (const row of rows) {
13782
- const id = trunc(row.id, 16).padEnd(COL.id);
13783
- const label = trunc(row.label, 16).padEnd(COL.label);
13784
- const stateRaw = row.state.padEnd(COL.state);
13785
- const stateColored = row.state === "active" ? pc5.green(stateRaw) : row.state === "cooldown" ? pc5.yellow(stateRaw) : row.state === "expired" ? pc5.red(stateRaw) : pc5.dim(stateRaw);
13786
- const reason = row.reason.padEnd(COL.reason);
13787
- const req5h = String(row.req5h).padEnd(COL.req5h);
13788
- if (row.isPicked) {
13789
- lines.push(
13790
- pc5.bold(id) + pc5.bold(label) + stateColored + pc5.green(reason) + pc5.dim(req5h) + pc5.dim(row.last429)
13791
- );
13792
- } else {
13793
- lines.push(id + label + stateColored + reason + pc5.dim(req5h) + pc5.dim(row.last429));
13794
- }
13795
- }
13796
- if (picked == null) {
13797
- const resetIso = nextCooldownReset(accounts, now);
13798
- lines.push("");
13799
- lines.push(
13800
- resetIso ? pc5.yellow(`Next reset: ${localHHMM(resetIso)}`) : pc5.dim("No reset scheduled")
13801
- );
13802
- return { output: lines.join("\n"), exitCode: EXIT_AUTH_NEEDS_ATTENTION };
13803
- }
13804
- return { output: lines.join("\n"), exitCode: 0 };
13805
- }
13806
- function toSafeAccount(a) {
13807
- return {
13808
- id: a.id,
13809
- accountLabel: a.accountLabel,
13810
- // expiresAt not exposed in summary — state is pre-computed server-side
13811
- rateLimited: a.rateLimited,
13812
- rateLimitResetsAt: a.rateLimitResetsAt,
13813
- lastUsed: a.lastUsed,
13814
- state: a.state,
13815
- usage: a.usage ? { requestCount5h: a.usage.requestCount5h, last429At: a.usage.last429At } : void 0
13816
- };
13817
- }
13818
- async function runAuthStatus(getStatus) {
13819
- const fetchStatus = getStatus ?? (() => new AuthClient().status());
13820
- let status;
13821
- try {
13822
- status = await fetchStatus();
13823
- } catch {
13824
- printError("Failed to contact auth service. Run `olam auth up` first.");
13825
- process.exitCode = 1;
13826
- return;
13827
- }
13828
- if (!status.reachable) {
13829
- printError("Auth container is not reachable. Run `olam auth up` first.");
13830
- process.exitCode = 1;
13831
- return;
13832
- }
13833
- if (status.accounts.length === 0) {
13834
- console.log(pc5.dim("No credentials found. Run: olam auth login"));
13835
- return;
13836
- }
13837
- const accounts = status.accounts.map(toSafeAccount);
13838
- const result = formatAuthStatus(accounts);
13839
- console.log(result.output);
13840
- if (result.exitCode !== 0) {
13841
- process.exitCode = result.exitCode;
13842
- }
13843
- }
13844
13618
 
13845
13619
  // src/commands/auth-upgrade.ts
13846
13620
  init_output();
13847
13621
  init_host_cp();
13848
13622
  init_auth();
13849
- import * as fs21 from "node:fs";
13850
- import * as path24 from "node:path";
13623
+ import * as fs20 from "node:fs";
13624
+ import * as path23 from "node:path";
13851
13625
  import { spawnSync as spawnSync7 } from "node:child_process";
13852
13626
  import ora2 from "ora";
13853
13627
  import pc7 from "picocolors";
@@ -13858,20 +13632,20 @@ init_exit_codes();
13858
13632
  init_protocol_version();
13859
13633
  init_output();
13860
13634
  import { spawn as spawn2, spawnSync as spawnSync6 } from "node:child_process";
13861
- import { existsSync as existsSync20, readFileSync as readFileSync16 } from "node:fs";
13635
+ import { existsSync as existsSync19, readFileSync as readFileSync15 } from "node:fs";
13862
13636
  import { join as join25 } from "node:path";
13863
13637
  import ora from "ora";
13864
13638
  import pc6 from "picocolors";
13865
13639
  function loadImageDigests(installRootDir = installRoot()) {
13866
13640
  const digestsPath = join25(installRootDir, "dist", "image-digests.json");
13867
- if (!existsSync20(digestsPath)) {
13641
+ if (!existsSync19(digestsPath)) {
13868
13642
  throw new Error(
13869
13643
  `image-digests.json missing at ${digestsPath}. Re-run \`npm install -g @pleri/olam-cli@<version>\` to refresh the tarball.`
13870
13644
  );
13871
13645
  }
13872
13646
  let parsed;
13873
13647
  try {
13874
- parsed = JSON.parse(readFileSync16(digestsPath, "utf8"));
13648
+ parsed = JSON.parse(readFileSync15(digestsPath, "utf8"));
13875
13649
  } catch (err) {
13876
13650
  throw new Error(`image-digests.json is not valid JSON: ${err.message}`);
13877
13651
  }
@@ -14129,9 +13903,9 @@ async function runBootstrap2(opts, deps = {}) {
14129
13903
  printSuccess("Smoke world created");
14130
13904
  }
14131
13905
  printHeader("Stack ready");
14132
- printInfo("host-cp", `running (${digests["host-cp"].slice(0, 19)}\u2026)`);
14133
- printInfo("auth", `running (${digests.auth.slice(0, 19)}\u2026)`);
14134
- printInfo("devbox", `pulled (${digests.devbox.slice(0, 19)}\u2026)`);
13906
+ printInfo("olam-host-cp", `running (${digests["host-cp"].slice(0, 19)}\u2026)`);
13907
+ printInfo("olam-auth", `running (${digests.auth.slice(0, 19)}\u2026)`);
13908
+ printInfo("olam-devbox", `pulled (${digests.devbox.slice(0, 19)}\u2026)`);
14135
13909
  printInfo("next", '`olam create --task "your task"` to spawn a world');
14136
13910
  return { exitCode: 0, summary: "stack ready" };
14137
13911
  }
@@ -14171,8 +13945,8 @@ function parseAuthUpgradeOpts(raw) {
14171
13945
  };
14172
13946
  }
14173
13947
  function validateAuthRepoRoot(cwd) {
14174
- const marker = path24.join(cwd, "packages/auth-service/Dockerfile");
14175
- if (!fs21.existsSync(marker)) {
13948
+ const marker = path23.join(cwd, "packages/auth-service/Dockerfile");
13949
+ if (!fs20.existsSync(marker)) {
14176
13950
  return {
14177
13951
  ok: false,
14178
13952
  error: `Not an olam repo root (expected ${marker}).
@@ -14539,6 +14313,185 @@ function registerAuthUpgrade(auth) {
14539
14313
  });
14540
14314
  }
14541
14315
 
14316
+ // src/commands/services.ts
14317
+ init_auth();
14318
+ init_output();
14319
+ import { execFileSync as execFileSync4, spawnSync as spawnSync8 } from "node:child_process";
14320
+ import pc8 from "picocolors";
14321
+ var MCP_AUTH_PORT = 9998;
14322
+ var MCP_AUTH_VOLUME = "olam-mcp-auth-data";
14323
+ var MCP_AUTH_CONTAINER = "olam-mcp-auth";
14324
+ var MCP_AUTH_LOCAL_TAG = "olam-mcp-auth:local";
14325
+ var MCP_AUTH_PUBLISHED_TAG = "ghcr.io/pleri/olam-mcp-auth:latest";
14326
+ var MCP_AUTH_HEALTH_URL = `http://127.0.0.1:${MCP_AUTH_PORT}/health`;
14327
+ var MCP_AUTH_HEALTH_TIMEOUT_MS = 15e3;
14328
+ var McpAuthContainerController = class {
14329
+ imageTag = MCP_AUTH_LOCAL_TAG;
14330
+ status() {
14331
+ const r = spawnSync8(
14332
+ "docker",
14333
+ ["inspect", "--format", "{{.State.Status}}|{{.Id}}", MCP_AUTH_CONTAINER],
14334
+ { encoding: "utf-8" }
14335
+ );
14336
+ if (r.status === 0) {
14337
+ const [stateRaw, id] = r.stdout.trim().split("|");
14338
+ return {
14339
+ state: stateRaw === "running" ? "running" : "stopped",
14340
+ port: MCP_AUTH_PORT,
14341
+ containerId: id
14342
+ };
14343
+ }
14344
+ return { state: "missing", port: MCP_AUTH_PORT };
14345
+ }
14346
+ imageExists(tag = this.imageTag) {
14347
+ return spawnSync8("docker", ["image", "inspect", tag], { encoding: "utf-8" }).status === 0;
14348
+ }
14349
+ start() {
14350
+ const current = this.status();
14351
+ if (current.state === "running") return;
14352
+ if (current.state === "stopped") {
14353
+ execFileSync4("docker", ["start", MCP_AUTH_CONTAINER], { stdio: "pipe" });
14354
+ return;
14355
+ }
14356
+ if (!this.imageExists()) {
14357
+ if (this.imageTag !== MCP_AUTH_PUBLISHED_TAG && this.imageExists(MCP_AUTH_PUBLISHED_TAG)) {
14358
+ this.imageTag = MCP_AUTH_PUBLISHED_TAG;
14359
+ } else {
14360
+ throw new Error(
14361
+ `mcp-auth image '${this.imageTag}' not found locally. Run \`olam bootstrap\` to pull the published image.`
14362
+ );
14363
+ }
14364
+ }
14365
+ execFileSync4(
14366
+ "docker",
14367
+ [
14368
+ "run",
14369
+ "--detach",
14370
+ "--name",
14371
+ MCP_AUTH_CONTAINER,
14372
+ "--restart",
14373
+ "unless-stopped",
14374
+ "--publish",
14375
+ `${MCP_AUTH_PORT}:${MCP_AUTH_PORT}`,
14376
+ "--volume",
14377
+ `${MCP_AUTH_VOLUME}:/mcp-auth-data`,
14378
+ this.imageTag
14379
+ ],
14380
+ { stdio: "pipe" }
14381
+ );
14382
+ }
14383
+ stop() {
14384
+ const current = this.status();
14385
+ if (current.state !== "running") return;
14386
+ execFileSync4("docker", ["stop", MCP_AUTH_CONTAINER], { stdio: "pipe" });
14387
+ }
14388
+ remove() {
14389
+ spawnSync8("docker", ["rm", "-f", MCP_AUTH_CONTAINER], { stdio: "pipe" });
14390
+ }
14391
+ async waitForReady(timeoutMs = MCP_AUTH_HEALTH_TIMEOUT_MS) {
14392
+ const deadline = Date.now() + timeoutMs;
14393
+ while (Date.now() < deadline) {
14394
+ try {
14395
+ const res = await fetch(MCP_AUTH_HEALTH_URL, { signal: AbortSignal.timeout(1500) });
14396
+ if (res.ok) return true;
14397
+ } catch {
14398
+ }
14399
+ await sleep3(500);
14400
+ }
14401
+ return false;
14402
+ }
14403
+ };
14404
+ function sleep3(ms) {
14405
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
14406
+ }
14407
+ async function servicesUp() {
14408
+ const auth = new AuthContainerController();
14409
+ const mcpAuth = new McpAuthContainerController();
14410
+ const authStatus = auth.status();
14411
+ if (authStatus.state === "running") {
14412
+ printSuccess(`olam-auth already running on :${authStatus.port}`);
14413
+ } else {
14414
+ try {
14415
+ auth.start();
14416
+ } catch (err) {
14417
+ printError(`olam-auth failed to start: ${err instanceof Error ? err.message : String(err)}`);
14418
+ return { exitCode: 1 };
14419
+ }
14420
+ const ready = await auth.waitForReady(15e3);
14421
+ if (!ready) {
14422
+ printWarning("olam-auth started but /health did not respond within 15s.");
14423
+ return { exitCode: 1 };
14424
+ }
14425
+ printSuccess("olam-auth started");
14426
+ }
14427
+ const mcpStatus = mcpAuth.status();
14428
+ if (mcpStatus.state === "running") {
14429
+ printSuccess(`olam-mcp-auth already running on :${mcpStatus.port}`);
14430
+ } else {
14431
+ try {
14432
+ mcpAuth.start();
14433
+ } catch (err) {
14434
+ printError(`olam-mcp-auth failed to start: ${err instanceof Error ? err.message : String(err)}`);
14435
+ return { exitCode: 1 };
14436
+ }
14437
+ const ready = await mcpAuth.waitForReady();
14438
+ if (!ready) {
14439
+ printWarning("olam-mcp-auth started but /health did not respond within 15s.");
14440
+ return { exitCode: 1 };
14441
+ }
14442
+ printSuccess("olam-mcp-auth started");
14443
+ }
14444
+ printHeader("Services up");
14445
+ printInfo("olam-auth", ":9999");
14446
+ printInfo("olam-mcp-auth", ":9998");
14447
+ return { exitCode: 0 };
14448
+ }
14449
+ function servicesDown() {
14450
+ const auth = new AuthContainerController();
14451
+ const mcpAuth = new McpAuthContainerController();
14452
+ let exitCode = 0;
14453
+ try {
14454
+ auth.stop();
14455
+ printSuccess("olam-auth stopped.");
14456
+ } catch (err) {
14457
+ printError(`olam-auth: ${err instanceof Error ? err.message : String(err)}`);
14458
+ exitCode = 1;
14459
+ }
14460
+ try {
14461
+ mcpAuth.stop();
14462
+ printSuccess("olam-mcp-auth stopped.");
14463
+ } catch (err) {
14464
+ printError(`olam-mcp-auth: ${err instanceof Error ? err.message : String(err)}`);
14465
+ exitCode = 1;
14466
+ }
14467
+ return { exitCode };
14468
+ }
14469
+ function servicesStatus() {
14470
+ const auth = new AuthContainerController();
14471
+ const mcpAuth = new McpAuthContainerController();
14472
+ printHeader("Services status");
14473
+ const authState = auth.status();
14474
+ const authStateStr = authState.state === "running" ? pc8.green("running") : authState.state === "stopped" ? pc8.yellow("stopped") : pc8.red("missing");
14475
+ printInfo("olam-auth", `${authStateStr} :${authState.port}`);
14476
+ const mcpState = mcpAuth.status();
14477
+ const mcpStateStr = mcpState.state === "running" ? pc8.green("running") : mcpState.state === "stopped" ? pc8.yellow("stopped") : pc8.red("missing");
14478
+ printInfo("olam-mcp-auth", `${mcpStateStr} :${mcpState.port}`);
14479
+ }
14480
+ function registerServices(program2) {
14481
+ const services = program2.command("services").description("Manage Olam service containers (olam-auth, olam-mcp-auth)");
14482
+ services.command("up").description("Start all service containers (idempotent)").action(async () => {
14483
+ const result = await servicesUp();
14484
+ if (result.exitCode !== 0) process.exitCode = result.exitCode;
14485
+ });
14486
+ services.command("down").description("Stop all service containers").action(() => {
14487
+ const result = servicesDown();
14488
+ if (result.exitCode !== 0) process.exitCode = result.exitCode;
14489
+ });
14490
+ services.command("status").description("Show state of all service containers").action(() => {
14491
+ servicesStatus();
14492
+ });
14493
+ }
14494
+
14542
14495
  // src/commands/auth.ts
14543
14496
  function openBrowser(url) {
14544
14497
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
@@ -14559,44 +14512,19 @@ async function promptLine(question) {
14559
14512
  }
14560
14513
  function registerAuth(program2) {
14561
14514
  const auth = program2.command("auth").description("Manage the local Claude auth container");
14562
- auth.command("up").description("Start the auth container (idempotent)").action(async () => {
14563
- const controller = new AuthContainerController();
14564
- const initial = controller.status();
14565
- if (initial.state === "running") {
14566
- printSuccess(`Auth container already running on :${initial.port}`);
14567
- return;
14568
- }
14569
- try {
14570
- controller.start();
14571
- } catch (err) {
14572
- printError(err instanceof Error ? err.message : "failed to start");
14573
- process.exitCode = 1;
14574
- return;
14575
- }
14576
- const ready = await controller.waitForReady(15e3);
14577
- if (!ready) {
14578
- printWarning("Container started but /health did not respond within 15s.");
14579
- process.exitCode = 1;
14580
- return;
14581
- }
14582
- printHeader("Auth container up");
14583
- printInfo("Port", String(initial.port));
14584
- printInfo("Volume", "olam-auth-data");
14585
- console.log(`
14586
- ${pc8.dim("Next: olam auth login")}`);
14515
+ auth.command("up").description("[deprecated] Start the auth container \u2014 use `olam services up` instead").action(async () => {
14516
+ printWarning("`olam auth up` is deprecated. Use `olam services up` instead.");
14517
+ const result = await servicesUp();
14518
+ if (result.exitCode !== 0) process.exitCode = result.exitCode;
14587
14519
  });
14588
- auth.command("down").description("Stop the auth container (tokens persist in the volume)").action(() => {
14589
- const controller = new AuthContainerController();
14590
- try {
14591
- controller.stop();
14592
- printSuccess("Auth container stopped.");
14593
- } catch (err) {
14594
- printError(err instanceof Error ? err.message : "failed to stop");
14595
- process.exitCode = 1;
14596
- }
14520
+ auth.command("down").description("[deprecated] Stop the auth container \u2014 use `olam services down` instead").action(() => {
14521
+ printWarning("`olam auth down` is deprecated. Use `olam services down` instead.");
14522
+ const result = servicesDown();
14523
+ if (result.exitCode !== 0) process.exitCode = result.exitCode;
14597
14524
  });
14598
- auth.command("status").description("Show credential states from auth-service (same source as `auth list`)").action(async () => {
14599
- await runAuthStatus();
14525
+ auth.command("status").description("[deprecated] Show container state \u2014 use `olam services status` instead").action(() => {
14526
+ printWarning("`olam auth status` is deprecated. Use `olam services status` instead.");
14527
+ servicesStatus();
14600
14528
  });
14601
14529
  auth.command("list").description("List all stored credentials with state, usage, and rate-limit status").action(async () => {
14602
14530
  const client = new AuthClient();
@@ -14608,15 +14536,15 @@ ${pc8.dim("Next: olam auth login")}`);
14608
14536
  }
14609
14537
  printHeader(`Credentials (${status.accounts.length})`);
14610
14538
  if (status.accounts.length === 0) {
14611
- console.log(` ${pc8.dim("No credentials \u2014 run: olam auth login --label primary")}`);
14539
+ console.log(` ${pc9.dim("No credentials \u2014 run: olam auth login --label primary")}`);
14612
14540
  return;
14613
14541
  }
14614
14542
  const stateColor = (s) => {
14615
- if (s === "active") return pc8.green("active");
14616
- if (s === "cooldown") return pc8.yellow("cooldown");
14617
- if (s === "expired") return pc8.red("expired");
14618
- if (s === "disabled") return pc8.dim("disabled");
14619
- return pc8.dim(s ?? "unknown");
14543
+ if (s === "active") return pc9.green("active");
14544
+ if (s === "cooldown") return pc9.yellow("cooldown");
14545
+ if (s === "expired") return pc9.red("expired");
14546
+ if (s === "disabled") return pc9.dim("disabled");
14547
+ return pc9.dim(s ?? "unknown");
14620
14548
  };
14621
14549
  for (const a of status.accounts) {
14622
14550
  const label = a.accountLabel ?? a.id;
@@ -14624,7 +14552,7 @@ ${pc8.dim("Next: olam auth login")}`);
14624
14552
  const last429 = a.usage?.last429At ? `last429=${a.usage.last429At}` : "last429=never";
14625
14553
  const reset = a.rateLimitResetsAt ? `resets=${a.rateLimitResetsAt}` : "";
14626
14554
  console.log(
14627
- ` ${pc8.bold(label.padEnd(18))} ${stateColor(a.state).padEnd(18)} ${pc8.dim(`req5h=${reqs}`)} ${pc8.dim(`exp=${a.expiresIn}`)} ${pc8.dim(last429)} ${pc8.yellow(reset)}`
14555
+ ` ${pc9.bold(label.padEnd(18))} ${stateColor(a.state).padEnd(18)} ${pc9.dim(`req5h=${reqs}`)} ${pc9.dim(`exp=${a.expiresIn}`)} ${pc9.dim(last429)} ${pc9.yellow(reset)}`
14628
14556
  );
14629
14557
  }
14630
14558
  });
@@ -14662,7 +14590,7 @@ ${pc8.dim("Next: olam auth login")}`);
14662
14590
  const preflight = await runAuthPreflight({ autoStart: true });
14663
14591
  if (preflight.verdict !== "ok" && preflight.verdict !== "no-accounts") {
14664
14592
  printError(preflight.message);
14665
- console.log(` ${pc8.dim(preflight.remedy)}`);
14593
+ console.log(` ${pc9.dim(preflight.remedy)}`);
14666
14594
  process.exitCode = 1;
14667
14595
  return;
14668
14596
  }
@@ -14695,14 +14623,14 @@ ${pc8.dim("Next: olam auth login")}`);
14695
14623
  }
14696
14624
  printHeader("Claude OAuth \u2014 PKCE flow");
14697
14625
  console.log(`
14698
- ${pc8.bold("1.")} Opening Claude in your default browser\u2026`);
14699
- console.log(` ${pc8.dim(pending.loginUrl)}`);
14626
+ ${pc9.bold("1.")} Opening Claude in your default browser\u2026`);
14627
+ console.log(` ${pc9.dim(pending.loginUrl)}`);
14700
14628
  openBrowser(pending.loginUrl);
14701
14629
  console.log(`
14702
- ${pc8.bold("2.")} After approving, paste the authorization code from the redirect page.`);
14703
- console.log(` ${pc8.dim("(Format: <code>#<state> or just <code>.)")}
14630
+ ${pc9.bold("2.")} After approving, paste the authorization code from the redirect page.`);
14631
+ console.log(` ${pc9.dim("(Format: <code>#<state> or just <code>.)")}
14704
14632
  `);
14705
- const raw = await promptLine(`${pc8.dim("code:")} `);
14633
+ const raw = await promptLine(`${pc9.dim("code:")} `);
14706
14634
  if (!raw) {
14707
14635
  printError("No code provided.");
14708
14636
  process.exitCode = 1;
@@ -14713,7 +14641,7 @@ ${pc8.dim("Next: olam auth login")}`);
14713
14641
  const result = await client.completeLogin(statePart, codePart);
14714
14642
  printSuccess(`Account stored: ${result.account} (${result.expiresIn})`);
14715
14643
  console.log(`
14716
- ${pc8.dim("Next: olam create --name my-world")}`);
14644
+ ${pc9.dim("Next: olam create --name my-world")}`);
14717
14645
  } catch (err) {
14718
14646
  printError(err instanceof Error ? err.message : "token exchange failed");
14719
14647
  process.exitCode = 1;
@@ -14744,15 +14672,15 @@ ${pc8.dim("Next: olam create --name my-world")}`);
14744
14672
 
14745
14673
  // src/commands/create.ts
14746
14674
  init_manager();
14747
- import { spawnSync as spawnSync8 } from "node:child_process";
14748
- import { existsSync as existsSync23 } from "node:fs";
14749
- import { dirname as dirname15, resolve as resolve7 } from "node:path";
14675
+ import { spawnSync as spawnSync9 } from "node:child_process";
14676
+ import { existsSync as existsSync22 } from "node:fs";
14677
+ import { dirname as dirname14, resolve as resolve7 } from "node:path";
14750
14678
  import ora3 from "ora";
14751
- import pc9 from "picocolors";
14679
+ import pc10 from "picocolors";
14752
14680
 
14753
14681
  // ../core/dist/world/devbox-freshness.js
14754
14682
  import { execSync as execSync6 } from "node:child_process";
14755
- import { existsSync as existsSync22, statSync as statSync5 } from "node:fs";
14683
+ import { existsSync as existsSync21, statSync as statSync5 } from "node:fs";
14756
14684
  import { join as join27 } from "node:path";
14757
14685
  var DEFAULT_DEVBOX_IMAGE = "olam-devbox:latest";
14758
14686
  var DEVBOX_BAKED_SOURCES = [
@@ -14821,9 +14749,9 @@ function formatFreshnessWarning(result, image = DEFAULT_DEVBOX_IMAGE) {
14821
14749
  "These source files have changed since the image was built; the",
14822
14750
  "changes will NOT take effect in fresh worlds until you rebuild:"
14823
14751
  ];
14824
- for (const { path: path45, mtimeMs } of result.newerSources) {
14752
+ for (const { path: path44, mtimeMs } of result.newerSources) {
14825
14753
  const when = new Date(mtimeMs).toISOString();
14826
- lines.push(` \u2022 ${path45} (modified ${when})`);
14754
+ lines.push(` \u2022 ${path44} (modified ${when})`);
14827
14755
  }
14828
14756
  lines.push("");
14829
14757
  lines.push("Rebuild with:");
@@ -14842,7 +14770,7 @@ function defaultDockerInspect(image) {
14842
14770
  }
14843
14771
  function defaultStatMtime(absPath) {
14844
14772
  try {
14845
- if (!existsSync22(absPath))
14773
+ if (!existsSync21(absPath))
14846
14774
  return null;
14847
14775
  return statSync5(absPath).mtimeMs;
14848
14776
  } catch {
@@ -14982,15 +14910,15 @@ init_host_cp();
14982
14910
  var HOST_CP_URL = "http://127.0.0.1:19000";
14983
14911
  async function readHostCpTokenForCreate() {
14984
14912
  try {
14985
- const { default: fs41 } = await import("node:fs");
14913
+ const { default: fs40 } = await import("node:fs");
14986
14914
  const { default: os24 } = await import("node:os");
14987
- const { default: path45 } = await import("node:path");
14988
- const tp = path45.join(
14989
- process.env.OLAM_HOME ?? path45.join(os24.homedir(), ".olam"),
14915
+ const { default: path44 } = await import("node:path");
14916
+ const tp = path44.join(
14917
+ process.env.OLAM_HOME ?? path44.join(os24.homedir(), ".olam"),
14990
14918
  "host-cp.token"
14991
14919
  );
14992
- if (!fs41.existsSync(tp)) return null;
14993
- return fs41.readFileSync(tp, "utf-8").trim();
14920
+ if (!fs40.existsSync(tp)) return null;
14921
+ return fs40.readFileSync(tp, "utf-8").trim();
14994
14922
  } catch {
14995
14923
  return null;
14996
14924
  }
@@ -15015,7 +14943,7 @@ function registerCreate(program2) {
15015
14943
  if (decision.stderrLine) {
15016
14944
  process.stderr.write(decision.stderrLine + "\n");
15017
14945
  }
15018
- spawnSync8("docker", ["pull", overrideRef], { stdio: "pipe" });
14946
+ spawnSync9("docker", ["pull", overrideRef], { stdio: "pipe" });
15019
14947
  const { inspectImageProtocolVersions: inspectImageProtocolVersions2, checkProtocolOverlap: checkProtocolOverlap2 } = await Promise.resolve().then(() => (init_protocol_version(), protocol_version_exports));
15020
14948
  const inspect = inspectImageProtocolVersions2(overrideRef);
15021
14949
  if (inspect.inspectFailed) {
@@ -15064,9 +14992,9 @@ function registerCreate(program2) {
15064
14992
  const reason = inferred.repos.length === 0 ? "no repo names extracted from prompt" : `inference confidence ${inferred.confidence.toFixed(2)} below ${PICKER_CONFIDENCE_THRESHOLD}`;
15065
14993
  printError(`Picker needed: ${reason}`);
15066
14994
  if (catalogRepos.length > 0) {
15067
- console.log(pc9.dim(` available repos: ${catalogRepos.join(", ")}`));
14995
+ console.log(pc10.dim(` available repos: ${catalogRepos.join(", ")}`));
15068
14996
  }
15069
- console.log(pc9.dim(" rerun with explicit --workspace <name> or --repos <a> <b> <c>"));
14997
+ console.log(pc10.dim(" rerun with explicit --workspace <name> or --repos <a> <b> <c>"));
15070
14998
  process.exitCode = 1;
15071
14999
  return;
15072
15000
  }
@@ -15084,7 +15012,7 @@ function registerCreate(program2) {
15084
15012
  inferenceSpinner.fail(`Multiple workspaces match (${decision.result})`);
15085
15013
  const cands = decision.result === "exact-N" ? decision.candidates.map((w) => w.name) : decision.candidates.map((c) => c.workspace.name);
15086
15014
  printError(`Picker needed: ${cands.join(", ")}`);
15087
- console.log(pc9.dim(" rerun with explicit --workspace <name>"));
15015
+ console.log(pc10.dim(" rerun with explicit --workspace <name>"));
15088
15016
  process.exitCode = 1;
15089
15017
  return;
15090
15018
  } else {
@@ -15132,7 +15060,7 @@ function registerCreate(program2) {
15132
15060
  throw err;
15133
15061
  }
15134
15062
  const spinner2 = ora3("Rebuilding olam-devbox:latest\u2026").start();
15135
- const rebuild = spawnSync8(
15063
+ const rebuild = spawnSync9(
15136
15064
  "bash",
15137
15065
  [buildScript],
15138
15066
  { cwd: repoRoot, stdio: "inherit" }
@@ -15198,10 +15126,10 @@ function registerCreate(program2) {
15198
15126
  }
15199
15127
  if (world.credentialsInjected?.claude) {
15200
15128
  console.log(`
15201
- ${pc9.green("Credentials injected. World is ready for dispatch.")}`);
15129
+ ${pc10.green("Credentials injected. World is ready for dispatch.")}`);
15202
15130
  } else if (world.dashboardUrl) {
15203
15131
  console.log(`
15204
- ${pc9.yellow("Authenticate at")} ${world.dashboardUrl}`);
15132
+ ${pc10.yellow("Authenticate at")} ${world.dashboardUrl}`);
15205
15133
  }
15206
15134
  if (opts.hostCp !== false) {
15207
15135
  const probeResult = await probeHostCp().catch(() => null);
@@ -15213,14 +15141,14 @@ ${pc9.yellow("Authenticate at")} ${world.dashboardUrl}`);
15213
15141
  process.stderr.write(
15214
15142
  [
15215
15143
  "",
15216
- pc9.red("Host CP probe failed."),
15144
+ pc10.red("Host CP probe failed."),
15217
15145
  ` tried: http://127.0.0.1:19000/api/bootstrap \u2192 ${diag.bootstrapStatus}`,
15218
15146
  ` tried: docker container "olam-host-cp" \u2192 ${diag.containerStatus}`,
15219
15147
  "",
15220
- pc9.yellow("World was created but the SPA inbox will not show it until you:"),
15221
- ` ${pc9.cyan("olam host-cp start")} (start the host CP)`,
15222
- ` ${pc9.cyan(`olam host-cp register --world ${world.id}`)} (register manually)`,
15223
- ` OR pass ${pc9.dim("--no-host-cp")} on next create to suppress this check.`,
15148
+ pc10.yellow("World was created but the SPA inbox will not show it until you:"),
15149
+ ` ${pc10.cyan("olam host-cp start")} (start the host CP)`,
15150
+ ` ${pc10.cyan(`olam host-cp register --world ${world.id}`)} (register manually)`,
15151
+ ` OR pass ${pc10.dim("--no-host-cp")} on next create to suppress this check.`,
15224
15152
  ""
15225
15153
  ].join("\n")
15226
15154
  );
@@ -15252,13 +15180,13 @@ ${pc9.yellow("Authenticate at")} ${world.dashboardUrl}`);
15252
15180
  process.stderr.write(
15253
15181
  [
15254
15182
  "",
15255
- pc9.red("Host CP registry POST failed."),
15183
+ pc10.red("Host CP registry POST failed."),
15256
15184
  ` url: ${hostCpUrl}/api/admin/registry`,
15257
15185
  ` status: ${reg.status}`,
15258
15186
  ` error: ${reg.error}`,
15259
15187
  "",
15260
- pc9.yellow("World was created but not registered. Run manually:"),
15261
- ` ${pc9.cyan(`olam host-cp register --world ${world.id}`)}`,
15188
+ pc10.yellow("World was created but not registered. Run manually:"),
15189
+ ` ${pc10.cyan(`olam host-cp register --world ${world.id}`)}`,
15262
15190
  ""
15263
15191
  ].join("\n")
15264
15192
  );
@@ -15313,7 +15241,7 @@ ${pc9.yellow("Authenticate at")} ${world.dashboardUrl}`);
15313
15241
  }
15314
15242
  const worldUrl = `${hostCpUrl}/world/${encodeURIComponent(world.id)}`;
15315
15243
  console.log(`
15316
- ${pc9.cyan("Host CP UI:")} ${worldUrl}`);
15244
+ ${pc10.cyan("Host CP UI:")} ${worldUrl}`);
15317
15245
  if (opts.open !== false && reg.ok) {
15318
15246
  const openResult = openUrl(worldUrl);
15319
15247
  if (openResult.opened) {
@@ -15327,14 +15255,7 @@ ${pc9.cyan("Host CP UI:")} ${worldUrl}`);
15327
15255
  spinner.fail("Failed to create world");
15328
15256
  if (err instanceof AuthPreflightError) {
15329
15257
  printError(err.message);
15330
- if (err.remedy) console.log(` ${pc9.dim(err.remedy)}`);
15331
- } else if (err instanceof RepoSelectionRequiredError) {
15332
- printError(err.message);
15333
- if (err.availableRepos.length > 0) {
15334
- const example = err.availableRepos[0];
15335
- console.log(` ${pc9.dim(`Example: olam create --name <name> --repos ${example} --task "<task>"`)}`);
15336
- console.log(` ${pc9.dim('Or: olam create --name <name> --workspace <workspace> --task "<task>"')}`);
15337
- }
15258
+ if (err.remedy) console.log(` ${pc10.dim(err.remedy)}`);
15338
15259
  } else {
15339
15260
  printError(err instanceof Error ? err.message : String(err));
15340
15261
  }
@@ -15345,10 +15266,10 @@ ${pc9.cyan("Host CP UI:")} ${worldUrl}`);
15345
15266
  function resolveRepoRoot(start) {
15346
15267
  let cur = start;
15347
15268
  while (true) {
15348
- if (existsSync23(resolve7(cur, "packages")) && existsSync23(resolve7(cur, "package.json"))) {
15269
+ if (existsSync22(resolve7(cur, "packages")) && existsSync22(resolve7(cur, "package.json"))) {
15349
15270
  return cur;
15350
15271
  }
15351
- const parent = dirname15(cur);
15272
+ const parent = dirname14(cur);
15352
15273
  if (parent === cur) return start;
15353
15274
  cur = parent;
15354
15275
  }
@@ -15359,12 +15280,12 @@ function defaultNameFromPrompt(prompt) {
15359
15280
  }
15360
15281
  async function readHostCpToken3() {
15361
15282
  try {
15362
- const { default: fs41 } = await import("node:fs");
15283
+ const { default: fs40 } = await import("node:fs");
15363
15284
  const { default: os24 } = await import("node:os");
15364
- const { default: path45 } = await import("node:path");
15365
- const tp = path45.join(os24.homedir(), ".olam", "host-cp.token");
15366
- if (!fs41.existsSync(tp)) return null;
15367
- const raw = fs41.readFileSync(tp, "utf-8").trim();
15285
+ const { default: path44 } = await import("node:path");
15286
+ const tp = path44.join(os24.homedir(), ".olam", "host-cp.token");
15287
+ if (!fs40.existsSync(tp)) return null;
15288
+ const raw = fs40.readFileSync(tp, "utf-8").trim();
15368
15289
  return raw.length > 0 ? raw : null;
15369
15290
  } catch {
15370
15291
  return null;
@@ -15409,7 +15330,7 @@ async function fetchHostCpExactMatches(projects) {
15409
15330
  init_context();
15410
15331
  init_output();
15411
15332
  import ora4 from "ora";
15412
- import pc10 from "picocolors";
15333
+ import pc11 from "picocolors";
15413
15334
 
15414
15335
  // ../core/dist/orchestrator/dispatch.js
15415
15336
  var DEEP_MODE_SUFFIX = "\n\nUltrathink and use sub-agents (the Agent tool) to parallelize independent work. Break complex tasks into focused sub-tasks.";
@@ -15496,7 +15417,7 @@ OLAM_EOF`
15496
15417
  const containerName = `olam-${worldId}-devbox`;
15497
15418
  console.log(
15498
15419
  `
15499
- ${pc10.dim(`Watch live: docker exec -it ${containerName} tmux attach -t claude-main -r`)}`
15420
+ ${pc11.dim(`Watch live: docker exec -it ${containerName} tmux attach -t claude-main -r`)}`
15500
15421
  );
15501
15422
  } catch (err) {
15502
15423
  spinner.fail("Dispatch failed");
@@ -15509,7 +15430,7 @@ ${pc10.dim(`Watch live: docker exec -it ${containerName} tmux attach -t claude-m
15509
15430
  // src/commands/observe.ts
15510
15431
  init_context();
15511
15432
  init_output();
15512
- import pc11 from "picocolors";
15433
+ import pc12 from "picocolors";
15513
15434
  function registerObserve(program2) {
15514
15435
  program2.command("observe").description("Stream thoughts from a world (coming soon)").argument("<world>", "World ID").action(async (worldId) => {
15515
15436
  const { ctx, error } = await loadContext();
@@ -15529,15 +15450,15 @@ function registerObserve(program2) {
15529
15450
  checkVersionPin2(worldId, world.workspacePath);
15530
15451
  }
15531
15452
  console.log(
15532
- pc11.yellow("Observation is coming in a future release.")
15453
+ pc12.yellow("Observation is coming in a future release.")
15533
15454
  );
15534
15455
  console.log(
15535
- pc11.dim("This will stream the world's reasoning in real-time.")
15456
+ pc12.dim("This will stream the world's reasoning in real-time.")
15536
15457
  );
15537
15458
  const containerName = `olam-${worldId}-devbox`;
15538
15459
  console.log(
15539
15460
  `
15540
- ${pc11.dim(`For now: docker exec -it ${containerName} tmux attach -t claude-main -r`)}`
15461
+ ${pc12.dim(`For now: docker exec -it ${containerName} tmux attach -t claude-main -r`)}`
15541
15462
  );
15542
15463
  });
15543
15464
  }
@@ -15545,7 +15466,7 @@ ${pc11.dim(`For now: docker exec -it ${containerName} tmux attach -t claude-main
15545
15466
  // src/commands/list.ts
15546
15467
  init_context();
15547
15468
  init_output();
15548
- import pc12 from "picocolors";
15469
+ import pc13 from "picocolors";
15549
15470
  function registerList(program2) {
15550
15471
  program2.command("list").alias("ls").description("List active worlds").action(async () => {
15551
15472
  const { ctx, error } = await loadContext();
@@ -15556,18 +15477,18 @@ function registerList(program2) {
15556
15477
  }
15557
15478
  const worlds = ctx.worldManager.listWorlds();
15558
15479
  if (worlds.length === 0) {
15559
- console.log(pc12.dim("No worlds. Create one with `olam create --name my-world`."));
15480
+ console.log(pc13.dim("No worlds. Create one with `olam create --name my-world`."));
15560
15481
  return;
15561
15482
  }
15562
- console.log(`${pc12.bold(String(worlds.length))} world(s)
15483
+ console.log(`${pc13.bold(String(worlds.length))} world(s)
15563
15484
  `);
15564
15485
  for (const w of worlds) {
15565
- const statusColor = w.status === "running" ? pc12.green(w.status) : w.status === "error" ? pc12.red(w.status) : pc12.yellow(w.status);
15486
+ const statusColor = w.status === "running" ? pc13.green(w.status) : w.status === "error" ? pc13.red(w.status) : pc13.yellow(w.status);
15566
15487
  const age = formatAge(w.createdAt);
15567
15488
  const cost = `$${w.totalCostUsd.toFixed(2)}`;
15568
- console.log(` ${pc12.bold(w.name)} ${pc12.dim(`(${w.id})`)}`);
15489
+ console.log(` ${pc13.bold(w.name)} ${pc13.dim(`(${w.id})`)}`);
15569
15490
  console.log(
15570
- ` ${statusColor} ${pc12.dim("|")} ${w.repos.join(", ")} ${pc12.dim("|")} ${cost} ${pc12.dim("|")} ${age}`
15491
+ ` ${statusColor} ${pc13.dim("|")} ${w.repos.join(", ")} ${pc13.dim("|")} ${cost} ${pc13.dim("|")} ${age}`
15571
15492
  );
15572
15493
  console.log();
15573
15494
  }
@@ -15576,9 +15497,9 @@ function registerList(program2) {
15576
15497
 
15577
15498
  // src/commands/status.ts
15578
15499
  init_output();
15579
- import * as fs23 from "node:fs";
15500
+ import * as fs22 from "node:fs";
15580
15501
  import * as os13 from "node:os";
15581
- import * as path26 from "node:path";
15502
+ import * as path25 from "node:path";
15582
15503
  var CLI_VERSION2 = process.env["OLAM_CLI_VERSION"] ?? "0.0.0";
15583
15504
  var HOST_CP_PORT2 = 19e3;
15584
15505
  async function getMachineStatus(_probe, _loadCtx, _readToken) {
@@ -15608,14 +15529,14 @@ async function getMachineStatus(_probe, _loadCtx, _readToken) {
15608
15529
  }
15609
15530
  } catch {
15610
15531
  }
15611
- const manifestPath2 = path26.join(os13.homedir(), ".olam", "cache", "manifest.json");
15532
+ const manifestPath2 = path25.join(os13.homedir(), ".olam", "cache", "manifest.json");
15612
15533
  let updateAvailable = null;
15613
15534
  let lastUpdateCheck = null;
15614
- if (fs23.existsSync(manifestPath2)) {
15615
- const mtime = fs23.statSync(manifestPath2).mtime;
15535
+ if (fs22.existsSync(manifestPath2)) {
15536
+ const mtime = fs22.statSync(manifestPath2).mtime;
15616
15537
  lastUpdateCheck = mtime.toISOString();
15617
15538
  try {
15618
- const manifest = JSON.parse(fs23.readFileSync(manifestPath2, "utf-8"));
15539
+ const manifest = JSON.parse(fs22.readFileSync(manifestPath2, "utf-8"));
15619
15540
  const latest = manifest["version"];
15620
15541
  updateAvailable = latest !== void 0 && latest !== CLI_VERSION2;
15621
15542
  } catch {
@@ -15738,10 +15659,10 @@ function registerDestroy(program2) {
15738
15659
  // src/commands/clean.ts
15739
15660
  init_context();
15740
15661
  init_output();
15741
- import fs24 from "node:fs";
15662
+ import fs23 from "node:fs";
15742
15663
  import os14 from "node:os";
15743
- import path27 from "node:path";
15744
- import { execFileSync as execFileSync4 } from "node:child_process";
15664
+ import path26 from "node:path";
15665
+ import { execFileSync as execFileSync5 } from "node:child_process";
15745
15666
  function registerClean(program2) {
15746
15667
  program2.command("clean").description("Reap orphan world filesystem state under ~/.olam/worlds/").option("--apply", "Actually delete the orphans (default is dry-run)", false).option(
15747
15668
  "--include-dirty",
@@ -15764,8 +15685,8 @@ async function runClean(opts) {
15764
15685
  printError(error?.message ?? "Olam is not configured. Run `olam init` first.");
15765
15686
  return 1;
15766
15687
  }
15767
- const worldsDir = path27.join(os14.homedir(), ".olam", "worlds");
15768
- if (!fs24.existsSync(worldsDir)) {
15688
+ const worldsDir = path26.join(os14.homedir(), ".olam", "worlds");
15689
+ if (!fs23.existsSync(worldsDir)) {
15769
15690
  if (opts.json) {
15770
15691
  process.stdout.write(`${JSON.stringify({ worldsDir, entries: [] })}
15771
15692
  `);
@@ -15780,8 +15701,8 @@ async function runClean(opts) {
15780
15701
  }
15781
15702
  const worktreeMap = collectWorktrees(worldsDir);
15782
15703
  const entries = [];
15783
- for (const id of fs24.readdirSync(worldsDir).sort()) {
15784
- const fullPath = path27.join(worldsDir, id);
15704
+ for (const id of fs23.readdirSync(worldsDir).sort()) {
15705
+ const fullPath = path26.join(worldsDir, id);
15785
15706
  const stat = safeStat(fullPath);
15786
15707
  if (!stat || !stat.isDirectory()) continue;
15787
15708
  entries.push(classifyWorld({ id, fullPath, liveIds, worktreeMap }));
@@ -15847,7 +15768,7 @@ function classifyWorld(args) {
15847
15768
  if (liveIds.has(id)) {
15848
15769
  return { id, path: fullPath, bytes, category: "active", note: "in registry" };
15849
15770
  }
15850
- const worktreeChild = path27.join(fullPath, "olam");
15771
+ const worktreeChild = path26.join(fullPath, "olam");
15851
15772
  const worktreeInfo = worktreeMap.get(worktreeChild);
15852
15773
  if (worktreeInfo) {
15853
15774
  if (worktreeInfo.dirty > 0 || worktreeInfo.unpushed > 0) {
@@ -15884,7 +15805,7 @@ function reapEntry(entry) {
15884
15805
  try {
15885
15806
  const gitDir = resolveGitDirForWorktree(entry.worktreePath);
15886
15807
  if (gitDir) {
15887
- execFileSync4("git", ["worktree", "remove", "--force", entry.worktreePath], {
15808
+ execFileSync5("git", ["worktree", "remove", "--force", entry.worktreePath], {
15888
15809
  cwd: gitDir,
15889
15810
  stdio: "pipe"
15890
15811
  });
@@ -15893,20 +15814,20 @@ function reapEntry(entry) {
15893
15814
  }
15894
15815
  }
15895
15816
  try {
15896
- fs24.rmSync(entry.path, { recursive: true, force: true });
15817
+ fs23.rmSync(entry.path, { recursive: true, force: true });
15897
15818
  } catch (err) {
15898
15819
  process.stderr.write(` ! rm ${entry.path}: ${err instanceof Error ? err.message : String(err)}
15899
15820
  `);
15900
15821
  return false;
15901
15822
  }
15902
- return !fs24.existsSync(entry.path);
15823
+ return !fs23.existsSync(entry.path);
15903
15824
  }
15904
15825
  function collectWorktrees(worldsDir) {
15905
15826
  const out = /* @__PURE__ */ new Map();
15906
- for (const id of fs24.readdirSync(worldsDir)) {
15907
- const child = path27.join(worldsDir, id, "olam");
15908
- const gitMarker = path27.join(child, ".git");
15909
- if (!fs24.existsSync(gitMarker)) continue;
15827
+ for (const id of fs23.readdirSync(worldsDir)) {
15828
+ const child = path26.join(worldsDir, id, "olam");
15829
+ const gitMarker = path26.join(child, ".git");
15830
+ if (!fs23.existsSync(gitMarker)) continue;
15910
15831
  const gitDir = resolveGitDirForWorktree(child);
15911
15832
  if (!gitDir) continue;
15912
15833
  const branch = readBranch(child);
@@ -15917,21 +15838,21 @@ function collectWorktrees(worldsDir) {
15917
15838
  return out;
15918
15839
  }
15919
15840
  function resolveGitDirForWorktree(worktreePath) {
15920
- const gitMarker = path27.join(worktreePath, ".git");
15841
+ const gitMarker = path26.join(worktreePath, ".git");
15921
15842
  try {
15922
- const top = execFileSync4("git", ["rev-parse", "--show-toplevel"], {
15843
+ const top = execFileSync5("git", ["rev-parse", "--show-toplevel"], {
15923
15844
  cwd: worktreePath,
15924
15845
  encoding: "utf-8",
15925
15846
  stdio: "pipe"
15926
15847
  }).trim();
15927
15848
  if (!top) return null;
15928
- const common = execFileSync4("git", ["rev-parse", "--git-common-dir"], {
15849
+ const common = execFileSync5("git", ["rev-parse", "--git-common-dir"], {
15929
15850
  cwd: worktreePath,
15930
15851
  encoding: "utf-8",
15931
15852
  stdio: "pipe"
15932
15853
  }).trim();
15933
15854
  if (!common) return top;
15934
- return path27.dirname(path27.resolve(worktreePath, common));
15855
+ return path26.dirname(path26.resolve(worktreePath, common));
15935
15856
  } catch {
15936
15857
  return null;
15937
15858
  }
@@ -15939,7 +15860,7 @@ function resolveGitDirForWorktree(worktreePath) {
15939
15860
  }
15940
15861
  function readBranch(worktreePath) {
15941
15862
  try {
15942
- return execFileSync4("git", ["branch", "--show-current"], {
15863
+ return execFileSync5("git", ["branch", "--show-current"], {
15943
15864
  cwd: worktreePath,
15944
15865
  encoding: "utf-8",
15945
15866
  stdio: "pipe"
@@ -15950,7 +15871,7 @@ function readBranch(worktreePath) {
15950
15871
  }
15951
15872
  function countDirty(worktreePath) {
15952
15873
  try {
15953
- const out = execFileSync4("git", ["status", "--porcelain"], {
15874
+ const out = execFileSync5("git", ["status", "--porcelain"], {
15954
15875
  cwd: worktreePath,
15955
15876
  encoding: "utf-8",
15956
15877
  stdio: "pipe"
@@ -15962,7 +15883,7 @@ function countDirty(worktreePath) {
15962
15883
  }
15963
15884
  function countUnpushed(worktreePath) {
15964
15885
  try {
15965
- const out = execFileSync4("git", ["log", "@{u}..HEAD", "--oneline"], {
15886
+ const out = execFileSync5("git", ["log", "@{u}..HEAD", "--oneline"], {
15966
15887
  cwd: worktreePath,
15967
15888
  encoding: "utf-8",
15968
15889
  stdio: "pipe"
@@ -15974,7 +15895,7 @@ function countUnpushed(worktreePath) {
15974
15895
  }
15975
15896
  function safeStat(p) {
15976
15897
  try {
15977
- return fs24.statSync(p);
15898
+ return fs23.statSync(p);
15978
15899
  } catch {
15979
15900
  return null;
15980
15901
  }
@@ -15986,7 +15907,7 @@ function computeBytes(p) {
15986
15907
  const cur = stack.pop();
15987
15908
  let st;
15988
15909
  try {
15989
- st = fs24.lstatSync(cur);
15910
+ st = fs23.lstatSync(cur);
15990
15911
  } catch {
15991
15912
  continue;
15992
15913
  }
@@ -15994,11 +15915,11 @@ function computeBytes(p) {
15994
15915
  if (st.isDirectory()) {
15995
15916
  let entries;
15996
15917
  try {
15997
- entries = fs24.readdirSync(cur);
15918
+ entries = fs23.readdirSync(cur);
15998
15919
  } catch {
15999
15920
  continue;
16000
15921
  }
16001
- for (const name of entries) stack.push(path27.join(cur, name));
15922
+ for (const name of entries) stack.push(path26.join(cur, name));
16002
15923
  } else {
16003
15924
  total += st.size;
16004
15925
  }
@@ -16051,7 +15972,7 @@ async function confirmInteractive() {
16051
15972
  init_context();
16052
15973
  init_output();
16053
15974
  import { execSync as execSync7 } from "node:child_process";
16054
- import pc13 from "picocolors";
15975
+ import pc14 from "picocolors";
16055
15976
  var SAFE_IDENT3 = /^[a-z0-9][a-z0-9-]{0,63}$/;
16056
15977
  function buildStartClaudeCommands(containerName, sessionName, task) {
16057
15978
  if (!SAFE_IDENT3.test(containerName)) {
@@ -16158,7 +16079,7 @@ function registerEnter(program2) {
16158
16079
  }
16159
16080
  console.log("Run these commands in order to enter the world:\n");
16160
16081
  for (const step of steps) {
16161
- console.log(` ${pc13.dim(`# ${step.description}`)}`);
16082
+ console.log(` ${pc14.dim(`# ${step.description}`)}`);
16162
16083
  if (step.stdin !== void 0) {
16163
16084
  const escaped = step.stdin.replace(/'/g, "'\\''");
16164
16085
  console.log(` printf '%s' '${escaped}' | ${step.command}`);
@@ -16192,11 +16113,11 @@ function registerEnter(program2) {
16192
16113
  return;
16193
16114
  }
16194
16115
  console.log("Run this command to enter the world:\n");
16195
- console.log(` ${pc13.bold(result.command)}`);
16116
+ console.log(` ${pc14.bold(result.command)}`);
16196
16117
  const containerName = `olam-${worldId}-devbox`;
16197
16118
  console.log(
16198
16119
  `
16199
- ${pc13.dim(`Observe dispatch: docker exec -it ${containerName} tmux attach -t olam-dispatch -r`)}`
16120
+ ${pc14.dim(`Observe dispatch: docker exec -it ${containerName} tmux attach -t olam-dispatch -r`)}`
16200
16121
  );
16201
16122
  });
16202
16123
  }
@@ -16206,7 +16127,7 @@ init_context();
16206
16127
  init_output();
16207
16128
  init_exit_codes();
16208
16129
  init_world_paths();
16209
- import * as fs25 from "node:fs";
16130
+ import * as fs24 from "node:fs";
16210
16131
  import "node:path";
16211
16132
  import ora6 from "ora";
16212
16133
  function registerCrystallize(program2, options = {}) {
@@ -16238,7 +16159,7 @@ function registerCrystallize(program2, options = {}) {
16238
16159
  return;
16239
16160
  }
16240
16161
  const thoughtDbPath = getWorldDbPath(world.workspacePath);
16241
- if (!fs25.existsSync(thoughtDbPath)) {
16162
+ if (!fs24.existsSync(thoughtDbPath)) {
16242
16163
  printError(`No thoughts captured yet for "${worldId}". Run a dispatch first.`);
16243
16164
  process.exitCode = EXIT_GENERIC_ERROR;
16244
16165
  return;
@@ -16308,7 +16229,7 @@ function registerCrystallize(program2, options = {}) {
16308
16229
 
16309
16230
  // src/commands/pr.ts
16310
16231
  init_registry();
16311
- import pc14 from "picocolors";
16232
+ import pc15 from "picocolors";
16312
16233
 
16313
16234
  // ../core/dist/pr-gate/client.js
16314
16235
  var HOST_CONTROL_PLANE_BASE2 = 19080;
@@ -16389,26 +16310,26 @@ async function findGate(id) {
16389
16310
  return null;
16390
16311
  }
16391
16312
  function formatStateBadge(state) {
16392
- if (state === "approve") return pc14.green("approve");
16393
- if (state === "block") return pc14.red("block");
16394
- if (state === "denied") return pc14.gray("denied");
16395
- return pc14.yellow("pending");
16313
+ if (state === "approve") return pc15.green("approve");
16314
+ if (state === "block") return pc15.red("block");
16315
+ if (state === "denied") return pc15.gray("denied");
16316
+ return pc15.yellow("pending");
16396
16317
  }
16397
16318
  function registerPr(program2) {
16398
16319
  const pr = program2.command("pr").description("Review and decide PR-gate requests from running worlds");
16399
16320
  pr.command("list").description("List all PR-gate requests across every running world").action(async () => {
16400
16321
  const all = await fanoutList();
16401
16322
  if (all.length === 0) {
16402
- console.log(pc14.dim("No gates open."));
16323
+ console.log(pc15.dim("No gates open."));
16403
16324
  return;
16404
16325
  }
16405
16326
  printHeader(`${all.length} gate(s)`);
16406
16327
  for (const { world, gate } of all) {
16407
16328
  const badge = formatStateBadge(gate.state);
16408
16329
  console.log(
16409
- ` ${pc14.bold(gate.id.slice(0, 8))} ${badge.padEnd(20)} ${pc14.dim(world.name)} ${pc14.dim(gate.branch)}`
16330
+ ` ${pc15.bold(gate.id.slice(0, 8))} ${badge.padEnd(20)} ${pc15.dim(world.name)} ${pc15.dim(gate.branch)}`
16410
16331
  );
16411
- console.log(` ${pc14.dim(gate.command.slice(0, 100))}`);
16332
+ console.log(` ${pc15.dim(gate.command.slice(0, 100))}`);
16412
16333
  }
16413
16334
  });
16414
16335
  pr.command("show").description("Show full gate detail (diff, command, commits)").argument("<id>", "Gate id (prefix match ok)").action(async (id) => {
@@ -16431,9 +16352,9 @@ function registerPr(program2) {
16431
16352
  if (gate.reason) printInfo("Reason", gate.reason);
16432
16353
  }
16433
16354
  printHeader("Commits");
16434
- console.log(gate.commitLog || pc14.dim(" (empty)"));
16355
+ console.log(gate.commitLog || pc15.dim(" (empty)"));
16435
16356
  printHeader("Diff stat");
16436
- console.log(gate.diffStat || pc14.dim(" (empty)"));
16357
+ console.log(gate.diffStat || pc15.dim(" (empty)"));
16437
16358
  });
16438
16359
  function decideCommand(verb, decision) {
16439
16360
  pr.command(verb).description(`${verb[0].toUpperCase()}${verb.slice(1)} a pending gate`).argument("<id>", "Gate id").option("--reason <reason>", "Short free-text reason").option("--by <name>", "Deciding identity (defaults to $USER)", process.env["USER"] ?? "human").action(async (id, opts) => {
@@ -16558,7 +16479,7 @@ function registerLanes(program2) {
16558
16479
  // src/commands/policy-check.ts
16559
16480
  init_loader2();
16560
16481
  import { execSync as execSync8 } from "node:child_process";
16561
- import pc15 from "picocolors";
16482
+ import pc16 from "picocolors";
16562
16483
 
16563
16484
  // ../../node_modules/balanced-match/dist/esm/index.js
16564
16485
  var balanced = (a, b, str) => {
@@ -17612,11 +17533,11 @@ var qmarksTestNoExtDot = ([$0]) => {
17612
17533
  return (f) => f.length === len && f !== "." && f !== "..";
17613
17534
  };
17614
17535
  var defaultPlatform = typeof process === "object" && process ? typeof process.env === "object" && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__ || process.platform : "posix";
17615
- var path29 = {
17536
+ var path28 = {
17616
17537
  win32: { sep: "\\" },
17617
17538
  posix: { sep: "/" }
17618
17539
  };
17619
- var sep = defaultPlatform === "win32" ? path29.win32.sep : path29.posix.sep;
17540
+ var sep = defaultPlatform === "win32" ? path28.win32.sep : path28.posix.sep;
17620
17541
  minimatch.sep = sep;
17621
17542
  var GLOBSTAR = /* @__PURE__ */ Symbol("globstar **");
17622
17543
  minimatch.GLOBSTAR = GLOBSTAR;
@@ -18418,7 +18339,7 @@ function registerPolicyCheck(program2) {
18418
18339
  const workspaceRoot = opts.workspace ?? process.cwd();
18419
18340
  const policies = loadPolicies(workspaceRoot);
18420
18341
  if (policies.length === 0) {
18421
- console.log(pc15.dim("policy-check: no policies found in .olam/policies/ \u2014 nothing to enforce"));
18342
+ console.log(pc16.dim("policy-check: no policies found in .olam/policies/ \u2014 nothing to enforce"));
18422
18343
  return;
18423
18344
  }
18424
18345
  const diff = getDiff(opts.base, workspaceRoot);
@@ -18427,11 +18348,11 @@ function registerPolicyCheck(program2) {
18427
18348
  for (const result of results) {
18428
18349
  if (result.passed) continue;
18429
18350
  if (result.severity === "error") {
18430
- console.error(`${pc15.red("policy error")} [${result.policyId}]`);
18351
+ console.error(`${pc16.red("policy error")} [${result.policyId}]`);
18431
18352
  console.error(result.message);
18432
18353
  hasErrorFailure = true;
18433
18354
  } else {
18434
- console.warn(`${pc15.yellow("policy warn")} [${result.policyId}]`);
18355
+ console.warn(`${pc16.yellow("policy warn")} [${result.policyId}]`);
18435
18356
  console.warn(result.message);
18436
18357
  }
18437
18358
  }
@@ -18444,23 +18365,23 @@ function registerPolicyCheck(program2) {
18444
18365
  // src/commands/upgrade.ts
18445
18366
  init_output();
18446
18367
  init_host_cp();
18447
- import * as fs28 from "node:fs";
18448
- import * as path32 from "node:path";
18449
- import { spawnSync as spawnSync10 } from "node:child_process";
18368
+ import * as fs27 from "node:fs";
18369
+ import * as path31 from "node:path";
18370
+ import { spawnSync as spawnSync11 } from "node:child_process";
18450
18371
  import ora7 from "ora";
18451
- import pc16 from "picocolors";
18372
+ import pc17 from "picocolors";
18452
18373
 
18453
18374
  // src/commands/upgrade-lock.ts
18454
- import * as fs26 from "node:fs";
18375
+ import * as fs25 from "node:fs";
18455
18376
  import * as os15 from "node:os";
18456
- import * as path30 from "node:path";
18457
- import { spawnSync as spawnSync9 } from "node:child_process";
18458
- var LOCK_FILE_PATH = path30.join(os15.homedir(), ".olam", ".upgrade.lock");
18377
+ import * as path29 from "node:path";
18378
+ import { spawnSync as spawnSync10 } from "node:child_process";
18379
+ var LOCK_FILE_PATH = path29.join(os15.homedir(), ".olam", ".upgrade.lock");
18459
18380
  var STALE_LOCK_TIMEOUT_MS = 5 * 60 * 1e3;
18460
18381
  function readLockFile(lockPath) {
18461
18382
  try {
18462
- if (!fs26.existsSync(lockPath)) return null;
18463
- const raw = fs26.readFileSync(lockPath, "utf-8").trim();
18383
+ if (!fs25.existsSync(lockPath)) return null;
18384
+ const raw = fs25.readFileSync(lockPath, "utf-8").trim();
18464
18385
  if (raw.length === 0) return null;
18465
18386
  const parsed = JSON.parse(raw);
18466
18387
  if (typeof parsed.pid !== "number" || typeof parsed.startTs !== "number") return null;
@@ -18479,7 +18400,7 @@ function isPidAlive(pid) {
18479
18400
  }
18480
18401
  var PS_UNAVAILABLE = "__ps_unavailable__";
18481
18402
  function getPidCommand(pid) {
18482
- const result = spawnSync9("ps", ["-p", String(pid), "-o", "comm="], {
18403
+ const result = spawnSync10("ps", ["-p", String(pid), "-o", "comm="], {
18483
18404
  encoding: "utf-8",
18484
18405
  stdio: ["ignore", "pipe", "ignore"]
18485
18406
  });
@@ -18505,16 +18426,16 @@ function isStaleLock(content, nowMs = Date.now()) {
18505
18426
  return false;
18506
18427
  }
18507
18428
  function acquireLock(lockPath = LOCK_FILE_PATH, nowMs = Date.now()) {
18508
- const dir = path30.dirname(lockPath);
18509
- fs26.mkdirSync(dir, { recursive: true });
18429
+ const dir = path29.dirname(lockPath);
18430
+ fs25.mkdirSync(dir, { recursive: true });
18510
18431
  for (let attempt = 0; attempt < 2; attempt++) {
18511
18432
  try {
18512
- const fd = fs26.openSync(lockPath, "wx", 420);
18433
+ const fd = fs25.openSync(lockPath, "wx", 420);
18513
18434
  try {
18514
18435
  const content = { pid: process.pid, startTs: nowMs };
18515
- fs26.writeSync(fd, JSON.stringify(content));
18436
+ fs25.writeSync(fd, JSON.stringify(content));
18516
18437
  } finally {
18517
- fs26.closeSync(fd);
18438
+ fs25.closeSync(fd);
18518
18439
  }
18519
18440
  return { acquired: true, lockPath };
18520
18441
  } catch (err) {
@@ -18523,7 +18444,7 @@ function acquireLock(lockPath = LOCK_FILE_PATH, nowMs = Date.now()) {
18523
18444
  const existing2 = readLockFile(lockPath);
18524
18445
  if (isStaleLock(existing2, nowMs)) {
18525
18446
  try {
18526
- fs26.unlinkSync(lockPath);
18447
+ fs25.unlinkSync(lockPath);
18527
18448
  } catch (unlinkErr) {
18528
18449
  const ucode = unlinkErr.code;
18529
18450
  if (ucode !== "ENOENT") throw unlinkErr;
@@ -18548,7 +18469,7 @@ function acquireLock(lockPath = LOCK_FILE_PATH, nowMs = Date.now()) {
18548
18469
  }
18549
18470
  function releaseLock(lockPath = LOCK_FILE_PATH) {
18550
18471
  try {
18551
- fs26.unlinkSync(lockPath);
18472
+ fs25.unlinkSync(lockPath);
18552
18473
  } catch (err) {
18553
18474
  const code = err.code;
18554
18475
  if (code !== "ENOENT") throw err;
@@ -18566,19 +18487,19 @@ function formatRefusalMessage(result, lockPath = LOCK_FILE_PATH) {
18566
18487
  }
18567
18488
 
18568
18489
  // src/commands/upgrade-log.ts
18569
- import * as fs27 from "node:fs";
18490
+ import * as fs26 from "node:fs";
18570
18491
  import * as os16 from "node:os";
18571
- import * as path31 from "node:path";
18492
+ import * as path30 from "node:path";
18572
18493
  function getUpgradeLogPath() {
18573
18494
  const home = process.env["HOME"] ?? os16.homedir();
18574
- return path31.join(home, ".olam", "upgrade.log");
18495
+ return path30.join(home, ".olam", "upgrade.log");
18575
18496
  }
18576
18497
  var UPGRADE_LOG_PATH = getUpgradeLogPath();
18577
18498
  function appendUpgradeLog(row, logPath = getUpgradeLogPath()) {
18578
18499
  try {
18579
- fs27.mkdirSync(path31.dirname(logPath), { recursive: true });
18500
+ fs26.mkdirSync(path30.dirname(logPath), { recursive: true });
18580
18501
  const line = JSON.stringify(row) + "\n";
18581
- fs27.appendFileSync(logPath, line, { mode: 420 });
18502
+ fs26.appendFileSync(logPath, line, { mode: 420 });
18582
18503
  } catch (err) {
18583
18504
  process.stderr.write(
18584
18505
  `[upgrade-log] failed to append: ${err instanceof Error ? err.message : String(err)}
@@ -18587,10 +18508,10 @@ function appendUpgradeLog(row, logPath = getUpgradeLogPath()) {
18587
18508
  }
18588
18509
  }
18589
18510
  function readUpgradeLog(limit = 10, logPath = getUpgradeLogPath()) {
18590
- if (!fs27.existsSync(logPath)) return [];
18511
+ if (!fs26.existsSync(logPath)) return [];
18591
18512
  let raw;
18592
18513
  try {
18593
- raw = fs27.readFileSync(logPath, "utf-8");
18514
+ raw = fs26.readFileSync(logPath, "utf-8");
18594
18515
  } catch (err) {
18595
18516
  process.stderr.write(
18596
18517
  `[upgrade-log] failed to read: ${err instanceof Error ? err.message : String(err)}
@@ -18683,12 +18604,12 @@ init_protocol_version();
18683
18604
  init_install_root();
18684
18605
  var AUTH_HEALTH_URL2 = "http://127.0.0.1:9999/health";
18685
18606
  function isNodeModulesInSync(cwd) {
18686
- const lockPath = path32.join(cwd, "package-lock.json");
18687
- const markerPath = path32.join(cwd, "node_modules", ".package-lock.json");
18688
- if (!fs28.existsSync(lockPath) || !fs28.existsSync(markerPath)) return false;
18607
+ const lockPath = path31.join(cwd, "package-lock.json");
18608
+ const markerPath = path31.join(cwd, "node_modules", ".package-lock.json");
18609
+ if (!fs27.existsSync(lockPath) || !fs27.existsSync(markerPath)) return false;
18689
18610
  try {
18690
- const lockStat = fs28.statSync(lockPath);
18691
- const markerStat = fs28.statSync(markerPath);
18611
+ const lockStat = fs27.statSync(lockPath);
18612
+ const markerStat = fs27.statSync(markerPath);
18692
18613
  return markerStat.mtimeMs >= lockStat.mtimeMs;
18693
18614
  } catch {
18694
18615
  return false;
@@ -18704,8 +18625,8 @@ function shouldSkipInstall(opts, cwd) {
18704
18625
  return { skip: false };
18705
18626
  }
18706
18627
  function validateRepoRoot(cwd) {
18707
- const marker = path32.join(cwd, "packages/host-cp/compose.yaml");
18708
- if (!fs28.existsSync(marker)) {
18628
+ const marker = path31.join(cwd, "packages/host-cp/compose.yaml");
18629
+ if (!fs27.existsSync(marker)) {
18709
18630
  return {
18710
18631
  ok: false,
18711
18632
  error: `Not an olam repo root (expected ${marker}).
@@ -18737,8 +18658,8 @@ function extractBundleHash(indexHtml) {
18737
18658
  }
18738
18659
  function runStep2(label, cmd, args, opts = {}) {
18739
18660
  const start = Date.now();
18740
- process.stdout.write(` ${pc16.dim(label.padEnd(34))}`);
18741
- const result = spawnSync10(cmd, [...args], {
18661
+ process.stdout.write(` ${pc17.dim(label.padEnd(34))}`);
18662
+ const result = spawnSync11(cmd, [...args], {
18742
18663
  encoding: "utf-8",
18743
18664
  stdio: ["ignore", "pipe", "pipe"],
18744
18665
  cwd: opts.cwd ?? process.cwd(),
@@ -18747,7 +18668,7 @@ function runStep2(label, cmd, args, opts = {}) {
18747
18668
  const durationMs = Date.now() - start;
18748
18669
  const ok = result.status === 0 && result.error === void 0;
18749
18670
  const dur = `${(durationMs / 1e3).toFixed(1)}s`;
18750
- process.stdout.write(`${ok ? pc16.green("\u2713") : pc16.red("\u2717")} ${dur}
18671
+ process.stdout.write(`${ok ? pc17.green("\u2713") : pc17.red("\u2717")} ${dur}
18751
18672
  `);
18752
18673
  return {
18753
18674
  ok,
@@ -18757,7 +18678,7 @@ function runStep2(label, cmd, args, opts = {}) {
18757
18678
  };
18758
18679
  }
18759
18680
  function isGitDirty(cwd) {
18760
- const result = spawnSync10("git", ["status", "--porcelain"], {
18681
+ const result = spawnSync11("git", ["status", "--porcelain"], {
18761
18682
  encoding: "utf-8",
18762
18683
  stdio: ["ignore", "pipe", "pipe"],
18763
18684
  cwd
@@ -18765,7 +18686,7 @@ function isGitDirty(cwd) {
18765
18686
  return (result.stdout ?? "").trim().length > 0;
18766
18687
  }
18767
18688
  function hasGitUpstream(cwd) {
18768
- const result = spawnSync10("git", ["rev-parse", "--abbrev-ref", "@{u}"], {
18689
+ const result = spawnSync11("git", ["rev-parse", "--abbrev-ref", "@{u}"], {
18769
18690
  encoding: "utf-8",
18770
18691
  stdio: ["ignore", "pipe", "pipe"],
18771
18692
  cwd
@@ -18773,7 +18694,7 @@ function hasGitUpstream(cwd) {
18773
18694
  return result.status === 0;
18774
18695
  }
18775
18696
  function captureHeadSha(cwd) {
18776
- const result = spawnSync10("git", ["rev-parse", "HEAD"], {
18697
+ const result = spawnSync11("git", ["rev-parse", "HEAD"], {
18777
18698
  encoding: "utf-8",
18778
18699
  stdio: ["ignore", "pipe", "pipe"],
18779
18700
  cwd
@@ -18788,7 +18709,7 @@ function abbreviateSha(sha) {
18788
18709
  }
18789
18710
  function imageExists(tag) {
18790
18711
  try {
18791
- const result = spawnSync10("docker", ["image", "inspect", "--format", "{{.Id}}", tag], {
18712
+ const result = spawnSync11("docker", ["image", "inspect", "--format", "{{.Id}}", tag], {
18792
18713
  encoding: "utf-8",
18793
18714
  stdio: ["ignore", "pipe", "ignore"]
18794
18715
  });
@@ -18802,10 +18723,12 @@ function checkRollbackSetExists(plan) {
18802
18723
  if (missing.length === 0) return null;
18803
18724
  return missing.join(", ");
18804
18725
  }
18726
+ var SMOKE_DOCKER_TIMEOUT_MS = 3e4;
18805
18727
  function smokeImage(image, targetSha) {
18806
- const createResult = spawnSync10("docker", ["create", "--name", `olam-smoke-${Date.now()}`, image], {
18728
+ const createResult = spawnSync11("docker", ["create", "--name", `olam-smoke-${Date.now()}`, image], {
18807
18729
  encoding: "utf-8",
18808
- stdio: ["ignore", "pipe", "pipe"]
18730
+ stdio: ["ignore", "pipe", "pipe"],
18731
+ timeout: SMOKE_DOCKER_TIMEOUT_MS
18809
18732
  });
18810
18733
  if (createResult.status !== 0) {
18811
18734
  return {
@@ -18816,18 +18739,20 @@ function smokeImage(image, targetSha) {
18816
18739
  };
18817
18740
  }
18818
18741
  const containerId = (createResult.stdout ?? "").trim();
18819
- const inspectResult = spawnSync10(
18742
+ const inspectResult = spawnSync11(
18820
18743
  "docker",
18821
18744
  ["inspect", "--format", '{{index .Config.Labels "olam.build.sha"}}', image],
18822
18745
  {
18823
18746
  encoding: "utf-8",
18824
- stdio: ["ignore", "pipe", "pipe"]
18747
+ stdio: ["ignore", "pipe", "pipe"],
18748
+ timeout: SMOKE_DOCKER_TIMEOUT_MS
18825
18749
  }
18826
18750
  );
18827
18751
  if (containerId.length > 0) {
18828
- spawnSync10("docker", ["rm", "-f", containerId], {
18752
+ spawnSync11("docker", ["rm", "-f", containerId], {
18829
18753
  encoding: "utf-8",
18830
- stdio: ["ignore", "ignore", "ignore"]
18754
+ stdio: ["ignore", "ignore", "ignore"],
18755
+ timeout: SMOKE_DOCKER_TIMEOUT_MS
18831
18756
  });
18832
18757
  }
18833
18758
  if (inspectResult.status !== 0) {
@@ -18864,7 +18789,7 @@ var PRODUCTION_SWAP_PLAN = [
18864
18789
  ];
18865
18790
  function dockerTag(source, dest) {
18866
18791
  try {
18867
- const result = spawnSync10("docker", ["tag", source, dest], {
18792
+ const result = spawnSync11("docker", ["tag", source, dest], {
18868
18793
  encoding: "utf-8",
18869
18794
  stdio: ["ignore", "ignore", "pipe"]
18870
18795
  });
@@ -19028,11 +18953,11 @@ async function waitForAuthHealthLocal(timeoutMs = AUTH_HEALTH_TIMEOUT_MS) {
19028
18953
  async function recreateAuthService() {
19029
18954
  const start = Date.now();
19030
18955
  try {
19031
- spawnSync10("docker", ["stop", "olam-auth"], {
18956
+ spawnSync11("docker", ["stop", "olam-auth"], {
19032
18957
  encoding: "utf-8",
19033
18958
  stdio: ["ignore", "ignore", "ignore"]
19034
18959
  });
19035
- spawnSync10("docker", ["rm", "olam-auth"], {
18960
+ spawnSync11("docker", ["rm", "olam-auth"], {
19036
18961
  encoding: "utf-8",
19037
18962
  stdio: ["ignore", "ignore", "ignore"]
19038
18963
  });
@@ -19057,9 +18982,9 @@ async function recreateAuthService() {
19057
18982
  }
19058
18983
  }
19059
18984
  function readBundleHash(cwd) {
19060
- const indexPath = path32.join(cwd, "packages/control-plane/public/index.html");
19061
- if (!fs28.existsSync(indexPath)) return null;
19062
- return extractBundleHash(fs28.readFileSync(indexPath, "utf-8"));
18985
+ const indexPath = path31.join(cwd, "packages/control-plane/public/index.html");
18986
+ if (!fs27.existsSync(indexPath)) return null;
18987
+ return extractBundleHash(fs27.readFileSync(indexPath, "utf-8"));
19063
18988
  }
19064
18989
  async function runUpgradePullByDigest(deps = {}) {
19065
18990
  const docker2 = deps.docker ?? realDocker;
@@ -19071,19 +18996,27 @@ async function runUpgradePullByDigest(deps = {}) {
19071
18996
  if (info.exitCode !== 0) {
19072
18997
  infoSpinner.fail("docker daemon not reachable");
19073
18998
  process.stderr.write(
19074
- `${pc16.red("error")} docker info exited with ${info.exitCode}.
18999
+ `${pc17.red("error")} docker info exited with ${info.exitCode}.
19075
19000
  Ensure Docker Desktop / Colima / Rancher is running, then retry.
19076
19001
  `
19077
19002
  );
19078
19003
  return { exitCode: EXIT_GENERIC_ERROR, summary: "docker daemon not reachable" };
19079
19004
  }
19080
19005
  infoSpinner.succeed("docker daemon reachable");
19081
- const imageRefs = [
19006
+ const hasMcpAuthDigest = typeof digests["mcp-auth"] === "string" && digests["mcp-auth"].length > 0;
19007
+ const baseRefs = [
19082
19008
  { name: "host-cp", ref: `${registry}/olam-host-cp@${digests["host-cp"]}` },
19083
19009
  { name: "auth", ref: `${registry}/olam-auth@${digests.auth}` },
19084
19010
  { name: "devbox", ref: `${registry}/olam-devbox@${digests.devbox}` }
19085
19011
  ];
19086
- const pullSpinner = ora7("Pulling images (3 parallel)").start();
19012
+ if (hasMcpAuthDigest) {
19013
+ baseRefs.push({
19014
+ name: "mcp-auth",
19015
+ ref: `${registry}/olam-mcp-auth@${digests["mcp-auth"]}`
19016
+ });
19017
+ }
19018
+ const imageRefs = baseRefs;
19019
+ const pullSpinner = ora7(`Pulling images (${imageRefs.length} parallel)`).start();
19087
19020
  const pullStart = Date.now();
19088
19021
  const pullResults = await Promise.all(
19089
19022
  imageRefs.map(async ({ name, ref }) => ({
@@ -19098,7 +19031,7 @@ async function runUpgradePullByDigest(deps = {}) {
19098
19031
  pullSpinner.fail(`Pull failed for ${failed.map((r) => r.name).join(", ")}`);
19099
19032
  for (const f of failed) {
19100
19033
  process.stderr.write(
19101
- ` ${pc16.red(f.name)} (${f.ref}):
19034
+ ` ${pc17.red(f.name)} (${f.ref}):
19102
19035
  exit=${f.result.exitCode}
19103
19036
  stderr: ${f.result.stderr.split("\n")[0] ?? "(empty)"}
19104
19037
  `
@@ -19112,14 +19045,14 @@ async function runUpgradePullByDigest(deps = {}) {
19112
19045
  summary: `pull failed: ${failed.map((r) => r.name).join(", ")}`
19113
19046
  };
19114
19047
  }
19115
- pullSpinner.succeed(`Pulled 3 images in ${pullElapsed}s`);
19048
+ pullSpinner.succeed(`Pulled ${imageRefs.length} images in ${pullElapsed}s`);
19116
19049
  const handshakeSpinner = ora7("Verifying olam.protocol.versions handshake").start();
19117
19050
  for (const { name, ref } of imageRefs) {
19118
19051
  const inspect = await docker2.inspectLabel(ref, "olam.protocol.versions");
19119
19052
  if (inspect.exitCode !== 0) {
19120
19053
  handshakeSpinner.fail(`Could not inspect ${name}`);
19121
19054
  process.stderr.write(
19122
- `${pc16.red("error")} docker inspect ${ref} failed: ${inspect.stderr}
19055
+ `${pc17.red("error")} docker inspect ${ref} failed: ${inspect.stderr}
19123
19056
  `
19124
19057
  );
19125
19058
  return { exitCode: EXIT_GENERIC_ERROR, summary: `inspect failed: ${name}` };
@@ -19131,7 +19064,7 @@ async function runUpgradePullByDigest(deps = {}) {
19131
19064
  const decision = checkProtocolOverlap(versions);
19132
19065
  if (!decision.compatible) {
19133
19066
  handshakeSpinner.fail(`Protocol mismatch on ${name}`);
19134
- process.stderr.write(`${pc16.red("error")} ${decision.remedy}
19067
+ process.stderr.write(`${pc17.red("error")} ${decision.remedy}
19135
19068
  `);
19136
19069
  return {
19137
19070
  exitCode: EXIT_PROTOCOL_MISMATCH,
@@ -19139,8 +19072,8 @@ async function runUpgradePullByDigest(deps = {}) {
19139
19072
  };
19140
19073
  }
19141
19074
  }
19142
- handshakeSpinner.succeed("Protocol handshake passed (all 3 images)");
19143
- const tagPlan = [
19075
+ handshakeSpinner.succeed(`Protocol handshake passed (all ${imageRefs.length} images)`);
19076
+ const tagPlanBase = [
19144
19077
  { from: imageRefs[0].ref, to: "olam-host-cp:latest", name: "host-cp (bare)" },
19145
19078
  { from: imageRefs[0].ref, to: `${registry}/olam-host-cp:latest`, name: "host-cp (registry)" },
19146
19079
  { from: imageRefs[1].ref, to: "olam-auth:local", name: "auth (bare)" },
@@ -19148,13 +19081,20 @@ async function runUpgradePullByDigest(deps = {}) {
19148
19081
  { from: imageRefs[2].ref, to: "olam-devbox:latest", name: "devbox (bare)" },
19149
19082
  { from: imageRefs[2].ref, to: `${registry}/olam-devbox:latest`, name: "devbox (registry)" }
19150
19083
  ];
19084
+ if (hasMcpAuthDigest && imageRefs[3]) {
19085
+ tagPlanBase.push(
19086
+ { from: imageRefs[3].ref, to: "olam-mcp-auth:local", name: "mcp-auth (bare)" },
19087
+ { from: imageRefs[3].ref, to: `${registry}/olam-mcp-auth:latest`, name: "mcp-auth (registry)" }
19088
+ );
19089
+ }
19090
+ const tagPlan = tagPlanBase;
19151
19091
  const tagSpinner = ora7("Tagging digests \u2192 canonical local refs").start();
19152
19092
  const tagger = deps.tagImpl ?? dockerTag;
19153
19093
  for (const t of tagPlan) {
19154
19094
  const r = tagger(t.from, t.to);
19155
19095
  if (!r.ok) {
19156
19096
  tagSpinner.fail(`docker tag failed for ${t.name}`);
19157
- process.stderr.write(`${pc16.red("error")} ${r.error ?? "docker tag failed"}
19097
+ process.stderr.write(`${pc17.red("error")} ${r.error ?? "docker tag failed"}
19158
19098
  `);
19159
19099
  return { exitCode: EXIT_GENERIC_ERROR, summary: `tag failed: ${t.name}` };
19160
19100
  }
@@ -19172,7 +19112,7 @@ async function runUpgradePullByDigest(deps = {}) {
19172
19112
  if (!composeResult.ok) {
19173
19113
  composeSpinner.fail("compose recreate failed");
19174
19114
  process.stderr.write(
19175
- `${pc16.red("error")} docker compose up --force-recreate host-cp failed:
19115
+ `${pc17.red("error")} docker compose up --force-recreate host-cp failed:
19176
19116
  ${composeResult.stderr.split("\n").slice(0, 3).join("\n ")}
19177
19117
  `
19178
19118
  );
@@ -19185,25 +19125,68 @@ async function runUpgradePullByDigest(deps = {}) {
19185
19125
  if (!authResult.ok) {
19186
19126
  authSpinner.fail("auth-service recreate failed");
19187
19127
  process.stderr.write(
19188
- `${pc16.red("error")} ${authResult.error ?? "unknown failure"}
19128
+ `${pc17.red("error")} ${authResult.error ?? "unknown failure"}
19189
19129
  `
19190
19130
  );
19191
19131
  return { exitCode: EXIT_GENERIC_ERROR, summary: "auth recreate failed" };
19192
19132
  }
19193
19133
  authSpinner.succeed("auth-service running on new image");
19134
+ if (hasMcpAuthDigest) {
19135
+ const mcpSpinner = ora7("recreate mcp-auth-service").start();
19136
+ const mcpRecreate = deps.recreateMcpAuth ?? defaultRecreateMcpAuthForUpgrade;
19137
+ const mcpResult = await mcpRecreate();
19138
+ if (!mcpResult.ok) {
19139
+ mcpSpinner.fail("mcp-auth-service recreate failed");
19140
+ process.stderr.write(
19141
+ `${pc17.red("error")} ${mcpResult.error ?? "unknown failure"}
19142
+ `
19143
+ );
19144
+ return { exitCode: EXIT_GENERIC_ERROR, summary: "mcp-auth recreate failed" };
19145
+ }
19146
+ mcpSpinner.succeed("mcp-auth-service running on new image");
19147
+ }
19194
19148
  printSuccess("Upgrade complete (pull-by-digest)");
19195
19149
  printInfo("host-cp", `running (${digests["host-cp"].slice(0, 19)}\u2026)`);
19196
19150
  printInfo("auth", `running (${digests.auth.slice(0, 19)}\u2026)`);
19197
19151
  printInfo("devbox", `pulled (${digests.devbox.slice(0, 19)}\u2026)`);
19152
+ if (hasMcpAuthDigest) {
19153
+ printInfo("mcp-auth", `running (${digests["mcp-auth"].slice(0, 19)}\u2026)`);
19154
+ }
19198
19155
  return { exitCode: 0, summary: "stack upgraded" };
19199
19156
  }
19157
+ async function defaultRecreateMcpAuthForUpgrade() {
19158
+ try {
19159
+ const { spawnSync: ss } = await import("node:child_process");
19160
+ ss("docker", ["stop", "olam-mcp-auth"], { stdio: "ignore" });
19161
+ ss("docker", ["rm", "-f", "olam-mcp-auth"], { stdio: "ignore" });
19162
+ const startResult = ss("docker", [
19163
+ "run",
19164
+ "-d",
19165
+ "--name",
19166
+ "olam-mcp-auth",
19167
+ "-p",
19168
+ "9998:9998",
19169
+ "-v",
19170
+ "olam-mcp-auth-data:/mcp-auth-data",
19171
+ "--restart",
19172
+ "unless-stopped",
19173
+ "olam-mcp-auth:local"
19174
+ ], { stdio: "pipe" });
19175
+ if (startResult.status !== 0) {
19176
+ return { ok: false, error: `docker run failed: ${startResult.stderr?.toString() ?? "unknown"}` };
19177
+ }
19178
+ return { ok: true };
19179
+ } catch (err) {
19180
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
19181
+ }
19182
+ }
19200
19183
  async function defaultRecreateAuthForUpgrade() {
19201
19184
  try {
19202
- spawnSync10("docker", ["stop", "olam-auth"], {
19185
+ spawnSync11("docker", ["stop", "olam-auth"], {
19203
19186
  encoding: "utf-8",
19204
19187
  stdio: ["ignore", "ignore", "ignore"]
19205
19188
  });
19206
- spawnSync10("docker", ["rm", "olam-auth"], {
19189
+ spawnSync11("docker", ["rm", "olam-auth"], {
19207
19190
  encoding: "utf-8",
19208
19191
  stdio: ["ignore", "ignore", "ignore"]
19209
19192
  });
@@ -19348,11 +19331,11 @@ manually inspect images with \`docker images olam-*:olam-rollback\`.`
19348
19331
  process.once("SIGINT", releaseOnSignal);
19349
19332
  process.once("SIGTERM", releaseOnSignal);
19350
19333
  try {
19351
- process.stdout.write(` ${pc16.dim("rollback retag (3 ops)".padEnd(34))}`);
19334
+ process.stdout.write(` ${pc17.dim("rollback retag (3 ops)".padEnd(34))}`);
19352
19335
  const swapStart = Date.now();
19353
19336
  const swapResult = performRollbackSwap(PRODUCTION_SWAP_PLAN);
19354
19337
  const swapDur = `${((Date.now() - swapStart) / 1e3).toFixed(1)}s`;
19355
- process.stdout.write(`${swapResult.ok ? pc16.green("\u2713") : pc16.red("\u2717")} ${swapDur}
19338
+ process.stdout.write(`${swapResult.ok ? pc17.green("\u2713") : pc17.red("\u2717")} ${swapDur}
19356
19339
  `);
19357
19340
  if (!swapResult.ok) {
19358
19341
  printError(`Rollback retag failed: ${swapResult.summary}`);
@@ -19362,11 +19345,11 @@ manually inspect images with \`docker images olam-*:olam-rollback\`.`
19362
19345
  printInfo("Rollback", swapResult.summary);
19363
19346
  const composeFile = findComposeFile();
19364
19347
  const authSecret = readAuthSecret2();
19365
- process.stdout.write(` ${pc16.dim("docker compose recreate host-cp".padEnd(34))}`);
19348
+ process.stdout.write(` ${pc17.dim("docker compose recreate host-cp".padEnd(34))}`);
19366
19349
  const composeStart = Date.now();
19367
19350
  const composeResult = runCompose(["up", "-d", "--force-recreate", "--no-deps", "host-cp"], composeFile, buildComposeEnv(authSecret));
19368
19351
  const composeDur = `${((Date.now() - composeStart) / 1e3).toFixed(1)}s`;
19369
- process.stdout.write(`${composeResult.ok ? pc16.green("\u2713") : pc16.red("\u2717")} ${composeDur}
19352
+ process.stdout.write(`${composeResult.ok ? pc17.green("\u2713") : pc17.red("\u2717")} ${composeDur}
19370
19353
  `);
19371
19354
  if (!composeResult.ok) {
19372
19355
  printError(
@@ -19377,10 +19360,10 @@ Canonical tags are at :olam-rollback (good); container restart pending. Manually
19377
19360
  process.exitCode = 1;
19378
19361
  return;
19379
19362
  }
19380
- process.stdout.write(` ${pc16.dim("recreate auth-service".padEnd(34))}`);
19363
+ process.stdout.write(` ${pc17.dim("recreate auth-service".padEnd(34))}`);
19381
19364
  const authResult = await recreateAuthService();
19382
19365
  const authDur = `${(authResult.durationMs / 1e3).toFixed(1)}s`;
19383
- process.stdout.write(`${authResult.ok ? pc16.green("\u2713") : pc16.red("\u2717")} ${authDur}
19366
+ process.stdout.write(`${authResult.ok ? pc17.green("\u2713") : pc17.red("\u2717")} ${authDur}
19384
19367
  `);
19385
19368
  if (!authResult.ok) {
19386
19369
  printError(`Auth-service recreate failed: ${authResult.error ?? "unknown"}`);
@@ -19501,7 +19484,7 @@ ${buildResult.stderr}`);
19501
19484
  return;
19502
19485
  }
19503
19486
  const authSecret = readAuthSecret2();
19504
- const spaDir = path32.join(cwd, "packages/control-plane/app");
19487
+ const spaDir = path31.join(cwd, "packages/control-plane/app");
19505
19488
  const spaResult = runStep2(
19506
19489
  "vite build (SPA)",
19507
19490
  "npx",
@@ -19546,10 +19529,10 @@ ${spaResult.stderr}`);
19546
19529
  throw err;
19547
19530
  }
19548
19531
  if (step.tee) {
19549
- process.stdout.write(` ${pc16.dim(step.label.padEnd(34))}
19532
+ process.stdout.write(` ${pc17.dim(step.label.padEnd(34))}
19550
19533
  `);
19551
19534
  const start = Date.now();
19552
- const result = spawnSync10("bash", [scriptPath], {
19535
+ const result = spawnSync11("bash", [scriptPath], {
19553
19536
  stdio: "inherit",
19554
19537
  cwd,
19555
19538
  env: { ...process.env, ...olamTagEnv }
@@ -19557,7 +19540,7 @@ ${spaResult.stderr}`);
19557
19540
  const durationMs = Date.now() - start;
19558
19541
  const ok = result.status === 0 && result.error === void 0;
19559
19542
  const dur = `${(durationMs / 1e3).toFixed(1)}s`;
19560
- process.stdout.write(` ${pc16.dim(step.label.padEnd(34))}${ok ? pc16.green("\u2713") : pc16.red("\u2717")} ${dur}
19543
+ process.stdout.write(` ${pc17.dim(step.label.padEnd(34))}${ok ? pc17.green("\u2713") : pc17.red("\u2717")} ${dur}
19561
19544
  `);
19562
19545
  timings.push({ label: step.label, durationMs });
19563
19546
  if (!ok) {
@@ -19583,7 +19566,7 @@ ${result.stderr.split("\n").slice(-3).join("\n")}`);
19583
19566
  }
19584
19567
  for (const t of timings) logRow.durations_ms[t.label] = t.durationMs;
19585
19568
  const smokeStart = Date.now();
19586
- process.stdout.write(` ${pc16.dim("smoke (docker create + inspect)".padEnd(34))}`);
19569
+ process.stdout.write(` ${pc17.dim("smoke (docker create + inspect)".padEnd(34))}`);
19587
19570
  const smokeImages = [
19588
19571
  "olam-auth:olam-next",
19589
19572
  "olam-devbox:olam-next",
@@ -19593,7 +19576,7 @@ ${result.stderr.split("\n").slice(-3).join("\n")}`);
19593
19576
  const smokeFailures = smokeResults.filter((r) => !r.ok);
19594
19577
  const smokeDurationMs = Date.now() - smokeStart;
19595
19578
  const smokeDur = `${(smokeDurationMs / 1e3).toFixed(1)}s`;
19596
- process.stdout.write(`${smokeFailures.length === 0 ? pc16.green("\u2713") : pc16.red("\u2717")} ${smokeDur}
19579
+ process.stdout.write(`${smokeFailures.length === 0 ? pc17.green("\u2713") : pc17.red("\u2717")} ${smokeDur}
19597
19580
  `);
19598
19581
  timings.push({ label: "smoke", durationMs: smokeDurationMs });
19599
19582
  if (smokeFailures.length > 0) {
@@ -19620,12 +19603,12 @@ Recovery options:
19620
19603
  process.exitCode = 1;
19621
19604
  return;
19622
19605
  }
19623
- process.stdout.write(` ${pc16.dim("atomic 6-tag swap".padEnd(34))}`);
19606
+ process.stdout.write(` ${pc17.dim("atomic 6-tag swap".padEnd(34))}`);
19624
19607
  const swapStart = Date.now();
19625
19608
  const swapResult = performAtomicSwap(PRODUCTION_SWAP_PLAN);
19626
19609
  const swapDurationMs = Date.now() - swapStart;
19627
19610
  const swapDur = `${(swapDurationMs / 1e3).toFixed(1)}s`;
19628
- process.stdout.write(`${swapResult.ok ? pc16.green("\u2713") : pc16.red("\u2717")} ${swapDur}
19611
+ process.stdout.write(`${swapResult.ok ? pc17.green("\u2713") : pc17.red("\u2717")} ${swapDur}
19629
19612
  `);
19630
19613
  timings.push({ label: "atomic swap", durationMs: swapDurationMs });
19631
19614
  if (!swapResult.ok) {
@@ -19635,7 +19618,7 @@ Recovery options:
19635
19618
  }
19636
19619
  printInfo("Swap", swapResult.summary);
19637
19620
  const composeFile = findComposeFile();
19638
- process.stdout.write(` ${pc16.dim("docker compose recreate".padEnd(34))}`);
19621
+ process.stdout.write(` ${pc17.dim("docker compose recreate".padEnd(34))}`);
19639
19622
  const composeStart = Date.now();
19640
19623
  const composeResult = runCompose(
19641
19624
  ["up", "-d", "--force-recreate"],
@@ -19645,7 +19628,7 @@ Recovery options:
19645
19628
  const composeDurationMs = Date.now() - composeStart;
19646
19629
  const composeOk = composeResult.ok;
19647
19630
  const composeDur = `${(composeDurationMs / 1e3).toFixed(1)}s`;
19648
- process.stdout.write(`${composeOk ? pc16.green("\u2713") : pc16.red("\u2717")} ${composeDur}
19631
+ process.stdout.write(`${composeOk ? pc17.green("\u2713") : pc17.red("\u2717")} ${composeDur}
19649
19632
  `);
19650
19633
  timings.push({ label: "container recreate", durationMs: composeDurationMs });
19651
19634
  if (!composeOk) {
@@ -19661,10 +19644,10 @@ Recovery options:
19661
19644
  process.exitCode = 1;
19662
19645
  return;
19663
19646
  }
19664
- process.stdout.write(` ${pc16.dim("recreate auth-service".padEnd(34))}`);
19647
+ process.stdout.write(` ${pc17.dim("recreate auth-service".padEnd(34))}`);
19665
19648
  const authResult = await recreateAuthService();
19666
19649
  const authDur = `${(authResult.durationMs / 1e3).toFixed(1)}s`;
19667
- process.stdout.write(`${authResult.ok ? pc16.green("\u2713") : pc16.red("\u2717")} ${authDur}
19650
+ process.stdout.write(`${authResult.ok ? pc17.green("\u2713") : pc17.red("\u2717")} ${authDur}
19668
19651
  `);
19669
19652
  timings.push({ label: "auth recreate", durationMs: authResult.durationMs });
19670
19653
  if (!authResult.ok) {
@@ -19679,12 +19662,12 @@ Recovery options:
19679
19662
  process.exitCode = 1;
19680
19663
  return;
19681
19664
  }
19682
- process.stdout.write(` ${pc16.dim("waiting for /health".padEnd(34))}`);
19665
+ process.stdout.write(` ${pc17.dim("waiting for /health".padEnd(34))}`);
19683
19666
  const healthStart = Date.now();
19684
19667
  const healthy = await waitForHealth(1e4);
19685
19668
  const healthDurationMs = Date.now() - healthStart;
19686
19669
  const healthDur = `${(healthDurationMs / 1e3).toFixed(1)}s`;
19687
- process.stdout.write(`${healthy ? pc16.green("\u2713") : pc16.yellow("?")} ${healthDur}
19670
+ process.stdout.write(`${healthy ? pc17.green("\u2713") : pc17.yellow("?")} ${healthDur}
19688
19671
  `);
19689
19672
  timings.push({ label: "/health", durationMs: healthDurationMs });
19690
19673
  if (!healthy) {
@@ -19692,12 +19675,12 @@ Recovery options:
19692
19675
  "Host CP started but /health did not respond within 10s.\n \u2022 Check: docker logs olam-host-cp\n \u2022 If the new SHA is broken: `olam upgrade --rollback` restores the prior set in <30s."
19693
19676
  );
19694
19677
  }
19695
- process.stdout.write(` ${pc16.dim("verify /version/status round-trip".padEnd(34))}`);
19678
+ process.stdout.write(` ${pc17.dim("verify /version/status round-trip".padEnd(34))}`);
19696
19679
  const versionStart = Date.now();
19697
19680
  const versionMatch = await waitForVersionMatch(_targetSha, 9e4);
19698
19681
  const versionDurationMs = Date.now() - versionStart;
19699
19682
  const versionDur = `${(versionDurationMs / 1e3).toFixed(1)}s`;
19700
- process.stdout.write(`${versionMatch.matched ? pc16.green("\u2713") : pc16.yellow("?")} ${versionDur}
19683
+ process.stdout.write(`${versionMatch.matched ? pc17.green("\u2713") : pc17.yellow("?")} ${versionDur}
19701
19684
  `);
19702
19685
  timings.push({ label: "/version/status round-trip", durationMs: versionDurationMs });
19703
19686
  if (!versionMatch.matched) {
@@ -19771,16 +19754,16 @@ init_host_cp();
19771
19754
  init_context();
19772
19755
  init_output();
19773
19756
  import * as http3 from "node:http";
19774
- import pc17 from "picocolors";
19757
+ import pc18 from "picocolors";
19775
19758
  var HOST_CP_PORT3 = 19e3;
19776
19759
  function colorLine(line) {
19777
- if (/\bERROR\b/.test(line)) return pc17.red(line);
19778
- if (/\bWARN\b/.test(line)) return pc17.yellow(line);
19779
- if (/\bINFO\b/.test(line)) return pc17.dim(line);
19760
+ if (/\bERROR\b/.test(line)) return pc18.red(line);
19761
+ if (/\bWARN\b/.test(line)) return pc18.yellow(line);
19762
+ if (/\bINFO\b/.test(line)) return pc18.dim(line);
19780
19763
  return line;
19781
19764
  }
19782
19765
  function formatLine(line, service, showService) {
19783
- const prefix = showService && service ? `${pc17.cyan(`[${service}]`)} ` : "";
19766
+ const prefix = showService && service ? `${pc18.cyan(`[${service}]`)} ` : "";
19784
19767
  return prefix + colorLine(line);
19785
19768
  }
19786
19769
  function parseSseEvent(raw) {
@@ -19897,8 +19880,8 @@ function registerLogs(program2) {
19897
19880
  // src/commands/ps.ts
19898
19881
  init_context();
19899
19882
  init_output();
19900
- import pc18 from "picocolors";
19901
- import { spawnSync as spawnSync11 } from "node:child_process";
19883
+ import pc19 from "picocolors";
19884
+ import { spawnSync as spawnSync12 } from "node:child_process";
19902
19885
  var SAFE_IDENT4 = /^[a-z0-9][a-z0-9-]{0,63}$/;
19903
19886
  function parseDockerTop(stdout) {
19904
19887
  const trimmed = stdout.trim();
@@ -19958,18 +19941,18 @@ function printTable2(rows) {
19958
19941
  const fixedWidth = 5 + 1 + 8 + 1 + 6 + 1 + 6 + 1 + 10 + 1 + 6 + 1;
19959
19942
  const cmdWidth = Math.max(20, cols - fixedWidth);
19960
19943
  const header = [
19961
- pc18.bold(pc18.dim("PID".padEnd(5))),
19962
- pc18.bold(pc18.dim("USER".padEnd(8))),
19963
- pc18.bold(pc18.dim("%CPU".padEnd(6))),
19964
- pc18.bold(pc18.dim("%MEM".padEnd(6))),
19965
- pc18.bold(pc18.dim("STARTED".padEnd(10))),
19966
- pc18.bold(pc18.dim("STATE".padEnd(6))),
19967
- pc18.bold(pc18.dim("COMMAND"))
19944
+ pc19.bold(pc19.dim("PID".padEnd(5))),
19945
+ pc19.bold(pc19.dim("USER".padEnd(8))),
19946
+ pc19.bold(pc19.dim("%CPU".padEnd(6))),
19947
+ pc19.bold(pc19.dim("%MEM".padEnd(6))),
19948
+ pc19.bold(pc19.dim("STARTED".padEnd(10))),
19949
+ pc19.bold(pc19.dim("STATE".padEnd(6))),
19950
+ pc19.bold(pc19.dim("COMMAND"))
19968
19951
  ].join(" ");
19969
19952
  console.log(header);
19970
19953
  for (const row of rows) {
19971
19954
  const cmd = row.command.length > cmdWidth ? row.command.slice(0, cmdWidth - 1) + "\u2026" : row.command;
19972
- const stateFn = row.state.startsWith("R") ? pc18.green : row.state.startsWith("Z") ? pc18.red : pc18.dim;
19955
+ const stateFn = row.state.startsWith("R") ? pc19.green : row.state.startsWith("Z") ? pc19.red : pc19.dim;
19973
19956
  console.log([
19974
19957
  row.pid.padEnd(5),
19975
19958
  row.user.slice(0, 8).padEnd(8),
@@ -19998,7 +19981,7 @@ function registerPs(program2) {
19998
19981
  const containerName = `olam-${worldId}-devbox`;
19999
19982
  let watchInterval;
20000
19983
  function fetchAndPrint() {
20001
- const result = spawnSync11(
19984
+ const result = spawnSync12(
20002
19985
  "docker",
20003
19986
  ["top", containerName, "pid", "user", "pcpu", "pmem", "stime", "stat", "cmd"],
20004
19987
  { encoding: "utf-8", timeout: 3e3 }
@@ -20018,7 +20001,7 @@ function registerPs(program2) {
20018
20001
  printTable2(rows);
20019
20002
  if (opts.watch) {
20020
20003
  process.stdout.write(`
20021
- ${pc18.dim(`world: ${worldId} sort: ${sortKey} refresh: 5s Ctrl-C to exit`)}
20004
+ ${pc19.dim(`world: ${worldId} sort: ${sortKey} refresh: 5s Ctrl-C to exit`)}
20022
20005
  `);
20023
20006
  }
20024
20007
  }
@@ -20035,20 +20018,20 @@ ${pc18.dim(`world: ${worldId} sort: ${sortKey} refresh: 5s Ctrl-C to exit`)}
20035
20018
 
20036
20019
  // src/commands/keys.ts
20037
20020
  init_output();
20038
- import * as fs29 from "node:fs";
20021
+ import * as fs28 from "node:fs";
20039
20022
  import * as os17 from "node:os";
20040
- import * as path33 from "node:path";
20023
+ import * as path32 from "node:path";
20041
20024
  import YAML4 from "yaml";
20042
20025
  function olamHome2() {
20043
- return process.env.OLAM_HOME ?? path33.join(os17.homedir(), ".olam");
20026
+ return process.env.OLAM_HOME ?? path32.join(os17.homedir(), ".olam");
20044
20027
  }
20045
20028
  function keysFilePath() {
20046
- return path33.join(olamHome2(), "keys.yaml");
20029
+ return path32.join(olamHome2(), "keys.yaml");
20047
20030
  }
20048
20031
  function readKeysFile() {
20049
20032
  const filePath = keysFilePath();
20050
- if (!fs29.existsSync(filePath)) return null;
20051
- const raw = fs29.readFileSync(filePath, "utf-8").trim();
20033
+ if (!fs28.existsSync(filePath)) return null;
20034
+ const raw = fs28.readFileSync(filePath, "utf-8").trim();
20052
20035
  if (raw.length === 0) return null;
20053
20036
  try {
20054
20037
  const parsed = YAML4.parse(raw);
@@ -20064,13 +20047,13 @@ function readKeysFile() {
20064
20047
  }
20065
20048
  function writeKeysFile(keys) {
20066
20049
  const dir = olamHome2();
20067
- if (!fs29.existsSync(dir)) {
20068
- fs29.mkdirSync(dir, { recursive: true });
20050
+ if (!fs28.existsSync(dir)) {
20051
+ fs28.mkdirSync(dir, { recursive: true });
20069
20052
  }
20070
20053
  const filePath = keysFilePath();
20071
20054
  const content = YAML4.stringify(keys);
20072
- fs29.writeFileSync(filePath, content, { encoding: "utf-8", mode: 384 });
20073
- fs29.chmodSync(filePath, 384);
20055
+ fs28.writeFileSync(filePath, content, { encoding: "utf-8", mode: 384 });
20056
+ fs28.chmodSync(filePath, 384);
20074
20057
  }
20075
20058
  function redact(value) {
20076
20059
  if (value.length <= 8) return value + "...";
@@ -20113,7 +20096,7 @@ function registerKeys(program2) {
20113
20096
  }
20114
20097
  const { [key]: _removed, ...rest } = existing;
20115
20098
  if (Object.keys(rest).length === 0) {
20116
- fs29.unlinkSync(keysFilePath());
20099
+ fs28.unlinkSync(keysFilePath());
20117
20100
  } else {
20118
20101
  writeKeysFile(rest);
20119
20102
  }
@@ -20136,33 +20119,33 @@ function registerKeys(program2) {
20136
20119
  }
20137
20120
 
20138
20121
  // src/commands/world-snapshot.ts
20139
- import * as fs31 from "node:fs";
20140
- import * as path35 from "node:path";
20122
+ import * as fs30 from "node:fs";
20123
+ import * as path34 from "node:path";
20141
20124
  import { execSync as execSync9 } from "node:child_process";
20142
- import pc19 from "picocolors";
20125
+ import pc20 from "picocolors";
20143
20126
 
20144
20127
  // ../core/dist/world/snapshot.js
20145
- import * as crypto7 from "node:crypto";
20146
- import * as fs30 from "node:fs";
20128
+ import * as crypto6 from "node:crypto";
20129
+ import * as fs29 from "node:fs";
20147
20130
  import * as os18 from "node:os";
20148
- import * as path34 from "node:path";
20149
- import { execFileSync as execFileSync5 } from "node:child_process";
20131
+ import * as path33 from "node:path";
20132
+ import { execFileSync as execFileSync6 } from "node:child_process";
20150
20133
  function snapshotsDir() {
20151
- return process.env["OLAM_SNAPSHOTS_DIR"] ?? path34.join(os18.homedir(), ".olam", "snapshots");
20134
+ return process.env["OLAM_SNAPSHOTS_DIR"] ?? path33.join(os18.homedir(), ".olam", "snapshots");
20152
20135
  }
20153
20136
  function snapshotKindDir(worldId, kind) {
20154
- return path34.join(snapshotsDir(), worldId, kind);
20137
+ return path33.join(snapshotsDir(), worldId, kind);
20155
20138
  }
20156
20139
  function snapshotTarPath(worldId, kind, repoName, hash) {
20157
20140
  const base = repoName ? `${repoName}-${hash}` : hash;
20158
- return path34.join(snapshotKindDir(worldId, kind), `${base}.tar.gz`);
20141
+ return path33.join(snapshotKindDir(worldId, kind), `${base}.tar.gz`);
20159
20142
  }
20160
20143
  function manifestPath(tarPath) {
20161
20144
  return tarPath.replace(/\.tar\.gz$/, ".manifest.json");
20162
20145
  }
20163
20146
  function hashBuffers(entries) {
20164
20147
  const sorted = [...entries].sort((a, b) => a.path.localeCompare(b.path));
20165
- const hash = crypto7.createHash("sha256");
20148
+ const hash = crypto6.createHash("sha256");
20166
20149
  for (const entry of sorted) {
20167
20150
  hash.update(entry.path);
20168
20151
  hash.update("\0");
@@ -20172,17 +20155,17 @@ function hashBuffers(entries) {
20172
20155
  return hash.digest("hex").slice(0, 12);
20173
20156
  }
20174
20157
  function computeGemsFingerprint(repoDir) {
20175
- const lockfile = path34.join(repoDir, "Gemfile.lock");
20176
- if (!fs30.existsSync(lockfile))
20158
+ const lockfile = path33.join(repoDir, "Gemfile.lock");
20159
+ if (!fs29.existsSync(lockfile))
20177
20160
  return null;
20178
- return hashBuffers([{ path: "Gemfile.lock", content: fs30.readFileSync(lockfile) }]);
20161
+ return hashBuffers([{ path: "Gemfile.lock", content: fs29.readFileSync(lockfile) }]);
20179
20162
  }
20180
20163
  function computeNodeFingerprint(repoDir) {
20181
20164
  const candidates = ["yarn.lock", "pnpm-lock.yaml", "package-lock.json"];
20182
20165
  for (const name of candidates) {
20183
- const lockfile = path34.join(repoDir, name);
20184
- if (fs30.existsSync(lockfile)) {
20185
- return hashBuffers([{ path: name, content: fs30.readFileSync(lockfile) }]);
20166
+ const lockfile = path33.join(repoDir, name);
20167
+ if (fs29.existsSync(lockfile)) {
20168
+ return hashBuffers([{ path: name, content: fs29.readFileSync(lockfile) }]);
20186
20169
  }
20187
20170
  }
20188
20171
  return null;
@@ -20192,64 +20175,64 @@ function computePgFingerprint(repoDirs) {
20192
20175
  const entries = [];
20193
20176
  for (const repoDir of repoDirs) {
20194
20177
  for (const pattern of patterns) {
20195
- const filePath = path34.join(repoDir, pattern);
20196
- if (fs30.existsSync(filePath)) {
20197
- entries.push({ path: filePath, content: fs30.readFileSync(filePath) });
20178
+ const filePath = path33.join(repoDir, pattern);
20179
+ if (fs29.existsSync(filePath)) {
20180
+ entries.push({ path: filePath, content: fs29.readFileSync(filePath) });
20198
20181
  }
20199
20182
  }
20200
20183
  }
20201
20184
  return entries.length > 0 ? hashBuffers(entries) : null;
20202
20185
  }
20203
20186
  function packTarball(srcDir, destPath, opts = {}) {
20204
- fs30.mkdirSync(path34.dirname(destPath), { recursive: true });
20187
+ fs29.mkdirSync(path33.dirname(destPath), { recursive: true });
20205
20188
  const tmp = `${destPath}.tmp`;
20206
20189
  const args = [];
20207
20190
  if (opts.followSymlinks)
20208
20191
  args.push("-h");
20209
20192
  args.push("-czf", tmp, "-C", srcDir, ".");
20210
20193
  try {
20211
- execFileSync5("tar", args, { stdio: "pipe" });
20212
- fs30.renameSync(tmp, destPath);
20194
+ execFileSync6("tar", args, { stdio: "pipe" });
20195
+ fs29.renameSync(tmp, destPath);
20213
20196
  } catch (err) {
20214
20197
  try {
20215
- fs30.rmSync(tmp, { force: true });
20198
+ fs29.rmSync(tmp, { force: true });
20216
20199
  } catch {
20217
20200
  }
20218
20201
  throw err;
20219
20202
  }
20220
20203
  }
20221
20204
  function writeManifest(manifest, tarPath) {
20222
- fs30.writeFileSync(manifestPath(tarPath), JSON.stringify(manifest, null, 2), "utf-8");
20205
+ fs29.writeFileSync(manifestPath(tarPath), JSON.stringify(manifest, null, 2), "utf-8");
20223
20206
  }
20224
20207
  function readManifest(tarPath) {
20225
20208
  const mPath = manifestPath(tarPath);
20226
- if (!fs30.existsSync(mPath))
20209
+ if (!fs29.existsSync(mPath))
20227
20210
  return null;
20228
20211
  try {
20229
- return JSON.parse(fs30.readFileSync(mPath, "utf-8"));
20212
+ return JSON.parse(fs29.readFileSync(mPath, "utf-8"));
20230
20213
  } catch {
20231
20214
  return null;
20232
20215
  }
20233
20216
  }
20234
20217
  function listSnapshots(worldIdFilter) {
20235
20218
  const root = snapshotsDir();
20236
- if (!fs30.existsSync(root))
20219
+ if (!fs29.existsSync(root))
20237
20220
  return [];
20238
20221
  const now = Date.now();
20239
20222
  const results = [];
20240
- const worlds = worldIdFilter ? [worldIdFilter] : fs30.readdirSync(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
20223
+ const worlds = worldIdFilter ? [worldIdFilter] : fs29.readdirSync(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
20241
20224
  for (const worldId of worlds) {
20242
- const worldDir = path34.join(root, worldId);
20243
- if (!fs30.existsSync(worldDir) || !fs30.statSync(worldDir).isDirectory())
20225
+ const worldDir = path33.join(root, worldId);
20226
+ if (!fs29.existsSync(worldDir) || !fs29.statSync(worldDir).isDirectory())
20244
20227
  continue;
20245
20228
  for (const kind of ["gems", "node", "pg"]) {
20246
- const kindDir = path34.join(worldDir, kind);
20247
- if (!fs30.existsSync(kindDir))
20229
+ const kindDir = path33.join(worldDir, kind);
20230
+ if (!fs29.existsSync(kindDir))
20248
20231
  continue;
20249
- const tarballs = fs30.readdirSync(kindDir).filter((f) => f.endsWith(".tar.gz"));
20232
+ const tarballs = fs29.readdirSync(kindDir).filter((f) => f.endsWith(".tar.gz"));
20250
20233
  for (const tarFile of tarballs) {
20251
- const tarPath = path34.join(kindDir, tarFile);
20252
- const stat = fs30.statSync(tarPath);
20234
+ const tarPath = path33.join(kindDir, tarFile);
20235
+ const stat = fs29.statSync(tarPath);
20253
20236
  const manifest = readManifest(tarPath);
20254
20237
  if (!manifest)
20255
20238
  continue;
@@ -20325,7 +20308,7 @@ async function handleCreate2(worldId, kindArg) {
20325
20308
  const label = r.repo ? `${r.kind}/${r.repo}` : r.kind;
20326
20309
  if (r.ok) {
20327
20310
  printSuccess(`${label}`);
20328
- console.log(` ${pc19.dim(r.tarPath)}`);
20311
+ console.log(` ${pc20.dim(r.tarPath)}`);
20329
20312
  } else {
20330
20313
  printWarning(`${label}: ${r.msg ?? "skipped"}`);
20331
20314
  }
@@ -20339,17 +20322,17 @@ function resolveKinds(arg) {
20339
20322
  return [];
20340
20323
  }
20341
20324
  async function captureGems(worldId, workspacePath, repo) {
20342
- const repoDir = path35.join(workspacePath, repo);
20325
+ const repoDir = path34.join(workspacePath, repo);
20343
20326
  const fingerprint = computeGemsFingerprint(repoDir);
20344
20327
  if (!fingerprint) {
20345
20328
  return { ok: false, tarPath: "", msg: "no Gemfile.lock \u2014 layer does not apply" };
20346
20329
  }
20347
20330
  const tarPath = snapshotTarPath(worldId, "gems", repo, fingerprint);
20348
- const vendorBundle = path35.join(repoDir, "vendor", "bundle");
20349
- if (fs31.existsSync(vendorBundle)) {
20331
+ const vendorBundle = path34.join(repoDir, "vendor", "bundle");
20332
+ if (fs30.existsSync(vendorBundle)) {
20350
20333
  try {
20351
20334
  packTarball(vendorBundle, tarPath);
20352
- const stat = fs31.statSync(tarPath);
20335
+ const stat = fs30.statSync(tarPath);
20353
20336
  const manifest = {
20354
20337
  kind: "gems",
20355
20338
  worldId,
@@ -20382,10 +20365,10 @@ async function captureGems(worldId, workspacePath, repo) {
20382
20365
  `docker exec ${containerName} sh -c 'mkdir -p "$(dirname ${tmpTar})" && tar -czf ${tmpTar}.tmp -C ${bundlePath} . && mv ${tmpTar}.tmp ${tmpTar}'`,
20383
20366
  { stdio: "pipe", timeout: 12e4 }
20384
20367
  );
20385
- fs31.mkdirSync(path35.dirname(tarPath), { recursive: true });
20368
+ fs30.mkdirSync(path34.dirname(tarPath), { recursive: true });
20386
20369
  execSync9(`docker cp ${containerName}:${tmpTar} "${tarPath}"`, { stdio: "pipe", timeout: 12e4 });
20387
20370
  execSync9(`docker exec ${containerName} rm -f ${tmpTar}`, { stdio: "pipe" });
20388
- const stat = fs31.statSync(tarPath);
20371
+ const stat = fs30.statSync(tarPath);
20389
20372
  const manifest = {
20390
20373
  kind: "gems",
20391
20374
  worldId,
@@ -20402,19 +20385,19 @@ async function captureGems(worldId, workspacePath, repo) {
20402
20385
  }
20403
20386
  }
20404
20387
  async function captureNode(worldId, workspacePath, repo) {
20405
- const repoDir = path35.join(workspacePath, repo);
20388
+ const repoDir = path34.join(workspacePath, repo);
20406
20389
  const fingerprint = computeNodeFingerprint(repoDir);
20407
20390
  if (!fingerprint) {
20408
20391
  return { ok: false, tarPath: "", msg: "no lockfile \u2014 layer does not apply" };
20409
20392
  }
20410
- const nodeModules = path35.join(repoDir, "node_modules");
20411
- if (!fs31.existsSync(nodeModules)) {
20393
+ const nodeModules = path34.join(repoDir, "node_modules");
20394
+ if (!fs30.existsSync(nodeModules)) {
20412
20395
  return { ok: false, tarPath: "", msg: "node_modules not installed yet" };
20413
20396
  }
20414
20397
  const tarPath = snapshotTarPath(worldId, "node", repo, fingerprint);
20415
20398
  try {
20416
20399
  packTarball(nodeModules, tarPath);
20417
- const stat = fs31.statSync(tarPath);
20400
+ const stat = fs30.statSync(tarPath);
20418
20401
  const manifest = {
20419
20402
  kind: "node",
20420
20403
  worldId,
@@ -20431,7 +20414,7 @@ async function captureNode(worldId, workspacePath, repo) {
20431
20414
  }
20432
20415
  }
20433
20416
  async function capturePg(worldId, workspacePath, repoNames) {
20434
- const repoDirs = repoNames.map((r) => path35.join(workspacePath, r));
20417
+ const repoDirs = repoNames.map((r) => path34.join(workspacePath, r));
20435
20418
  const fingerprint = computePgFingerprint(repoDirs);
20436
20419
  if (!fingerprint) {
20437
20420
  return { ok: false, tarPath: "", msg: "no Gemfile.lock / schema.rb \u2014 layer does not apply" };
@@ -20446,13 +20429,13 @@ async function capturePg(worldId, workspacePath, repoNames) {
20446
20429
  }
20447
20430
  try {
20448
20431
  execSync9(`docker stop ${containerName}`, { stdio: "pipe", timeout: 3e4 });
20449
- fs31.mkdirSync(path35.dirname(tarPath), { recursive: true });
20432
+ fs30.mkdirSync(path34.dirname(tarPath), { recursive: true });
20450
20433
  execSync9(
20451
- `docker run --rm -v "${volumeName2}:/pgdata:ro" -v "${path35.dirname(tarPath)}:/dest" alpine sh -c 'tar -czf /dest/${path35.basename(tarPath)}.tmp -C /pgdata . && mv /dest/${path35.basename(tarPath)}.tmp /dest/${path35.basename(tarPath)}'`,
20434
+ `docker run --rm -v "${volumeName2}:/pgdata:ro" -v "${path34.dirname(tarPath)}:/dest" alpine sh -c 'tar -czf /dest/${path34.basename(tarPath)}.tmp -C /pgdata . && mv /dest/${path34.basename(tarPath)}.tmp /dest/${path34.basename(tarPath)}'`,
20452
20435
  { stdio: "pipe", timeout: 18e4 }
20453
20436
  );
20454
20437
  execSync9(`docker start ${containerName}`, { stdio: "pipe", timeout: 3e4 });
20455
- const stat = fs31.statSync(tarPath);
20438
+ const stat = fs30.statSync(tarPath);
20456
20439
  const manifest = {
20457
20440
  kind: "pg",
20458
20441
  worldId,
@@ -20475,7 +20458,7 @@ function handleList2(worldIdFilter) {
20475
20458
  const entries = listSnapshots(worldIdFilter);
20476
20459
  if (entries.length === 0) {
20477
20460
  const where = worldIdFilter ? ` for world "${worldIdFilter}"` : "";
20478
- console.log(pc19.dim(`No snapshots found${where}. Run \`olam world snapshot create <worldId>\` first.`));
20461
+ console.log(pc20.dim(`No snapshots found${where}. Run \`olam world snapshot create <worldId>\` first.`));
20479
20462
  return;
20480
20463
  }
20481
20464
  printHeader(`${entries.length} snapshot(s)`);
@@ -20484,15 +20467,15 @@ function handleList2(worldIdFilter) {
20484
20467
  for (const entry of entries) {
20485
20468
  const { manifest } = entry;
20486
20469
  if (manifest.worldId !== lastWorldId) {
20487
- console.log(pc19.bold(manifest.worldId));
20470
+ console.log(pc20.bold(manifest.worldId));
20488
20471
  lastWorldId = manifest.worldId;
20489
20472
  }
20490
20473
  const repo = manifest.repo ?? "(all repos)";
20491
20474
  const size = formatBytes2(manifest.sizeBytes);
20492
20475
  const age = formatAge2(entry.ageMs);
20493
- const kindColor = manifest.kind === "gems" ? pc19.magenta(manifest.kind) : manifest.kind === "node" ? pc19.cyan(manifest.kind) : pc19.yellow(manifest.kind);
20476
+ const kindColor = manifest.kind === "gems" ? pc20.magenta(manifest.kind) : manifest.kind === "node" ? pc20.cyan(manifest.kind) : pc20.yellow(manifest.kind);
20494
20477
  console.log(
20495
- ` ${kindColor.padEnd(6)} ${pc19.dim(repo.padEnd(24))} ${manifest.fingerprint} ${size.padStart(8)} ${age}`
20478
+ ` ${kindColor.padEnd(6)} ${pc20.dim(repo.padEnd(24))} ${manifest.fingerprint} ${size.padStart(8)} ${age}`
20496
20479
  );
20497
20480
  }
20498
20481
  console.log();
@@ -20527,35 +20510,35 @@ function formatAge2(ms) {
20527
20510
  // src/commands/refresh.ts
20528
20511
  init_context();
20529
20512
  init_output();
20530
- import * as fs33 from "node:fs";
20513
+ import * as fs32 from "node:fs";
20531
20514
  import * as os19 from "node:os";
20532
- import * as path37 from "node:path";
20533
- import { spawnSync as spawnSync12 } from "node:child_process";
20515
+ import * as path36 from "node:path";
20516
+ import { spawnSync as spawnSync13 } from "node:child_process";
20534
20517
  import ora8 from "ora";
20535
20518
 
20536
20519
  // src/commands/refresh-helpers.ts
20537
- import * as fs32 from "node:fs";
20538
- import * as path36 from "node:path";
20520
+ import * as fs31 from "node:fs";
20521
+ import * as path35 from "node:path";
20539
20522
  function collectCpSourceFiles(standaloneDir) {
20540
- if (!fs32.existsSync(standaloneDir)) {
20523
+ if (!fs31.existsSync(standaloneDir)) {
20541
20524
  throw new Error(`CP standalone dir not found: ${standaloneDir}`);
20542
20525
  }
20543
20526
  const entries = [];
20544
- const topLevel = fs32.readdirSync(standaloneDir).filter((f) => {
20545
- const stat = fs32.statSync(path36.join(standaloneDir, f));
20527
+ const topLevel = fs31.readdirSync(standaloneDir).filter((f) => {
20528
+ const stat = fs31.statSync(path35.join(standaloneDir, f));
20546
20529
  return stat.isFile() && f.endsWith(".mjs") && !f.endsWith(".test.mjs");
20547
20530
  }).sort();
20548
20531
  for (const f of topLevel) {
20549
- entries.push({ srcPath: path36.join(standaloneDir, f), destRelPath: f });
20532
+ entries.push({ srcPath: path35.join(standaloneDir, f), destRelPath: f });
20550
20533
  }
20551
- const libDir = path36.join(standaloneDir, "lib");
20552
- if (fs32.existsSync(libDir) && fs32.statSync(libDir).isDirectory()) {
20553
- const libFiles = fs32.readdirSync(libDir).filter((f) => {
20554
- const stat = fs32.statSync(path36.join(libDir, f));
20534
+ const libDir = path35.join(standaloneDir, "lib");
20535
+ if (fs31.existsSync(libDir) && fs31.statSync(libDir).isDirectory()) {
20536
+ const libFiles = fs31.readdirSync(libDir).filter((f) => {
20537
+ const stat = fs31.statSync(path35.join(libDir, f));
20555
20538
  return stat.isFile() && f.endsWith(".mjs") && !f.endsWith(".test.mjs");
20556
20539
  }).sort();
20557
20540
  for (const f of libFiles) {
20558
- entries.push({ srcPath: path36.join(libDir, f), destRelPath: `lib/${f}` });
20541
+ entries.push({ srcPath: path35.join(libDir, f), destRelPath: `lib/${f}` });
20559
20542
  }
20560
20543
  }
20561
20544
  return entries;
@@ -20574,7 +20557,7 @@ var RESTART_TIMEOUT_S = 30;
20574
20557
  var HEALTH_POLL_MS = 500;
20575
20558
  var HEALTH_TIMEOUT_MS = 3e4;
20576
20559
  function docker(args) {
20577
- const result = spawnSync12("docker", args, {
20560
+ const result = spawnSync13("docker", args, {
20578
20561
  encoding: "utf-8",
20579
20562
  stdio: ["ignore", "pipe", "pipe"]
20580
20563
  });
@@ -20613,16 +20596,16 @@ async function refreshWorld(worldId, portOffset, standaloneDir, opts) {
20613
20596
  error: err instanceof Error ? err.message : String(err)
20614
20597
  };
20615
20598
  }
20616
- const stagingDir = fs33.mkdtempSync(
20617
- path37.join(os19.tmpdir(), `olam-refresh-${worldId}-`)
20599
+ const stagingDir = fs32.mkdtempSync(
20600
+ path36.join(os19.tmpdir(), `olam-refresh-${worldId}-`)
20618
20601
  );
20619
20602
  try {
20620
20603
  const hasLib = entries.some((e) => e.destRelPath.startsWith("lib/"));
20621
20604
  if (hasLib) {
20622
- fs33.mkdirSync(path37.join(stagingDir, "lib"), { recursive: true });
20605
+ fs32.mkdirSync(path36.join(stagingDir, "lib"), { recursive: true });
20623
20606
  }
20624
20607
  for (const { srcPath, destRelPath } of entries) {
20625
- fs33.copyFileSync(srcPath, path37.join(stagingDir, destRelPath));
20608
+ fs32.copyFileSync(srcPath, path36.join(stagingDir, destRelPath));
20626
20609
  }
20627
20610
  const cpResult = docker([
20628
20611
  "cp",
@@ -20637,7 +20620,7 @@ async function refreshWorld(worldId, portOffset, standaloneDir, opts) {
20637
20620
  };
20638
20621
  }
20639
20622
  } finally {
20640
- fs33.rmSync(stagingDir, { recursive: true, force: true });
20623
+ fs32.rmSync(stagingDir, { recursive: true, force: true });
20641
20624
  }
20642
20625
  if (opts.restart) {
20643
20626
  const restartResult = docker([
@@ -20674,11 +20657,11 @@ function registerRefresh(program2) {
20674
20657
  process.exitCode = 1;
20675
20658
  return;
20676
20659
  }
20677
- const standaloneDir = path37.join(
20660
+ const standaloneDir = path36.join(
20678
20661
  process.cwd(),
20679
20662
  "packages/control-plane/standalone"
20680
20663
  );
20681
- if (!fs33.existsSync(standaloneDir)) {
20664
+ if (!fs32.existsSync(standaloneDir)) {
20682
20665
  printError(
20683
20666
  `CP standalone source not found at ${standaloneDir}.
20684
20667
  Run \`olam refresh\` from the olam repo root.`
@@ -20757,11 +20740,11 @@ Run \`olam refresh\` from the olam repo root.`
20757
20740
  }
20758
20741
 
20759
20742
  // src/commands/diagnose.ts
20760
- import * as fs34 from "node:fs";
20743
+ import * as fs33 from "node:fs";
20761
20744
  import * as os20 from "node:os";
20762
- import * as path38 from "node:path";
20763
- import { execFileSync as execFileSync6, execSync as execSync10 } from "node:child_process";
20764
- import pc20 from "picocolors";
20745
+ import * as path37 from "node:path";
20746
+ import { execFileSync as execFileSync7, execSync as execSync10 } from "node:child_process";
20747
+ import pc21 from "picocolors";
20765
20748
 
20766
20749
  // ../core/dist/diagnose/secret-stripper.js
20767
20750
  var SECRET_PATTERNS = [
@@ -20794,9 +20777,9 @@ function stripSecrets(input) {
20794
20777
  }
20795
20778
 
20796
20779
  // src/commands/diagnose.ts
20797
- var DIAGNOSTICS_DIR = path38.join(os20.homedir(), ".olam", "diagnostics");
20798
- var LOG_DIR = path38.join(os20.homedir(), ".olam", "log");
20799
- var CACHE_DIR = path38.join(os20.homedir(), ".olam", "cache");
20780
+ var DIAGNOSTICS_DIR = path37.join(os20.homedir(), ".olam", "diagnostics");
20781
+ var LOG_DIR = path37.join(os20.homedir(), ".olam", "log");
20782
+ var CACHE_DIR = path37.join(os20.homedir(), ".olam", "cache");
20800
20783
  var LOG_TAIL_LINES = 200;
20801
20784
  function safeExec(cmd) {
20802
20785
  try {
@@ -20806,14 +20789,14 @@ function safeExec(cmd) {
20806
20789
  }
20807
20790
  }
20808
20791
  function defaultZip(zipPath, files) {
20809
- execFileSync6("zip", ["-j", zipPath, ...files]);
20792
+ execFileSync7("zip", ["-j", zipPath, ...files]);
20810
20793
  }
20811
20794
  async function buildDiagnosticsZip(_exec = (cmd) => safeExec(cmd), _outDir = DIAGNOSTICS_DIR, _logDir = LOG_DIR, _zip = defaultZip) {
20812
20795
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 23);
20813
- const zipPath = path38.join(_outDir, `olam-diag-${ts}.zip`);
20814
- const tmpDir = fs34.mkdtempSync(path38.join(os20.tmpdir(), "olam-diag-"));
20796
+ const zipPath = path37.join(_outDir, `olam-diag-${ts}.zip`);
20797
+ const tmpDir = fs33.mkdtempSync(path37.join(os20.tmpdir(), "olam-diag-"));
20815
20798
  try {
20816
- fs34.mkdirSync(_outDir, { recursive: true });
20799
+ fs33.mkdirSync(_outDir, { recursive: true });
20817
20800
  const entries = [];
20818
20801
  const version = process.env["OLAM_CLI_VERSION"] ?? "unknown";
20819
20802
  const nodeVersion = process.version;
@@ -20829,14 +20812,14 @@ platform: ${platform}
20829
20812
  `uptime: ${os20.uptime()}s`
20830
20813
  ].join("\n") + "\n";
20831
20814
  _writeEntry(tmpDir, "os-info.txt", stripSecrets(osContent), entries);
20832
- const depsFile = path38.join(CACHE_DIR, "deps.json");
20833
- if (fs34.existsSync(depsFile)) {
20834
- const deps = fs34.readFileSync(depsFile, "utf-8");
20815
+ const depsFile = path37.join(CACHE_DIR, "deps.json");
20816
+ if (fs33.existsSync(depsFile)) {
20817
+ const deps = fs33.readFileSync(depsFile, "utf-8");
20835
20818
  _writeEntry(tmpDir, "deps.json", stripSecrets(deps), entries);
20836
20819
  }
20837
20820
  const latestLog = _latestLog(_logDir);
20838
20821
  if (latestLog) {
20839
- const lines = fs34.readFileSync(latestLog, "utf-8").split("\n");
20822
+ const lines = fs33.readFileSync(latestLog, "utf-8").split("\n");
20840
20823
  const tail = lines.slice(-LOG_TAIL_LINES).join("\n");
20841
20824
  _writeEntry(tmpDir, "log-tail.txt", stripSecrets(tail), entries);
20842
20825
  }
@@ -20848,38 +20831,38 @@ platform: ${platform}
20848
20831
  if (authAudit) {
20849
20832
  _writeEntry(tmpDir, "audit-auth-callers.txt", stripSecrets(authAudit), entries);
20850
20833
  }
20851
- const fileArgs = entries.map((e) => path38.join(tmpDir, e));
20834
+ const fileArgs = entries.map((e) => path37.join(tmpDir, e));
20852
20835
  try {
20853
20836
  _zip(zipPath, fileArgs);
20854
20837
  } catch (err) {
20855
20838
  throw new Error(`zip command produced no output file. zip stderr: ${err.message}`);
20856
20839
  }
20857
- if (!fs34.existsSync(zipPath)) {
20840
+ if (!fs33.existsSync(zipPath)) {
20858
20841
  throw new Error("zip command produced no output file.");
20859
20842
  }
20860
20843
  return { zipPath, entries };
20861
20844
  } finally {
20862
20845
  try {
20863
- fs34.rmSync(tmpDir, { recursive: true, force: true });
20846
+ fs33.rmSync(tmpDir, { recursive: true, force: true });
20864
20847
  } catch {
20865
20848
  }
20866
20849
  }
20867
20850
  }
20868
20851
  function _writeEntry(dir, name, content, entries) {
20869
- fs34.writeFileSync(path38.join(dir, name), content, { mode: 420 });
20852
+ fs33.writeFileSync(path37.join(dir, name), content, { mode: 420 });
20870
20853
  entries.push(name);
20871
20854
  }
20872
20855
  function _latestLog(logDir) {
20873
- if (!fs34.existsSync(logDir)) return null;
20874
- const files = fs34.readdirSync(logDir).filter((f) => f.startsWith("host-")).sort().reverse();
20875
- return files.length > 0 ? path38.join(logDir, files[0]) : null;
20856
+ if (!fs33.existsSync(logDir)) return null;
20857
+ const files = fs33.readdirSync(logDir).filter((f) => f.startsWith("host-")).sort().reverse();
20858
+ return files.length > 0 ? path37.join(logDir, files[0]) : null;
20876
20859
  }
20877
20860
  async function buildTelemetryPayload() {
20878
20861
  const channel = "stable";
20879
- const manifestFile = path38.join(CACHE_DIR, "manifest.json");
20862
+ const manifestFile = path37.join(CACHE_DIR, "manifest.json");
20880
20863
  let manifestAgeHours = null;
20881
- if (fs34.existsSync(manifestFile)) {
20882
- const mtime = fs34.statSync(manifestFile).mtime.getTime();
20864
+ if (fs33.existsSync(manifestFile)) {
20865
+ const mtime = fs33.statSync(manifestFile).mtime.getTime();
20883
20866
  manifestAgeHours = Math.round((Date.now() - mtime) / 36e5);
20884
20867
  }
20885
20868
  return {
@@ -20899,47 +20882,47 @@ function registerDiagnose(program2) {
20899
20882
  return;
20900
20883
  }
20901
20884
  if (!opts.quiet) {
20902
- console.log(pc20.cyan("Building diagnostics zip\u2026"));
20885
+ console.log(pc21.cyan("Building diagnostics zip\u2026"));
20903
20886
  }
20904
20887
  try {
20905
20888
  const { zipPath, entries } = await buildDiagnosticsZip();
20906
20889
  if (!opts.quiet) {
20907
- console.log(pc20.green(`Done: ${zipPath}`));
20908
- console.log(pc20.dim(`Contents: ${entries.join(", ")}`));
20890
+ console.log(pc21.green(`Done: ${zipPath}`));
20891
+ console.log(pc21.dim(`Contents: ${entries.join(", ")}`));
20909
20892
  }
20910
20893
  if (opts.upload) {
20911
- console.log(pc20.yellow(
20894
+ console.log(pc21.yellow(
20912
20895
  `Telemetry endpoint not yet provisioned. Share the zip manually:
20913
20896
  File: ${zipPath}
20914
20897
  See docs/runbooks/share-diagnostics.md for instructions.`
20915
20898
  ));
20916
20899
  }
20917
20900
  } catch (err) {
20918
- console.error(pc20.red(`Diagnose failed: ${err.message}`));
20901
+ console.error(pc21.red(`Diagnose failed: ${err.message}`));
20919
20902
  process.exitCode = 1;
20920
20903
  }
20921
20904
  });
20922
20905
  }
20923
20906
 
20924
20907
  // src/commands/update.ts
20925
- import * as fs37 from "node:fs";
20908
+ import * as fs36 from "node:fs";
20926
20909
  import * as os22 from "node:os";
20927
- import * as path41 from "node:path";
20910
+ import * as path40 from "node:path";
20928
20911
  import { execSync as execSync11 } from "node:child_process";
20929
- import pc21 from "picocolors";
20912
+ import pc22 from "picocolors";
20930
20913
 
20931
20914
  // src/lib/symlink-reconcile.ts
20932
- import * as fs35 from "node:fs";
20933
- import * as path39 from "node:path";
20915
+ import * as fs34 from "node:fs";
20916
+ import * as path38 from "node:path";
20934
20917
  var realFs = {
20935
- readdirSync: (p) => fs35.readdirSync(p),
20936
- existsSync: (p) => fs35.existsSync(p),
20937
- lstatSync: (p) => fs35.lstatSync(p),
20938
- readlinkSync: (p) => fs35.readlinkSync(p),
20939
- symlinkSync: (t, l) => fs35.symlinkSync(t, l),
20940
- unlinkSync: (p) => fs35.unlinkSync(p),
20918
+ readdirSync: (p) => fs34.readdirSync(p),
20919
+ existsSync: (p) => fs34.existsSync(p),
20920
+ lstatSync: (p) => fs34.lstatSync(p),
20921
+ readlinkSync: (p) => fs34.readlinkSync(p),
20922
+ symlinkSync: (t, l) => fs34.symlinkSync(t, l),
20923
+ unlinkSync: (p) => fs34.unlinkSync(p),
20941
20924
  mkdirSync: (p, o) => {
20942
- fs35.mkdirSync(p, o);
20925
+ fs34.mkdirSync(p, o);
20943
20926
  }
20944
20927
  };
20945
20928
  function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir, _fs = realFs) {
@@ -20949,8 +20932,8 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir, _fs = realFs) {
20949
20932
  _fs.mkdirSync(claudeSkillsDir, { recursive: true });
20950
20933
  const sourceSkills = _fs.existsSync(npmSkillsDir) ? _fs.readdirSync(npmSkillsDir).filter((d) => d.startsWith("olam-")) : [];
20951
20934
  for (const skill of sourceSkills) {
20952
- const linkPath = path39.join(claudeSkillsDir, skill);
20953
- const target = path39.join(npmSkillsDir, skill);
20935
+ const linkPath = path38.join(claudeSkillsDir, skill);
20936
+ const target = path38.join(npmSkillsDir, skill);
20954
20937
  if (!_fs.existsSync(linkPath)) {
20955
20938
  try {
20956
20939
  _fs.symlinkSync(target, linkPath);
@@ -20963,7 +20946,7 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir, _fs = realFs) {
20963
20946
  }
20964
20947
  const deployedEntries = _fs.existsSync(claudeSkillsDir) ? _fs.readdirSync(claudeSkillsDir).filter((d) => d.startsWith("olam-")) : [];
20965
20948
  for (const entry of deployedEntries) {
20966
- const linkPath = path39.join(claudeSkillsDir, entry);
20949
+ const linkPath = path38.join(claudeSkillsDir, entry);
20967
20950
  let isSymlink = false;
20968
20951
  try {
20969
20952
  isSymlink = _fs.lstatSync(linkPath).isSymbolicLink();
@@ -20988,9 +20971,9 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir, _fs = realFs) {
20988
20971
 
20989
20972
  // src/commands/update.ts
20990
20973
  var PACKAGE_NAME = "@pleri/olam-cli";
20991
- var CACHE_DIR2 = path41.join(os22.homedir(), ".olam", "cache");
20992
- var LOG_DIR2 = path41.join(os22.homedir(), ".olam", "log");
20993
- var LAST_STABLE_FILE = path41.join(CACHE_DIR2, "last-stable.txt");
20974
+ var CACHE_DIR2 = path40.join(os22.homedir(), ".olam", "cache");
20975
+ var LOG_DIR2 = path40.join(os22.homedir(), ".olam", "log");
20976
+ var LAST_STABLE_FILE = path40.join(CACHE_DIR2, "last-stable.txt");
20994
20977
  function defaultExec(cmd) {
20995
20978
  try {
20996
20979
  const stdout = execSync11(cmd, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
@@ -21012,22 +20995,22 @@ function getCurrentVersion(_exec = defaultExec) {
21012
20995
  }
21013
20996
  function readLastStable(file = LAST_STABLE_FILE) {
21014
20997
  try {
21015
- const v = fs37.readFileSync(file, "utf-8").trim();
20998
+ const v = fs36.readFileSync(file, "utf-8").trim();
21016
20999
  return v || null;
21017
21000
  } catch {
21018
21001
  return null;
21019
21002
  }
21020
21003
  }
21021
21004
  function writeLastStable(version, file = LAST_STABLE_FILE) {
21022
- fs37.mkdirSync(path41.dirname(file), { recursive: true });
21023
- fs37.writeFileSync(file, version, { mode: 420 });
21005
+ fs36.mkdirSync(path40.dirname(file), { recursive: true });
21006
+ fs36.writeFileSync(file, version, { mode: 420 });
21024
21007
  }
21025
21008
  function logUpdateFailure(stderr) {
21026
21009
  const ts = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
21027
- const logFile = path41.join(LOG_DIR2, `update-${ts}.log`);
21010
+ const logFile = path40.join(LOG_DIR2, `update-${ts}.log`);
21028
21011
  try {
21029
- fs37.mkdirSync(LOG_DIR2, { recursive: true });
21030
- fs37.appendFileSync(logFile, `[update-failure ${(/* @__PURE__ */ new Date()).toISOString()}]
21012
+ fs36.mkdirSync(LOG_DIR2, { recursive: true });
21013
+ fs36.appendFileSync(logFile, `[update-failure ${(/* @__PURE__ */ new Date()).toISOString()}]
21031
21014
  ${stderr}
21032
21015
  `, "utf-8");
21033
21016
  } catch {
@@ -21078,52 +21061,52 @@ async function doUpdate(opts, _exec = defaultExec, _reconcile = reconcileSkillSy
21078
21061
  writeLastStable(prevVersion);
21079
21062
  }
21080
21063
  if (!quiet) {
21081
- console.log(pc21.cyan(`Installing ${PACKAGE_NAME}@${channel}\u2026`));
21064
+ console.log(pc22.cyan(`Installing ${PACKAGE_NAME}@${channel}\u2026`));
21082
21065
  }
21083
21066
  const installResult = _exec(`npm install -g ${PACKAGE_NAME}@${channel}`);
21084
21067
  if (installResult.exitCode !== 0) {
21085
21068
  logUpdateFailure(installResult.stderr);
21086
21069
  if (!quiet) {
21087
- console.error(pc21.red("Update failed."));
21070
+ console.error(pc22.red("Update failed."));
21088
21071
  }
21089
21072
  const prev = readLastStable();
21090
21073
  if (prev) {
21091
21074
  if (!quiet) {
21092
- console.log(pc21.yellow(`Restoring to ${prev}\u2026`));
21075
+ console.log(pc22.yellow(`Restoring to ${prev}\u2026`));
21093
21076
  }
21094
21077
  const restoreResult = _exec(`npm install -g ${PACKAGE_NAME}@${prev}`);
21095
21078
  if (restoreResult.exitCode !== 0) {
21096
21079
  if (!quiet) {
21097
- console.error(pc21.red(
21080
+ console.error(pc22.red(
21098
21081
  `Restore also failed. Run: npm install -g ${PACKAGE_NAME}@${prev} manually.`
21099
21082
  ));
21100
21083
  }
21101
21084
  } else if (!quiet) {
21102
- console.log(pc21.yellow(`Restored to ${prev}.`));
21085
+ console.log(pc22.yellow(`Restored to ${prev}.`));
21103
21086
  }
21104
21087
  } else if (!quiet) {
21105
- console.error(pc21.red("No previous version cached; cannot auto-restore."));
21088
+ console.error(pc22.red("No previous version cached; cannot auto-restore."));
21106
21089
  }
21107
21090
  return { action: "restored", prevVersion: prev ?? void 0, exitCode: 11 };
21108
21091
  }
21109
21092
  const newVersion = getCurrentVersion(_exec) ?? void 0;
21110
21093
  if (!quiet && newVersion) {
21111
- console.log(pc21.green(`Updated to ${newVersion}.`));
21094
+ console.log(pc22.green(`Updated to ${newVersion}.`));
21112
21095
  }
21113
21096
  const npmRootResult = _getNpmRoot("npm root -g");
21114
21097
  let symlinkResult = { added: [], removed: [] };
21115
21098
  if (npmRootResult.exitCode === 0) {
21116
21099
  const npmRoot = npmRootResult.stdout.trim();
21117
- const npmSkillsDir = path41.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills");
21118
- const claudeSkillsDir = path41.join(os22.homedir(), ".claude", "skills");
21100
+ const npmSkillsDir = path40.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills");
21101
+ const claudeSkillsDir = path40.join(os22.homedir(), ".claude", "skills");
21119
21102
  const rec = _reconcile(npmSkillsDir, claudeSkillsDir);
21120
21103
  symlinkResult = { added: rec.added, removed: rec.removed };
21121
21104
  if (!quiet && (rec.added.length > 0 || rec.removed.length > 0)) {
21122
21105
  if (rec.added.length > 0) {
21123
- console.log(pc21.dim(`Skills added: ${rec.added.join(", ")}`));
21106
+ console.log(pc22.dim(`Skills added: ${rec.added.join(", ")}`));
21124
21107
  }
21125
21108
  if (rec.removed.length > 0) {
21126
- console.log(pc21.dim(`Skills removed (dangling): ${rec.removed.join(", ")}`));
21109
+ console.log(pc22.dim(`Skills removed (dangling): ${rec.removed.join(", ")}`));
21127
21110
  }
21128
21111
  }
21129
21112
  }
@@ -21161,8 +21144,8 @@ async function doRollback(_exec = defaultExec, _reconcile = reconcileSkillSymlin
21161
21144
  if (npmRootResult.exitCode === 0) {
21162
21145
  const npmRoot = npmRootResult.stdout.trim();
21163
21146
  _reconcile(
21164
- path41.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills"),
21165
- path41.join(os22.homedir(), ".claude", "skills")
21147
+ path40.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills"),
21148
+ path40.join(os22.homedir(), ".claude", "skills")
21166
21149
  );
21167
21150
  }
21168
21151
  return { action: "rolled-back", restoredVersion: prev, exitCode: 0 };
@@ -21217,7 +21200,7 @@ function registerUpdate(program2) {
21217
21200
  // src/commands/begin.ts
21218
21201
  init_host_cp();
21219
21202
  init_open_url();
21220
- import pc22 from "picocolors";
21203
+ import pc23 from "picocolors";
21221
21204
  async function doBegin(opts, _startFn = startHostCp, _openFn = openUrl) {
21222
21205
  const prevExitCode = process.exitCode;
21223
21206
  await _startFn({ showToken: opts.showToken });
@@ -21227,7 +21210,7 @@ async function doBegin(opts, _startFn = startHostCp, _openFn = openUrl) {
21227
21210
  const token = readToken();
21228
21211
  if (token) {
21229
21212
  const base = `http://127.0.0.1:${HOST_CP_PORT}/`;
21230
- console.log(pc22.dim(`Opening ${base}`));
21213
+ console.log(pc23.dim(`Opening ${base}`));
21231
21214
  _openFn(`${base}?token=${token}`);
21232
21215
  }
21233
21216
  }
@@ -21323,8 +21306,8 @@ var SECRET = process.env["OLAM_MCP_AUTH_SECRET"] ?? "";
21323
21306
  function authHeaders() {
21324
21307
  return SECRET ? { "X-Olam-Mcp-Secret": SECRET } : {};
21325
21308
  }
21326
- async function apiFetch(path45, init = {}) {
21327
- const res = await fetch(`${BASE_URL}${path45}`, {
21309
+ async function apiFetch(path44, init = {}) {
21310
+ const res = await fetch(`${BASE_URL}${path44}`, {
21328
21311
  ...init,
21329
21312
  headers: {
21330
21313
  "Content-Type": "application/json",
@@ -21476,7 +21459,7 @@ function registerMcpAdd(cmd) {
21476
21459
 
21477
21460
  // src/commands/mcp/list.ts
21478
21461
  init_output();
21479
- import pc23 from "picocolors";
21462
+ import pc24 from "picocolors";
21480
21463
  function registerMcpList(cmd) {
21481
21464
  cmd.command("list").description("List all registered MCP credentials").action(async () => {
21482
21465
  const client = getMcpAuthClient();
@@ -21491,8 +21474,8 @@ function registerMcpList(cmd) {
21491
21474
  }
21492
21475
  const mcps = data.mcps ?? [];
21493
21476
  if (mcps.length === 0) {
21494
- console.log(pc23.dim("No MCP credentials registered."));
21495
- console.log(pc23.dim("Add one with: olam mcp add <service>"));
21477
+ console.log(pc24.dim("No MCP credentials registered."));
21478
+ console.log(pc24.dim("Add one with: olam mcp add <service>"));
21496
21479
  return;
21497
21480
  }
21498
21481
  const [c0, c1, c2, c3] = [16, 20, 10, 24];
@@ -21503,12 +21486,12 @@ function registerMcpList(cmd) {
21503
21486
  "ENV VAR".padEnd(c3),
21504
21487
  "STATUS"
21505
21488
  ].join(" ");
21506
- console.log(pc23.dim(header));
21507
- console.log(pc23.dim("\u2500".repeat(header.length)));
21489
+ console.log(pc24.dim(header));
21490
+ console.log(pc24.dim("\u2500".repeat(header.length)));
21508
21491
  for (const m of mcps) {
21509
- const status = !m.validated ? pc23.yellow("unvalidated") : m.expired ? pc23.red("expired") : pc23.green("active");
21492
+ const status = !m.validated ? pc24.yellow("unvalidated") : m.expired ? pc24.red("expired") : pc24.green("active");
21510
21493
  const row = [
21511
- pc23.cyan(m.service.padEnd(c0)),
21494
+ pc24.cyan(m.service.padEnd(c0)),
21512
21495
  m.label.padEnd(c1).slice(0, c1),
21513
21496
  m.type.padEnd(c2),
21514
21497
  (m.envName ?? "\u2014").padEnd(c3).slice(0, c3),
@@ -21536,13 +21519,13 @@ function registerMcpRemove(cmd) {
21536
21519
 
21537
21520
  // src/commands/mcp/status.ts
21538
21521
  init_output();
21539
- import pc24 from "picocolors";
21522
+ import pc25 from "picocolors";
21540
21523
  function formatExpiry(expiresAt) {
21541
21524
  if (!expiresAt) return "\u2014";
21542
21525
  const ms = expiresAt - Date.now();
21543
- if (ms <= 0) return pc24.red("expired");
21526
+ if (ms <= 0) return pc25.red("expired");
21544
21527
  const hours = ms / (1e3 * 60 * 60);
21545
- if (hours < 1) return pc24.yellow(`${Math.ceil(ms / 6e4)}m`);
21528
+ if (hours < 1) return pc25.yellow(`${Math.ceil(ms / 6e4)}m`);
21546
21529
  return `${hours.toFixed(1)}h`;
21547
21530
  }
21548
21531
  function registerMcpStatus(cmd) {
@@ -21559,14 +21542,14 @@ function registerMcpStatus(cmd) {
21559
21542
  const mcps = data.mcps ?? [];
21560
21543
  printHeader(`MCP Credentials (${mcps.length})`);
21561
21544
  if (mcps.length === 0) {
21562
- console.log(pc24.dim("No credentials registered."));
21545
+ console.log(pc25.dim("No credentials registered."));
21563
21546
  return;
21564
21547
  }
21565
21548
  for (const m of mcps) {
21566
- const stateColor = !m.validated ? pc24.yellow : m.expired ? pc24.red : pc24.green;
21549
+ const stateColor = !m.validated ? pc25.yellow : m.expired ? pc25.red : pc25.green;
21567
21550
  const stateLabel = !m.validated ? "unvalidated" : m.expired ? "expired" : "active";
21568
21551
  console.log(`
21569
- ${pc24.cyan(m.service)} ${stateColor(`[${stateLabel}]`)}`);
21552
+ ${pc25.cyan(m.service)} ${stateColor(`[${stateLabel}]`)}`);
21570
21553
  console.log(` label: ${m.label}`);
21571
21554
  console.log(` type: ${m.type}`);
21572
21555
  if (m.envName) console.log(` env var: ${m.envName}`);
@@ -21581,15 +21564,15 @@ function registerMcpStatus(cmd) {
21581
21564
  // src/commands/mcp/import.ts
21582
21565
  init_output();
21583
21566
  import * as readline3 from "node:readline";
21584
- import pc25 from "picocolors";
21567
+ import pc26 from "picocolors";
21585
21568
 
21586
21569
  // src/commands/mcp/import-discovery.ts
21587
- import * as fs38 from "node:fs";
21570
+ import * as fs37 from "node:fs";
21588
21571
  import * as os23 from "node:os";
21589
- import * as path42 from "node:path";
21572
+ import * as path41 from "node:path";
21590
21573
  function readJsonFile(filePath) {
21591
21574
  try {
21592
- const raw = fs38.readFileSync(filePath, "utf-8");
21575
+ const raw = fs37.readFileSync(filePath, "utf-8");
21593
21576
  return JSON.parse(raw);
21594
21577
  } catch {
21595
21578
  return null;
@@ -21618,24 +21601,24 @@ function extractMcpServers(obj, source, sourceLabel) {
21618
21601
  }
21619
21602
  function getClaudeDesktopPath() {
21620
21603
  if (process.platform === "darwin") {
21621
- return path42.join(os23.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
21604
+ return path41.join(os23.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
21622
21605
  }
21623
21606
  if (process.platform === "win32") {
21624
- const appData = process.env["APPDATA"] ?? path42.join(os23.homedir(), "AppData", "Roaming");
21625
- return path42.join(appData, "Claude", "claude_desktop_config.json");
21607
+ const appData = process.env["APPDATA"] ?? path41.join(os23.homedir(), "AppData", "Roaming");
21608
+ return path41.join(appData, "Claude", "claude_desktop_config.json");
21626
21609
  }
21627
- return path42.join(os23.homedir(), ".config", "Claude", "claude_desktop_config.json");
21610
+ return path41.join(os23.homedir(), ".config", "Claude", "claude_desktop_config.json");
21628
21611
  }
21629
21612
  function getOlamRepoPaths() {
21630
21613
  const configPaths = [
21631
- path42.join(os23.homedir(), ".olam", "config.yaml"),
21632
- path42.join(process.cwd(), ".olam", "config.yaml")
21614
+ path41.join(os23.homedir(), ".olam", "config.yaml"),
21615
+ path41.join(process.cwd(), ".olam", "config.yaml")
21633
21616
  ];
21634
21617
  const paths = [];
21635
21618
  for (const configPath of configPaths) {
21636
- if (!fs38.existsSync(configPath)) continue;
21619
+ if (!fs37.existsSync(configPath)) continue;
21637
21620
  try {
21638
- const raw = fs38.readFileSync(configPath, "utf-8");
21621
+ const raw = fs37.readFileSync(configPath, "utf-8");
21639
21622
  const repoMatches = [...raw.matchAll(/path:\s*["']?([^\s"'\n]+)/g)];
21640
21623
  for (const m of repoMatches) {
21641
21624
  if (m[1]) paths.push(m[1]);
@@ -21651,7 +21634,7 @@ async function discoverMcpSources(repoPaths) {
21651
21634
  const sources = [];
21652
21635
  const sourceDefs = [
21653
21636
  {
21654
- path: path42.join(os23.homedir(), ".claude.json"),
21637
+ path: path41.join(os23.homedir(), ".claude.json"),
21655
21638
  label: "Claude Code (~/.claude.json)"
21656
21639
  },
21657
21640
  {
@@ -21659,19 +21642,19 @@ async function discoverMcpSources(repoPaths) {
21659
21642
  label: "Claude Desktop"
21660
21643
  },
21661
21644
  {
21662
- path: path42.join(os23.homedir(), ".cursor", "mcp.json"),
21645
+ path: path41.join(os23.homedir(), ".cursor", "mcp.json"),
21663
21646
  label: "Cursor (~/.cursor/mcp.json)"
21664
21647
  },
21665
21648
  {
21666
- path: path42.join(os23.homedir(), ".codeium", "windsurf", "mcp_config.json"),
21649
+ path: path41.join(os23.homedir(), ".codeium", "windsurf", "mcp_config.json"),
21667
21650
  label: "Windsurf (~/.codeium/windsurf/mcp_config.json)"
21668
21651
  }
21669
21652
  ];
21670
21653
  const resolvedRepoPaths = repoPaths ?? getOlamRepoPaths();
21671
21654
  for (const repoPath of resolvedRepoPaths) {
21672
21655
  sourceDefs.push({
21673
- path: path42.join(repoPath, ".mcp.json"),
21674
- label: `.mcp.json (${path42.basename(repoPath)})`
21656
+ path: path41.join(repoPath, ".mcp.json"),
21657
+ label: `.mcp.json (${path41.basename(repoPath)})`
21675
21658
  });
21676
21659
  }
21677
21660
  const reads = await Promise.all(
@@ -21751,13 +21734,13 @@ async function validateMcpEntry(entry) {
21751
21734
  // src/commands/mcp/import.ts
21752
21735
  async function multiSelectPicker(entries) {
21753
21736
  if (entries.length === 0) return [];
21754
- console.log("\n" + pc25.bold("Discovered MCP servers:"));
21737
+ console.log("\n" + pc26.bold("Discovered MCP servers:"));
21755
21738
  entries.forEach((e, i) => {
21756
21739
  console.log(
21757
- ` ${pc25.dim(`[${i + 1}]`)} ${pc25.cyan(e.name.padEnd(20))} ${pc25.dim(e.sourceLabel)}`
21740
+ ` ${pc26.dim(`[${i + 1}]`)} ${pc26.cyan(e.name.padEnd(20))} ${pc26.dim(e.sourceLabel)}`
21758
21741
  );
21759
21742
  });
21760
- console.log("\n" + pc25.dim('Enter numbers to import (e.g. 1,2,3 or "all" or Enter to skip):'));
21743
+ console.log("\n" + pc26.dim('Enter numbers to import (e.g. 1,2,3 or "all" or Enter to skip):'));
21761
21744
  const answer = await new Promise((resolve8) => {
21762
21745
  const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
21763
21746
  rl.question("> ", (ans) => {
@@ -21784,7 +21767,7 @@ function registerMcpImport(cmd) {
21784
21767
  const repoPaths = opts.repoPaths ? opts.repoPaths.split(",").map((s) => s.trim()) : void 0;
21785
21768
  const { entries, sources, durationMs } = await discoverMcpSources(repoPaths);
21786
21769
  if (entries.length === 0) {
21787
- console.log(pc25.dim("No MCP servers found in any source path."));
21770
+ console.log(pc26.dim("No MCP servers found in any source path."));
21788
21771
  return;
21789
21772
  }
21790
21773
  printInfo("Sources", sources.length > 0 ? sources.join(", ") : "none");
@@ -21797,15 +21780,15 @@ function registerMcpImport(cmd) {
21797
21780
  candidates = filtered;
21798
21781
  }
21799
21782
  if (skippedCount > 0) {
21800
- console.log(pc25.dim(`skipped: ${skippedCount} already registered`));
21783
+ console.log(pc26.dim(`skipped: ${skippedCount} already registered`));
21801
21784
  }
21802
21785
  if (candidates.length === 0) {
21803
- console.log(pc25.dim("Nothing new to import. Use --reimport to force."));
21786
+ console.log(pc26.dim("Nothing new to import. Use --reimport to force."));
21804
21787
  return;
21805
21788
  }
21806
21789
  const selected = await multiSelectPicker(candidates);
21807
21790
  if (selected.length === 0) {
21808
- console.log(pc25.dim("No servers selected."));
21791
+ console.log(pc26.dim("No servers selected."));
21809
21792
  return;
21810
21793
  }
21811
21794
  console.log(`
@@ -21816,16 +21799,16 @@ Importing ${selected.length} server(s)\u2026`);
21816
21799
  let validated = false;
21817
21800
  let validationReason = "skipped";
21818
21801
  if (opts.validate !== false) {
21819
- process.stdout.write(` ${pc25.dim("\u2192")} ${entry.name} validating\u2026 `);
21802
+ process.stdout.write(` ${pc26.dim("\u2192")} ${entry.name} validating\u2026 `);
21820
21803
  const vr = await validateMcpEntry(entry);
21821
21804
  validated = vr.validated;
21822
21805
  validationReason = vr.reason;
21823
21806
  process.stdout.write(
21824
- validated ? pc25.green("ok\n") : pc25.yellow(`unvalidated (${vr.reason})
21807
+ validated ? pc26.green("ok\n") : pc26.yellow(`unvalidated (${vr.reason})
21825
21808
  `)
21826
21809
  );
21827
21810
  } else {
21828
- console.log(` ${pc25.dim("\u2192")} ${entry.name} ${pc25.dim("(validation skipped)")}`);
21811
+ console.log(` ${pc26.dim("\u2192")} ${entry.name} ${pc26.dim("(validation skipped)")}`);
21829
21812
  }
21830
21813
  if (validated) validatedCount++;
21831
21814
  const result = await client.staticAdd({
@@ -21840,21 +21823,21 @@ Importing ${selected.length} server(s)\u2026`);
21840
21823
  }
21841
21824
  }
21842
21825
  console.log("");
21843
- console.log(pc25.green(`\u2713 Imported ${importedCount}/${selected.length}`));
21826
+ console.log(pc26.green(`\u2713 Imported ${importedCount}/${selected.length}`));
21844
21827
  if (validatedCount > 0) {
21845
- console.log(pc25.dim(` ${validatedCount} validated, ${importedCount - validatedCount} unvalidated`));
21828
+ console.log(pc26.dim(` ${validatedCount} validated, ${importedCount - validatedCount} unvalidated`));
21846
21829
  }
21847
21830
  });
21848
21831
  }
21849
21832
 
21850
21833
  // src/commands/mcp/revoke.ts
21851
21834
  init_output();
21852
- import pc26 from "picocolors";
21835
+ import pc27 from "picocolors";
21853
21836
  function registerMcpRevoke(cmd) {
21854
21837
  cmd.command("revoke <user> <world> <service>").description("Revoke a user's MCP service entitlement (multi-tenant mode only)").action(async (user, world, service) => {
21855
21838
  const multiTenant = (process.env["OLAM_MCP_MULTI_TENANT"] ?? "").toLowerCase() === "true";
21856
21839
  if (!multiTenant) {
21857
- console.warn(pc26.yellow("\u26A0 revocation only meaningful in multi_tenant mode \u2014 no-op"));
21840
+ console.warn(pc27.yellow("\u26A0 revocation only meaningful in multi_tenant mode \u2014 no-op"));
21858
21841
  return;
21859
21842
  }
21860
21843
  const baseUrl = process.env["OLAM_MCP_AUTH_SERVICE_URL"] ?? "http://127.0.0.1:9998";
@@ -21883,8 +21866,8 @@ function registerMcpRevoke(cmd) {
21883
21866
  process.exitCode = 1;
21884
21867
  return;
21885
21868
  }
21886
- console.log(pc26.green(`\u2713 Revoked: ${user} / ${world} / ${service}`));
21887
- console.log(pc26.dim(" Next fetch-creds call returns 403; token cleared on next merge."));
21869
+ console.log(pc27.green(`\u2713 Revoked: ${user} / ${world} / ${service}`));
21870
+ console.log(pc27.dim(" Next fetch-creds call returns 403; token cleared on next merge."));
21888
21871
  });
21889
21872
  }
21890
21873
 
@@ -21901,18 +21884,18 @@ function registerMcp(program2) {
21901
21884
  }
21902
21885
 
21903
21886
  // src/pleri-config.ts
21904
- import * as fs39 from "node:fs";
21905
- import * as path43 from "node:path";
21887
+ import * as fs38 from "node:fs";
21888
+ import * as path42 from "node:path";
21906
21889
  function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
21907
21890
  if (process.env.PLERI_BASE_URL) {
21908
21891
  return true;
21909
21892
  }
21910
- const configPath = path43.join(configDir, "config.yaml");
21911
- if (!fs39.existsSync(configPath)) {
21893
+ const configPath = path42.join(configDir, "config.yaml");
21894
+ if (!fs38.existsSync(configPath)) {
21912
21895
  return false;
21913
21896
  }
21914
21897
  try {
21915
- const contents = fs39.readFileSync(configPath, "utf8");
21898
+ const contents = fs38.readFileSync(configPath, "utf8");
21916
21899
  return /^[^#\n]*\bpleri:/m.test(contents);
21917
21900
  } catch {
21918
21901
  return false;
@@ -21923,14 +21906,14 @@ function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
21923
21906
  var program = new Command();
21924
21907
  function readCliVersion() {
21925
21908
  try {
21926
- const here = path44.dirname(fileURLToPath4(import.meta.url));
21909
+ const here = path43.dirname(fileURLToPath4(import.meta.url));
21927
21910
  for (const candidate of [
21928
- path44.join(here, "package.json"),
21929
- path44.join(here, "..", "package.json"),
21930
- path44.join(here, "..", "..", "package.json")
21911
+ path43.join(here, "package.json"),
21912
+ path43.join(here, "..", "package.json"),
21913
+ path43.join(here, "..", "..", "package.json")
21931
21914
  ]) {
21932
- if (fs40.existsSync(candidate)) {
21933
- const pkg = JSON.parse(fs40.readFileSync(candidate, "utf-8"));
21915
+ if (fs39.existsSync(candidate)) {
21916
+ const pkg = JSON.parse(fs39.readFileSync(candidate, "utf-8"));
21934
21917
  if (typeof pkg.version === "string" && pkg.version.length > 0) return pkg.version;
21935
21918
  }
21936
21919
  }
@@ -21969,4 +21952,5 @@ registerBegin(program);
21969
21952
  registerStop(program);
21970
21953
  registerWorldUpgrade(program);
21971
21954
  registerMcp(program);
21955
+ registerServices(program);
21972
21956
  program.parse();