@pleri/olam-cli 0.1.173 → 0.1.174

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 (33) hide show
  1. package/dist/commands/auth.d.ts +22 -7
  2. package/dist/commands/auth.d.ts.map +1 -1
  3. package/dist/commands/auth.js +414 -46
  4. package/dist/commands/auth.js.map +1 -1
  5. package/dist/commands/create.d.ts.map +1 -1
  6. package/dist/commands/create.js +45 -1
  7. package/dist/commands/create.js.map +1 -1
  8. package/dist/commands/services.d.ts +39 -0
  9. package/dist/commands/services.d.ts.map +1 -1
  10. package/dist/commands/services.js +64 -9
  11. package/dist/commands/services.js.map +1 -1
  12. package/dist/from-manifest.d.ts +53 -0
  13. package/dist/from-manifest.d.ts.map +1 -0
  14. package/dist/from-manifest.js +95 -0
  15. package/dist/from-manifest.js.map +1 -0
  16. package/dist/image-digests.json +8 -8
  17. package/dist/index.js +907 -136
  18. package/dist/lib/auth-remote.d.ts +130 -0
  19. package/dist/lib/auth-remote.d.ts.map +1 -0
  20. package/dist/lib/auth-remote.js +307 -0
  21. package/dist/lib/auth-remote.js.map +1 -0
  22. package/dist/mcp-server.js +254 -57
  23. package/hermes-bundle/version.json +1 -1
  24. package/host-cp/k8s/manifests/50-deployment.yaml +1 -1
  25. package/host-cp/k8s/manifests/auth-service/50-deployment.yaml +1 -1
  26. package/host-cp/k8s/manifests/kg-service/50-deployment.yaml +1 -1
  27. package/host-cp/k8s/manifests/mcp-auth-service/50-deployment.yaml +1 -1
  28. package/host-cp/k8s/manifests/memory-service/50-deployment.yaml +1 -1
  29. package/host-cp/src/boot-reconciler.mjs +238 -0
  30. package/host-cp/src/port-bridge-manager.mjs +116 -10
  31. package/host-cp/src/server.mjs +32 -0
  32. package/host-cp/src/world-activity-tracker.mjs +392 -0
  33. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -8314,6 +8314,21 @@ CREATE TABLE IF NOT EXISTS meta (
8314
8314
  const row = this.db.prepare("SELECT * FROM worlds WHERE id = ?").get(worldId);
8315
8315
  return row ? rowToMetadata(row) : void 0;
8316
8316
  }
