@pleri/olam-cli 0.1.170 → 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 (37) hide show
  1. package/dist/agent-stream/driver-runner.js +13 -0
  2. package/dist/commands/auth.d.ts +22 -7
  3. package/dist/commands/auth.d.ts.map +1 -1
  4. package/dist/commands/auth.js +414 -46
  5. package/dist/commands/auth.js.map +1 -1
  6. package/dist/commands/create.d.ts.map +1 -1
  7. package/dist/commands/create.js +45 -1
  8. package/dist/commands/create.js.map +1 -1
  9. package/dist/commands/services.d.ts +39 -0
  10. package/dist/commands/services.d.ts.map +1 -1
  11. package/dist/commands/services.js +64 -9
  12. package/dist/commands/services.js.map +1 -1
  13. package/dist/from-manifest.d.ts +53 -0
  14. package/dist/from-manifest.d.ts.map +1 -0
  15. package/dist/from-manifest.js +95 -0
  16. package/dist/from-manifest.js.map +1 -0
  17. package/dist/image-digests.json +8 -8
  18. package/dist/index.js +911 -137
  19. package/dist/lib/auth-remote.d.ts +130 -0
  20. package/dist/lib/auth-remote.d.ts.map +1 -0
  21. package/dist/lib/auth-remote.js +307 -0
  22. package/dist/lib/auth-remote.js.map +1 -0
  23. package/dist/mcp-server.js +1487 -435
  24. package/hermes-bundle/version.json +1 -1
  25. package/host-cp/k8s/manifests/50-deployment.yaml +1 -1
  26. package/host-cp/k8s/manifests/auth-service/50-deployment.yaml +1 -1
  27. package/host-cp/k8s/manifests/kg-service/50-deployment.yaml +1 -1
  28. package/host-cp/k8s/manifests/mcp-auth-service/50-deployment.yaml +1 -1
  29. package/host-cp/k8s/manifests/memory-service/50-deployment.yaml +1 -1
  30. package/host-cp/observability/ndjson-span-sink.mjs +52 -0
  31. package/host-cp/src/boot-reconciler.mjs +238 -0
  32. package/host-cp/src/linear-sync.mjs +43 -0
  33. package/host-cp/src/plan-chat-service.mjs +129 -1
  34. package/host-cp/src/port-bridge-manager.mjs +116 -10
  35. package/host-cp/src/server.mjs +121 -1
  36. package/host-cp/src/world-activity-tracker.mjs +392 -0
  37. 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);
@@ -8769,6 +8784,8 @@ function stripMcpServers(mcpServers) {
8769
8784
  stripped.type = value;
8770
8785
  } else if (key === "url" && typeof value === "string") {
8771
8786
  stripped.url = value;
8787
+ } else if (key === "alwaysLoad" && typeof value === "boolean") {
8788
+ stripped.alwaysLoad = value;
8772
8789
  }
8773
8790
  }
8774
8791
  out[svc] = stripped;
@@ -8861,8 +8878,8 @@ function copyDirRecursive(src, dest, depth = 0, skipFiles = /* @__PURE__ */ new
8861
8878
  }
8862
8879
  }
8863
8880
  async function copyClaudeConfigIntoContainer(containerName) {
8864
- const { execSync: execSync15 } = await import("node:child_process");
8865
- 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" });
8866
8883
  dockerExec("mkdir -p $HOME/.claude");
8867
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");
8868
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");
@@ -8878,7 +8895,7 @@ async function copyClaudeConfigIntoContainer(containerName) {
8878
8895
  await sanitizeContainerClaudeHooks(containerName);
8879
8896
  }
8880
8897
  async function sanitizeContainerClaudeHooks(containerName) {
8881
- const { execSync: execSync15 } = await import("node:child_process");
8898
+ const { execSync: execSync16 } = await import("node:child_process");
8882
8899
  const script = `
8883
8900
  const fs = require('fs');
8884
8901
  const p = (process.env.HOME || '/home/olam') + '/.claude/settings.json';
@@ -8922,7 +8939,7 @@ if (changed) {
8922
8939
  }
8923
8940
  `;
8924
8941
  try {
8925
- 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" });
8926
8943
  } catch {
8927
8944
  }
8928
8945
  }
@@ -9086,7 +9103,8 @@ var init_env_setup = __esm({
9086
9103
  "command",
9087
9104
  "args",
9088
9105
  "type",
9089
- "url"
9106
+ "url",
9107
+ "alwaysLoad"
9090
9108
  ]);
9091
9109
  SKIP_FILES = /* @__PURE__ */ new Set([
9092
9110
  ".credentials.json",
@@ -11712,6 +11730,60 @@ var init_bootstrap_hooks = __esm({
11712
11730
  }
11713
11731
  });
11714
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
+
11715
11787
  // ../core/dist/world/tmux-supervisor.js
11716
11788
  function injectBindAll(start) {
11717
11789
  let result = start;
@@ -11849,6 +11921,7 @@ var manager_exports = {};
11849
11921
  __export(manager_exports, {
11850
11922
  AuthPreflightError: () => AuthPreflightError,
11851
11923
  BotIdentityError: () => BotIdentityError,
11924
+ ContainerOrphanError: () => ContainerOrphanError,
11852
11925
  TaskDispatchError: () => TaskDispatchError,
11853
11926
  WorkspaceNotFoundError: () => WorkspaceNotFoundError,
11854
11927
  WorldManager: () => WorldManager,
@@ -11868,12 +11941,12 @@ __export(manager_exports, {
11868
11941
  runManifestRuntime: () => runManifestRuntime
11869
11942
  });
11870
11943
  import * as crypto5 from "node:crypto";
11871
- import { execSync as execSync5, spawnSync as spawnSync5 } from "node:child_process";
11944
+ import { execSync as execSync6, spawnSync as spawnSync5 } from "node:child_process";
11872
11945
  import * as fs23 from "node:fs";
11873
11946
  import * as os13 from "node:os";
11874
11947
  import * as path25 from "node:path";
11875
11948
  import YAML3 from "yaml";
11876
- function getTokenScopes(ghToken, _exec = execSync5) {
11949
+ function getTokenScopes(ghToken, _exec = execSync6) {
11877
11950
  try {
11878
11951
  const out = _exec("gh auth status 2>&1", {
11879
11952
  encoding: "utf-8",
@@ -11890,13 +11963,13 @@ function getTokenScopes(ghToken, _exec = execSync5) {
11890
11963
  }
11891
11964
  }
11892
11965
  async function setupContainerGit(containerName, repos, branch) {
11893
- 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, "'\\''")}'`, {
11894
11967
  stdio: "pipe",
11895
11968
  timeout: 6e4
11896
11969
  }).toString();
11897
11970
  let ghToken = "";
11898
11971
  try {
11899
- 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();
11900
11973
  } catch {
11901
11974
  }
11902
11975
  const actorName = process.env.OLAM_BOT_NAME ?? "Claude Code (olam)";
@@ -11916,7 +11989,7 @@ async function setupContainerGit(containerName, repos, branch) {
11916
11989
  continue;
11917
11990
  const ownerRepo = ghMatch[1];
11918
11991
  try {
11919
- execSync5(`gh api repos/${ownerRepo} --silent`, {
11992
+ execSync6(`gh api repos/${ownerRepo} --silent`, {
11920
11993
  stdio: "pipe",
11921
11994
  timeout: 5e3,
11922
11995
  env: { ...process.env, GH_TOKEN: ghToken }
@@ -11964,7 +12037,7 @@ ${stderr.split("\n").slice(0, 3).join(" ")}`);
11964
12037
  if (!olamUserPresent) {
11965
12038
  const imageName = (() => {
11966
12039
  try {
11967
- return execSync5(`docker inspect ${containerName} --format '{{.Config.Image}}'`, {
12040
+ return execSync6(`docker inspect ${containerName} --format '{{.Config.Image}}'`, {
11968
12041
  encoding: "utf8",
11969
12042
  timeout: 5e3
11970
12043
  }).trim() || "(unknown)";
@@ -12007,7 +12080,7 @@ ${stderr.split("\n").slice(0, 3).join(" ")}`);
12007
12080
  function makeHostExecFn() {
12008
12081
  return async (cmd) => {
12009
12082
  try {
12010
- const stdout = execSync5(cmd, { encoding: "utf-8", timeout: 5e3 });
12083
+ const stdout = execSync6(cmd, { encoding: "utf-8", timeout: 5e3 });
12011
12084
  return { stdout, stderr: "", exitCode: 0 };
12012
12085
  } catch {
12013
12086
  return { stdout: "", stderr: "", exitCode: 1 };
@@ -12017,7 +12090,7 @@ function makeHostExecFn() {
12017
12090
  function makeContainerExecFn(containerName) {
12018
12091
  return async (cmd) => {
12019
12092
  try {
12020
- 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 });
12021
12094
  return { stdout: result.toString(), stderr: "", exitCode: 0 };
12022
12095
  } catch (err) {
12023
12096
  const execErr = err;
@@ -12031,7 +12104,7 @@ function makeContainerExecFn(containerName) {
12031
12104
  }
12032
12105
  function defaultDockerExec2() {
12033
12106
  return (containerName, cmd) => {
12034
- const result = execSync5(
12107
+ const result = execSync6(
12035
12108
  `docker exec ${containerName} sh -c '${cmd.replace(/'/g, "'\\''")}'`,
12036
12109
  // Phase E E5 raise: 10min was too tight on cold-boot for atlas-core's
12037
12110
  // `rails db:create` chain (Rails 7 boot + initializer load + first
@@ -12211,7 +12284,7 @@ function buildManifestRuntime(worldId, repos) {
12211
12284
  }
12212
12285
  return { worldId, repos: runtimeRepos };
12213
12286
  }
12214
- function exposeWorldOverTailscale(appPortUrls, worldId, registry, _exec = execSync5) {
12287
+ function exposeWorldOverTailscale(appPortUrls, worldId, registry, _exec = execSync6) {
12215
12288
  if (process.env["OLAM_TAILSCALE_SERVE"] !== "true")
12216
12289
  return;
12217
12290
  if (appPortUrls.length === 0)
@@ -12239,7 +12312,7 @@ function exposeWorldOverTailscale(appPortUrls, worldId, registry, _exec = execSy
12239
12312
  registry.storeTailscalePaths(worldId, registeredPaths);
12240
12313
  }
12241
12314
  }
12242
- function cleanupWorldTailscale(worldId, registry, _exec = execSync5) {
12315
+ function cleanupWorldTailscale(worldId, registry, _exec = execSync6) {
12243
12316
  const paths = registry.loadTailscalePaths(worldId);
12244
12317
  if (paths.length === 0)
12245
12318
  return;
@@ -12258,7 +12331,7 @@ function cleanupWorldTailscale(worldId, registry, _exec = execSync5) {
12258
12331
  }
12259
12332
  }
12260
12333
  }
12261
- function resolveTailscaleBin(_exec = execSync5) {
12334
+ function resolveTailscaleBin(_exec = execSync6) {
12262
12335
  const candidates2 = [
12263
12336
  process.env["TAILSCALE_BIN"],
12264
12337
  "/Applications/Tailscale.app/Contents/MacOS/Tailscale",
@@ -12657,6 +12730,8 @@ var init_manager = __esm({
12657
12730
  init_runbook_resolver();
12658
12731
  init_port_validator();
12659
12732
  init_bootstrap_hooks();
12733
+ init_create_dedup();
12734
+ init_create_dedup();
12660
12735
  init_tmux_supervisor();
12661
12736
  BotIdentityError = class extends Error {
12662
12737
  constructor(message) {
@@ -12691,19 +12766,38 @@ var init_manager = __esm({
12691
12766
  dashboardManager;
12692
12767
  pleriClient;
12693
12768
  dockerExec;
12769
+ containerProbe;
12694
12770
  manifestRuntimes = /* @__PURE__ */ new Map();
12695
- constructor(config, provider, registry, dashboardManager, pleriClient, dockerExec) {
12771
+ constructor(config, provider, registry, dashboardManager, pleriClient, dockerExec, containerProbe) {
12696
12772
  this.config = config;
12697
12773
  this.provider = provider;
12698
12774
  this.registry = registry;
12699
12775
  this.dashboardManager = dashboardManager;
12700
12776
  this.pleriClient = pleriClient;
12701
12777
  this.dockerExec = dockerExec ?? defaultDockerExec2();
12778
+ this.containerProbe = containerProbe;
12702
12779
  }
12703
12780
  // -----------------------------------------------------------------------
12704
12781
  // createWorld
12705
12782
  // -----------------------------------------------------------------------
12706
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
+ }
12707
12801
  if (!opts.noAuth) {
12708
12802
  const preflight2 = await runAuthPreflight({ autoStart: true });
12709
12803
  if (preflight2.verdict !== "ok") {
@@ -13387,7 +13481,7 @@ ${detail}`);
13387
13481
  const escapedDir = `/home/olam/workspace/${repo.name.replace(/["$`\\]/g, "\\$&")}`;
13388
13482
  for (const cmd of repo.setup_commands) {
13389
13483
  try {
13390
- 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 });
13391
13485
  } catch (err) {
13392
13486
  const msg = err instanceof Error ? err.message : String(err);
13393
13487
  console.warn(`[WorldManager] setup command failed for ${repo.name}: ${msg}`);
@@ -13408,11 +13502,11 @@ ${detail}`);
13408
13502
  });
13409
13503
  if (allPolicies.length > 0) {
13410
13504
  try {
13411
- 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 });
13412
13506
  for (const repo of repos) {
13413
13507
  const policiesDir = path25.join(workspacePath, repo.name, ".olam", "policies");
13414
13508
  if (fs23.existsSync(policiesDir)) {
13415
- 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 });
13416
13510
  }
13417
13511
  }
13418
13512
  } catch (err) {
@@ -14900,10 +14994,10 @@ var init_state2 = __esm({
14900
14994
  });
14901
14995
 
14902
14996
  // ../core/dist/dashboard/tunnel.js
14903
- import { spawn as spawn3, execSync as execSync6 } from "node:child_process";
14997
+ import { spawn as spawn3, execSync as execSync7 } from "node:child_process";
14904
14998
  function isCloudflaredAvailable() {
14905
14999
  try {
14906
- execSync6("which cloudflared", { stdio: "ignore" });
15000
+ execSync7("which cloudflared", { stdio: "ignore" });
14907
15001
  return true;
14908
15002
  } catch {
14909
15003
  return false;
@@ -16235,6 +16329,69 @@ var init_registry_allowlist = __esm({
16235
16329
  }
16236
16330
  });
16237
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
+
16238
16395
  // src/spawn/home-override.ts
16239
16396
  var home_override_exports = {};
16240
16397
  __export(home_override_exports, {
@@ -18146,13 +18303,13 @@ var init_file_lock = __esm({
18146
18303
  });
18147
18304
 
18148
18305
  // ../core/dist/lib/min-version-filter.js
18149
- import { existsSync as existsSync73, readFileSync as readFileSync60 } from "node:fs";
18306
+ import { existsSync as existsSync73, readFileSync as readFileSync61 } from "node:fs";
18150
18307
  function readOlamMinVersion(filepath) {
18151
18308
  if (!existsSync73(filepath))
18152
18309
  return void 0;
18153
18310
  let text;
18154
18311
  try {
18155
- text = readFileSync60(filepath, "utf8");
18312
+ text = readFileSync61(filepath, "utf8");
18156
18313
  } catch {
18157
18314
  return void 0;
18158
18315
  }
@@ -18800,7 +18957,7 @@ var init_meta_hook_injector = __esm({
18800
18957
 
18801
18958
  // ../core/dist/lib/markdown-merger.js
18802
18959
  import { createHash as createHash8 } from "node:crypto";
18803
- 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";
18804
18961
  function parseFrontmatter3(text) {
18805
18962
  const match2 = FM_RE2.exec(text);
18806
18963
  if (match2 === null)
@@ -18922,7 +19079,7 @@ function mergeMarkdown(upstreamText, overlayText, labelForError, upstreamPath, o
18922
19079
  function sha256OfPath(p) {
18923
19080
  if (!existsSync76(p) || !statSync22(p).isFile())
18924
19081
  return "MISSING";
18925
- return createHash8("sha256").update(readFileSync64(p)).digest("hex");
19082
+ return createHash8("sha256").update(readFileSync65(p)).digest("hex");
18926
19083
  }
18927
19084
  var FM_RE2, H2_RE;
18928
19085
  var init_markdown_merger = __esm({
@@ -19174,7 +19331,7 @@ var init_prefix_deploy = __esm({
19174
19331
  });
19175
19332
 
19176
19333
  // ../core/dist/skill-sync/resolve-source-config.js
19177
- import { readFileSync as readFileSync66, existsSync as existsSync77 } from "node:fs";
19334
+ import { readFileSync as readFileSync67, existsSync as existsSync77 } from "node:fs";
19178
19335
  import { join as join76 } from "node:path";
19179
19336
  import { parse as parseYaml6 } from "yaml";
19180
19337
  function sourceConfigPath(clonePath) {
@@ -19186,7 +19343,7 @@ function readSourceConfig(clonePath, sourceId) {
19186
19343
  return void 0;
19187
19344
  let raw;
19188
19345
  try {
19189
- raw = readFileSync66(path96, "utf-8");
19346
+ raw = readFileSync67(path96, "utf-8");
19190
19347
  } catch (err) {
19191
19348
  emitMalformedWarning(sourceId, `read failed: ${errToMsg(err)}`);
19192
19349
  return void 0;
@@ -23373,6 +23530,7 @@ var MCP_AUTH_CONTAINER = "olam-mcp-auth";
23373
23530
  var MCP_AUTH_LOCAL_TAG = "olam-mcp-auth:local";
23374
23531
  var MCP_AUTH_PUBLISHED_TAG = "ghcr.io/pleri/olam-mcp-auth:latest";
23375
23532
  var MCP_AUTH_HEALTH_URL = `http://127.0.0.1:${MCP_AUTH_PORT}/health`;
23533
+ var SOCAT_IMAGE = "alpine/socat:latest";
23376
23534
  var MCP_AUTH_HEALTH_TIMEOUT_MS = 6e4;
23377
23535
  var McpAuthContainerController = class {
23378
23536
  imageTag = MCP_AUTH_LOCAL_TAG;
@@ -23596,6 +23754,40 @@ async function servicesRestartKubernetes(name, deps = {}) {
23596
23754
  printSuccess(`${deploymentName}: rollout restart triggered`);
23597
23755
  return { exitCode: 0 };
23598
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
+ }
23599
23791
  function dumpContainerLogs(container, tail = 40) {
23600
23792
  try {
23601
23793
  const result = spawnSync16("docker", ["logs", "--tail", String(tail), container], {
@@ -23620,6 +23812,21 @@ async function servicesUp() {
23620
23812
  const mcpAuth = new McpAuthContainerController();
23621
23813
  const kgService = new KgServiceContainerController();
23622
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
+ }
23623
23830
  const authStatus = auth.status();
23624
23831
  if (authStatus.state === "running") {
23625
23832
  printSuccess(`olam-auth already running on :${authStatus.port}`);
@@ -24201,7 +24408,7 @@ function appendAuditEntry(entry, auditLogPath, writeFileSyncImpl) {
24201
24408
  async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}, peripheral) {
24202
24409
  const auditLogPath = deps.auditLogPath ?? MANIFEST_REFRESH_AUDIT_LOG;
24203
24410
  const readdirSync33 = deps.readdirSync ?? fs31.readdirSync;
24204
- const readFileSync95 = deps.readFileSync ?? fs31.readFileSync;
24411
+ const readFileSync96 = deps.readFileSync ?? fs31.readFileSync;
24205
24412
  const writeFileSyncImpl = deps.writeFileSync ?? fs31.writeFileSync;
24206
24413
  const existsSync113 = deps.existsSync ?? fs31.existsSync;
24207
24414
  const now = deps.now ? deps.now() : /* @__PURE__ */ new Date();
@@ -24227,7 +24434,7 @@ async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}, per
24227
24434
  const filePath = path32.join(targetDir, file);
24228
24435
  let content;
24229
24436
  try {
24230
- content = readFileSync95(filePath, "utf8");
24437
+ content = readFileSync96(filePath, "utf8");
24231
24438
  } catch {
24232
24439
  continue;
24233
24440
  }
@@ -24478,11 +24685,11 @@ async function checkSecretPreCondition(context, deps) {
24478
24685
  }
24479
24686
  async function applyConfigMapSubstitution(context, manifestsDir, deps) {
24480
24687
  const wrap = deps.kubectlWrapImpl ?? kubectlWrap;
24481
- const readFileSync95 = deps.readFileSyncImpl ?? fs32.readFileSync;
24688
+ const readFileSync96 = deps.readFileSyncImpl ?? fs32.readFileSync;
24482
24689
  const configMapPath = path33.join(manifestsDir, "30-configmap.yaml");
24483
24690
  let rawYaml;
24484
24691
  try {
24485
- rawYaml = readFileSync95(configMapPath, "utf8");
24692
+ rawYaml = readFileSync96(configMapPath, "utf8");
24486
24693
  } catch (err) {
24487
24694
  return `Failed to read ConfigMap at ${configMapPath}: ${err instanceof Error ? err.message : String(err)}`;
24488
24695
  }
@@ -25034,6 +25241,223 @@ async function applyK8sAuthRefresh(pinnedContext, deps = {}) {
25034
25241
  return 0;
25035
25242
  }
25036
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
+
25037
25461
  // src/commands/auth.ts
25038
25462
  function openBrowser(url2) {
25039
25463
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
@@ -25068,36 +25492,6 @@ function registerAuth(program2) {
25068
25492
  printWarning("`olam auth status` is deprecated. Use `olam services status` instead.");
25069
25493
  servicesStatus();
25070
25494
  });
25071
- auth.command("list").description("List all stored credentials with state, usage, and rate-limit status").action(async () => {
25072
- const client = new AuthClient();
25073
- const status2 = await client.status();
25074
- if (!status2.reachable) {
25075
- printError("Auth container is not reachable. Run `olam auth up` first.");
25076
- process.exitCode = 1;
25077
- return;
25078
- }
25079
- printHeader(`Credentials (${status2.accounts.length})`);
25080
- if (status2.accounts.length === 0) {
25081
- console.log(` ${pc12.dim("No credentials \u2014 run: olam auth login --label primary")}`);
25082
- return;
25083
- }
25084
- const stateColor = (s) => {
25085
- if (s === "active") return pc12.green("active");
25086
- if (s === "cooldown") return pc12.yellow("cooldown");
25087
- if (s === "expired") return pc12.red("expired");
25088
- if (s === "disabled") return pc12.dim("disabled");
25089
- return pc12.dim(s ?? "unknown");
25090
- };
25091
- for (const a of status2.accounts) {
25092
- const label = a.accountLabel ?? a.id;
25093
- const reqs = a.usage?.requestCount5h ?? 0;
25094
- const last429 = a.usage?.last429At ? `last429=${a.usage.last429At}` : "last429=never";
25095
- const reset = a.rateLimitResetsAt ? `resets=${a.rateLimitResetsAt}` : "";
25096
- console.log(
25097
- ` ${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)}`
25098
- );
25099
- }
25100
- });
25101
25495
  auth.command("disable").description("Take a credential out of rotation (manual cooldown)").argument("<label>", "Credential label or id").action(async (label) => {
25102
25496
  const client = new AuthClient();
25103
25497
  try {
@@ -25128,7 +25522,68 @@ function registerAuth(program2) {
25128
25522
  process.exitCode = 1;
25129
25523
  }
25130
25524
  });
25131
- 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
+ }
25132
25587
  const preflight2 = await runAuthPreflight({ autoStart: true });
25133
25588
  if (preflight2.verdict !== "ok" && preflight2.verdict !== "no-accounts") {
25134
25589
  printError(preflight2.message);
@@ -25230,6 +25685,297 @@ ${pc12.dim("Next: olam create --name my-world")}`);
25230
25685
  }
25231
25686
  }
25232
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
+ });
25233
25979
  registerAuthUpgrade(auth);
25234
25980
  }
25235
25981
 
@@ -25242,7 +25988,7 @@ import ora5 from "ora";
25242
25988
  import pc13 from "picocolors";
25243
25989
 
25244
25990
  // ../core/dist/world/devbox-freshness.js
25245
- import { execSync as execSync7 } from "node:child_process";
25991
+ import { execSync as execSync8 } from "node:child_process";
25246
25992
  import { existsSync as existsSync36, statSync as statSync9 } from "node:fs";
25247
25993
  import { join as join43 } from "node:path";
25248
25994
  var DEFAULT_DEVBOX_IMAGE = "olam-devbox:base";
@@ -25326,7 +26072,7 @@ function formatFreshnessWarning(result, image = DEFAULT_DEVBOX_IMAGE) {
25326
26072
  }
25327
26073
  function defaultDockerInspect(image) {
25328
26074
  try {
25329
- 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();
25330
26076
  return out.length > 0 ? out : null;
25331
26077
  } catch {
25332
26078
  return null;
@@ -25708,7 +26454,7 @@ async function readHostCpTokenForCreate() {
25708
26454
  }
25709
26455
  }
25710
26456
  function registerCreate(program2) {
25711
- 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(
25712
26458
  "--allow-bootstrap-failure",
25713
26459
  "Treat bootstrap step failures as warnings instead of destroying the world (dogfood escape hatch for cross-repo seed coupling)"
25714
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(
@@ -25753,6 +26499,32 @@ function registerCreate(program2) {
25753
26499
  let resolvedWorkspace = opts.workspace;
25754
26500
  let resolvedRepos = opts.repos;
25755
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
+ }
25756
26528
  if (opts.fromPrompt) {
25757
26529
  if (opts.task) {
25758
26530
  printError("--from-prompt and --task are mutually exclusive (the prompt IS the task).");
@@ -26138,6 +26910,8 @@ ${pc13.cyan("Host CP UI:")} ${worldUrl}`);
26138
26910
  if (err instanceof AuthPreflightError) {
26139
26911
  printError(err.message);
26140
26912
  if (err.remedy) console.log(` ${pc13.dim(err.remedy)}`);
26913
+ } else if (err instanceof ContainerOrphanError) {
26914
+ printError(err.message);
26141
26915
  } else {
26142
26916
  printError(err instanceof Error ? err.message : String(err));
26143
26917
  }
@@ -27299,7 +28073,7 @@ async function runImplode(opts) {
27299
28073
  // src/commands/enter.ts
27300
28074
  init_context();
27301
28075
  init_output();
27302
- import { execSync as execSync8 } from "node:child_process";
28076
+ import { execSync as execSync9 } from "node:child_process";
27303
28077
  import pc18 from "picocolors";
27304
28078
  var SAFE_IDENT3 = /^[a-z0-9][a-z0-9-]{0,63}$/;
27305
28079
  function buildStartClaudeCommands(containerName, sessionName, task) {
@@ -27396,7 +28170,7 @@ function registerEnter(program2) {
27396
28170
  if (opts.exec) {
27397
28171
  for (const step2 of steps) {
27398
28172
  try {
27399
- execSync8(step2.command, {
28173
+ execSync9(step2.command, {
27400
28174
  stdio: step2.stdin !== void 0 ? ["pipe", "inherit", "inherit"] : "inherit",
27401
28175
  input: step2.stdin
27402
28176
  });
@@ -27436,7 +28210,7 @@ function registerEnter(program2) {
27436
28210
  }
27437
28211
  if (opts.exec) {
27438
28212
  try {
27439
- execSync8(result.command, { stdio: "inherit" });
28213
+ execSync9(result.command, { stdio: "inherit" });
27440
28214
  } catch (err) {
27441
28215
  printError(
27442
28216
  err instanceof Error ? err.message : `Command failed: ${result.command}`
@@ -28211,7 +28985,7 @@ function registerLanes(program2) {
28211
28985
 
28212
28986
  // src/commands/policy-check.ts
28213
28987
  init_loader2();
28214
- import { execSync as execSync9 } from "node:child_process";
28988
+ import { execSync as execSync10 } from "node:child_process";
28215
28989
  import pc20 from "picocolors";
28216
28990
 
28217
28991
  // ../../node_modules/balanced-match/dist/esm/index.js
@@ -30049,7 +30823,7 @@ function enforcePolicies(policies, diff) {
30049
30823
  function getDiff(base, cwd) {
30050
30824
  for (const range2 of [`${base}...HEAD`, `${base}..HEAD`]) {
30051
30825
  try {
30052
- return execSync9(`git diff --name-only ${range2}`, {
30826
+ return execSync10(`git diff --name-only ${range2}`, {
30053
30827
  cwd,
30054
30828
  encoding: "utf8",
30055
30829
  stdio: ["pipe", "pipe", "pipe"]
@@ -30058,7 +30832,7 @@ function getDiff(base, cwd) {
30058
30832
  }
30059
30833
  }
30060
30834
  try {
30061
- return execSync9("git diff --name-only HEAD", {
30835
+ return execSync10("git diff --name-only HEAD", {
30062
30836
  cwd,
30063
30837
  encoding: "utf8",
30064
30838
  stdio: ["pipe", "pipe", "pipe"]
@@ -30096,7 +30870,7 @@ function registerPolicyCheck(program2) {
30096
30870
  }
30097
30871
 
30098
30872
  // src/commands/worldspec/compile.ts
30099
- 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";
30100
30874
  import { resolve as resolvePath } from "node:path";
30101
30875
  import YAML5 from "yaml";
30102
30876
 
@@ -30905,7 +31679,7 @@ function registerWorldspecCompile(parent) {
30905
31679
  }
30906
31680
  let yaml;
30907
31681
  try {
30908
- yaml = YAML5.parse(readFileSync33(abs, "utf8"));
31682
+ yaml = YAML5.parse(readFileSync34(abs, "utf8"));
30909
31683
  } catch (err) {
30910
31684
  printError(
30911
31685
  `${p}: YAML parse error: ${err.message}`
@@ -30990,8 +31764,8 @@ function getPkgVersion() {
30990
31764
  // src/commands/worldspec/init.ts
30991
31765
  init_exit_codes();
30992
31766
  init_output();
30993
- import { existsSync as existsSync45, mkdirSync as mkdirSync29, readFileSync as readFileSync34, writeFileSync as writeFileSync23 } from "node:fs";
30994
- 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";
30995
31769
  import { basename as basename3, resolve as resolvePath2 } from "node:path";
30996
31770
  function registerWorldspecInit(parent) {
30997
31771
  parent.command("init").description(
@@ -31049,7 +31823,7 @@ function detectProjectShape(root, useAdbYaml) {
31049
31823
  const rubyVersionPath = resolvePath2(root, ".ruby-version");
31050
31824
  if (existsSync45(rubyVersionPath)) {
31051
31825
  try {
31052
- const raw = readFileSync34(rubyVersionPath, "utf8").trim();
31826
+ const raw = readFileSync35(rubyVersionPath, "utf8").trim();
31053
31827
  const match2 = raw.match(/(\d+\.\d+\.\d+)/);
31054
31828
  if (match2) rubyVersion = match2[1] ?? null;
31055
31829
  } catch {
@@ -31066,7 +31840,7 @@ function detectProjectShape(root, useAdbYaml) {
31066
31840
  }
31067
31841
  function getRepoName2(root) {
31068
31842
  try {
31069
- const url2 = execSync10("git remote get-url origin", {
31843
+ const url2 = execSync11("git remote get-url origin", {
31070
31844
  cwd: root,
31071
31845
  encoding: "utf-8",
31072
31846
  stdio: ["ignore", "pipe", "ignore"]
@@ -32459,7 +33233,7 @@ function registerWorldspecSchema(parent) {
32459
33233
  }
32460
33234
 
32461
33235
  // src/commands/worldspec/validate.ts
32462
- import { existsSync as existsSync46, readFileSync as readFileSync35 } from "node:fs";
33236
+ import { existsSync as existsSync46, readFileSync as readFileSync36 } from "node:fs";
32463
33237
  import { resolve as resolvePath4 } from "node:path";
32464
33238
  init_exit_codes();
32465
33239
  init_output();
@@ -32482,7 +33256,7 @@ function registerWorldspecValidate(parent) {
32482
33256
  }
32483
33257
  let yamlSource;
32484
33258
  try {
32485
- yamlSource = readFileSync35(absPath, "utf8");
33259
+ yamlSource = readFileSync36(absPath, "utf8");
32486
33260
  } catch (err) {
32487
33261
  printError(
32488
33262
  `failed to read ${absPath}: ${err.message}`
@@ -34401,7 +35175,7 @@ init_snapshot();
34401
35175
  init_output();
34402
35176
  import * as fs45 from "node:fs";
34403
35177
  import * as path48 from "node:path";
34404
- import { execSync as execSync11 } from "node:child_process";
35178
+ import { execSync as execSync12 } from "node:child_process";
34405
35179
  import pc24 from "picocolors";
34406
35180
 
34407
35181
  // src/commands/world.ts
@@ -34537,7 +35311,7 @@ async function captureGems(worldId, workspacePath, repo) {
34537
35311
  const containerName = `olam-${worldId}-devbox`;
34538
35312
  let bundlePath;
34539
35313
  try {
34540
- bundlePath = execSync11(
35314
+ bundlePath = execSync12(
34541
35315
  `docker exec ${containerName} sh -c 'bundle config get path 2>/dev/null || echo ~/.bundle'`,
34542
35316
  { encoding: "utf-8", timeout: 1e4 }
34543
35317
  ).trim();
@@ -34547,13 +35321,13 @@ async function captureGems(worldId, workspacePath, repo) {
34547
35321
  }
34548
35322
  try {
34549
35323
  const tmpTar = `/tmp/olam-snap-gems-${repo}-${fingerprint}.tar.gz`;
34550
- execSync11(
35324
+ execSync12(
34551
35325
  `docker exec ${containerName} sh -c 'mkdir -p "$(dirname ${tmpTar})" && tar -czf ${tmpTar}.tmp -C ${bundlePath} . && mv ${tmpTar}.tmp ${tmpTar}'`,
34552
35326
  { stdio: "pipe", timeout: 12e4 }
34553
35327
  );
34554
35328
  fs45.mkdirSync(path48.dirname(tarPath), { recursive: true });
34555
- execSync11(`docker cp ${containerName}:${tmpTar} "${tarPath}"`, { stdio: "pipe", timeout: 12e4 });
34556
- 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" });
34557
35331
  const stat = fs45.statSync(tarPath);
34558
35332
  const manifest = {
34559
35333
  kind: "gems",
@@ -34609,18 +35383,18 @@ async function capturePg(worldId, workspacePath, repoNames) {
34609
35383
  const containerName = `olam-${worldId}-postgres`;
34610
35384
  const volumeName2 = `olam-${worldId}-postgres-data`;
34611
35385
  try {
34612
- execSync11(`docker inspect ${containerName}`, { stdio: "pipe", timeout: 5e3 });
35386
+ execSync12(`docker inspect ${containerName}`, { stdio: "pipe", timeout: 5e3 });
34613
35387
  } catch {
34614
35388
  return { ok: false, tarPath, msg: "postgres container not found; world may not use postgres" };
34615
35389
  }
34616
35390
  try {
34617
- execSync11(`docker stop ${containerName}`, { stdio: "pipe", timeout: 3e4 });
35391
+ execSync12(`docker stop ${containerName}`, { stdio: "pipe", timeout: 3e4 });
34618
35392
  fs45.mkdirSync(path48.dirname(tarPath), { recursive: true });
34619
- execSync11(
35393
+ execSync12(
34620
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)}'`,
34621
35395
  { stdio: "pipe", timeout: 18e4 }
34622
35396
  );
34623
- execSync11(`docker start ${containerName}`, { stdio: "pipe", timeout: 3e4 });
35397
+ execSync12(`docker start ${containerName}`, { stdio: "pipe", timeout: 3e4 });
34624
35398
  const stat = fs45.statSync(tarPath);
34625
35399
  const manifest = {
34626
35400
  kind: "pg",
@@ -34634,7 +35408,7 @@ async function capturePg(worldId, workspacePath, repoNames) {
34634
35408
  return { ok: true, tarPath };
34635
35409
  } catch (err) {
34636
35410
  try {
34637
- execSync11(`docker start ${containerName}`, { stdio: "pipe", timeout: 1e4 });
35411
+ execSync12(`docker start ${containerName}`, { stdio: "pipe", timeout: 1e4 });
34638
35412
  } catch {
34639
35413
  }
34640
35414
  return { ok: false, tarPath, msg: `pg capture failed: ${String(err)}` };
@@ -35065,7 +35839,7 @@ function registerRestart(program2) {
35065
35839
  import * as fs48 from "node:fs";
35066
35840
  import * as os26 from "node:os";
35067
35841
  import * as path51 from "node:path";
35068
- import { execFileSync as execFileSync13, execSync as execSync12 } from "node:child_process";
35842
+ import { execFileSync as execFileSync13, execSync as execSync13 } from "node:child_process";
35069
35843
  import pc25 from "picocolors";
35070
35844
 
35071
35845
  // ../core/dist/diagnose/secret-stripper.js
@@ -35105,7 +35879,7 @@ var CACHE_DIR = path51.join(os26.homedir(), ".olam", "cache");
35105
35879
  var LOG_TAIL_LINES = 200;
35106
35880
  function safeExec(cmd) {
35107
35881
  try {
35108
- return execSync12(cmd, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
35882
+ return execSync13(cmd, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
35109
35883
  } catch {
35110
35884
  return "";
35111
35885
  }
@@ -35231,7 +36005,7 @@ init_health_probes();
35231
36005
 
35232
36006
  // src/lib/bundle-freshness.ts
35233
36007
  import { createHash as createHash4 } from "node:crypto";
35234
- 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";
35235
36009
  import { join as join58, resolve as resolve16 } from "node:path";
35236
36010
  var BUNDLE_FILES = [
35237
36011
  "driver-runner.js",
@@ -35276,7 +36050,7 @@ async function probeBundleFreshness(deps = {}) {
35276
36050
  for (const f of BUNDLE_FILES) {
35277
36051
  const p = join58(hostDistDir, f);
35278
36052
  if (!existsSync56(p)) continue;
35279
- const buf = readFileSync42(p);
36053
+ const buf = readFileSync43(p);
35280
36054
  const sha = createHash4("sha256").update(buf).digest("hex");
35281
36055
  const mtimeMs = statSync17(p).mtimeMs;
35282
36056
  hostShas.set(f, { sha, mtimeMs });
@@ -36185,7 +36959,7 @@ function registerSubstrate(program2) {
36185
36959
  }
36186
36960
 
36187
36961
  // ../cli-plugin-tasks/dist/client.js
36188
- import { readFileSync as readFileSync46 } from "node:fs";
36962
+ import { readFileSync as readFileSync47 } from "node:fs";
36189
36963
  import { homedir as homedir31 } from "node:os";
36190
36964
  import { join as join61 } from "node:path";
36191
36965
  var TasksClient = class {
@@ -36197,7 +36971,7 @@ var TasksClient = class {
36197
36971
  this.baseUrl = (opts.hostCpUrl ?? process.env.OLAM_HOST_CP_URL ?? "http://localhost:19000").replace(/\/$/, "");
36198
36972
  const tokenPath2 = opts.tokenPath ?? join61(homedir31(), ".olam", "host-cp.token");
36199
36973
  try {
36200
- this.token = readFileSync46(tokenPath2, "utf8").trim();
36974
+ this.token = readFileSync47(tokenPath2, "utf8").trim();
36201
36975
  } catch (e) {
36202
36976
  throw new Error(`cli-plugin-tasks: cannot read host-cp token at ${tokenPath2} (${e instanceof Error ? e.message : "unknown"}). Bootstrap host-cp first.`);
36203
36977
  }
@@ -36224,7 +36998,7 @@ var TasksClient = class {
36224
36998
  };
36225
36999
 
36226
37000
  // ../cli-plugin-tasks/dist/tracker-parser.js
36227
- import { readFileSync as readFileSync47 } from "node:fs";
37001
+ import { readFileSync as readFileSync48 } from "node:fs";
36228
37002
  import { createHash as createHash6 } from "node:crypto";
36229
37003
  function contentHash(parts) {
36230
37004
  const normalized = parts.map((p) => (p ?? "").trim()).join("|");
@@ -36258,7 +37032,7 @@ function parseFrontmatter2(raw) {
36258
37032
  return { frontmatter: fm, body };
36259
37033
  }
36260
37034
  function parseTracker(path96) {
36261
- const raw = readFileSync47(path96, "utf8");
37035
+ const raw = readFileSync48(path96, "utf8");
36262
37036
  const { frontmatter, body } = parseFrontmatter2(raw);
36263
37037
  const lines = body.split("\n");
36264
37038
  const tasks = [];
@@ -36651,7 +37425,7 @@ function registerCompletion(program2) {
36651
37425
  init_cli_version();
36652
37426
  init_health_probes();
36653
37427
  import { spawn as spawn7, spawnSync as spawnSync27 } from "node:child_process";
36654
- import { existsSync as existsSync85, readFileSync as readFileSync70 } from "node:fs";
37428
+ import { existsSync as existsSync85, readFileSync as readFileSync71 } from "node:fs";
36655
37429
  import { homedir as homedir45 } from "node:os";
36656
37430
  import path77 from "node:path";
36657
37431
  import { createInterface as createInterface3 } from "node:readline";
@@ -36718,14 +37492,14 @@ function discoverOfferableContexts(deps = {}) {
36718
37492
  }
36719
37493
 
36720
37494
  // src/lib/shell-rc.ts
36721
- 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";
36722
37496
  import path54 from "node:path";
36723
37497
  function appendIdempotent(opts) {
36724
37498
  const { rcPath, marker, contentLine, clock = () => /* @__PURE__ */ new Date() } = opts;
36725
37499
  if (!existsSync60(rcPath)) {
36726
37500
  return { status: "no-rc-file", backupPath: null };
36727
37501
  }
36728
- const content = readFileSync48(rcPath, "utf-8");
37502
+ const content = readFileSync49(rcPath, "utf-8");
36729
37503
  if (content.includes(marker)) {
36730
37504
  return { status: "already-present", backupPath: null };
36731
37505
  }
@@ -37098,7 +37872,7 @@ function resolveSubstrate(opts, deps) {
37098
37872
  const configPath = deps.configPath ?? OLAM_CONFIG_PATH;
37099
37873
  if (existsSync85(configPath)) {
37100
37874
  try {
37101
- const raw = readFileSync70(configPath, "utf8");
37875
+ const raw = readFileSync71(configPath, "utf8");
37102
37876
  const parsed = JSON.parse(raw);
37103
37877
  const host = parsed.host;
37104
37878
  if (host?.substrate === "kubernetes") return "kubernetes";
@@ -37778,11 +38552,11 @@ function registerSetupMetrics(program2) {
37778
38552
 
37779
38553
  // ../core/dist/setup/linux-gate.js
37780
38554
  init_trust_audit_log();
37781
- import { execSync as execSync13 } from "node:child_process";
38555
+ import { execSync as execSync14 } from "node:child_process";
37782
38556
  var GH_LABEL = "linux-platform-request";
37783
38557
  var LINUX_INVOCATION_THRESHOLD = 3;
37784
38558
  function defaultExecGhIssueList(label) {
37785
- 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"] });
37786
38560
  }
37787
38561
  function countLinuxInvocations(readLog) {
37788
38562
  const { entries } = readLog();
@@ -37857,7 +38631,7 @@ function registerSetupLinuxGate(program2) {
37857
38631
  import * as fs78 from "node:fs";
37858
38632
  import * as os42 from "node:os";
37859
38633
  import * as path80 from "node:path";
37860
- import { execSync as execSync14 } from "node:child_process";
38634
+ import { execSync as execSync15 } from "node:child_process";
37861
38635
  import pc28 from "picocolors";
37862
38636
 
37863
38637
  // src/lib/symlink-reconcile.ts
@@ -37925,7 +38699,7 @@ var LOG_DIR2 = path80.join(os42.homedir(), ".olam", "log");
37925
38699
  var LAST_STABLE_FILE = path80.join(CACHE_DIR2, "last-stable.txt");
37926
38700
  function defaultExec(cmd) {
37927
38701
  try {
37928
- const stdout = execSync14(cmd, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
38702
+ const stdout = execSync15(cmd, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
37929
38703
  return { exitCode: 0, stdout, stderr: "" };
37930
38704
  } catch (err) {
37931
38705
  const e = err;
@@ -38450,7 +39224,7 @@ import * as readline2 from "node:readline";
38450
39224
  import pc32 from "picocolors";
38451
39225
 
38452
39226
  // src/commands/flywheel/install-shims.ts
38453
- 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";
38454
39228
  import { homedir as homedir48 } from "node:os";
38455
39229
  import { dirname as dirname48, join as join87 } from "node:path";
38456
39230
 
@@ -38554,7 +39328,7 @@ function installOne(spec, targetDir, opts) {
38554
39328
  }
38555
39329
  return { basename: spec.basename, action: "written", targetPath };
38556
39330
  }
38557
- const existing = readFileSync74(targetPath, "utf8");
39331
+ const existing = readFileSync75(targetPath, "utf8");
38558
39332
  if (existing === newContent) {
38559
39333
  return { basename: spec.basename, action: "unchanged", targetPath };
38560
39334
  }
@@ -39214,7 +39988,7 @@ import {
39214
39988
  lstatSync as lstatSync8,
39215
39989
  mkdirSync as mkdirSync54,
39216
39990
  readdirSync as readdirSync27,
39217
- readFileSync as readFileSync75,
39991
+ readFileSync as readFileSync76,
39218
39992
  readlinkSync as readlinkSync4,
39219
39993
  rmSync as rmSync9,
39220
39994
  statSync as statSync27,
@@ -39321,8 +40095,8 @@ function postMergeSanitize(mergedText, label) {
39321
40095
  return { ok: false, reason: `[post-merge-sanitize] ${label} merged output failed sanitizer: ${result.reason}` };
39322
40096
  }
39323
40097
  function mergeOne(upstreamPath, overlayPath, destPath2, label, dryRun, messages) {
39324
- const upstreamText = readFileSync75(upstreamPath, "utf8");
39325
- const overlayText = readFileSync75(overlayPath, "utf8");
40098
+ const upstreamText = readFileSync76(upstreamPath, "utf8");
40099
+ const overlayText = readFileSync76(overlayPath, "utf8");
39326
40100
  const result = mergeMarkdown(upstreamText, overlayText, label, upstreamPath, overlayPath);
39327
40101
  if ("error" in result) {
39328
40102
  messages.push(`ERROR ${result.error.reason}`);
@@ -39342,7 +40116,7 @@ function mergeOne(upstreamPath, overlayPath, destPath2, label, dryRun, messages)
39342
40116
  }
39343
40117
  function isNewAgentOverlay(overlayPath) {
39344
40118
  try {
39345
- const text = readFileSync75(overlayPath, "utf8");
40119
+ const text = readFileSync76(overlayPath, "utf8");
39346
40120
  const { fm } = parseFrontmatter3(text);
39347
40121
  return fm["overlay-intent"] === "new-agent";
39348
40122
  } catch {
@@ -42120,7 +42894,7 @@ function registerMcp(program2) {
42120
42894
  init_output();
42121
42895
 
42122
42896
  // src/lib/memory-host-process-migration.ts
42123
- 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";
42124
42898
  import { spawnSync as spawnSync30 } from "node:child_process";
42125
42899
 
42126
42900
  // src/commands/memory/_paths.ts
@@ -42189,7 +42963,7 @@ function migrateFromHostProcess(opts = {}) {
42189
42963
  }
42190
42964
  function readPidFromFile(pidPath2) {
42191
42965
  try {
42192
- const raw = readFileSync83(pidPath2, "utf8").trim();
42966
+ const raw = readFileSync84(pidPath2, "utf8").trim();
42193
42967
  const pid = parseInt(raw, 10);
42194
42968
  if (!Number.isFinite(pid) || pid <= 0) return null;
42195
42969
  return pid;
@@ -42622,7 +43396,7 @@ function registerMemoryUninstall(cmd) {
42622
43396
  // src/commands/memory/mode.ts
42623
43397
  init_schema2();
42624
43398
  init_output();
42625
- 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";
42626
43400
  import { join as join96 } from "node:path";
42627
43401
  import * as readline7 from "node:readline/promises";
42628
43402
  import { parse as parseYaml8, stringify as stringifyYaml6 } from "yaml";
@@ -42637,7 +43411,7 @@ function locateConfig(cwd) {
42637
43411
  return { absPath };
42638
43412
  }
42639
43413
  function readConfigYaml(absPath) {
42640
- const raw = readFileSync84(absPath, "utf-8");
43414
+ const raw = readFileSync85(absPath, "utf-8");
42641
43415
  const parsed = parseYaml8(raw) ?? {};
42642
43416
  if (typeof parsed !== "object" || parsed === null) {
42643
43417
  throw new Error(`${absPath} is not a YAML object`);
@@ -43124,7 +43898,7 @@ function registerMemoryStats(cmd) {
43124
43898
  }
43125
43899
 
43126
43900
  // src/commands/memory/install-hooks.ts
43127
- 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";
43128
43902
  import { homedir as homedir54 } from "node:os";
43129
43903
  import { dirname as dirname56, join as join98, resolve as resolve25 } from "node:path";
43130
43904
  import { fileURLToPath as fileURLToPath9 } from "node:url";
@@ -43147,7 +43921,7 @@ function installOne2(basename16, sourceDir, targetDir, opts) {
43147
43921
  if (!existsSync106(sourcePath)) {
43148
43922
  throw new Error(`canonical hook source missing at ${sourcePath} \u2014 olam install corrupt or sourceDir is wrong`);
43149
43923
  }
43150
- const newContent = readFileSync85(sourcePath, "utf8");
43924
+ const newContent = readFileSync86(sourcePath, "utf8");
43151
43925
  if (!existsSync106(targetPath)) {
43152
43926
  if (opts.dryRun !== true) {
43153
43927
  mkdirSync60(dirname56(targetPath), { recursive: true });
@@ -43155,7 +43929,7 @@ function installOne2(basename16, sourceDir, targetDir, opts) {
43155
43929
  }
43156
43930
  return { basename: basename16, action: "written", targetPath };
43157
43931
  }
43158
- const existing = readFileSync85(targetPath, "utf8");
43932
+ const existing = readFileSync86(targetPath, "utf8");
43159
43933
  if (existing === newContent) {
43160
43934
  return { basename: basename16, action: "unchanged", targetPath };
43161
43935
  }
@@ -44633,7 +45407,7 @@ function registerFlywheelK5Score(parent) {
44633
45407
  }
44634
45408
 
44635
45409
  // src/commands/flywheel/k5-validate.ts
44636
- import { readFileSync as readFileSync89, statSync as statSync30 } from "node:fs";
45410
+ import { readFileSync as readFileSync90, statSync as statSync30 } from "node:fs";
44637
45411
  import { parse as parseYAML } from "yaml";
44638
45412
  var K5_DIMS = ["direction", "approach", "open_questions", "constraints", "reuse"];
44639
45413
  var MAX_PLAN_BYTES = 1048576;
@@ -44703,7 +45477,7 @@ function validatePlan(path96) {
44703
45477
  }
44704
45478
  let text;
44705
45479
  try {
44706
- text = readFileSync89(path96, "utf8");
45480
+ text = readFileSync90(path96, "utf8");
44707
45481
  } catch (err) {
44708
45482
  return { ok: false, message: `FAIL cannot read ${path96}: ${err instanceof Error ? err.message : "unknown"}` };
44709
45483
  }
@@ -44785,7 +45559,7 @@ function registerFlywheelK5Validate(parent) {
44785
45559
  }
44786
45560
 
44787
45561
  // src/commands/flywheel/k10-measure.ts
44788
- import { readFileSync as readFileSync90 } from "node:fs";
45562
+ import { readFileSync as readFileSync91 } from "node:fs";
44789
45563
 
44790
45564
  // ../core/dist/lib/k10-budget.js
44791
45565
  var K10_TOKEN_CAP = 5500;
@@ -44842,7 +45616,7 @@ function registerFlywheelK10Measure(parent) {
44842
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) => {
44843
45617
  let upstreamText;
44844
45618
  try {
44845
- upstreamText = readFileSync90(opts.upstream, "utf8");
45619
+ upstreamText = readFileSync91(opts.upstream, "utf8");
44846
45620
  } catch (err) {
44847
45621
  process.stderr.write(
44848
45622
  `[k10-measure-error] cannot read upstream ${opts.upstream}: ${err instanceof Error ? err.message : "unknown"}
@@ -44854,7 +45628,7 @@ function registerFlywheelK10Measure(parent) {
44854
45628
  let overlayTokens = null;
44855
45629
  if (opts.overlay !== void 0) {
44856
45630
  try {
44857
- const overlayText = readFileSync90(opts.overlay, "utf8");
45631
+ const overlayText = readFileSync91(opts.overlay, "utf8");
44858
45632
  overlayTokens = tokensFromText(overlayText);
44859
45633
  } catch (err) {
44860
45634
  process.stderr.write(
@@ -44888,7 +45662,7 @@ function registerFlywheelK10Measure(parent) {
44888
45662
  }
44889
45663
 
44890
45664
  // src/commands/flywheel/check-persona-skeleton.ts
44891
- 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";
44892
45666
  import { homedir as homedir60 } from "node:os";
44893
45667
  import { basename as basename14, join as join103 } from "node:path";
44894
45668
  import { parse as parseYAML2 } from "yaml";
@@ -44937,7 +45711,7 @@ function checkFile(filepath) {
44937
45711
  if (!existsSync110(filepath) || !statSync31(filepath).isFile()) {
44938
45712
  return { passed: false, failures: [`file not found: ${filepath}`], tokens: 0, mergedSkipped: false };
44939
45713
  }
44940
- const text = readFileSync91(filepath, "utf8");
45714
+ const text = readFileSync92(filepath, "utf8");
44941
45715
  const { fm, body } = parseFile(text);
44942
45716
  const failures = [];
44943
45717
  for (const key of REQUIRED_FRONTMATTER_KEYS) {
@@ -45003,7 +45777,7 @@ Results: ${passCount} passed, ${failCount} failed
45003
45777
  }
45004
45778
 
45005
45779
  // src/commands/flywheel/diversity-check.ts
45006
- import { readFileSync as readFileSync92 } from "node:fs";
45780
+ import { readFileSync as readFileSync93 } from "node:fs";
45007
45781
  import { basename as basename15 } from "node:path";
45008
45782
  import { globSync as globSync2 } from "node:fs";
45009
45783
 
@@ -45112,7 +45886,7 @@ function registerFlywheelDiversityCheck(parent) {
45112
45886
  const personas = /* @__PURE__ */ new Map();
45113
45887
  for (const filepath of files) {
45114
45888
  try {
45115
- const body = readFileSync92(filepath, "utf8");
45889
+ const body = readFileSync93(filepath, "utf8");
45116
45890
  if (body.trim().length > 0) {
45117
45891
  personas.set(basename15(filepath, ".md"), body);
45118
45892
  }
@@ -45205,7 +45979,7 @@ import {
45205
45979
  copyFileSync as copyFileSync15,
45206
45980
  existsSync as existsSync111,
45207
45981
  mkdirSync as mkdirSync65,
45208
- readFileSync as readFileSync93,
45982
+ readFileSync as readFileSync94,
45209
45983
  readdirSync as readdirSync32,
45210
45984
  statSync as statSync32,
45211
45985
  writeFileSync as writeFileSync57
@@ -45291,7 +46065,7 @@ function resolveAtlasUser2(opts) {
45291
46065
  const claudeDir2 = opts._testClaudeDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join105(homedir62(), ".claude");
45292
46066
  const f = join105(claudeDir2, ".atlas-user");
45293
46067
  if (existsSync111(f)) {
45294
- const v = readFileSync93(f, "utf-8").trim();
46068
+ const v = readFileSync94(f, "utf-8").trim();
45295
46069
  if (v.length === 0) return null;
45296
46070
  assertValidAtlasUser(v);
45297
46071
  return v;
@@ -45433,7 +46207,7 @@ function pushOverlays(opts) {
45433
46207
  const basename16 = relPath.split("/").pop() ?? relPath;
45434
46208
  let content;
45435
46209
  try {
45436
- content = readFileSync93(srcFile);
46210
+ content = readFileSync94(srcFile);
45437
46211
  } catch {
45438
46212
  continue;
45439
46213
  }
@@ -45481,12 +46255,12 @@ function pushOverlays(opts) {
45481
46255
  const targetFile = join105(targetDir, relPath);
45482
46256
  let srcBuf;
45483
46257
  try {
45484
- srcBuf = readFileSync93(srcFile);
46258
+ srcBuf = readFileSync94(srcFile);
45485
46259
  } catch {
45486
46260
  continue;
45487
46261
  }
45488
46262
  if (existsSync111(targetFile)) {
45489
- const dstBuf = readFileSync93(targetFile);
46263
+ const dstBuf = readFileSync94(targetFile);
45490
46264
  if (srcBuf.equals(dstBuf)) {
45491
46265
  wouldUnchange += 1;
45492
46266
  process.stdout.write(` [skip] ${overlayKind}.overrides/${relPath} (unchanged)
@@ -45537,13 +46311,13 @@ function pushOverlays(opts) {
45537
46311
  const targetFile = join105(membersBase, `${overlayKind}.overrides`, relPath);
45538
46312
  let srcBuf;
45539
46313
  try {
45540
- srcBuf = readFileSync93(srcFile);
46314
+ srcBuf = readFileSync94(srcFile);
45541
46315
  } catch {
45542
46316
  continue;
45543
46317
  }
45544
46318
  const targetExists = existsSync111(targetFile);
45545
46319
  if (targetExists) {
45546
- const dstBuf = readFileSync93(targetFile);
46320
+ const dstBuf = readFileSync94(targetFile);
45547
46321
  if (srcBuf.equals(dstBuf)) {
45548
46322
  filesUnchanged += 1;
45549
46323
  continue;
@@ -45752,7 +46526,7 @@ function migrateOverlays(opts = {}) {
45752
46526
  for (const filePath of allFiles) {
45753
46527
  let original;
45754
46528
  try {
45755
- original = readFileSync93(filePath, "utf8");
46529
+ original = readFileSync94(filePath, "utf8");
45756
46530
  } catch {
45757
46531
  continue;
45758
46532
  }