8317
+ /**
8318
+ * Find all worlds with a given `name`. Returns rows of every lifecycle
8319
+ * status — callers filter as needed (e.g. active-only for dedup, error-
8320
+ * only for cleanup).
8321
+ *
8322
+ * The schema has UNIQUE on `id` but NOT on `name`, so a single name can
8323
+ * legitimately have multiple rows (e.g. one destroyed + one new). Issue
8324
+ * #962: `olam create <name>` was generating fresh ids without checking
8325
+ * for an existing row, accumulating orphan error rows under the same
8326
+ * name. This is the registry-level primitive the manager's dedup uses.
8327
+ */
8328
+ findByName(name) {
8329
+ const rows = this.db.prepare("SELECT * FROM worlds WHERE name = ? ORDER BY created_at DESC").all(name);
8330
+ return rows.map(rowToMetadata);
8331
+ }
8317
8332
  list(filter2) {
8318
8333
  if (filter2?.status) {
8319
8334
  const rows2 = this.db.prepare("SELECT * FROM worlds WHERE status = ? ORDER BY created_at DESC").all(filter2.status);
@@ -8863,8 +8878,8 @@ function copyDirRecursive(src, dest, depth = 0, skipFiles = /* @__PURE__ */ new
8863
8878
  }
8864
8879
  }
8865
8880
  async function copyClaudeConfigIntoContainer(containerName) {
8866
- const { execSync: execSync15 } = await import("node:child_process");
8867
- const dockerExec = (cmd) => execSync15(`docker exec ${containerName} sh -c '${cmd}'`, { stdio: "pipe" });
8881
+ const { execSync: execSync16 } = await import("node:child_process");
8882
+ const dockerExec = (cmd) => execSync16(`docker exec ${containerName} sh -c '${cmd}'`, { stdio: "pipe" });
8868
8883
  dockerExec("mkdir -p $HOME/.claude");
8869
8884
  dockerExec("test -f /home/olam/workspace/.claude-host-config/settings.json && cp /home/olam/workspace/.claude-host-config/settings.json $HOME/.claude/settings.json || true");
8870
8885
  dockerExec("test -f /home/olam/workspace/.claude-host-config/CLAUDE.md && cp /home/olam/workspace/.claude-host-config/CLAUDE.md $HOME/.claude/CLAUDE.md || true");
@@ -8880,7 +8895,7 @@ async function copyClaudeConfigIntoContainer(containerName) {
8880
8895
  await sanitizeContainerClaudeHooks(containerName);
8881
8896
  }
8882
8897
  async function sanitizeContainerClaudeHooks(containerName) {
8883
- const { execSync: execSync15 } = await import("node:child_process");
8898
+ const { execSync: execSync16 } = await import("node:child_process");
8884
8899
  const script = `
8885
8900
  const fs = require('fs');
8886
8901
  const p = (process.env.HOME || '/home/olam') + '/.claude/settings.json';
@@ -8924,7 +8939,7 @@ if (changed) {
8924
8939
  }
8925
8940
  `;
8926
8941
  try {
8927
- execSync15(`docker exec ${containerName} /usr/local/bin/node -e ${shQuote(script)}`, { stdio: "pipe" });
8942
+ execSync16(`docker exec ${containerName} /usr/local/bin/node -e ${shQuote(script)}`, { stdio: "pipe" });
8928
8943
  } catch {
8929
8944
  }
8930
8945
  }
@@ -11715,6 +11730,60 @@ var init_bootstrap_hooks = __esm({
11715
11730
  }
11716
11731
  });
11717
11732
 
11733
+ // ../core/dist/world/create-dedup.js
11734
+ import { execSync as execSync5 } from "node:child_process";
11735
+ function resolveCreateDedup(opts) {
11736
+ const { registry, name } = opts;
11737
+ const probe2 = opts.probeContainer ?? defaultContainerProbe;
11738
+ const containerName = `olam-${name}-devbox`;
11739
+ const existing = registry.findByName(name);
11740
+ const active = existing.find((w) => ACTIVE_STATUSES.has(w.status));
11741
+ if (active) {
11742
+ return { action: "reuse", world: active };
11743
+ }
11744
+ const errorRows = existing.filter((w) => w.status === "error");
11745
+ for (const er of errorRows) {
11746
+ registry.remove(er.id);
11747
+ }
11748
+ if (probe2(containerName)) {
11749
+ return {
11750
+ action: "container-orphan",
11751
+ containerName,
11752
+ remediation: `A container '${containerName}' is running on this host but no worlds.db row exists for it. Either destroy the orphan with 'docker rm -f ${containerName}' and re-run, or wait for the reconciler (issue #963) to insert a row.`
11753
+ };
11754
+ }
11755
+ return { action: "fresh", cleanedErrorRows: errorRows.length };
11756
+ }
11757
+ var ACTIVE_STATUSES, defaultContainerProbe, ContainerOrphanError;
11758
+ var init_create_dedup = __esm({
11759
+ "../core/dist/world/create-dedup.js"() {
11760
+ "use strict";
11761
+ ACTIVE_STATUSES = /* @__PURE__ */ new Set([
11762
+ "creating",
11763
+ "running",
11764
+ "paused",
11765
+ "crystallizing"
11766
+ ]);
11767
+ defaultContainerProbe = (containerName) => {
11768
+ try {
11769
+ const out = execSync5(`docker ps --filter name=^/${containerName}$ --format '{{.Names}}'`, { stdio: ["pipe", "pipe", "pipe"], timeout: 5e3 }).toString().trim();
11770
+ return out.length > 0;
11771
+ } catch {
11772
+ return false;
11773
+ }
11774
+ };
11775
+ ContainerOrphanError = class extends Error {
11776
+ containerName;
11777
+ kind = "container-orphan";
11778
+ constructor(message, containerName) {
11779
+ super(message);
11780
+ this.containerName = containerName;
11781
+ this.name = "ContainerOrphanError";
11782
+ }
11783
+ };
11784
+ }
11785
+ });
11786
+
11718
11787
  // ../core/dist/world/tmux-supervisor.js
11719
11788
  function injectBindAll(start) {
11720
11789
  let result = start;
@@ -11852,6 +11921,7 @@ var manager_exports = {};
11852
11921
  __export(manager_exports, {
11853
11922
  AuthPreflightError: () => AuthPreflightError,
11854
11923
  BotIdentityError: () => BotIdentityError,
11924
+ ContainerOrphanError: () => ContainerOrphanError,
11855
11925
  TaskDispatchError: () => TaskDispatchError,
11856
11926
  WorkspaceNotFoundError: () => WorkspaceNotFoundError,
11857
11927
  WorldManager: () => WorldManager,
@@ -11871,12 +11941,12 @@ __export(manager_exports, {
11871
11941
  runManifestRuntime: () => runManifestRuntime
11872
11942
  });
11873
11943
  import * as crypto5 from "node:crypto";
11874
- import { execSync as execSync5, spawnSync as spawnSync5 } from "node:child_process";
11944
+ import { execSync as execSync6, spawnSync as spawnSync5 } from "node:child_process";
11875
11945
  import * as fs23 from "node:fs";
11876
11946
  import * as os13 from "node:os";
11877
11947
  import * as path25 from "node:path";
11878
11948
  import YAML3 from "yaml";
11879
- function getTokenScopes(ghToken, _exec = execSync5) {
11949
+ function getTokenScopes(ghToken, _exec = execSync6) {
11880
11950
  try {
11881
11951
  const out = _exec("gh auth status 2>&1", {
11882
11952
  encoding: "utf-8",
@@ -11893,13 +11963,13 @@ function getTokenScopes(ghToken, _exec = execSync5) {
11893
11963
  }
11894
11964
  }
11895
11965
  async function setupContainerGit(containerName, repos, branch) {
11896
- const dockerExec = (cmd) => execSync5(`docker exec ${containerName} sh -c '${cmd.replace(/'/g, "'\\''")}'`, {
11966
+ const dockerExec = (cmd) => execSync6(`docker exec ${containerName} sh -c '${cmd.replace(/'/g, "'\\''")}'`, {
11897
11967
  stdio: "pipe",
11898
11968
  timeout: 6e4
11899
11969
  }).toString();
11900
11970
  let ghToken = "";
11901
11971
  try {
11902
- ghToken = execSync5("gh auth token 2>/dev/null", { encoding: "utf-8", timeout: 5e3 }).trim();
11972
+ ghToken = execSync6("gh auth token 2>/dev/null", { encoding: "utf-8", timeout: 5e3 }).trim();
11903
11973
  } catch {
11904
11974
  }
11905
11975
  const actorName = process.env.OLAM_BOT_NAME ?? "Claude Code (olam)";
@@ -11919,7 +11989,7 @@ async function setupContainerGit(containerName, repos, branch) {
11919
11989
  continue;
11920
11990
  const ownerRepo = ghMatch[1];
11921
11991
  try {
11922
- execSync5(`gh api repos/${ownerRepo} --silent`, {
11992
+ execSync6(`gh api repos/${ownerRepo} --silent`, {
11923
11993
  stdio: "pipe",
11924
11994
  timeout: 5e3,
11925
11995
  env: { ...process.env, GH_TOKEN: ghToken }
@@ -11967,7 +12037,7 @@ ${stderr.split("\n").slice(0, 3).join(" ")}`);
11967
12037
  if (!olamUserPresent) {
11968
12038
  const imageName = (() => {
11969
12039
  try {
11970
- return execSync5(`docker inspect ${containerName} --format '{{.Config.Image}}'`, {
12040
+ return execSync6(`docker inspect ${containerName} --format '{{.Config.Image}}'`, {
11971
12041
  encoding: "utf8",
11972
12042
  timeout: 5e3
11973
12043
  }).trim() || "(unknown)";
@@ -12010,7 +12080,7 @@ ${stderr.split("\n").slice(0, 3).join(" ")}`);
12010
12080
  function makeHostExecFn() {
12011
12081
  return async (cmd) => {
12012
12082
  try {
12013
- const stdout = execSync5(cmd, { encoding: "utf-8", timeout: 5e3 });
12083
+ const stdout = execSync6(cmd, { encoding: "utf-8", timeout: 5e3 });
12014
12084
  return { stdout, stderr: "", exitCode: 0 };
12015
12085
  } catch {
12016
12086
  return { stdout: "", stderr: "", exitCode: 1 };
@@ -12020,7 +12090,7 @@ function makeHostExecFn() {
12020
12090
  function makeContainerExecFn(containerName) {
12021
12091
  return async (cmd) => {
12022
12092
  try {
12023
- const result = execSync5(`docker exec ${containerName} sh -c '${cmd.replace(/'/g, "'\\''")}'`, { stdio: "pipe", timeout: 6e5 });
12093
+ const result = execSync6(`docker exec ${containerName} sh -c '${cmd.replace(/'/g, "'\\''")}'`, { stdio: "pipe", timeout: 6e5 });
12024
12094
  return { stdout: result.toString(), stderr: "", exitCode: 0 };
12025
12095
  } catch (err) {
12026
12096
  const execErr = err;
@@ -12034,7 +12104,7 @@ function makeContainerExecFn(containerName) {
12034
12104
  }
12035
12105
  function defaultDockerExec2() {
12036
12106
  return (containerName, cmd) => {
12037
- const result = execSync5(
12107
+ const result = execSync6(
12038
12108
  `docker exec ${containerName} sh -c '${cmd.replace(/'/g, "'\\''")}'`,
12039
12109
  // Phase E E5 raise: 10min was too tight on cold-boot for atlas-core's
12040
12110
  // `rails db:create` chain (Rails 7 boot + initializer load + first
@@ -12214,7 +12284,7 @@ function buildManifestRuntime(worldId, repos) {
12214
12284
  }
12215
12285
  return { worldId, repos: runtimeRepos };
12216
12286
  }
12217
- function exposeWorldOverTailscale(appPortUrls, worldId, registry, _exec = execSync5) {
12287
+ function exposeWorldOverTailscale(appPortUrls, worldId, registry, _exec = execSync6) {
12218
12288
  if (process.env["OLAM_TAILSCALE_SERVE"] !== "true")
12219
12289
  return;
12220
12290
  if (appPortUrls.length === 0)
@@ -12242,7 +12312,7 @@ function exposeWorldOverTailscale(appPortUrls, worldId, registry, _exec = execSy
12242
12312
  registry.storeTailscalePaths(worldId, registeredPaths);
12243
12313
  }
12244
12314
  }
12245
- function cleanupWorldTailscale(worldId, registry, _exec = execSync5) {
12315
+ function cleanupWorldTailscale(worldId, registry, _exec = execSync6) {
12246
12316
  const paths = registry.loadTailscalePaths(worldId);
12247
12317
  if (paths.length === 0)
12248
12318
  return;
@@ -12261,7 +12331,7 @@ function cleanupWorldTailscale(worldId, registry, _exec = execSync5) {
12261
12331
  }
12262
12332
  }
12263
12333
  }
12264
- function resolveTailscaleBin(_exec = execSync5) {
12334
+ function resolveTailscaleBin(_exec = execSync6) {
12265
12335
  const candidates2 = [
12266
12336
  process.env["TAILSCALE_BIN"],
12267
12337
  "/Applications/Tailscale.app/Contents/MacOS/Tailscale",
@@ -12660,6 +12730,8 @@ var init_manager = __esm({
12660
12730
  init_runbook_resolver();
12661
12731
  init_port_validator();
12662
12732
  init_bootstrap_hooks();
12733
+ init_create_dedup();
12734
+ init_create_dedup();
12663
12735
  init_tmux_supervisor();
12664
12736
  BotIdentityError = class extends Error {
12665
12737
  constructor(message) {
@@ -12694,19 +12766,38 @@ var init_manager = __esm({
12694
12766
  dashboardManager;
12695
12767
  pleriClient;
12696
12768
  dockerExec;
12769
+ containerProbe;
12697
12770
  manifestRuntimes = /* @__PURE__ */ new Map();
12698
- constructor(config, provider, registry, dashboardManager, pleriClient, dockerExec) {
12771
+ constructor(config, provider, registry, dashboardManager, pleriClient, dockerExec, containerProbe) {
12699
12772
  this.config = config;
12700
12773
  this.provider = provider;
12701
12774
  this.registry = registry;
12702
12775
  this.dashboardManager = dashboardManager;
12703
12776
  this.pleriClient = pleriClient;
12704
12777
  this.dockerExec = dockerExec ?? defaultDockerExec2();
12778
+ this.containerProbe = containerProbe;
12705
12779
  }
12706
12780
  // -----------------------------------------------------------------------
12707
12781
  // createWorld
12708
12782
  // -----------------------------------------------------------------------
12709
12783
  async createWorld(opts) {
12784
+ {
12785
+ const dedupOpts = {
12786
+ registry: this.registry,
12787
+ name: opts.name,
12788
+ ...this.containerProbe ? { probeContainer: this.containerProbe } : {}
12789
+ };
12790
+ const dedup = resolveCreateDedup(dedupOpts);
12791
+ if (dedup.action === "reuse") {
12792
+ return dedup.world;
12793
+ }
12794
+ if (dedup.action === "container-orphan") {
12795
+ throw new ContainerOrphanError(dedup.remediation, dedup.containerName);
12796
+ }
12797
+ if (dedup.cleanedErrorRows > 0) {
12798
+ console.log(`[manager] removed ${dedup.cleanedErrorRows} stale error row(s) for world name "${opts.name}" before fresh create (issue #962)`);
12799
+ }
12800
+ }
12710
12801
  if (!opts.noAuth) {
12711
12802
  const preflight2 = await runAuthPreflight({ autoStart: true });
12712
12803
  if (preflight2.verdict !== "ok") {
@@ -13390,7 +13481,7 @@ ${detail}`);
13390
13481
  const escapedDir = `/home/olam/workspace/${repo.name.replace(/["$`\\]/g, "\\$&")}`;
13391
13482
  for (const cmd of repo.setup_commands) {
13392
13483
  try {
13393
- execSync5(`docker exec ${containerName} sh -c 'cd "${escapedDir}" && ${cmd.replace(/'/g, "'\\''")}'`, { stdio: "pipe", timeout: 6e5 });
13484
+ execSync6(`docker exec ${containerName} sh -c 'cd "${escapedDir}" && ${cmd.replace(/'/g, "'\\''")}'`, { stdio: "pipe", timeout: 6e5 });
13394
13485
  } catch (err) {
13395
13486
  const msg = err instanceof Error ? err.message : String(err);
13396
13487
  console.warn(`[WorldManager] setup command failed for ${repo.name}: ${msg}`);
@@ -13411,11 +13502,11 @@ ${detail}`);
13411
13502
  });
13412
13503
  if (allPolicies.length > 0) {
13413
13504
  try {
13414
- execSync5(`docker exec ${containerName} mkdir -p /home/olam/.olam/policies`, { stdio: "pipe", timeout: 1e4 });
13505
+ execSync6(`docker exec ${containerName} mkdir -p /home/olam/.olam/policies`, { stdio: "pipe", timeout: 1e4 });
13415
13506
  for (const repo of repos) {
13416
13507
  const policiesDir = path25.join(workspacePath, repo.name, ".olam", "policies");
13417
13508
  if (fs23.existsSync(policiesDir)) {
13418
- execSync5(`docker cp "${policiesDir}/." "${containerName}:/home/olam/.olam/policies/"`, { stdio: "pipe", timeout: 15e3 });
13509
+ execSync6(`docker cp "${policiesDir}/." "${containerName}:/home/olam/.olam/policies/"`, { stdio: "pipe", timeout: 15e3 });
13419
13510
  }
13420
13511
  }
13421
13512
  } catch (err) {
@@ -14903,10 +14994,10 @@ var init_state2 = __esm({
14903
14994
  });
14904
14995
 
14905
14996
  // ../core/dist/dashboard/tunnel.js
14906
- import { spawn as spawn3, execSync as execSync6 } from "node:child_process";
14997
+ import { spawn as spawn3, execSync as execSync7 } from "node:child_process";
14907
14998
  function isCloudflaredAvailable() {
14908
14999
  try {
14909
- execSync6("which cloudflared", { stdio: "ignore" });
15000
+ execSync7("which cloudflared", { stdio: "ignore" });
14910
15001
  return true;
14911
15002
  } catch {
14912
15003
  return false;
@@ -16238,6 +16329,69 @@ var init_registry_allowlist = __esm({
16238
16329
  }
16239
16330
  });
16240
16331
 
16332
+ // src/from-manifest.ts
16333
+ var from_manifest_exports = {};
16334
+ __export(from_manifest_exports, {
16335
+ defaultNameFromManifest: () => defaultNameFromManifest,
16336
+ parseForkManifest: () => parseForkManifest,
16337
+ provenanceLine: () => provenanceLine
16338
+ });
16339
+ import { readFileSync as readFileSync30 } from "node:fs";
16340
+ function parseForkManifest(path96) {
16341
+ let raw;
16342
+ try {
16343
+ raw = readFileSync30(path96, "utf8");
16344
+ } catch (err) {
16345
+ const reason = err?.code === "ENOENT" ? "file does not exist" : err.message;
16346
+ throw new Error(`--from-manifest: cannot read ${path96} (${reason})`);
16347
+ }
16348
+ let json;
16349
+ try {
16350
+ json = JSON.parse(raw);
16351
+ } catch (err) {
16352
+ throw new Error(`--from-manifest: ${path96} is not valid JSON (${err.message})`);
16353
+ }
16354
+ if (!isPlainObject2(json)) {
16355
+ throw new Error(`--from-manifest: ${path96} root must be a JSON object`);
16356
+ }
16357
+ const originalWorldId = json.originalWorldId;
16358
+ if (typeof originalWorldId !== "string" || originalWorldId.trim().length === 0) {
16359
+ throw new Error(`--from-manifest: ${path96} missing required string "originalWorldId"`);
16360
+ }
16361
+ const newPrompt = json.newPrompt;
16362
+ if (typeof newPrompt !== "string" || newPrompt.trim().length === 0) {
16363
+ throw new Error(
16364
+ `--from-manifest: ${path96} has no "newPrompt" \u2014 re-run trace-replay with --with-prompt "<alternate dispatch>"`
16365
+ );
16366
+ }
16367
+ const fp = isPlainObject2(json.forkPoint) ? json.forkPoint : {};
16368
+ const resolvedPhase = typeof fp.resolvedPhase === "string" ? fp.resolvedPhase : null;
16369
+ const resolvedSpanId = typeof fp.resolvedSpanId === "string" ? fp.resolvedSpanId : null;
16370
+ const resolvedAt = typeof fp.resolvedAt === "number" ? fp.resolvedAt : 0;
16371
+ return {
16372
+ originalWorldId: originalWorldId.trim(),
16373
+ forkPoint: { resolvedPhase, resolvedSpanId, resolvedAt },
16374
+ newPrompt,
16375
+ manifestPath: path96
16376
+ };
16377
+ }
16378
+ function defaultNameFromManifest(manifest) {
16379
+ const base = `fork-${manifest.originalWorldId}`.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
16380
+ return (base || "fork").slice(0, 40);
16381
+ }
16382
+ function provenanceLine(manifest) {
16383
+ const phase = manifest.forkPoint.resolvedPhase ?? "end-of-trace";
16384
+ return `Forking from ${manifest.originalWorldId} @ phase=${phase} (manifest: ${manifest.manifestPath})`;
16385
+ }
16386
+ function isPlainObject2(v) {
16387
+ return typeof v === "object" && v !== null && !Array.isArray(v);
16388
+ }
16389
+ var init_from_manifest = __esm({
16390
+ "src/from-manifest.ts"() {
16391
+ "use strict";
16392
+ }
16393
+ });
16394
+
16241
16395
  // src/spawn/home-override.ts
16242
16396
  var home_override_exports = {};
16243
16397
  __export(home_override_exports, {
@@ -18149,13 +18303,13 @@ var init_file_lock = __esm({
18149
18303
  });
18150
18304
 
18151
18305
  // ../core/dist/lib/min-version-filter.js
18152
- import { existsSync as existsSync73, readFileSync as readFileSync60 } from "node:fs";
18306
+ import { existsSync as existsSync73, readFileSync as readFileSync61 } from "node:fs";
18153
18307
  function readOlamMinVersion(filepath) {
18154
18308
  if (!existsSync73(filepath))
18155
18309
  return void 0;
18156
18310
  let text;
18157
18311
  try {
18158
- text = readFileSync60(filepath, "utf8");
18312
+ text = readFileSync61(filepath, "utf8");
18159
18313
  } catch {
18160
18314
  return void 0;
18161
18315
  }
@@ -18803,7 +18957,7 @@ var init_meta_hook_injector = __esm({
18803
18957
 
18804
18958
  // ../core/dist/lib/markdown-merger.js
18805
18959
  import { createHash as createHash8 } from "node:crypto";
18806
- import { readFileSync as readFileSync64, existsSync as existsSync76, statSync as statSync22 } from "node:fs";
18960
+ import { readFileSync as readFileSync65, existsSync as existsSync76, statSync as statSync22 } from "node:fs";
18807
18961
  function parseFrontmatter3(text) {
18808
18962
  const match2 = FM_RE2.exec(text);
18809
18963
  if (match2 === null)
@@ -18925,7 +19079,7 @@ function mergeMarkdown(upstreamText, overlayText, labelForError, upstreamPath, o
18925
19079
  function sha256OfPath(p) {
18926
19080
  if (!existsSync76(p) || !statSync22(p).isFile())
18927
19081
  return "MISSING";
18928
- return createHash8("sha256").update(readFileSync64(p)).digest("hex");
19082
+ return createHash8("sha256").update(readFileSync65(p)).digest("hex");
18929
19083
  }
18930
19084
  var FM_RE2, H2_RE;
18931
19085
  var init_markdown_merger = __esm({
@@ -19177,7 +19331,7 @@ var init_prefix_deploy = __esm({
19177
19331
  });
19178
19332
 
19179
19333
  // ../core/dist/skill-sync/resolve-source-config.js
19180
- import { readFileSync as readFileSync66, existsSync as existsSync77 } from "node:fs";
19334
+ import { readFileSync as readFileSync67, existsSync as existsSync77 } from "node:fs";
19181
19335
  import { join as join76 } from "node:path";
19182
19336
  import { parse as parseYaml6 } from "yaml";
19183
19337
  function sourceConfigPath(clonePath) {
@@ -19189,7 +19343,7 @@ function readSourceConfig(clonePath, sourceId) {
19189
19343
  return void 0;
19190
19344
  let raw;
19191
19345
  try {
19192
- raw = readFileSync66(path96, "utf-8");
19346
+ raw = readFileSync67(path96, "utf-8");
19193
19347
  } catch (err) {
19194
19348
  emitMalformedWarning(sourceId, `read failed: ${errToMsg(err)}`);
19195
19349
  return void 0;
@@ -23376,6 +23530,7 @@ var MCP_AUTH_CONTAINER = "olam-mcp-auth";
23376
23530
  var MCP_AUTH_LOCAL_TAG = "olam-mcp-auth:local";
23377
23531
  var MCP_AUTH_PUBLISHED_TAG = "ghcr.io/pleri/olam-mcp-auth:latest";
23378
23532
  var MCP_AUTH_HEALTH_URL = `http://127.0.0.1:${MCP_AUTH_PORT}/health`;
23533
+ var SOCAT_IMAGE = "alpine/socat:latest";
23379
23534
  var MCP_AUTH_HEALTH_TIMEOUT_MS = 6e4;
23380
23535
  var McpAuthContainerController = class {
23381
23536
  imageTag = MCP_AUTH_LOCAL_TAG;
@@ -23599,6 +23754,40 @@ async function servicesRestartKubernetes(name, deps = {}) {
23599
23754
  printSuccess(`${deploymentName}: rollout restart triggered`);
23600
23755
  return { exitCode: 0 };
23601
23756
  }
23757
+ function pullSocatImage(deps = {}) {
23758
+ const spawnImpl = deps.spawnImpl ?? ((cmd, args, opts) => {
23759
+ const r = spawnSync16(cmd, [...args], { encoding: "utf-8", ...opts });
23760
+ return {
23761
+ status: r.status,
23762
+ stdout: r.stdout ?? "",
23763
+ stderr: r.stderr ?? ""
23764
+ };
23765
+ });
23766
+ const info = spawnImpl("docker", ["info"], { encoding: "utf-8", timeout: 5e3 });
23767
+ if (info.status !== 0) {
23768
+ return { dockerAvailable: false, alreadyPresent: false, pulled: false };
23769
+ }
23770
+ const inspect = spawnImpl("docker", ["image", "inspect", SOCAT_IMAGE], {
23771
+ encoding: "utf-8",
23772
+ timeout: 5e3
23773
+ });
23774
+ if (inspect.status === 0) {
23775
+ return { dockerAvailable: true, alreadyPresent: true, pulled: false };
23776
+ }
23777
+ const pull = spawnImpl("docker", ["pull", SOCAT_IMAGE], {
23778
+ encoding: "utf-8",
23779
+ timeout: 6e4
23780
+ });
23781
+ if (pull.status === 0) {
23782
+ return { dockerAvailable: true, alreadyPresent: false, pulled: true };
23783
+ }
23784
+ return {
23785
+ dockerAvailable: true,
23786
+ alreadyPresent: false,
23787
+ pulled: false,
23788
+ error: pull.stderr.trim() || pull.stdout.trim() || "docker pull failed"
23789
+ };
23790
+ }
23602
23791
  function dumpContainerLogs(container, tail = 40) {
23603
23792
  try {
23604
23793
  const result = spawnSync16("docker", ["logs", "--tail", String(tail), container], {
@@ -23623,6 +23812,21 @@ async function servicesUp() {
23623
23812
  const mcpAuth = new McpAuthContainerController();
23624
23813
  const kgService = new KgServiceContainerController();
23625
23814
  const memoryService = new MemoryServiceContainerController();
23815
+ const socatResult = pullSocatImage();
23816
+ if (!socatResult.dockerAvailable) {
23817
+ printWarning(
23818
+ "docker daemon not reachable \u2014 skipped alpine/socat:latest preflight; olam_port_expose will fail until docker is available"
23819
+ );
23820
+ } else if (socatResult.error !== void 0) {
23821
+ printWarning(
23822
+ `alpine/socat:latest preflight pull failed: ${socatResult.error}
23823
+ olam_port_expose will attempt a fallback pull on first call`
23824
+ );
23825
+ } else if (socatResult.pulled) {
23826
+ printSuccess("alpine/socat:latest pulled");
23827
+ } else {
23828
+ printInfo("alpine/socat:latest", "already cached");
23829
+ }
23626
23830
  const authStatus = auth.status();
23627
23831
  if (authStatus.state === "running") {
23628
23832
  printSuccess(`olam-auth already running on :${authStatus.port}`);
@@ -24204,7 +24408,7 @@ function appendAuditEntry(entry, auditLogPath, writeFileSyncImpl) {
24204
24408
  async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}, peripheral) {
24205
24409
  const auditLogPath = deps.auditLogPath ?? MANIFEST_REFRESH_AUDIT_LOG;
24206
24410
  const readdirSync33 = deps.readdirSync ?? fs31.readdirSync;
24207
- const readFileSync95 = deps.readFileSync ?? fs31.readFileSync;
24411
+ const readFileSync96 = deps.readFileSync ?? fs31.readFileSync;
24208
24412
  const writeFileSyncImpl = deps.writeFileSync ?? fs31.writeFileSync;
24209
24413
  const existsSync113 = deps.existsSync ?? fs31.existsSync;
24210
24414
  const now = deps.now ? deps.now() : /* @__PURE__ */ new Date();
@@ -24230,7 +24434,7 @@ async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}, per
24230
24434
  const filePath = path32.join(targetDir, file);
24231
24435
  let content;
24232
24436
  try {
24233
- content = readFileSync95(filePath, "utf8");
24437
+ content = readFileSync96(filePath, "utf8");
24234
24438
  } catch {
24235
24439
  continue;
24236
24440
  }
@@ -24481,11 +24685,11 @@ async function checkSecretPreCondition(context, deps) {
24481
24685
  }
24482
24686
  async function applyConfigMapSubstitution(context, manifestsDir, deps) {
24483
24687
  const wrap = deps.kubectlWrapImpl ?? kubectlWrap;
24484
- const readFileSync95 = deps.readFileSyncImpl ?? fs32.readFileSync;
24688
+ const readFileSync96 = deps.readFileSyncImpl ?? fs32.readFileSync;
24485
24689
  const configMapPath = path33.join(manifestsDir, "30-configmap.yaml");
24486
24690
  let rawYaml;
24487
24691
  try {
24488
- rawYaml = readFileSync95(configMapPath, "utf8");
24692
+ rawYaml = readFileSync96(configMapPath, "utf8");
24489
24693
  } catch (err) {
24490
24694
  return `Failed to read ConfigMap at ${configMapPath}: ${err instanceof Error ? err.message : String(err)}`;
24491
24695
  }
@@ -25037,6 +25241,223 @@ async function applyK8sAuthRefresh(pinnedContext, deps = {}) {
25037
25241
  return 0;
25038
25242
  }
25039
25243
 
25244
+ // src/lib/auth-remote.ts
25245
+ function normalizeBase(url2) {
25246
+ return url2.replace(/\/+$/, "");
25247
+ }
25248
+ function buildHeaders(cookie) {
25249
+ const headers = {
25250
+ "Content-Type": "application/json",
25251
+ Accept: "application/json"
25252
+ };
25253
+ if (cookie) {
25254
+ headers["Cookie"] = `CF_Authorization=${cookie}`;
25255
+ }
25256
+ return headers;
25257
+ }
25258
+ async function remoteHealth(opts) {
25259
+ const { baseUrl, cfAuthCookie, fetchFn = fetch } = opts;
25260
+ const url2 = `${normalizeBase(baseUrl)}/v1/health`;
25261
+ const res = await fetchFn(url2, {
25262
+ method: "GET",
25263
+ headers: buildHeaders(cfAuthCookie)
25264
+ });
25265
+ if (!res.ok) {
25266
+ throw new Error(`Health check failed: HTTP ${res.status}`);
25267
+ }
25268
+ return res.json();
25269
+ }
25270
+ async function remoteOAuthStart(opts) {
25271
+ const { baseUrl, cfAuthCookie, fetchFn = fetch } = opts;
25272
+ const url2 = `${normalizeBase(baseUrl)}/v1/oauth/start`;
25273
+ const res = await fetchFn(url2, {
25274
+ method: "POST",
25275
+ headers: buildHeaders(cfAuthCookie),
25276
+ body: JSON.stringify({})
25277
+ });
25278
+ if (!res.ok) {
25279
+ const body = await res.text().catch(() => "");
25280
+ throw new Error(`OAuth start failed: HTTP ${res.status}${body ? ` \u2014 ${body}` : ""}`);
25281
+ }
25282
+ return res.json();
25283
+ }
25284
+ async function remoteListServiceTokens(opts) {
25285
+ const { baseUrl, cfAuthCookie, fetchFn = fetch } = opts;
25286
+ const url2 = `${normalizeBase(baseUrl)}/v1/service-tokens`;
25287
+ const res = await fetchFn(url2, {
25288
+ method: "GET",
25289
+ headers: buildHeaders(cfAuthCookie)
25290
+ });
25291
+ if (!res.ok) {
25292
+ throw new Error(`List service-tokens failed: HTTP ${res.status}`);
25293
+ }
25294
+ return res.json();
25295
+ }
25296
+ async function remoteListAccounts(opts) {
25297
+ const { baseUrl, cfAuthCookie, fetchFn = fetch } = opts;
25298
+ const url2 = `${normalizeBase(baseUrl)}/v1/accounts`;
25299
+ const res = await fetchFn(url2, {
25300
+ method: "GET",
25301
+ headers: buildHeaders(cfAuthCookie)
25302
+ });
25303
+ if (!res.ok) {
25304
+ throw new Error(`List accounts failed: HTTP ${res.status}`);
25305
+ }
25306
+ return res.json();
25307
+ }
25308
+ async function remoteBindServiceToken(opts, payload) {
25309
+ const { baseUrl, cfAuthCookie, fetchFn = fetch } = opts;
25310
+ const url2 = `${normalizeBase(baseUrl)}/v1/service-tokens/bind`;
25311
+ const res = await fetchFn(url2, {
25312
+ method: "POST",
25313
+ headers: buildHeaders(cfAuthCookie),
25314
+ body: JSON.stringify(payload)
25315
+ });
25316
+ if (!res.ok) {
25317
+ const body = await res.text().catch(() => "");
25318
+ throw new Error(`Bind service-token failed: HTTP ${res.status}${body ? ` \u2014 ${body}` : ""}`);
25319
+ }
25320
+ return { ok: true };
25321
+ }
25322
+ async function remoteDeleteServiceToken(opts, clientId) {
25323
+ const { baseUrl, cfAuthCookie, fetchFn = fetch } = opts;
25324
+ const url2 = `${normalizeBase(baseUrl)}/v1/service-tokens/${encodeURIComponent(clientId)}`;
25325
+ const res = await fetchFn(url2, {
25326
+ method: "DELETE",
25327
+ headers: buildHeaders(cfAuthCookie)
25328
+ });
25329
+ if (!res.ok) {
25330
+ throw new Error(`Delete service-token failed: HTTP ${res.status}`);
25331
+ }
25332
+ return { ok: true };
25333
+ }
25334
+ async function remoteIssueAnthropicToken(opts, label) {
25335
+ const { baseUrl, cfAuthCookie, fetchFn = fetch } = opts;
25336
+ const url2 = `${normalizeBase(baseUrl)}/v1/anthropic-tokens/issue`;
25337
+ const res = await fetchFn(url2, {
25338
+ method: "POST",
25339
+ headers: buildHeaders(cfAuthCookie),
25340
+ body: JSON.stringify({ label })
25341
+ });
25342
+ if (!res.ok) {
25343
+ const body = await res.text().catch(() => "");
25344
+ throw new Error(`Issue anthropic-token failed: HTTP ${res.status}${body ? ` \u2014 ${body}` : ""}`);
25345
+ }
25346
+ return res.json();
25347
+ }
25348
+ async function remoteListAnthropicTokens(opts) {
25349
+ const { baseUrl, cfAuthCookie, fetchFn = fetch } = opts;
25350
+ const url2 = `${normalizeBase(baseUrl)}/v1/anthropic-tokens`;
25351
+ const res = await fetchFn(url2, {
25352
+ method: "GET",
25353
+ headers: buildHeaders(cfAuthCookie)
25354
+ });
25355
+ if (!res.ok) {
25356
+ const body = await res.text().catch(() => "");
25357
+ throw new Error(`List anthropic-tokens failed: HTTP ${res.status}${body ? ` \u2014 ${body}` : ""}`);
25358
+ }
25359
+ return res.json();
25360
+ }
25361
+ async function remoteRevokeAnthropicToken(opts, tokenHash) {
25362
+ const { baseUrl, cfAuthCookie, fetchFn = fetch } = opts;
25363
+ const url2 = `${normalizeBase(baseUrl)}/v1/anthropic-tokens/${encodeURIComponent(tokenHash)}`;
25364
+ const res = await fetchFn(url2, {
25365
+ method: "DELETE",
25366
+ headers: buildHeaders(cfAuthCookie)
25367
+ });
25368
+ if (res.status === 404) return false;
25369
+ if (!res.ok) {
25370
+ throw new Error(`Revoke anthropic-token failed: HTTP ${res.status}`);
25371
+ }
25372
+ return true;
25373
+ }
25374
+ async function runDoctorChecks(opts) {
25375
+ const results = [];
25376
+ const { baseUrl, cfAuthCookie, fetchFn = fetch } = opts;
25377
+ const base = normalizeBase(baseUrl);
25378
+ try {
25379
+ const h = await remoteHealth({ baseUrl, cfAuthCookie, fetchFn });
25380
+ results.push({
25381
+ probe: "worker-health",
25382
+ status: "pass",
25383
+ message: `Worker alive${h.version ? ` (version=${h.version})` : ""}`
25384
+ });
25385
+ } catch (err) {
25386
+ results.push({
25387
+ probe: "worker-health",
25388
+ status: "fail",
25389
+ message: err instanceof Error ? err.message : "Health check failed",
25390
+ remedy: `Verify the worker is deployed and reachable at ${base}`
25391
+ });
25392
+ }
25393
+ let jwksUrl;
25394
+ try {
25395
+ const parsed = new URL(baseUrl);
25396
+ const parts = parsed.hostname.split(".");
25397
+ const team = parts.length >= 3 ? parts[parts.length - 3] : parts[0];
25398
+ jwksUrl = `https://${team}.cloudflareaccess.com/cdn-cgi/access/certs`;
25399
+ } catch {
25400
+ jwksUrl = `${base}/.well-known/jwks.json`;
25401
+ }
25402
+ try {
25403
+ const res = await fetchFn(jwksUrl, { method: "GET" });
25404
+ if (res.ok) {
25405
+ results.push({
25406
+ probe: "cf-access-jwks",
25407
+ status: "pass",
25408
+ message: `CF Access JWKS reachable at ${jwksUrl}`
25409
+ });
25410
+ } else {
25411
+ results.push({
25412
+ probe: "cf-access-jwks",
25413
+ status: "warn",
25414
+ message: `CF Access JWKS returned HTTP ${res.status}`,
25415
+ remedy: `Verify Cloudflare Access is configured for your zone. JWKS checked: ${jwksUrl}`
25416
+ });
25417
+ }
25418
+ } catch (err) {
25419
+ results.push({
25420
+ probe: "cf-access-jwks",
25421
+ status: "warn",
25422
+ message: `CF Access JWKS unreachable: ${err instanceof Error ? err.message : String(err)}`,
25423
+ remedy: `Check network access to ${jwksUrl}. CF Access may not be configured for this zone.`
25424
+ });
25425
+ }
25426
+ try {
25427
+ await remoteOAuthStart({ baseUrl, cfAuthCookie, fetchFn });
25428
+ results.push({
25429
+ probe: "oauth-start",
25430
+ status: "pass",
25431
+ message: "OAuth start endpoint is reachable"
25432
+ });
25433
+ } catch (err) {
25434
+ const msg = err instanceof Error ? err.message : String(err);
25435
+ const status2 = msg.includes("HTTP 403") ? "warn" : "fail";
25436
+ results.push({
25437
+ probe: "oauth-start",
25438
+ status: status2,
25439
+ message: `OAuth start: ${msg}`,
25440
+ remedy: status2 === "warn" ? "Open the worker URL in a browser to complete CF Access SSO, then re-run with --cookie." : `Check that /v1/oauth/start is deployed at ${base}`
25441
+ });
25442
+ }
25443
+ const clientId = process.env["ANTHROPIC_OAUTH_CLIENT_ID"];
25444
+ if (clientId) {
25445
+ results.push({
25446
+ probe: "env-client-id",
25447
+ status: "pass",
25448
+ message: `ANTHROPIC_OAUTH_CLIENT_ID is set (length=${clientId.length})`
25449
+ });
25450
+ } else {
25451
+ results.push({
25452
+ probe: "env-client-id",
25453
+ status: "warn",
25454
+ message: "ANTHROPIC_OAUTH_CLIENT_ID is not set in the environment",
25455
+ remedy: "Set ANTHROPIC_OAUTH_CLIENT_ID in your shell profile (the Anthropic OAuth app client ID)."
25456
+ });
25457
+ }
25458
+ return results;
25459
+ }
25460
+
25040
25461
  // src/commands/auth.ts
25041
25462
  function openBrowser(url2) {
25042
25463
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
@@ -25071,36 +25492,6 @@ function registerAuth(program2) {
25071
25492
  printWarning("`olam auth status` is deprecated. Use `olam services status` instead.");
25072
25493
  servicesStatus();
25073
25494
  });
25074
- auth.command("list").description("List all stored credentials with state, usage, and rate-limit status").action(async () => {
25075
- const client = new AuthClient();
25076
- const status2 = await client.status();
25077
- if (!status2.reachable) {
25078
- printError("Auth container is not reachable. Run `olam auth up` first.");
25079
- process.exitCode = 1;
25080
- return;
25081
- }
25082
- printHeader(`Credentials (${status2.accounts.length})`);
25083
- if (status2.accounts.length === 0) {
25084
- console.log(` ${pc12.dim("No credentials \u2014 run: olam auth login --label primary")}`);
25085
- return;
25086
- }
25087
- const stateColor = (s) => {
25088
- if (s === "active") return pc12.green("active");
25089
- if (s === "cooldown") return pc12.yellow("cooldown");
25090
- if (s === "expired") return pc12.red("expired");
25091
- if (s === "disabled") return pc12.dim("disabled");
25092
- return pc12.dim(s ?? "unknown");
25093
- };
25094
- for (const a of status2.accounts) {
25095
- const label = a.accountLabel ?? a.id;
25096
- const reqs = a.usage?.requestCount5h ?? 0;
25097
- const last429 = a.usage?.last429At ? `last429=${a.usage.last429At}` : "last429=never";
25098
- const reset = a.rateLimitResetsAt ? `resets=${a.rateLimitResetsAt}` : "";
25099
- console.log(
25100
- ` ${pc12.bold(label.padEnd(18))} ${stateColor(a.state).padEnd(18)} ${pc12.dim(`req5h=${reqs}`)} ${pc12.dim(`exp=${a.expiresIn}`)} ${pc12.dim(last429)} ${pc12.yellow(reset)}`
25101
- );
25102
- }
25103
- });
25104
25495
  auth.command("disable").description("Take a credential out of rotation (manual cooldown)").argument("<label>", "Credential label or id").action(async (label) => {
25105
25496
  const client = new AuthClient();
25106
25497
  try {
@@ -25131,7 +25522,68 @@ function registerAuth(program2) {
25131
25522
  process.exitCode = 1;
25132
25523
  }
25133
25524
  });
25134
- auth.command("login").description("Run the OAuth PKCE flow to store a Claude account in the auth container").option("--label <label>", 'Account label (e.g. primary, burner-1). Defaults to "primary" for the first account, "burner-N" thereafter.').action(async (opts) => {
25525
+ auth.command("login").description("Run the OAuth PKCE flow to store a Claude account in the auth container, or print a remote OAuth URL (--remote)").option("--label <label>", 'Account label (e.g. primary, burner-1). Defaults to "primary" for the first account, "burner-N" thereafter.').option("--remote <url>", "Auth-worker base URL. Prints the OAuth start URL for browser completion (v1 dogfood).").option("--print-url", "Print the OAuth URL without attempting to open a browser (implied by --remote).").option("--service-token <client_id:secret>", "Delegate to bind-service-token flow instead (use with --remote).").action(async (opts) => {
25526
+ if (opts.remote) {
25527
+ const baseUrl = opts.remote;
25528
+ if (opts.serviceToken) {
25529
+ const parts = opts.serviceToken.split(":");
25530
+ if (parts.length < 2) {
25531
+ printError("--service-token must be in format <client_id>:<secret>");
25532
+ process.exitCode = 1;
25533
+ return;
25534
+ }
25535
+ const [clientId] = parts;
25536
+ const label2 = opts.label ?? clientId ?? "service-token";
25537
+ printHeader("Auth worker \u2014 bind service token");
25538
+ console.log(`
25539
+ ${pc12.bold("Step 1:")} Open ${pc12.cyan(baseUrl + "/v1/oauth/start")} in a browser.`);
25540
+ console.log(` Complete CF Access SSO. You may see a JSON response or "no credentials" \u2014 that is normal.`);
25541
+ const rawCookie = await promptLine(`
25542
+ ${pc12.dim("Paste CF_Authorization cookie value (from DevTools > Application > Cookies):")} `);
25543
+ if (!rawCookie) {
25544
+ printError("No cookie provided. Aborting.");
25545
+ process.exitCode = 1;
25546
+ return;
25547
+ }
25548
+ const clientIdStr = clientId ?? "";
25549
+ try {
25550
+ await remoteBindServiceToken({ baseUrl, cfAuthCookie: rawCookie }, { client_id: clientIdStr, label: label2 });
25551
+ printSuccess(`Service token bound: ${clientIdStr} (label=${label2})`);
25552
+ console.log(`
25553
+ ${pc12.dim("Set ANTHROPIC_BASE_URL=" + baseUrl + "/v1/proxy in your shell to route Claude API calls through this worker.")}`);
25554
+ } catch (err) {
25555
+ printError(err instanceof Error ? err.message : "bind failed");
25556
+ process.exitCode = 1;
25557
+ }
25558
+ return;
25559
+ }
25560
+ let startUrl;
25561
+ try {
25562
+ const r = await remoteOAuthStart({ baseUrl });
25563
+ startUrl = r.authorize_url;
25564
+ } catch {
25565
+ startUrl = `${baseUrl.replace(/\/+$/, "")}/v1/oauth/start`;
25566
+ }
25567
+ printHeader("Auth worker \u2014 OAuth login (v1 dogfood)");
25568
+ console.log(`
25569
+ ${pc12.bold("1.")} Open this URL in your browser to authenticate via CF Access + Anthropic OAuth:`);
25570
+ console.log(`
25571
+ ${pc12.cyan(startUrl)}
25572
+ `);
25573
+ console.log(` ${pc12.bold("2.")} Complete the CF Access SSO and Anthropic OAuth consent.`);
25574
+ console.log(` The worker stores your tokens on callback \u2014 the browser lands on a success page.`);
25575
+ console.log(`
25576
+ ${pc12.bold("3.")} Confirm your credentials are stored:
25577
+ `);
25578
+ console.log(` ${pc12.dim("olam auth list --remote " + baseUrl)}
25579
+ `);
25580
+ console.log(` ${pc12.dim("Note: full CLI-orchestrated browser SSO flow is deferred to v2 (cookie-bridging complexity).")}
25581
+ `);
25582
+ if (!opts.printUrl) {
25583
+ openBrowser(startUrl);
25584
+ }
25585
+ return;
25586
+ }
25135
25587
  const preflight2 = await runAuthPreflight({ autoStart: true });
25136
25588
  if (preflight2.verdict !== "ok" && preflight2.verdict !== "no-accounts") {
25137
25589
  printError(preflight2.message);
@@ -25233,6 +25685,297 @@ ${pc12.dim("Next: olam create --name my-world")}`);
25233
25685
  }
25234
25686
  }
25235
25687
  });
25688
+ auth.command("bind-service-token").description("Bind a Cloudflare service token to your CF Access user sub on the remote auth-worker").requiredOption("--remote <url>", "Auth-worker base URL").requiredOption("--token <client_id:secret>", "CF service token in format <client_id>:<secret>").option("--label <name>", "Friendly label for this token (defaults to client_id)").action(async (opts) => {
25689
+ const baseUrl = opts.remote;
25690
+ const parts = opts.token.split(":");
25691
+ if (parts.length < 2) {
25692
+ printError("--token must be in format <client_id>:<secret>");
25693
+ process.exitCode = 1;
25694
+ return;
25695
+ }
25696
+ const [clientId] = parts;
25697
+ const clientIdStr = clientId ?? "";
25698
+ const label = opts.label ?? clientIdStr;
25699
+ printHeader("Auth worker \u2014 bind service token");
25700
+ console.log(`
25701
+ ${pc12.bold("Step 1:")} Open the URL below in your browser to authenticate via CF Access SSO:`);
25702
+ console.log(`
25703
+ ${pc12.cyan(baseUrl.replace(/\/+$/, "") + "/v1/oauth/start")}
25704
+ `);
25705
+ console.log(` You may see a JSON response or a "no credentials" page \u2014 that is normal.`);
25706
+ console.log(` This establishes the session that associates your user sub with the binding.
25707
+ `);
25708
+ await promptLine(` ${pc12.dim("Press Enter once you have completed the CF Access SSO step...")}`);
25709
+ const rawCookie = await promptLine(
25710
+ `
25711
+ ${pc12.dim("Paste your CF_Authorization cookie value (DevTools > Application > Cookies > CF_Authorization):")} `
25712
+ );
25713
+ if (!rawCookie) {
25714
+ printError("No cookie provided. Aborting.");
25715
+ process.exitCode = 1;
25716
+ return;
25717
+ }
25718
+ try {
25719
+ await remoteBindServiceToken(
25720
+ { baseUrl, cfAuthCookie: rawCookie },
25721
+ { client_id: clientIdStr, label }
25722
+ );
25723
+ printSuccess(`Service token bound: ${clientIdStr} (label=${label})`);
25724
+ console.log(
25725
+ `
25726
+ ${pc12.dim("Tip: set ANTHROPIC_BASE_URL=" + baseUrl.replace(/\/+$/, "") + "/v1/proxy")}`
25727
+ );
25728
+ console.log(`${pc12.dim(" to route Claude API calls through this worker.")}
25729
+ `);
25730
+ } catch (err) {
25731
+ printError(err instanceof Error ? err.message : "bind failed");
25732
+ process.exitCode = 1;
25733
+ }
25734
+ });
25735
+ auth.command("list").description("List credentials (local by default; --remote to query a remote auth-worker)").option("--remote <url>", "Auth-worker base URL").option("--cookie <value>", "CF_Authorization cookie for authenticated requests").action(async (opts) => {
25736
+ if (opts.remote) {
25737
+ const baseUrl = opts.remote;
25738
+ const clientOpts = { baseUrl, cfAuthCookie: opts.cookie };
25739
+ let accounts = [];
25740
+ let tokens = [];
25741
+ try {
25742
+ accounts = await remoteListAccounts(clientOpts);
25743
+ } catch (err) {
25744
+ printWarning(`Could not fetch accounts: ${err instanceof Error ? err.message : String(err)}`);
25745
+ }
25746
+ try {
25747
+ tokens = await remoteListServiceTokens(clientOpts);
25748
+ } catch (err) {
25749
+ printWarning(`Could not fetch service tokens: ${err instanceof Error ? err.message : String(err)}`);
25750
+ }
25751
+ printHeader(`Remote accounts (${accounts.length})`);
25752
+ if (accounts.length === 0) {
25753
+ console.log(` ${pc12.dim("No accounts \u2014 run: olam auth login --remote " + baseUrl)}`);
25754
+ } else {
25755
+ for (const a of accounts) {
25756
+ const label = a.label ?? a.id;
25757
+ const state = a.state ?? "unknown";
25758
+ const exp = a.expiresIn ?? "";
25759
+ console.log(` ${pc12.bold(label.padEnd(20))} ${pc12.green(state).padEnd(16)} ${pc12.dim(exp)}`);
25760
+ }
25761
+ }
25762
+ printHeader(`Remote service tokens (${tokens.length})`);
25763
+ if (tokens.length === 0) {
25764
+ console.log(` ${pc12.dim("No service tokens \u2014 run: olam auth bind-service-token --remote " + baseUrl)}`);
25765
+ } else {
25766
+ for (const t of tokens) {
25767
+ const label = t.label ?? t.client_id;
25768
+ const created = t.created_at ?? "";
25769
+ console.log(` ${pc12.bold(label.padEnd(20))} ${pc12.dim(t.client_id)} ${pc12.dim(created)}`);
25770
+ }
25771
+ }
25772
+ return;
25773
+ }
25774
+ const client = new AuthClient();
25775
+ const status2 = await client.status();
25776
+ if (!status2.reachable) {
25777
+ printError("Auth container is not reachable. Run `olam auth up` first.");
25778
+ process.exitCode = 1;
25779
+ return;
25780
+ }
25781
+ printHeader(`Credentials (${status2.accounts.length})`);
25782
+ if (status2.accounts.length === 0) {
25783
+ console.log(` ${pc12.dim("No credentials \u2014 run: olam auth login --label primary")}`);
25784
+ return;
25785
+ }
25786
+ const stateColor = (s) => {
25787
+ if (s === "active") return pc12.green("active");
25788
+ if (s === "cooldown") return pc12.yellow("cooldown");
25789
+ if (s === "expired") return pc12.red("expired");
25790
+ if (s === "disabled") return pc12.dim("disabled");
25791
+ return pc12.dim(s ?? "unknown");
25792
+ };
25793
+ for (const a of status2.accounts) {
25794
+ const label = a.accountLabel ?? a.id;
25795
+ const reqs = a.usage?.requestCount5h ?? 0;
25796
+ const last429 = a.usage?.last429At ? `last429=${a.usage.last429At}` : "last429=never";
25797
+ const reset = a.rateLimitResetsAt ? `resets=${a.rateLimitResetsAt}` : "";
25798
+ console.log(
25799
+ ` ${pc12.bold(label.padEnd(18))} ${stateColor(a.state).padEnd(18)} ${pc12.dim(`req5h=${reqs}`)} ${pc12.dim(`exp=${a.expiresIn}`)} ${pc12.dim(last429)} ${pc12.yellow(reset)}`
25800
+ );
25801
+ }
25802
+ });
25803
+ auth.command("migrate-to-remote").description("Print guidance for re-authenticating local credentials against the remote auth-worker (v1: no auto-migration of secrets)").requiredOption("--url <url>", "Auth-worker base URL").action(async (opts) => {
25804
+ const baseUrl = opts.url;
25805
+ let accountLabels = [];
25806
+ try {
25807
+ const client = new AuthClient();
25808
+ const status2 = await client.status();
25809
+ accountLabels = status2.accounts.map((a) => a.accountLabel ?? a.id);
25810
+ } catch {
25811
+ }
25812
+ printHeader("Migrate local credentials to remote auth-worker");
25813
+ console.log(`
25814
+ Remote URL: ${pc12.cyan(baseUrl)}
25815
+ `);
25816
+ console.log(
25817
+ ` ${pc12.dim("V1 note: secrets cannot be migrated automatically. Each account must re-authenticate via OAuth.")}
25818
+ `
25819
+ );
25820
+ if (accountLabels.length === 0) {
25821
+ console.log(` No local accounts found. Run:`);
25822
+ console.log(`
25823
+ ${pc12.cyan("olam auth login --remote " + baseUrl)}
25824
+ `);
25825
+ } else {
25826
+ console.log(` Found ${accountLabels.length} local account(s). For each, run:
25827
+ `);
25828
+ for (const label of accountLabels) {
25829
+ console.log(` ${pc12.cyan("olam auth login --remote " + baseUrl + " --label " + label)}`);
25830
+ }
25831
+ console.log();
25832
+ }
25833
+ });
25834
+ auth.command("rotate-service-token").description("Revoke a service token and guide through re-binding a replacement").requiredOption("--url <url>", "Auth-worker base URL").requiredOption("--client-id <id>", "CF service token client_id to revoke").option("--cookie <value>", "CF_Authorization cookie for the DELETE request").action(async (opts) => {
25835
+ const baseUrl = opts.url;
25836
+ const clientId = opts.clientId;
25837
+ printHeader("Auth worker \u2014 rotate service token");
25838
+ console.log(`
25839
+ Revoking service token: ${pc12.yellow(clientId)}
25840
+ `);
25841
+ try {
25842
+ await remoteDeleteServiceToken({ baseUrl, cfAuthCookie: opts.cookie }, clientId);
25843
+ printSuccess(`Revoked: ${clientId}`);
25844
+ } catch (err) {
25845
+ printError(err instanceof Error ? err.message : "revoke failed");
25846
+ process.exitCode = 1;
25847
+ return;
25848
+ }
25849
+ console.log(`
25850
+ ${pc12.bold("Next steps:")}`);
25851
+ console.log(` 1. Mint a new service token in the Cloudflare Zero Trust dashboard.`);
25852
+ console.log(` 2. Bind it:
25853
+ `);
25854
+ console.log(` ${pc12.cyan("olam auth bind-service-token --remote " + baseUrl + " --token <new_client_id>:<secret>")}
25855
+ `);
25856
+ });
25857
+ auth.command("doctor").description("Run 4 diagnostic probes against the remote auth-worker").requiredOption("--auth-worker <url>", "Auth-worker base URL").option("--cookie <value>", "CF_Authorization cookie (optional, for authenticated probes)").option("--json", "Emit JSON output").action(async (opts) => {
25858
+ const checks = await runDoctorChecks({
25859
+ baseUrl: opts.authWorker,
25860
+ cfAuthCookie: opts.cookie
25861
+ });
25862
+ if (opts.json) {
25863
+ console.log(JSON.stringify(checks, null, 2));
25864
+ const failed = checks.filter((c) => c.status === "fail").length;
25865
+ if (failed > 0) process.exitCode = 1;
25866
+ return;
25867
+ }
25868
+ printHeader(`Auth-worker diagnostics (${opts.authWorker})`);
25869
+ let hasFailure = false;
25870
+ for (const c of checks) {
25871
+ const icon = c.status === "pass" ? pc12.green("\u2713") : c.status === "warn" ? pc12.yellow("\u26A0") : pc12.red("\u2717");
25872
+ console.log(` ${icon} ${pc12.bold(c.probe.padEnd(20))} ${c.message}`);
25873
+ if (c.remedy) {
25874
+ console.log(` ${pc12.dim("\u21B3 " + c.remedy)}`);
25875
+ }
25876
+ if (c.status === "fail") hasFailure = true;
25877
+ }
25878
+ console.log();
25879
+ if (hasFailure) {
25880
+ printError("One or more probes failed \u2014 see remediation steps above.");
25881
+ process.exitCode = 1;
25882
+ } else {
25883
+ printSuccess("All probes passed (warnings are non-blocking).");
25884
+ }
25885
+ });
25886
+ auth.command("issue-anthropic-token").description("Mint a new Anthropic proxy token via the remote auth-worker (g4)").requiredOption("--remote <url>", "Auth-worker base URL").requiredOption("--label <name>", "Friendly label for this token (e.g. my-laptop)").action(async (opts) => {
25887
+ const baseUrl = opts.remote;
25888
+ printHeader("Auth worker \u2014 issue Anthropic proxy token");
25889
+ console.log(`
25890
+ Open ${pc12.cyan(baseUrl.replace(/\/+$/, "") + "/v1/oauth/start")} in a browser to authenticate via CF Access SSO.`);
25891
+ console.log(` Once you've completed SSO, paste your CF_Authorization cookie below`);
25892
+ console.log(` (from browser DevTools \u2192 Application \u2192 Cookies \u2192 CF_Authorization).
25893
+ `);
25894
+ const rawCookie = await promptLine(` ${pc12.dim("CF_Authorization cookie:")} `);
25895
+ if (!rawCookie) {
25896
+ printError("No cookie provided. Aborting.");
25897
+ process.exitCode = 1;
25898
+ return;
25899
+ }
25900
+ try {
25901
+ const result = await remoteIssueAnthropicToken({ baseUrl, cfAuthCookie: rawCookie }, opts.label);
25902
+ printSuccess(`Anthropic proxy token issued (label: ${result.label})`);
25903
+ console.log(`
25904
+ Set this in your Claude Code environment:`);
25905
+ const exportHint = `export ANTHROPIC_BASE_URL='${result.anthropic_base_url_hint}'`;
25906
+ console.log(` ${pc12.cyan(exportHint)}`);
25907
+ console.log(`
25908
+ ${pc12.yellow("WARNING: the secret above is shown ONCE. Save it now \u2014 you cannot retrieve it later.")}`);
25909
+ console.log(` Secret: ${pc12.bold(result.secret)}`);
25910
+ console.log(` Token hash (for revocation): ${pc12.dim(result.token_hash)}
25911
+ `);
25912
+ } catch (err) {
25913
+ printError(err instanceof Error ? err.message : "issue failed");
25914
+ process.exitCode = 1;
25915
+ }
25916
+ });
25917
+ auth.command("list-anthropic-tokens").description("List Anthropic proxy tokens from the remote auth-worker (g4)").requiredOption("--remote <url>", "Auth-worker base URL").action(async (opts) => {
25918
+ const baseUrl = opts.remote;
25919
+ printHeader("Auth worker \u2014 list Anthropic proxy tokens");
25920
+ console.log(`
25921
+ Open ${pc12.cyan(baseUrl.replace(/\/+$/, "") + "/v1/oauth/start")} in a browser to authenticate via CF Access SSO.`);
25922
+ console.log(` Once you've completed SSO, paste your CF_Authorization cookie below.
25923
+ `);
25924
+ const rawCookie = await promptLine(` ${pc12.dim("CF_Authorization cookie:")} `);
25925
+ if (!rawCookie) {
25926
+ printError("No cookie provided. Aborting.");
25927
+ process.exitCode = 1;
25928
+ return;
25929
+ }
25930
+ try {
25931
+ const tokens = await remoteListAnthropicTokens({ baseUrl, cfAuthCookie: rawCookie });
25932
+ if (tokens.length === 0) {
25933
+ console.log(`
25934
+ ${pc12.dim("No Anthropic proxy tokens found. Run: olam auth issue-anthropic-token --remote " + baseUrl + " --label <name>")}
25935
+ `);
25936
+ return;
25937
+ }
25938
+ const col = (s, w) => s.padEnd(w);
25939
+ console.log(`
25940
+ ${"Label".padEnd(20)} ${"Issued".padEnd(22)} ${"Last Used".padEnd(22)} ${"Token Hash (prefix)"}`);
25941
+ console.log(` ${"-".repeat(20)} ${"-".repeat(22)} ${"-".repeat(22)} ${"-".repeat(10)}`);
25942
+ for (const t of tokens) {
25943
+ const issued = t.issued_at ?? "\u2014";
25944
+ const lastUsed = t.last_used_at ?? "\u2014";
25945
+ const hashPrefix = t.token_hash.slice(0, 8);
25946
+ console.log(` ${col(t.label, 20)} ${col(issued, 22)} ${col(lastUsed, 22)} ${pc12.dim(hashPrefix)}`);
25947
+ }
25948
+ console.log();
25949
+ } catch (err) {
25950
+ printError(err instanceof Error ? err.message : "list failed");
25951
+ process.exitCode = 1;
25952
+ }
25953
+ });
25954
+ auth.command("revoke-anthropic-token").description("Revoke an Anthropic proxy token on the remote auth-worker (g4)").requiredOption("--remote <url>", "Auth-worker base URL").requiredOption("--token-hash <hash>", "Token hash to revoke (from issue or list output)").action(async (opts) => {
25955
+ const baseUrl = opts.remote;
25956
+ printHeader("Auth worker \u2014 revoke Anthropic proxy token");
25957
+ console.log(`
25958
+ Open ${pc12.cyan(baseUrl.replace(/\/+$/, "") + "/v1/oauth/start")} in a browser to authenticate via CF Access SSO.`);
25959
+ console.log(` Once you've completed SSO, paste your CF_Authorization cookie below.
25960
+ `);
25961
+ const rawCookie = await promptLine(` ${pc12.dim("CF_Authorization cookie:")} `);
25962
+ if (!rawCookie) {
25963
+ printError("No cookie provided. Aborting.");
25964
+ process.exitCode = 1;
25965
+ return;
25966
+ }
25967
+ try {
25968
+ const revoked = await remoteRevokeAnthropicToken({ baseUrl, cfAuthCookie: rawCookie }, opts.tokenHash);
25969
+ if (revoked) {
25970
+ printSuccess(`Token ${opts.tokenHash} revoked.`);
25971
+ } else {
25972
+ printWarning(`Token ${opts.tokenHash} not found (may already be revoked).`);
25973
+ }
25974
+ } catch (err) {
25975
+ printError(err instanceof Error ? err.message : "revoke failed");
25976
+ process.exitCode = 1;
25977
+ }
25978
+ });
25236
25979
  registerAuthUpgrade(auth);
25237
25980
  }
25238
25981
 
@@ -25245,7 +25988,7 @@ import ora5 from "ora";
25245
25988
  import pc13 from "picocolors";
25246
25989
 
25247
25990
  // ../core/dist/world/devbox-freshness.js
25248
- import { execSync as execSync7 } from "node:child_process";
25991
+ import { execSync as execSync8 } from "node:child_process";
25249
25992
  import { existsSync as existsSync36, statSync as statSync9 } from "node:fs";
25250
25993
  import { join as join43 } from "node:path";
25251
25994
  var DEFAULT_DEVBOX_IMAGE = "olam-devbox:base";
@@ -25329,7 +26072,7 @@ function formatFreshnessWarning(result, image = DEFAULT_DEVBOX_IMAGE) {
25329
26072
  }
25330
26073
  function defaultDockerInspect(image) {
25331
26074
  try {
25332
- const out = execSync7(`docker inspect ${image} --format '{{.Created}}'`, { encoding: "utf-8", timeout: 5e3, stdio: ["ignore", "pipe", "pipe"] }).trim();
26075
+ const out = execSync8(`docker inspect ${image} --format '{{.Created}}'`, { encoding: "utf-8", timeout: 5e3, stdio: ["ignore", "pipe", "pipe"] }).trim();
25333
26076
  return out.length > 0 ? out : null;
25334
26077
  } catch {
25335
26078
  return null;
@@ -25711,7 +26454,7 @@ async function readHostCpTokenForCreate() {
25711
26454
  }
25712
26455
  }
25713
26456
  function registerCreate(program2) {
25714
- program2.command("create").description("Create a new development world").option("--name <name>", "World name (required unless --from-prompt is set; auto-derived in that case)").option("--repos <repos...>", "Repos to include (names from .olam/config.yaml; wins over --workspace)").option("--workspace <name>", "Named workspace from the host catalog (~/.olam/workspaces/<name>.yaml)").option("--task <task>", "Initial task to dispatch").option("--branch <branch>", "Override default branch name").option("--plan <file>", "Path to a plan file to inject").option("--no-auth", "Skip auto-injecting host credentials").option("--no-host-cp", 'Suppress the host CP "you might want to start it" hint').option("--auto-codex-review", "Spawn a parallel codex-review lane that critiques main as it works").option("--no-open", "Suppress auto-opening the Host CP UI in the browser on success").option("--rebuild-base", "Rebuild olam-devbox:latest before creating (slow)").option("--no-freshness-check", "Skip the devbox image freshness check").option("--from-prompt <prompt>", "NL prompt \u2192 infer workspace + dispatch (CLI parity for olam_create_from_prompt MCP tool)").option("--keep-after-merge", "Disable auto-destroy when the world's PR merges (useful for inspection/debugging)").option("--carry-uncommitted", "Preserve operator's uncommitted edits in the world's worktree").option(
26457
+ program2.command("create").description("Create a new development world").option("--name <name>", "World name (required unless --from-prompt is set; auto-derived in that case)").option("--repos <repos...>", "Repos to include (names from .olam/config.yaml; wins over --workspace)").option("--workspace <name>", "Named workspace from the host catalog (~/.olam/workspaces/<name>.yaml)").option("--task <task>", "Initial task to dispatch").option("--branch <branch>", "Override default branch name").option("--plan <file>", "Path to a plan file to inject").option("--no-auth", "Skip auto-injecting host credentials").option("--no-host-cp", 'Suppress the host CP "you might want to start it" hint').option("--auto-codex-review", "Spawn a parallel codex-review lane that critiques main as it works").option("--no-open", "Suppress auto-opening the Host CP UI in the browser on success").option("--rebuild-base", "Rebuild olam-devbox:latest before creating (slow)").option("--no-freshness-check", "Skip the devbox image freshness check").option("--from-prompt <prompt>", "NL prompt \u2192 infer workspace + dispatch (CLI parity for olam_create_from_prompt MCP tool)").option("--from-manifest <path>", "Spawn a world from a trace-replay fork manifest (ADR 044)").option("--keep-after-merge", "Disable auto-destroy when the world's PR merges (useful for inspection/debugging)").option("--carry-uncommitted", "Preserve operator's uncommitted edits in the world's worktree").option(
25715
26458
  "--allow-bootstrap-failure",
25716
26459
  "Treat bootstrap step failures as warnings instead of destroying the world (dogfood escape hatch for cross-repo seed coupling)"
25717
26460
  ).option("--devbox-image <ref>", "Override the default devbox image (full registry/name:tag or @sha256: ref)").option("--allow-custom-registry", "Allow --devbox-image refs outside ghcr.io/pleri/* (logs a warning)").option("--runbook <name>", "Named runbook profile from ~/.olam/config.json").option(
@@ -25756,6 +26499,32 @@ function registerCreate(program2) {
25756
26499
  let resolvedWorkspace = opts.workspace;
25757
26500
  let resolvedRepos = opts.repos;
25758
26501
  let resolvedTask = opts.task;
26502
+ if (opts.fromManifest) {
26503
+ if (opts.task) {
26504
+ printError("--from-manifest and --task are mutually exclusive (the manifest carries the task).");
26505
+ process.exitCode = 1;
26506
+ return;
26507
+ }
26508
+ if (opts.fromPrompt) {
26509
+ printError("--from-manifest and --from-prompt are mutually exclusive.");
26510
+ process.exitCode = 1;
26511
+ return;
26512
+ }
26513
+ const { parseForkManifest: parseForkManifest2, defaultNameFromManifest: defaultNameFromManifest2, provenanceLine: provenanceLine2 } = await Promise.resolve().then(() => (init_from_manifest(), from_manifest_exports));
26514
+ let manifest;
26515
+ try {
26516
+ manifest = parseForkManifest2(opts.fromManifest);
26517
+ } catch (err) {
26518
+ printError(err.message);
26519
+ process.exitCode = 1;
26520
+ return;
26521
+ }
26522
+ resolvedTask = manifest.newPrompt;
26523
+ if (!resolvedName) {
26524
+ resolvedName = defaultNameFromManifest2(manifest);
26525
+ }
26526
+ printInfo("Replay", provenanceLine2(manifest));
26527
+ }
25759
26528
  if (opts.fromPrompt) {
25760
26529
  if (opts.task) {
25761
26530
  printError("--from-prompt and --task are mutually exclusive (the prompt IS the task).");
@@ -26141,6 +26910,8 @@ ${pc13.cyan("Host CP UI:")} ${worldUrl}`);
26141
26910
  if (err instanceof AuthPreflightError) {
26142
26911
  printError(err.message);
26143
26912
  if (err.remedy) console.log(` ${pc13.dim(err.remedy)}`);
26913
+ } else if (err instanceof ContainerOrphanError) {
26914
+ printError(err.message);
26144
26915
  } else {
26145
26916
  printError(err instanceof Error ? err.message : String(err));
26146
26917
  }
@@ -27302,7 +28073,7 @@ async function runImplode(opts) {
27302
28073
  // src/commands/enter.ts
27303
28074
  init_context();
27304
28075
  init_output();
27305
- import { execSync as execSync8 } from "node:child_process";
28076
+ import { execSync as execSync9 } from "node:child_process";
27306
28077
  import pc18 from "picocolors";
27307
28078
  var SAFE_IDENT3 = /^[a-z0-9][a-z0-9-]{0,63}$/;
27308
28079
  function buildStartClaudeCommands(containerName, sessionName, task) {
@@ -27399,7 +28170,7 @@ function registerEnter(program2) {
27399
28170
  if (opts.exec) {
27400
28171
  for (const step2 of steps) {
27401
28172
  try {
27402
- execSync8(step2.command, {
28173
+ execSync9(step2.command, {
27403
28174
  stdio: step2.stdin !== void 0 ? ["pipe", "inherit", "inherit"] : "inherit",
27404
28175
  input: step2.stdin
27405
28176
  });
@@ -27439,7 +28210,7 @@ function registerEnter(program2) {
27439
28210
  }
27440
28211
  if (opts.exec) {
27441
28212
  try {
27442
- execSync8(result.command, { stdio: "inherit" });
28213
+ execSync9(result.command, { stdio: "inherit" });
27443
28214
  } catch (err) {
27444
28215
  printError(
27445
28216
  err instanceof Error ? err.message : `Command failed: ${result.command}`
@@ -28214,7 +28985,7 @@ function registerLanes(program2) {
28214
28985
 
28215
28986
  // src/commands/policy-check.ts
28216
28987
  init_loader2();
28217
- import { execSync as execSync9 } from "node:child_process";
28988
+ import { execSync as execSync10 } from "node:child_process";
28218
28989
  import pc20 from "picocolors";
28219
28990
 
28220
28991
  // ../../node_modules/balanced-match/dist/esm/index.js
@@ -30052,7 +30823,7 @@ function enforcePolicies(policies, diff) {
30052
30823
  function getDiff(base, cwd) {
30053
30824
  for (const range2 of [`${base}...HEAD`, `${base}..HEAD`]) {
30054
30825
  try {
30055
- return execSync9(`git diff --name-only ${range2}`, {
30826
+ return execSync10(`git diff --name-only ${range2}`, {
30056
30827
  cwd,
30057
30828
  encoding: "utf8",
30058
30829
  stdio: ["pipe", "pipe", "pipe"]
@@ -30061,7 +30832,7 @@ function getDiff(base, cwd) {
30061
30832
  }
30062
30833
  }
30063
30834
  try {
30064
- return execSync9("git diff --name-only HEAD", {
30835
+ return execSync10("git diff --name-only HEAD", {
30065
30836
  cwd,
30066
30837
  encoding: "utf8",
30067
30838
  stdio: ["pipe", "pipe", "pipe"]
@@ -30099,7 +30870,7 @@ function registerPolicyCheck(program2) {
30099
30870
  }
30100
30871
 
30101
30872
  // src/commands/worldspec/compile.ts
30102
- import { existsSync as existsSync44, mkdirSync as mkdirSync28, readFileSync as readFileSync33, writeFileSync as writeFileSync22 } from "node:fs";
30873
+ import { existsSync as existsSync44, mkdirSync as mkdirSync28, readFileSync as readFileSync34, writeFileSync as writeFileSync22 } from "node:fs";
30103
30874
  import { resolve as resolvePath } from "node:path";
30104
30875
  import YAML5 from "yaml";
30105
30876
 
@@ -30908,7 +31679,7 @@ function registerWorldspecCompile(parent) {
30908
31679
  }
30909
31680
  let yaml;
30910
31681
  try {
30911
- yaml = YAML5.parse(readFileSync33(abs, "utf8"));
31682
+ yaml = YAML5.parse(readFileSync34(abs, "utf8"));
30912
31683
  } catch (err) {
30913
31684
  printError(
30914
31685
  `${p}: YAML parse error: ${err.message}`
@@ -30993,8 +31764,8 @@ function getPkgVersion() {
30993
31764
  // src/commands/worldspec/init.ts
30994
31765
  init_exit_codes();
30995
31766
  init_output();
30996
- import { existsSync as existsSync45, mkdirSync as mkdirSync29, readFileSync as readFileSync34, writeFileSync as writeFileSync23 } from "node:fs";
30997
- import { execSync as execSync10 } from "node:child_process";
31767
+ import { existsSync as existsSync45, mkdirSync as mkdirSync29, readFileSync as readFileSync35, writeFileSync as writeFileSync23 } from "node:fs";
31768
+ import { execSync as execSync11 } from "node:child_process";
30998
31769
  import { basename as basename3, resolve as resolvePath2 } from "node:path";
30999
31770
  function registerWorldspecInit(parent) {
31000
31771
  parent.command("init").description(
@@ -31052,7 +31823,7 @@ function detectProjectShape(root, useAdbYaml) {
31052
31823
  const rubyVersionPath = resolvePath2(root, ".ruby-version");
31053
31824
  if (existsSync45(rubyVersionPath)) {
31054
31825
  try {
31055
- const raw = readFileSync34(rubyVersionPath, "utf8").trim();
31826
+ const raw = readFileSync35(rubyVersionPath, "utf8").trim();
31056
31827
  const match2 = raw.match(/(\d+\.\d+\.\d+)/);
31057
31828
  if (match2) rubyVersion = match2[1] ?? null;
31058
31829
  } catch {
@@ -31069,7 +31840,7 @@ function detectProjectShape(root, useAdbYaml) {
31069
31840
  }
31070
31841
  function getRepoName2(root) {
31071
31842
  try {
31072
- const url2 = execSync10("git remote get-url origin", {
31843
+ const url2 = execSync11("git remote get-url origin", {
31073
31844
  cwd: root,
31074
31845
  encoding: "utf-8",
31075
31846
  stdio: ["ignore", "pipe", "ignore"]
@@ -32462,7 +33233,7 @@ function registerWorldspecSchema(parent) {
32462
33233
  }
32463
33234
 
32464
33235
  // src/commands/worldspec/validate.ts
32465
- import { existsSync as existsSync46, readFileSync as readFileSync35 } from "node:fs";
33236
+ import { existsSync as existsSync46, readFileSync as readFileSync36 } from "node:fs";
32466
33237
  import { resolve as resolvePath4 } from "node:path";
32467
33238
  init_exit_codes();
32468
33239
  init_output();
@@ -32485,7 +33256,7 @@ function registerWorldspecValidate(parent) {
32485
33256
  }
32486
33257
  let yamlSource;
32487
33258
  try {
32488
- yamlSource = readFileSync35(absPath, "utf8");
33259
+ yamlSource = readFileSync36(absPath, "utf8");
32489
33260
  } catch (err) {
32490
33261
  printError(
32491
33262
  `failed to read ${absPath}: ${err.message}`
@@ -34404,7 +35175,7 @@ init_snapshot();
34404
35175
  init_output();
34405
35176
  import * as fs45 from "node:fs";
34406
35177
  import * as path48 from "node:path";
34407
- import { execSync as execSync11 } from "node:child_process";
35178
+ import { execSync as execSync12 } from "node:child_process";
34408
35179
  import pc24 from "picocolors";
34409
35180
 
34410
35181
  // src/commands/world.ts
@@ -34540,7 +35311,7 @@ async function captureGems(worldId, workspacePath, repo) {
34540
35311
  const containerName = `olam-${worldId}-devbox`;
34541
35312
  let bundlePath;
34542
35313
  try {
34543
- bundlePath = execSync11(
35314
+ bundlePath = execSync12(
34544
35315
  `docker exec ${containerName} sh -c 'bundle config get path 2>/dev/null || echo ~/.bundle'`,
34545
35316
  { encoding: "utf-8", timeout: 1e4 }
34546
35317
  ).trim();
@@ -34550,13 +35321,13 @@ async function captureGems(worldId, workspacePath, repo) {
34550
35321
  }
34551
35322
  try {
34552
35323
  const tmpTar = `/tmp/olam-snap-gems-${repo}-${fingerprint}.tar.gz`;
34553
- execSync11(
35324
+ execSync12(
34554
35325
  `docker exec ${containerName} sh -c 'mkdir -p "$(dirname ${tmpTar})" && tar -czf ${tmpTar}.tmp -C ${bundlePath} . && mv ${tmpTar}.tmp ${tmpTar}'`,
34555
35326
  { stdio: "pipe", timeout: 12e4 }
34556
35327
  );
34557
35328
  fs45.mkdirSync(path48.dirname(tarPath), { recursive: true });
34558
- execSync11(`docker cp ${containerName}:${tmpTar} "${tarPath}"`, { stdio: "pipe", timeout: 12e4 });
34559
- execSync11(`docker exec ${containerName} rm -f ${tmpTar}`, { stdio: "pipe" });
35329
+ execSync12(`docker cp ${containerName}:${tmpTar} "${tarPath}"`, { stdio: "pipe", timeout: 12e4 });
35330
+ execSync12(`docker exec ${containerName} rm -f ${tmpTar}`, { stdio: "pipe" });
34560
35331
  const stat = fs45.statSync(tarPath);
34561
35332
  const manifest = {
34562
35333
  kind: "gems",
@@ -34612,18 +35383,18 @@ async function capturePg(worldId, workspacePath, repoNames) {
34612
35383
  const containerName = `olam-${worldId}-postgres`;
34613
35384
  const volumeName2 = `olam-${worldId}-postgres-data`;
34614
35385
  try {
34615
- execSync11(`docker inspect ${containerName}`, { stdio: "pipe", timeout: 5e3 });
35386
+ execSync12(`docker inspect ${containerName}`, { stdio: "pipe", timeout: 5e3 });
34616
35387
  } catch {
34617
35388
  return { ok: false, tarPath, msg: "postgres container not found; world may not use postgres" };
34618
35389
  }
34619
35390
  try {
34620
- execSync11(`docker stop ${containerName}`, { stdio: "pipe", timeout: 3e4 });
35391
+ execSync12(`docker stop ${containerName}`, { stdio: "pipe", timeout: 3e4 });
34621
35392
  fs45.mkdirSync(path48.dirname(tarPath), { recursive: true });
34622
- execSync11(
35393
+ execSync12(
34623
35394
  `docker run --rm -v "${volumeName2}:/pgdata:ro" -v "${path48.dirname(tarPath)}:/dest" alpine sh -c 'tar -czf /dest/${path48.basename(tarPath)}.tmp -C /pgdata . && mv /dest/${path48.basename(tarPath)}.tmp /dest/${path48.basename(tarPath)}'`,
34624
35395
  { stdio: "pipe", timeout: 18e4 }
34625
35396
  );
34626
- execSync11(`docker start ${containerName}`, { stdio: "pipe", timeout: 3e4 });
35397
+ execSync12(`docker start ${containerName}`, { stdio: "pipe", timeout: 3e4 });
34627
35398
  const stat = fs45.statSync(tarPath);
34628
35399
  const manifest = {
34629
35400
  kind: "pg",
@@ -34637,7 +35408,7 @@ async function capturePg(worldId, workspacePath, repoNames) {
34637
35408
  return { ok: true, tarPath };
34638
35409
  } catch (err) {
34639
35410
  try {
34640
- execSync11(`docker start ${containerName}`, { stdio: "pipe", timeout: 1e4 });
35411
+ execSync12(`docker start ${containerName}`, { stdio: "pipe", timeout: 1e4 });
34641
35412
  } catch {
34642
35413
  }
34643
35414
  return { ok: false, tarPath, msg: `pg capture failed: ${String(err)}` };
@@ -35068,7 +35839,7 @@ function registerRestart(program2) {
35068
35839
  import * as fs48 from "node:fs";
35069
35840
  import * as os26 from "node:os";
35070
35841
  import * as path51 from "node:path";
35071
- import { execFileSync as execFileSync13, execSync as execSync12 } from "node:child_process";
35842
+ import { execFileSync as execFileSync13, execSync as execSync13 } from "node:child_process";
35072
35843
  import pc25 from "picocolors";
35073
35844
 
35074
35845
  // ../core/dist/diagnose/secret-stripper.js
@@ -35108,7 +35879,7 @@ var CACHE_DIR = path51.join(os26.homedir(), ".olam", "cache");
35108
35879
  var LOG_TAIL_LINES = 200;
35109
35880
  function safeExec(cmd) {
35110
35881
  try {
35111
- return execSync12(cmd, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
35882
+ return execSync13(cmd, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
35112
35883
  } catch {
35113
35884
  return "";
35114
35885
  }
@@ -35234,7 +36005,7 @@ init_health_probes();
35234
36005
 
35235
36006
  // src/lib/bundle-freshness.ts
35236
36007
  import { createHash as createHash4 } from "node:crypto";
35237
- import { existsSync as existsSync56, readFileSync as readFileSync42, statSync as statSync17 } from "node:fs";
36008
+ import { existsSync as existsSync56, readFileSync as readFileSync43, statSync as statSync17 } from "node:fs";
35238
36009
  import { join as join58, resolve as resolve16 } from "node:path";
35239
36010
  var BUNDLE_FILES = [
35240
36011
  "driver-runner.js",
@@ -35279,7 +36050,7 @@ async function probeBundleFreshness(deps = {}) {
35279
36050
  for (const f of BUNDLE_FILES) {
35280
36051
  const p = join58(hostDistDir, f);
35281
36052
  if (!existsSync56(p)) continue;
35282
- const buf = readFileSync42(p);
36053
+ const buf = readFileSync43(p);
35283
36054
  const sha = createHash4("sha256").update(buf).digest("hex");
35284
36055
  const mtimeMs = statSync17(p).mtimeMs;
35285
36056
  hostShas.set(f, { sha, mtimeMs });
@@ -36188,7 +36959,7 @@ function registerSubstrate(program2) {
36188
36959
  }
36189
36960
 
36190
36961
  // ../cli-plugin-tasks/dist/client.js
36191
- import { readFileSync as readFileSync46 } from "node:fs";
36962
+ import { readFileSync as readFileSync47 } from "node:fs";
36192
36963
  import { homedir as homedir31 } from "node:os";
36193
36964
  import { join as join61 } from "node:path";
36194
36965
  var TasksClient = class {
@@ -36200,7 +36971,7 @@ var TasksClient = class {
36200
36971
  this.baseUrl = (opts.hostCpUrl ?? process.env.OLAM_HOST_CP_URL ?? "http://localhost:19000").replace(/\/$/, "");
36201
36972
  const tokenPath2 = opts.tokenPath ?? join61(homedir31(), ".olam", "host-cp.token");
36202
36973
  try {
36203
- this.token = readFileSync46(tokenPath2, "utf8").trim();
36974
+ this.token = readFileSync47(tokenPath2, "utf8").trim();
36204
36975
  } catch (e) {
36205
36976
  throw new Error(`cli-plugin-tasks: cannot read host-cp token at ${tokenPath2} (${e instanceof Error ? e.message : "unknown"}). Bootstrap host-cp first.`);
36206
36977
  }
@@ -36227,7 +36998,7 @@ var TasksClient = class {
36227
36998
  };
36228
36999
 
36229
37000
  // ../cli-plugin-tasks/dist/tracker-parser.js
36230
- import { readFileSync as readFileSync47 } from "node:fs";
37001
+ import { readFileSync as readFileSync48 } from "node:fs";
36231
37002
  import { createHash as createHash6 } from "node:crypto";
36232
37003
  function contentHash(parts) {
36233
37004
  const normalized = parts.map((p) => (p ?? "").trim()).join("|");
@@ -36261,7 +37032,7 @@ function parseFrontmatter2(raw) {
36261
37032
  return { frontmatter: fm, body };
36262
37033
  }
36263
37034
  function parseTracker(path96) {
36264
- const raw = readFileSync47(path96, "utf8");
37035
+ const raw = readFileSync48(path96, "utf8");
36265
37036
  const { frontmatter, body } = parseFrontmatter2(raw);
36266
37037
  const lines = body.split("\n");
36267
37038
  const tasks = [];
@@ -36654,7 +37425,7 @@ function registerCompletion(program2) {
36654
37425
  init_cli_version();
36655
37426
  init_health_probes();
36656
37427
  import { spawn as spawn7, spawnSync as spawnSync27 } from "node:child_process";
36657
- import { existsSync as existsSync85, readFileSync as readFileSync70 } from "node:fs";
37428
+ import { existsSync as existsSync85, readFileSync as readFileSync71 } from "node:fs";
36658
37429
  import { homedir as homedir45 } from "node:os";
36659
37430
  import path77 from "node:path";
36660
37431
  import { createInterface as createInterface3 } from "node:readline";
@@ -36721,14 +37492,14 @@ function discoverOfferableContexts(deps = {}) {
36721
37492
  }
36722
37493
 
36723
37494
  // src/lib/shell-rc.ts
36724
- import { copyFileSync as copyFileSync5, existsSync as existsSync60, readFileSync as readFileSync48, renameSync as renameSync8, writeFileSync as writeFileSync29 } from "node:fs";
37495
+ import { copyFileSync as copyFileSync5, existsSync as existsSync60, readFileSync as readFileSync49, renameSync as renameSync8, writeFileSync as writeFileSync29 } from "node:fs";
36725
37496
  import path54 from "node:path";
36726
37497
  function appendIdempotent(opts) {
36727
37498
  const { rcPath, marker, contentLine, clock = () => /* @__PURE__ */ new Date() } = opts;
36728
37499
  if (!existsSync60(rcPath)) {
36729
37500
  return { status: "no-rc-file", backupPath: null };
36730
37501
  }
36731
- const content = readFileSync48(rcPath, "utf-8");
37502
+ const content = readFileSync49(rcPath, "utf-8");
36732
37503
  if (content.includes(marker)) {
36733
37504
  return { status: "already-present", backupPath: null };
36734
37505
  }
@@ -37101,7 +37872,7 @@ function resolveSubstrate(opts, deps) {
37101
37872
  const configPath = deps.configPath ?? OLAM_CONFIG_PATH;
37102
37873
  if (existsSync85(configPath)) {
37103
37874
  try {
37104
- const raw = readFileSync70(configPath, "utf8");
37875
+ const raw = readFileSync71(configPath, "utf8");
37105
37876
  const parsed = JSON.parse(raw);
37106
37877
  const host = parsed.host;
37107
37878
  if (host?.substrate === "kubernetes") return "kubernetes";
@@ -37781,11 +38552,11 @@ function registerSetupMetrics(program2) {
37781
38552
 
37782
38553
  // ../core/dist/setup/linux-gate.js
37783
38554
  init_trust_audit_log();
37784
- import { execSync as execSync13 } from "node:child_process";
38555
+ import { execSync as execSync14 } from "node:child_process";
37785
38556
  var GH_LABEL = "linux-platform-request";
37786
38557
  var LINUX_INVOCATION_THRESHOLD = 3;
37787
38558
  function defaultExecGhIssueList(label) {
37788
- return execSync13(`gh issue list --label ${label} --json number,title --state all`, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
38559
+ return execSync14(`gh issue list --label ${label} --json number,title --state all`, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
37789
38560
  }
37790
38561
  function countLinuxInvocations(readLog) {
37791
38562
  const { entries } = readLog();
@@ -37860,7 +38631,7 @@ function registerSetupLinuxGate(program2) {
37860
38631
  import * as fs78 from "node:fs";
37861
38632
  import * as os42 from "node:os";
37862
38633
  import * as path80 from "node:path";
37863
- import { execSync as execSync14 } from "node:child_process";
38634
+ import { execSync as execSync15 } from "node:child_process";
37864
38635
  import pc28 from "picocolors";
37865
38636
 
37866
38637
  // src/lib/symlink-reconcile.ts
@@ -37928,7 +38699,7 @@ var LOG_DIR2 = path80.join(os42.homedir(), ".olam", "log");
37928
38699
  var LAST_STABLE_FILE = path80.join(CACHE_DIR2, "last-stable.txt");
37929
38700
  function defaultExec(cmd) {
37930
38701
  try {
37931
- const stdout = execSync14(cmd, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
38702
+ const stdout = execSync15(cmd, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
37932
38703
  return { exitCode: 0, stdout, stderr: "" };
37933
38704
  } catch (err) {
37934
38705
  const e = err;
@@ -38453,7 +39224,7 @@ import * as readline2 from "node:readline";
38453
39224
  import pc32 from "picocolors";
38454
39225
 
38455
39226
  // src/commands/flywheel/install-shims.ts
38456
- import { copyFileSync as copyFileSync9, existsSync as existsSync89, mkdirSync as mkdirSync53, readFileSync as readFileSync74, writeFileSync as writeFileSync44 } from "node:fs";
39227
+ import { copyFileSync as copyFileSync9, existsSync as existsSync89, mkdirSync as mkdirSync53, readFileSync as readFileSync75, writeFileSync as writeFileSync44 } from "node:fs";
38457
39228
  import { homedir as homedir48 } from "node:os";
38458
39229
  import { dirname as dirname48, join as join87 } from "node:path";
38459
39230
 
@@ -38557,7 +39328,7 @@ function installOne(spec, targetDir, opts) {
38557
39328
  }
38558
39329
  return { basename: spec.basename, action: "written", targetPath };
38559
39330
  }
38560
- const existing = readFileSync74(targetPath, "utf8");
39331
+ const existing = readFileSync75(targetPath, "utf8");
38561
39332
  if (existing === newContent) {
38562
39333
  return { basename: spec.basename, action: "unchanged", targetPath };
38563
39334
  }
@@ -39217,7 +39988,7 @@ import {
39217
39988
  lstatSync as lstatSync8,
39218
39989
  mkdirSync as mkdirSync54,
39219
39990
  readdirSync as readdirSync27,
39220
- readFileSync as readFileSync75,
39991
+ readFileSync as readFileSync76,
39221
39992
  readlinkSync as readlinkSync4,
39222
39993
  rmSync as rmSync9,
39223
39994
  statSync as statSync27,
@@ -39324,8 +40095,8 @@ function postMergeSanitize(mergedText, label) {
39324
40095
  return { ok: false, reason: `[post-merge-sanitize] ${label} merged output failed sanitizer: ${result.reason}` };
39325
40096
  }
39326
40097
  function mergeOne(upstreamPath, overlayPath, destPath2, label, dryRun, messages) {
39327
- const upstreamText = readFileSync75(upstreamPath, "utf8");
39328
- const overlayText = readFileSync75(overlayPath, "utf8");
40098
+ const upstreamText = readFileSync76(upstreamPath, "utf8");
40099
+ const overlayText = readFileSync76(overlayPath, "utf8");
39329
40100
  const result = mergeMarkdown(upstreamText, overlayText, label, upstreamPath, overlayPath);
39330
40101
  if ("error" in result) {
39331
40102
  messages.push(`ERROR ${result.error.reason}`);
@@ -39345,7 +40116,7 @@ function mergeOne(upstreamPath, overlayPath, destPath2, label, dryRun, messages)
39345
40116
  }
39346
40117
  function isNewAgentOverlay(overlayPath) {
39347
40118
  try {
39348
- const text = readFileSync75(overlayPath, "utf8");
40119
+ const text = readFileSync76(overlayPath, "utf8");
39349
40120
  const { fm } = parseFrontmatter3(text);
39350
40121
  return fm["overlay-intent"] === "new-agent";
39351
40122
  } catch {
@@ -42123,7 +42894,7 @@ function registerMcp(program2) {
42123
42894
  init_output();
42124
42895
 
42125
42896
  // src/lib/memory-host-process-migration.ts
42126
- import { existsSync as existsSync101, readFileSync as readFileSync83, unlinkSync as unlinkSync23 } from "node:fs";
42897
+ import { existsSync as existsSync101, readFileSync as readFileSync84, unlinkSync as unlinkSync23 } from "node:fs";
42127
42898
  import { spawnSync as spawnSync30 } from "node:child_process";
42128
42899
 
42129
42900
  // src/commands/memory/_paths.ts
@@ -42192,7 +42963,7 @@ function migrateFromHostProcess(opts = {}) {
42192
42963
  }
42193
42964
  function readPidFromFile(pidPath2) {
42194
42965
  try {
42195
- const raw = readFileSync83(pidPath2, "utf8").trim();
42966
+ const raw = readFileSync84(pidPath2, "utf8").trim();
42196
42967
  const pid = parseInt(raw, 10);
42197
42968
  if (!Number.isFinite(pid) || pid <= 0) return null;
42198
42969
  return pid;
@@ -42625,7 +43396,7 @@ function registerMemoryUninstall(cmd) {
42625
43396
  // src/commands/memory/mode.ts
42626
43397
  init_schema2();
42627
43398
  init_output();
42628
- import { existsSync as existsSync104, readFileSync as readFileSync84, writeFileSync as writeFileSync51 } from "node:fs";
43399
+ import { existsSync as existsSync104, readFileSync as readFileSync85, writeFileSync as writeFileSync51 } from "node:fs";
42629
43400
  import { join as join96 } from "node:path";
42630
43401
  import * as readline7 from "node:readline/promises";
42631
43402
  import { parse as parseYaml8, stringify as stringifyYaml6 } from "yaml";
@@ -42640,7 +43411,7 @@ function locateConfig(cwd) {
42640
43411
  return { absPath };
42641
43412
  }
42642
43413
  function readConfigYaml(absPath) {
42643
- const raw = readFileSync84(absPath, "utf-8");
43414
+ const raw = readFileSync85(absPath, "utf-8");
42644
43415
  const parsed = parseYaml8(raw) ?? {};
42645
43416
  if (typeof parsed !== "object" || parsed === null) {
42646
43417
  throw new Error(`${absPath} is not a YAML object`);
@@ -43127,7 +43898,7 @@ function registerMemoryStats(cmd) {
43127
43898
  }
43128
43899
 
43129
43900
  // src/commands/memory/install-hooks.ts
43130
- import { copyFileSync as copyFileSync12, existsSync as existsSync106, mkdirSync as mkdirSync60, readFileSync as readFileSync85, writeFileSync as writeFileSync52 } from "node:fs";
43901
+ import { copyFileSync as copyFileSync12, existsSync as existsSync106, mkdirSync as mkdirSync60, readFileSync as readFileSync86, writeFileSync as writeFileSync52 } from "node:fs";
43131
43902
  import { homedir as homedir54 } from "node:os";
43132
43903
  import { dirname as dirname56, join as join98, resolve as resolve25 } from "node:path";
43133
43904
  import { fileURLToPath as fileURLToPath9 } from "node:url";
@@ -43150,7 +43921,7 @@ function installOne2(basename16, sourceDir, targetDir, opts) {
43150
43921
  if (!existsSync106(sourcePath)) {
43151
43922
  throw new Error(`canonical hook source missing at ${sourcePath} \u2014 olam install corrupt or sourceDir is wrong`);
43152
43923
  }
43153
- const newContent = readFileSync85(sourcePath, "utf8");
43924
+ const newContent = readFileSync86(sourcePath, "utf8");
43154
43925
  if (!existsSync106(targetPath)) {
43155
43926
  if (opts.dryRun !== true) {
43156
43927
  mkdirSync60(dirname56(targetPath), { recursive: true });
@@ -43158,7 +43929,7 @@ function installOne2(basename16, sourceDir, targetDir, opts) {
43158
43929
  }
43159
43930
  return { basename: basename16, action: "written", targetPath };
43160
43931
  }
43161
- const existing = readFileSync85(targetPath, "utf8");
43932
+ const existing = readFileSync86(targetPath, "utf8");
43162
43933
  if (existing === newContent) {
43163
43934
  return { basename: basename16, action: "unchanged", targetPath };
43164
43935
  }
@@ -44636,7 +45407,7 @@ function registerFlywheelK5Score(parent) {
44636
45407
  }
44637
45408
 
44638
45409
  // src/commands/flywheel/k5-validate.ts
44639
- import { readFileSync as readFileSync89, statSync as statSync30 } from "node:fs";
45410
+ import { readFileSync as readFileSync90, statSync as statSync30 } from "node:fs";
44640
45411
  import { parse as parseYAML } from "yaml";
44641
45412
  var K5_DIMS = ["direction", "approach", "open_questions", "constraints", "reuse"];
44642
45413
  var MAX_PLAN_BYTES = 1048576;
@@ -44706,7 +45477,7 @@ function validatePlan(path96) {
44706
45477
  }
44707
45478
  let text;
44708
45479
  try {
44709
- text = readFileSync89(path96, "utf8");
45480
+ text = readFileSync90(path96, "utf8");
44710
45481
  } catch (err) {
44711
45482
  return { ok: false, message: `FAIL cannot read ${path96}: ${err instanceof Error ? err.message : "unknown"}` };
44712
45483
  }
@@ -44788,7 +45559,7 @@ function registerFlywheelK5Validate(parent) {
44788
45559
  }
44789
45560
 
44790
45561
  // src/commands/flywheel/k10-measure.ts
44791
- import { readFileSync as readFileSync90 } from "node:fs";
45562
+ import { readFileSync as readFileSync91 } from "node:fs";
44792
45563
 
44793
45564
  // ../core/dist/lib/k10-budget.js
44794
45565
  var K10_TOKEN_CAP = 5500;
@@ -44845,7 +45616,7 @@ function registerFlywheelK10Measure(parent) {
44845
45616
  parent.command("k10-measure").description("Measure K10 token budget for upstream + optional overlay; emit PASS/REJECT verdict").requiredOption("--upstream <path>", "path to upstream file (e.g. persona prompt)").option("--overlay <path>", "path to overlay file (omit if none \u2014 PASS without enforcement)").option("--json", "emit verdict as JSON instead of human-readable").action((opts) => {
44846
45617
  let upstreamText;
44847
45618
  try {
44848
- upstreamText = readFileSync90(opts.upstream, "utf8");
45619
+ upstreamText = readFileSync91(opts.upstream, "utf8");
44849
45620
  } catch (err) {
44850
45621
  process.stderr.write(
44851
45622
  `[k10-measure-error] cannot read upstream ${opts.upstream}: ${err instanceof Error ? err.message : "unknown"}
@@ -44857,7 +45628,7 @@ function registerFlywheelK10Measure(parent) {
44857
45628
  let overlayTokens = null;
44858
45629
  if (opts.overlay !== void 0) {
44859
45630
  try {
44860
- const overlayText = readFileSync90(opts.overlay, "utf8");
45631
+ const overlayText = readFileSync91(opts.overlay, "utf8");
44861
45632
  overlayTokens = tokensFromText(overlayText);
44862
45633
  } catch (err) {
44863
45634
  process.stderr.write(
@@ -44891,7 +45662,7 @@ function registerFlywheelK10Measure(parent) {
44891
45662
  }
44892
45663
 
44893
45664
  // src/commands/flywheel/check-persona-skeleton.ts
44894
- import { existsSync as existsSync110, readFileSync as readFileSync91, statSync as statSync31 } from "node:fs";
45665
+ import { existsSync as existsSync110, readFileSync as readFileSync92, statSync as statSync31 } from "node:fs";
44895
45666
  import { homedir as homedir60 } from "node:os";
44896
45667
  import { basename as basename14, join as join103 } from "node:path";
44897
45668
  import { parse as parseYAML2 } from "yaml";
@@ -44940,7 +45711,7 @@ function checkFile(filepath) {
44940
45711
  if (!existsSync110(filepath) || !statSync31(filepath).isFile()) {
44941
45712
  return { passed: false, failures: [`file not found: ${filepath}`], tokens: 0, mergedSkipped: false };
44942
45713
  }
44943
- const text = readFileSync91(filepath, "utf8");
45714
+ const text = readFileSync92(filepath, "utf8");
44944
45715
  const { fm, body } = parseFile(text);
44945
45716
  const failures = [];
44946
45717
  for (const key of REQUIRED_FRONTMATTER_KEYS) {
@@ -45006,7 +45777,7 @@ Results: ${passCount} passed, ${failCount} failed
45006
45777
  }
45007
45778
 
45008
45779
  // src/commands/flywheel/diversity-check.ts
45009
- import { readFileSync as readFileSync92 } from "node:fs";
45780
+ import { readFileSync as readFileSync93 } from "node:fs";
45010
45781
  import { basename as basename15 } from "node:path";
45011
45782
  import { globSync as globSync2 } from "node:fs";
45012
45783
 
@@ -45115,7 +45886,7 @@ function registerFlywheelDiversityCheck(parent) {
45115
45886
  const personas = /* @__PURE__ */ new Map();
45116
45887
  for (const filepath of files) {
45117
45888
  try {
45118
- const body = readFileSync92(filepath, "utf8");
45889
+ const body = readFileSync93(filepath, "utf8");
45119
45890
  if (body.trim().length > 0) {
45120
45891
  personas.set(basename15(filepath, ".md"), body);
45121
45892
  }
@@ -45208,7 +45979,7 @@ import {
45208
45979
  copyFileSync as copyFileSync15,
45209
45980
  existsSync as existsSync111,
45210
45981
  mkdirSync as mkdirSync65,
45211
- readFileSync as readFileSync93,
45982
+ readFileSync as readFileSync94,
45212
45983
  readdirSync as readdirSync32,
45213
45984
  statSync as statSync32,
45214
45985
  writeFileSync as writeFileSync57
@@ -45294,7 +46065,7 @@ function resolveAtlasUser2(opts) {
45294
46065
  const claudeDir2 = opts._testClaudeDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join105(homedir62(), ".claude");
45295
46066
  const f = join105(claudeDir2, ".atlas-user");
45296
46067
  if (existsSync111(f)) {
45297
- const v = readFileSync93(f, "utf-8").trim();
46068
+ const v = readFileSync94(f, "utf-8").trim();
45298
46069
  if (v.length === 0) return null;
45299
46070
  assertValidAtlasUser(v);
45300
46071
  return v;
@@ -45436,7 +46207,7 @@ function pushOverlays(opts) {
45436
46207
  const basename16 = relPath.split("/").pop() ?? relPath;
45437
46208
  let content;
45438
46209
  try {
45439
- content = readFileSync93(srcFile);
46210
+ content = readFileSync94(srcFile);
45440
46211
  } catch {
45441
46212
  continue;
45442
46213
  }
@@ -45484,12 +46255,12 @@ function pushOverlays(opts) {
45484
46255
  const targetFile = join105(targetDir, relPath);
45485
46256
  let srcBuf;
45486
46257
  try {
45487
- srcBuf = readFileSync93(srcFile);
46258
+ srcBuf = readFileSync94(srcFile);
45488
46259
  } catch {
45489
46260
  continue;
45490
46261
  }
45491
46262
  if (existsSync111(targetFile)) {
45492
- const dstBuf = readFileSync93(targetFile);
46263
+ const dstBuf = readFileSync94(targetFile);
45493
46264
  if (srcBuf.equals(dstBuf)) {
45494
46265
  wouldUnchange += 1;
45495
46266
  process.stdout.write(` [skip] ${overlayKind}.overrides/${relPath} (unchanged)
@@ -45540,13 +46311,13 @@ function pushOverlays(opts) {
45540
46311
  const targetFile = join105(membersBase, `${overlayKind}.overrides`, relPath);
45541
46312
  let srcBuf;
45542
46313
  try {
45543
- srcBuf = readFileSync93(srcFile);
46314
+ srcBuf = readFileSync94(srcFile);
45544
46315
  } catch {
45545
46316
  continue;
45546
46317
  }
45547
46318
  const targetExists = existsSync111(targetFile);
45548
46319
  if (targetExists) {
45549
- const dstBuf = readFileSync93(targetFile);
46320
+ const dstBuf = readFileSync94(targetFile);
45550
46321
  if (srcBuf.equals(dstBuf)) {
45551
46322
  filesUnchanged += 1;
45552
46323
  continue;
@@ -45755,7 +46526,7 @@ function migrateOverlays(opts = {}) {
45755
46526
  for (const filePath of allFiles) {
45756
46527
  let original;
45757
46528
  try {
45758
- original = readFileSync93(filePath, "utf8");
46529
+ original = readFileSync94(filePath, "utf8");
45759
46530
  } catch {
45760
46531
  continue;
45761
46532
  }