@pleri/olam-cli 0.1.14 → 0.1.21

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/__tests__/auth-upgrade.test.js +236 -1
  2. package/dist/__tests__/auth-upgrade.test.js.map +1 -1
  3. package/dist/__tests__/install-root.test.d.ts +2 -0
  4. package/dist/__tests__/install-root.test.d.ts.map +1 -0
  5. package/dist/__tests__/install-root.test.js +119 -0
  6. package/dist/__tests__/install-root.test.js.map +1 -0
  7. package/dist/__tests__/upgrade.test.js +292 -2
  8. package/dist/__tests__/upgrade.test.js.map +1 -1
  9. package/dist/commands/__tests__/bootstrap.test.d.ts +2 -0
  10. package/dist/commands/__tests__/bootstrap.test.d.ts.map +1 -0
  11. package/dist/commands/__tests__/bootstrap.test.js +288 -0
  12. package/dist/commands/__tests__/bootstrap.test.js.map +1 -0
  13. package/dist/commands/__tests__/upgrade.rollback.test.js +1 -1
  14. package/dist/commands/__tests__/upgrade.swap.test.js +1 -1
  15. package/dist/commands/auth-upgrade.d.ts +41 -0
  16. package/dist/commands/auth-upgrade.d.ts.map +1 -1
  17. package/dist/commands/auth-upgrade.js +158 -6
  18. package/dist/commands/auth-upgrade.js.map +1 -1
  19. package/dist/commands/bootstrap.d.ts +95 -0
  20. package/dist/commands/bootstrap.d.ts.map +1 -0
  21. package/dist/commands/bootstrap.js +329 -0
  22. package/dist/commands/bootstrap.js.map +1 -0
  23. package/dist/commands/create.d.ts.map +1 -1
  24. package/dist/commands/create.js +19 -1
  25. package/dist/commands/create.js.map +1 -1
  26. package/dist/commands/upgrade.d.ts +76 -1
  27. package/dist/commands/upgrade.d.ts.map +1 -1
  28. package/dist/commands/upgrade.js +215 -8
  29. package/dist/commands/upgrade.js.map +1 -1
  30. package/dist/image-digests.json +8 -0
  31. package/dist/index.js +951 -201
  32. package/dist/index.js.map +1 -1
  33. package/dist/install-root.d.ts +74 -0
  34. package/dist/install-root.d.ts.map +1 -0
  35. package/dist/install-root.js +98 -0
  36. package/dist/install-root.js.map +1 -0
  37. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5088,7 +5088,7 @@ async function safeText(res) {
5088
5088
  }
5089
5089
  }
5090
5090
  function sleep(ms) {
5091
- return new Promise((resolve7) => setTimeout(resolve7, ms));
5091
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
5092
5092
  }
5093
5093
  var DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, RETRY_COUNT, RETRY_BACKOFF_MS, AuthClient;
5094
5094
  var init_client = __esm({
@@ -5246,7 +5246,7 @@ function resolveAuthServicePath() {
5246
5246
  return path8.join(pkgsDir, "auth-service");
5247
5247
  }
5248
5248
  function sleep2(ms) {
5249
- return new Promise((resolve7) => setTimeout(resolve7, ms));
5249
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
5250
5250
  }
5251
5251
  var DEFAULT_PORT, DEFAULT_VOLUME, DEFAULT_CONTAINER, DEFAULT_IMAGE, AuthContainerController;
5252
5252
  var init_container = __esm({
@@ -5800,7 +5800,7 @@ var demuxStream, execInContainer;
5800
5800
  var init_exec = __esm({
5801
5801
  "../adapters/dist/docker/exec.js"() {
5802
5802
  "use strict";
5803
- demuxStream = (stream) => new Promise((resolve7, reject) => {
5803
+ demuxStream = (stream) => new Promise((resolve8, reject) => {
5804
5804
  const stdoutChunks = [];
5805
5805
  const stderrChunks = [];
5806
5806
  const stdout = new PassThrough();
@@ -5814,7 +5814,7 @@ var init_exec = __esm({
5814
5814
  stream.pipe(stdout);
5815
5815
  }
5816
5816
  stream.on("end", () => {
5817
- resolve7({
5817
+ resolve8({
5818
5818
  stdout: Buffer.concat(stdoutChunks).toString("utf-8"),
5819
5819
  stderr: Buffer.concat(stderrChunks).toString("utf-8")
5820
5820
  });
@@ -6188,7 +6188,7 @@ var init_connection = __esm({
6188
6188
  // -----------------------------------------------------------------------
6189
6189
  async exec(host, command) {
6190
6190
  const client = await this.getConnection(host);
6191
- return new Promise((resolve7, reject) => {
6191
+ return new Promise((resolve8, reject) => {
6192
6192
  client.exec(command, (err, stream) => {
6193
6193
  if (err) {
6194
6194
  reject(new Error(`SSH exec failed on ${host}: ${err.message}`));
@@ -6203,7 +6203,7 @@ var init_connection = __esm({
6203
6203
  stderr += data.toString();
6204
6204
  });
6205
6205
  stream.on("close", (code) => {
6206
- resolve7({
6206
+ resolve8({
6207
6207
  exitCode: code ?? 0,
6208
6208
  stdout: stdout.trimEnd(),
6209
6209
  stderr: stderr.trimEnd()
@@ -6234,10 +6234,10 @@ var init_connection = __esm({
6234
6234
  throw new Error(`No SSH configuration found for host: ${host}`);
6235
6235
  }
6236
6236
  const client = new SSHClient();
6237
- return new Promise((resolve7, reject) => {
6237
+ return new Promise((resolve8, reject) => {
6238
6238
  client.on("ready", () => {
6239
6239
  this.connections.set(host, client);
6240
- resolve7(client);
6240
+ resolve8(client);
6241
6241
  }).on("error", (err) => {
6242
6242
  this.connections.delete(host);
6243
6243
  reject(new Error(`SSH connection to ${host} failed: ${err.message}`));
@@ -11420,7 +11420,7 @@ function isCloudflaredAvailable() {
11420
11420
  }
11421
11421
  }
11422
11422
  function startTunnel(port) {
11423
- return new Promise((resolve7, reject) => {
11423
+ return new Promise((resolve8, reject) => {
11424
11424
  const child = spawn("cloudflared", ["tunnel", "--url", `http://localhost:${port}`], {
11425
11425
  stdio: ["ignore", "pipe", "pipe"],
11426
11426
  detached: false
@@ -11441,7 +11441,7 @@ function startTunnel(port) {
11441
11441
  if (match2) {
11442
11442
  resolved = true;
11443
11443
  clearTimeout(timeout);
11444
- resolve7(match2[0]);
11444
+ resolve8(match2[0]);
11445
11445
  }
11446
11446
  }
11447
11447
  child.stdout?.on("data", scan);
@@ -11528,8 +11528,8 @@ var init_dashboard = __esm({
11528
11528
  }
11529
11529
  throw err;
11530
11530
  }
11531
- await new Promise((resolve7, reject) => {
11532
- this.server.on("listening", resolve7);
11531
+ await new Promise((resolve8, reject) => {
11532
+ this.server.on("listening", resolve8);
11533
11533
  this.server.on("error", reject);
11534
11534
  });
11535
11535
  this.info = { localUrl: `http://localhost:${port}` };
@@ -11574,8 +11574,8 @@ var init_dashboard = __esm({
11574
11574
  async stop() {
11575
11575
  stopTunnel();
11576
11576
  if (this.server) {
11577
- await new Promise((resolve7) => {
11578
- this.server.close(() => resolve7());
11577
+ await new Promise((resolve8) => {
11578
+ this.server.close(() => resolve8());
11579
11579
  });
11580
11580
  this.server = null;
11581
11581
  }
@@ -11780,6 +11780,54 @@ var init_context = __esm({
11780
11780
  }
11781
11781
  });
11782
11782
 
11783
+ // src/install-root.ts
11784
+ var install_root_exports = {};
11785
+ __export(install_root_exports, {
11786
+ MissingBuildScriptError: () => MissingBuildScriptError,
11787
+ installRoot: () => installRoot,
11788
+ isDevMode: () => isDevMode,
11789
+ resolveBuildScript: () => resolveBuildScript
11790
+ });
11791
+ import { existsSync as existsSync17 } from "node:fs";
11792
+ import { dirname as dirname13, join as join24, resolve as resolve6 } from "node:path";
11793
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
11794
+ function installRoot(metaUrl = import.meta.url) {
11795
+ const here = fileURLToPath3(metaUrl);
11796
+ return resolve6(dirname13(here), "..");
11797
+ }
11798
+ function isDevMode(env = process.env, installRootDir = installRoot()) {
11799
+ if (env.OLAM_DEV !== "1") return false;
11800
+ const repoRoot = resolve6(installRootDir, "..", "..");
11801
+ return existsSync17(join24(repoRoot, "packages")) && existsSync17(join24(repoRoot, "package.json"));
11802
+ }
11803
+ function resolveBuildScript(input) {
11804
+ const { scriptRelPath, env = process.env, installRootDir = installRoot() } = input;
11805
+ if (!isDevMode(env, installRootDir)) {
11806
+ throw new MissingBuildScriptError(scriptRelPath);
11807
+ }
11808
+ const repoRoot = resolve6(installRootDir, "..", "..");
11809
+ return join24(repoRoot, scriptRelPath);
11810
+ }
11811
+ var MissingBuildScriptError;
11812
+ var init_install_root = __esm({
11813
+ "src/install-root.ts"() {
11814
+ "use strict";
11815
+ MissingBuildScriptError = class extends Error {
11816
+ constructor(scriptRelPath) {
11817
+ super(
11818
+ `Build script ${scriptRelPath} is not available in this CLI install.
11819
+ Source-build paths require a monorepo clone:
11820
+ git clone https://github.com/pleri/olam && cd olam
11821
+ OLAM_DEV=1 olam <command> --from-source
11822
+ For published-image upgrades (Phase B+), drop the --from-source flag
11823
+ and the CLI will pull pre-built images from ghcr.io/pleri/* by digest.`
11824
+ );
11825
+ this.name = "MissingBuildScriptError";
11826
+ }
11827
+ };
11828
+ }
11829
+ });
11830
+
11783
11831
  // src/registry-allowlist.ts
11784
11832
  var registry_allowlist_exports = {};
11785
11833
  __export(registry_allowlist_exports, {
@@ -11900,7 +11948,7 @@ var init_checksum = __esm({
11900
11948
  import { Command } from "commander";
11901
11949
  import * as fs31 from "node:fs";
11902
11950
  import * as path35 from "node:path";
11903
- import { fileURLToPath as fileURLToPath3 } from "node:url";
11951
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
11904
11952
 
11905
11953
  // src/commands/init.ts
11906
11954
  import * as fs5 from "node:fs";
@@ -12504,9 +12552,9 @@ function registerInstall(program2) {
12504
12552
 
12505
12553
  // src/commands/auth.ts
12506
12554
  init_auth();
12507
- import pc7 from "picocolors";
12555
+ import pc8 from "picocolors";
12508
12556
  import * as readline from "node:readline/promises";
12509
- import { spawn as spawn2 } from "node:child_process";
12557
+ import { spawn as spawn3 } from "node:child_process";
12510
12558
 
12511
12559
  // src/commands/auth-status.ts
12512
12560
  import * as fs8 from "node:fs";
@@ -12558,6 +12606,8 @@ init_auth();
12558
12606
  // src/exit-codes.ts
12559
12607
  var EXIT_GENERIC_ERROR = 1;
12560
12608
  var EXIT_PLERI_NOT_CONFIGURED = 2;
12609
+ var EXIT_BOOTSTRAP_PULL_FAILED = 3;
12610
+ var EXIT_PROTOCOL_MISMATCH = 4;
12561
12611
  var EXIT_AUTH_NEEDS_ATTENTION = 5;
12562
12612
 
12563
12613
  // src/commands/auth-status.ts
@@ -12683,8 +12733,9 @@ async function runAuthStatus(getStatus) {
12683
12733
  // src/commands/auth-upgrade.ts
12684
12734
  import * as fs20 from "node:fs";
12685
12735
  import * as path23 from "node:path";
12686
- import { spawnSync as spawnSync4 } from "node:child_process";
12687
- import pc6 from "picocolors";
12736
+ import { spawnSync as spawnSync6 } from "node:child_process";
12737
+ import ora2 from "ora";
12738
+ import pc7 from "picocolors";
12688
12739
 
12689
12740
  // src/commands/host-cp.ts
12690
12741
  init_dist();
@@ -13240,13 +13291,348 @@ async function handleDeregister(opts) {
13240
13291
 
13241
13292
  // src/commands/auth-upgrade.ts
13242
13293
  init_auth();
13294
+
13295
+ // src/commands/bootstrap.ts
13296
+ init_install_root();
13297
+ import { spawn as spawn2, spawnSync as spawnSync5 } from "node:child_process";
13298
+ import { existsSync as existsSync18, readFileSync as readFileSync15 } from "node:fs";
13299
+ import { join as join25 } from "node:path";
13300
+ import ora from "ora";
13301
+ import pc6 from "picocolors";
13302
+
13303
+ // src/protocol-version.ts
13304
+ import { spawnSync as spawnSync4 } from "node:child_process";
13305
+ var OLAM_PROTOCOL_VERSIONS_SUPPORTED = [1];
13306
+ function parseProtocolVersionsLabel(labelValue) {
13307
+ if (!labelValue) return [];
13308
+ const parts = labelValue.split(",").map((s) => s.trim()).filter(Boolean);
13309
+ const versions = /* @__PURE__ */ new Set();
13310
+ for (const part of parts) {
13311
+ const n = Number.parseInt(part, 10);
13312
+ if (Number.isFinite(n) && n > 0 && String(n) === part) {
13313
+ versions.add(n);
13314
+ }
13315
+ }
13316
+ return Array.from(versions).sort((a, b) => a - b);
13317
+ }
13318
+ function checkProtocolOverlap(imageVersions, cliVersions = OLAM_PROTOCOL_VERSIONS_SUPPORTED) {
13319
+ const cliSet = new Set(cliVersions);
13320
+ const overlap = imageVersions.filter((v) => cliSet.has(v));
13321
+ if (imageVersions.length === 0) {
13322
+ return {
13323
+ overlap: [],
13324
+ imageVersions: [],
13325
+ cliVersions,
13326
+ compatible: false,
13327
+ remedy: `Devbox image is missing the \`olam.protocol.versions\` LABEL. This CLI requires versions [${cliVersions.join(", ")}]. See docs/architecture/devbox-contract.md \xA71 for the contract; rebuild the image with \`LABEL olam.protocol.versions="1"\`.`
13328
+ };
13329
+ }
13330
+ if (overlap.length === 0) {
13331
+ const imgLow = Math.min(...imageVersions);
13332
+ const imgHigh = Math.max(...imageVersions);
13333
+ const cliLow = Math.min(...cliVersions);
13334
+ const cliHigh = Math.max(...cliVersions);
13335
+ return {
13336
+ overlap: [],
13337
+ imageVersions: [...imageVersions],
13338
+ cliVersions,
13339
+ compatible: false,
13340
+ remedy: `Devbox image protocol versions [${imageVersions.join(", ")}] don't overlap CLI's [${cliVersions.join(", ")}]. ` + (imgHigh < cliLow ? `The image is older than this CLI supports \u2014 rebuild against the contract version ${cliLow}+ at docs/architecture/devbox-contract.md.` : imgLow > cliHigh ? `The image is newer than this CLI supports \u2014 pin a compatible CLI: \`npm install -g @pleri/olam-cli@<version-with-protocol-${imgLow}>\`.` : `Pin a compatible CLI version that overlaps with the image's range.`)
13341
+ };
13342
+ }
13343
+ return {
13344
+ overlap,
13345
+ imageVersions: [...imageVersions],
13346
+ cliVersions,
13347
+ compatible: true,
13348
+ remedy: ""
13349
+ };
13350
+ }
13351
+
13352
+ // src/commands/bootstrap.ts
13353
+ function loadImageDigests(installRootDir = installRoot()) {
13354
+ const digestsPath = join25(installRootDir, "dist", "image-digests.json");
13355
+ if (!existsSync18(digestsPath)) {
13356
+ throw new Error(
13357
+ `image-digests.json missing at ${digestsPath}. Re-run \`npm install -g @pleri/olam-cli@<version>\` to refresh the tarball.`
13358
+ );
13359
+ }
13360
+ let parsed;
13361
+ try {
13362
+ parsed = JSON.parse(readFileSync15(digestsPath, "utf8"));
13363
+ } catch (err) {
13364
+ throw new Error(`image-digests.json is not valid JSON: ${err.message}`);
13365
+ }
13366
+ if (typeof parsed !== "object" || parsed === null) {
13367
+ throw new Error("image-digests.json is not an object");
13368
+ }
13369
+ const obj = parsed;
13370
+ const required = ["host-cp", "auth", "devbox"];
13371
+ const missing = required.filter((k) => typeof obj[k] !== "string" || !obj[k]);
13372
+ if (missing.length > 0) {
13373
+ throw new Error(
13374
+ `image-digests.json missing required key(s): ${missing.join(", ")}. Tarball may be corrupted; reinstall the CLI.`
13375
+ );
13376
+ }
13377
+ return parsed;
13378
+ }
13379
+ var realDocker = {
13380
+ async info() {
13381
+ return spawnAsync("docker", ["info"]);
13382
+ },
13383
+ async pull(imageRef, opts) {
13384
+ return spawnAsync("docker", ["pull", imageRef], { signal: opts?.signal });
13385
+ },
13386
+ async inspectLabel(imageRef, label) {
13387
+ return spawnAsync("docker", [
13388
+ "inspect",
13389
+ imageRef,
13390
+ "--format",
13391
+ `{{ index .Config.Labels "${label}" }}`
13392
+ ]);
13393
+ }
13394
+ };
13395
+ function spawnAsync(cmd, args, opts = {}) {
13396
+ return new Promise((resolve8) => {
13397
+ const child = spawn2(cmd, [...args], {
13398
+ stdio: ["ignore", "pipe", "pipe"],
13399
+ signal: opts.signal
13400
+ });
13401
+ let stdout = "";
13402
+ let stderr = "";
13403
+ child.stdout?.on("data", (chunk) => {
13404
+ stdout += chunk.toString();
13405
+ });
13406
+ child.stderr?.on("data", (chunk) => {
13407
+ stderr += chunk.toString();
13408
+ });
13409
+ child.on("error", (err) => {
13410
+ resolve8({ exitCode: -1, stdout, stderr: stderr + err.message });
13411
+ });
13412
+ child.on("close", (code) => {
13413
+ resolve8({ exitCode: code ?? -1, stdout, stderr });
13414
+ });
13415
+ });
13416
+ }
13417
+ var inflightPulls = /* @__PURE__ */ new Map();
13418
+ var DEFAULT_PULL_POLICY = {
13419
+ perAttemptTimeoutMs: 18e4,
13420
+ retryOnce: true
13421
+ };
13422
+ function isTransientPullFailure(result) {
13423
+ const s = result.stderr.toLowerCase();
13424
+ return result.exitCode !== 0 && (/timeout|connection|temporarily|429|503|tls handshake|network/.test(s) || result.exitCode === 124 || result.exitCode === -1);
13425
+ }
13426
+ async function pullImageWithRetry(imageRef, docker2 = realDocker, policy = DEFAULT_PULL_POLICY) {
13427
+ const existing = inflightPulls.get(imageRef);
13428
+ if (existing) return existing;
13429
+ const promise = (async () => {
13430
+ let result = await pullOnce(imageRef, docker2, policy.perAttemptTimeoutMs);
13431
+ if (result.exitCode !== 0 && policy.retryOnce && isTransientPullFailure(result)) {
13432
+ result = await pullOnce(imageRef, docker2, policy.perAttemptTimeoutMs);
13433
+ }
13434
+ return result;
13435
+ })();
13436
+ inflightPulls.set(imageRef, promise);
13437
+ try {
13438
+ return await promise;
13439
+ } finally {
13440
+ inflightPulls.delete(imageRef);
13441
+ }
13442
+ }
13443
+ async function pullOnce(imageRef, docker2, timeoutMs) {
13444
+ const ac = new AbortController();
13445
+ const timer = setTimeout(() => ac.abort(), timeoutMs).unref?.();
13446
+ try {
13447
+ return await docker2.pull(imageRef, { signal: ac.signal });
13448
+ } finally {
13449
+ if (timer) clearTimeout(timer);
13450
+ }
13451
+ }
13452
+ var REAL_OLAM_SUBCOMMAND = (args) => {
13453
+ const result = spawnSync5(process.execPath, [
13454
+ process.argv[1] ?? "olam",
13455
+ ...args
13456
+ ], {
13457
+ encoding: "utf8",
13458
+ stdio: ["ignore", "pipe", "pipe"]
13459
+ });
13460
+ return {
13461
+ exitCode: result.status ?? -1,
13462
+ stdout: result.stdout ?? "",
13463
+ stderr: result.stderr ?? ""
13464
+ };
13465
+ };
13466
+ async function runBootstrap2(opts, deps = {}) {
13467
+ const docker2 = deps.docker ?? realDocker;
13468
+ const digests = deps.digests ?? loadImageDigests();
13469
+ const registry = opts.registry ?? deps.registry ?? digests.$registry ?? "ghcr.io/pleri";
13470
+ printHeader("olam bootstrap");
13471
+ const infoSpinner = ora("Checking docker daemon").start();
13472
+ const info = await docker2.info();
13473
+ if (info.exitCode !== 0) {
13474
+ infoSpinner.fail("docker daemon not reachable");
13475
+ process.stderr.write(
13476
+ `${pc6.red("error")} docker info exited with ${info.exitCode}.
13477
+ Ensure Docker Desktop / Colima / Rancher is running, then retry.
13478
+ stderr: ${info.stderr.split("\n")[0] ?? ""}
13479
+ `
13480
+ );
13481
+ return { exitCode: EXIT_GENERIC_ERROR, summary: "docker daemon not reachable" };
13482
+ }
13483
+ infoSpinner.succeed("docker daemon reachable");
13484
+ const imageRefs = [
13485
+ { name: "host-cp", ref: `${registry}/olam-host-cp@${digests["host-cp"]}` },
13486
+ { name: "auth", ref: `${registry}/olam-auth@${digests.auth}` },
13487
+ { name: "devbox", ref: `${registry}/olam-devbox@${digests.devbox}` }
13488
+ ];
13489
+ const pullSpinner = ora("Pulling images (3 parallel)").start();
13490
+ const pullStart = Date.now();
13491
+ const pullResults = await Promise.all(
13492
+ imageRefs.map(async ({ name, ref }) => ({
13493
+ name,
13494
+ ref,
13495
+ result: await pullImageWithRetry(ref, docker2)
13496
+ }))
13497
+ );
13498
+ const pullElapsed = ((Date.now() - pullStart) / 1e3).toFixed(1);
13499
+ const failed = pullResults.filter((r) => r.result.exitCode !== 0);
13500
+ if (failed.length > 0) {
13501
+ pullSpinner.fail(`Pull failed for ${failed.map((r) => r.name).join(", ")}`);
13502
+ for (const f of failed) {
13503
+ process.stderr.write(
13504
+ ` ${pc6.red(f.name)} (${f.ref}):
13505
+ exit=${f.result.exitCode}
13506
+ stderr: ${f.result.stderr.split("\n")[0] ?? "(empty)"}
13507
+ `
13508
+ );
13509
+ }
13510
+ process.stderr.write(
13511
+ "\n Remedy: `olam bootstrap` is the only on-ramp. Re-run after\n resolving network / GHCR availability. If a specific image is\n permanently unavailable, file a bug at github.com/pleri/olam/issues.\n"
13512
+ );
13513
+ return {
13514
+ exitCode: EXIT_BOOTSTRAP_PULL_FAILED,
13515
+ summary: `pull failed: ${failed.map((r) => r.name).join(", ")}`
13516
+ };
13517
+ }
13518
+ pullSpinner.succeed(`Pulled 3 images in ${pullElapsed}s`);
13519
+ const handshakeSpinner = ora("Verifying olam.protocol.versions handshake").start();
13520
+ for (const { name, ref } of imageRefs) {
13521
+ const inspect = await docker2.inspectLabel(ref, "olam.protocol.versions");
13522
+ if (inspect.exitCode !== 0) {
13523
+ handshakeSpinner.fail(`Could not inspect ${name}`);
13524
+ process.stderr.write(
13525
+ `${pc6.red("error")} docker inspect ${ref} failed: ${inspect.stderr}
13526
+ `
13527
+ );
13528
+ return { exitCode: EXIT_GENERIC_ERROR, summary: `inspect failed: ${name}` };
13529
+ }
13530
+ const labelValue = (inspect.stdout || "").trim();
13531
+ const versions = parseProtocolVersionsLabel(
13532
+ labelValue === "<no value>" ? "" : labelValue
13533
+ );
13534
+ const decision = checkProtocolOverlap(versions);
13535
+ if (!decision.compatible) {
13536
+ handshakeSpinner.fail(`Protocol mismatch on ${name}`);
13537
+ process.stderr.write(`${pc6.red("error")} ${decision.remedy}
13538
+ `);
13539
+ return {
13540
+ exitCode: EXIT_PROTOCOL_MISMATCH,
13541
+ summary: `protocol mismatch: ${name}`
13542
+ };
13543
+ }
13544
+ }
13545
+ handshakeSpinner.succeed("Protocol handshake passed (all 3 images)");
13546
+ const runOlam = deps.runOlamSubcommand ?? REAL_OLAM_SUBCOMMAND;
13547
+ const hostCpSpinner = ora("Starting host-cp").start();
13548
+ const hostCp = runOlam(["host-cp", "start"]);
13549
+ if (hostCp.exitCode !== 0) {
13550
+ hostCpSpinner.fail("host-cp start failed");
13551
+ process.stderr.write(` stderr: ${hostCp.stderr.split("\n").slice(0, 3).join("\n ")}
13552
+ `);
13553
+ return { exitCode: EXIT_GENERIC_ERROR, summary: "host-cp start failed" };
13554
+ }
13555
+ hostCpSpinner.succeed("host-cp running");
13556
+ const authUpSpinner = ora("Starting auth-service").start();
13557
+ const authUp = runOlam(["auth", "up"]);
13558
+ if (authUp.exitCode !== 0) {
13559
+ authUpSpinner.fail("auth up failed");
13560
+ process.stderr.write(` stderr: ${authUp.stderr.split("\n").slice(0, 3).join("\n ")}
13561
+ `);
13562
+ return { exitCode: EXIT_GENERIC_ERROR, summary: "auth up failed" };
13563
+ }
13564
+ authUpSpinner.succeed("auth-service running");
13565
+ if (opts.skipAuthLogin || process.env.OLAM_BOOTSTRAP_SKIP_AUTH_LOGIN === "1") {
13566
+ printInfo("auth login", "skipped");
13567
+ } else {
13568
+ printHeader("Authenticate with Anthropic");
13569
+ process.stdout.write(
13570
+ " This opens an OAuth PKCE flow against Anthropic. The auth-service\n will hold your refresh token; per-world access tokens are issued\n on demand and rotated every 6h.\n\n Press Ctrl+C to cancel \u2014 re-run `olam bootstrap` to retry.\n\n"
13571
+ );
13572
+ const login = runOlam(["auth", "login"]);
13573
+ if (login.exitCode !== 0) {
13574
+ printError("auth login failed (or was cancelled)");
13575
+ process.stderr.write(` Re-run \`olam bootstrap\` after resolving.
13576
+ `);
13577
+ return { exitCode: EXIT_GENERIC_ERROR, summary: "auth login failed" };
13578
+ }
13579
+ printSuccess("auth login complete");
13580
+ }
13581
+ if (opts.withSmoke) {
13582
+ printHeader("Smoke test");
13583
+ const smoke = runOlam([
13584
+ "create",
13585
+ "--workspace",
13586
+ "smoke",
13587
+ "--task",
13588
+ "smoke test from olam bootstrap"
13589
+ ]);
13590
+ if (smoke.exitCode !== 0) {
13591
+ printError("smoke world create failed");
13592
+ process.stderr.write(` stderr: ${smoke.stderr.split("\n").slice(0, 3).join("\n ")}
13593
+ `);
13594
+ return { exitCode: EXIT_GENERIC_ERROR, summary: "smoke create failed" };
13595
+ }
13596
+ printSuccess("Smoke world created");
13597
+ }
13598
+ printHeader("Stack ready");
13599
+ printInfo("host-cp", `running (${digests["host-cp"].slice(0, 19)}\u2026)`);
13600
+ printInfo("auth", `running (${digests.auth.slice(0, 19)}\u2026)`);
13601
+ printInfo("devbox", `pulled (${digests.devbox.slice(0, 19)}\u2026)`);
13602
+ printInfo("next", '`olam create --task "your task"` to spawn a world');
13603
+ return { exitCode: 0, summary: "stack ready" };
13604
+ }
13605
+ function registerBootstrap(program2) {
13606
+ program2.command("bootstrap").description(
13607
+ "Bootstrap the olam stack: pull 3 images by digest, verify protocol handshake, start host-cp + auth, run auth login."
13608
+ ).option("--with-smoke", "After bootstrap, create a smoke-test world to verify end-to-end").option("--skip-auth-login", "Skip the interactive PKCE step (CI / scripted use only)").option(
13609
+ "--registry <ref>",
13610
+ "Override the registry prefix (default: read from image-digests.json or fall back to ghcr.io/pleri)"
13611
+ ).action(async (opts) => {
13612
+ try {
13613
+ const result = await runBootstrap2({
13614
+ withSmoke: opts.withSmoke === true,
13615
+ skipAuthLogin: opts.skipAuthLogin === true,
13616
+ registry: opts.registry
13617
+ });
13618
+ process.exitCode = result.exitCode;
13619
+ } catch (err) {
13620
+ printError(err instanceof Error ? err.message : String(err));
13621
+ process.exitCode = EXIT_GENERIC_ERROR;
13622
+ }
13623
+ });
13624
+ }
13625
+
13626
+ // src/commands/auth-upgrade.ts
13627
+ init_install_root();
13243
13628
  var AUTH_PORT = 9999;
13244
13629
  var AUTH_HEALTH_URL = `http://127.0.0.1:${AUTH_PORT}/health`;
13245
13630
  var AUTH_ADD_URL = `http://127.0.0.1:${AUTH_PORT}/credentials/add`;
13246
13631
  function parseAuthUpgradeOpts(raw) {
13247
13632
  return {
13248
13633
  yes: raw.yes === true,
13249
- skipRecreate: raw.skipRecreate === true
13634
+ skipRecreate: raw.skipRecreate === true,
13635
+ fromSource: raw.fromSource === true
13250
13636
  };
13251
13637
  }
13252
13638
  function validateAuthRepoRoot(cwd) {
@@ -13307,8 +13693,8 @@ async function smokeTestCodexProvider(authSecret) {
13307
13693
  }
13308
13694
  function runStep(label, cmd, args, opts = {}) {
13309
13695
  const start = Date.now();
13310
- process.stdout.write(` ${pc6.dim(label.padEnd(34))}`);
13311
- const result = spawnSync4(cmd, [...args], {
13696
+ process.stdout.write(` ${pc7.dim(label.padEnd(34))}`);
13697
+ const result = spawnSync6(cmd, [...args], {
13312
13698
  encoding: "utf-8",
13313
13699
  stdio: ["ignore", "pipe", "pipe"],
13314
13700
  cwd: opts.cwd ?? process.cwd(),
@@ -13317,7 +13703,7 @@ function runStep(label, cmd, args, opts = {}) {
13317
13703
  const durationMs = Date.now() - start;
13318
13704
  const ok = result.status === 0 && result.error === void 0;
13319
13705
  const dur = `${(durationMs / 1e3).toFixed(1)}s`;
13320
- process.stdout.write(`${ok ? pc6.green("\u2713") : pc6.red("\u2717")} ${dur}
13706
+ process.stdout.write(`${ok ? pc7.green("\u2713") : pc7.red("\u2717")} ${dur}
13321
13707
  `);
13322
13708
  return {
13323
13709
  ok,
@@ -13330,10 +13716,10 @@ async function confirm(message) {
13330
13716
  if (!process.stdin.isTTY) return true;
13331
13717
  const { createInterface: createInterface2 } = await import("node:readline");
13332
13718
  const rl = createInterface2({ input: process.stdin, output: process.stdout });
13333
- return new Promise((resolve7) => {
13719
+ return new Promise((resolve8) => {
13334
13720
  rl.question(`${message} [y/N] `, (answer) => {
13335
13721
  rl.close();
13336
- resolve7(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
13722
+ resolve8(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
13337
13723
  });
13338
13724
  });
13339
13725
  }
@@ -13345,6 +13731,126 @@ function printTimings(timings) {
13345
13731
  }
13346
13732
  printInfo("total", `${(total / 1e3).toFixed(1)}s`);
13347
13733
  }
13734
+ async function runAuthUpgradePullByDigest(deps = {}) {
13735
+ const docker2 = deps.docker ?? realDocker;
13736
+ const digests = deps.digests ?? loadImageDigests();
13737
+ const registry = deps.registry ?? digests.$registry ?? "ghcr.io/pleri";
13738
+ printHeader("olam auth upgrade (pull-by-digest)");
13739
+ const infoSpinner = ora2("Checking docker daemon").start();
13740
+ const info = await docker2.info();
13741
+ if (info.exitCode !== 0) {
13742
+ infoSpinner.fail("docker daemon not reachable");
13743
+ process.stderr.write(
13744
+ `${pc7.red("error")} docker info exited with ${info.exitCode}.
13745
+ Ensure Docker is running, then retry.
13746
+ `
13747
+ );
13748
+ return { exitCode: EXIT_GENERIC_ERROR, summary: "docker daemon not reachable" };
13749
+ }
13750
+ infoSpinner.succeed("docker daemon reachable");
13751
+ const ref = `${registry}/olam-auth@${digests.auth}`;
13752
+ const pullSpinner = ora2(`Pulling ${ref.slice(0, 60)}\u2026`).start();
13753
+ const pullResult = await pullImageWithRetry(ref, docker2);
13754
+ if (pullResult.exitCode !== 0) {
13755
+ pullSpinner.fail("Pull failed");
13756
+ process.stderr.write(
13757
+ `${pc7.red("error")} pull failed (exit ${pullResult.exitCode}):
13758
+ ${pullResult.stderr.split("\n")[0] ?? "(empty)"}
13759
+
13760
+ Remedy: re-run after resolving network / GHCR availability.
13761
+ For monorepo dev, \`OLAM_DEV=1 olam auth upgrade --from-source\` builds locally.
13762
+ `
13763
+ );
13764
+ return { exitCode: EXIT_BOOTSTRAP_PULL_FAILED, summary: "pull failed: auth" };
13765
+ }
13766
+ pullSpinner.succeed("Image pulled");
13767
+ const handshakeSpinner = ora2("Verifying olam.protocol.versions handshake").start();
13768
+ const inspect = await docker2.inspectLabel(ref, "olam.protocol.versions");
13769
+ if (inspect.exitCode !== 0) {
13770
+ handshakeSpinner.fail("Could not inspect auth image");
13771
+ process.stderr.write(
13772
+ `${pc7.red("error")} docker inspect ${ref} failed: ${inspect.stderr}
13773
+ `
13774
+ );
13775
+ return { exitCode: EXIT_GENERIC_ERROR, summary: "inspect failed: auth" };
13776
+ }
13777
+ const labelValue = (inspect.stdout || "").trim();
13778
+ const versions = parseProtocolVersionsLabel(
13779
+ labelValue === "<no value>" ? "" : labelValue
13780
+ );
13781
+ const decision = checkProtocolOverlap(versions);
13782
+ if (!decision.compatible) {
13783
+ handshakeSpinner.fail("Protocol mismatch on auth image");
13784
+ process.stderr.write(`${pc7.red("error")} ${decision.remedy}
13785
+ `);
13786
+ return { exitCode: EXIT_PROTOCOL_MISMATCH, summary: "protocol mismatch: auth" };
13787
+ }
13788
+ handshakeSpinner.succeed("Protocol handshake passed");
13789
+ const tagSpinner = ora2("Tagging digest \u2192 olam-auth:local").start();
13790
+ const tagger = deps.tagImpl ?? defaultTagAuth;
13791
+ const tagResult = tagger(ref, "olam-auth:local");
13792
+ if (!tagResult.ok) {
13793
+ tagSpinner.fail("docker tag failed");
13794
+ process.stderr.write(`${pc7.red("error")} ${tagResult.error ?? "docker tag failed"}
13795
+ `);
13796
+ return { exitCode: EXIT_GENERIC_ERROR, summary: "tag failed: auth" };
13797
+ }
13798
+ tagSpinner.succeed("Re-tagged \u2192 olam-auth:local");
13799
+ const authSpinner = ora2("Recreating auth-service container").start();
13800
+ const recreate = deps.recreateAuth ?? defaultRecreateAuth;
13801
+ const recreateResult = await recreate();
13802
+ if (!recreateResult.ok) {
13803
+ authSpinner.fail("auth-service recreate failed");
13804
+ process.stderr.write(
13805
+ `${pc7.red("error")} ${recreateResult.error ?? "unknown failure"}
13806
+ `
13807
+ );
13808
+ return { exitCode: EXIT_GENERIC_ERROR, summary: "auth recreate failed" };
13809
+ }
13810
+ authSpinner.succeed("auth-service running on new image");
13811
+ printSuccess("Auth upgrade complete (pull-by-digest)");
13812
+ printInfo("digest", digests.auth.slice(0, 32) + "\u2026");
13813
+ return { exitCode: 0, summary: "auth upgraded" };
13814
+ }
13815
+ function defaultTagAuth(from, to) {
13816
+ try {
13817
+ const r = spawnSync6("docker", ["tag", from, to], {
13818
+ encoding: "utf-8",
13819
+ stdio: ["ignore", "ignore", "pipe"]
13820
+ });
13821
+ if (r.status === 0 && r.error === void 0) return { ok: true };
13822
+ return {
13823
+ ok: false,
13824
+ error: (r.stderr ?? "").trim() || r.error?.message || "docker tag failed"
13825
+ };
13826
+ } catch (err) {
13827
+ return {
13828
+ ok: false,
13829
+ error: err instanceof Error ? `spawnSync threw: ${err.message}` : "spawnSync threw"
13830
+ };
13831
+ }
13832
+ }
13833
+ async function defaultRecreateAuth() {
13834
+ try {
13835
+ spawnSync6("docker", ["stop", "olam-auth"], {
13836
+ encoding: "utf-8",
13837
+ stdio: ["ignore", "ignore", "ignore"]
13838
+ });
13839
+ spawnSync6("docker", ["rm", "olam-auth"], {
13840
+ encoding: "utf-8",
13841
+ stdio: ["ignore", "ignore", "ignore"]
13842
+ });
13843
+ const controller = new AuthContainerController();
13844
+ controller.start();
13845
+ const healthy = await waitForAuthHealth(15e3);
13846
+ if (!healthy) {
13847
+ return { ok: false, error: "auth-service /health did not respond within 15s" };
13848
+ }
13849
+ return { ok: true };
13850
+ } catch (err) {
13851
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
13852
+ }
13853
+ }
13348
13854
  async function handleAuthUpgrade(opts) {
13349
13855
  const cwd = process.cwd();
13350
13856
  const rootCheck = validateAuthRepoRoot(cwd);
@@ -13372,7 +13878,17 @@ async function handleAuthUpgrade(opts) {
13372
13878
  }
13373
13879
  }
13374
13880
  const timings = [];
13375
- const buildScript = path23.join(cwd, "packages/adapters/src/docker/build-auth.sh");
13881
+ let buildScript;
13882
+ try {
13883
+ const { resolveBuildScript: resolveBuildScript2 } = await Promise.resolve().then(() => (init_install_root(), install_root_exports));
13884
+ buildScript = resolveBuildScript2({
13885
+ scriptRelPath: "packages/adapters/src/docker/build-auth.sh"
13886
+ });
13887
+ } catch (err) {
13888
+ printError(err instanceof Error ? err.message : String(err));
13889
+ process.exitCode = 1;
13890
+ return;
13891
+ }
13376
13892
  const imageResult = runStep("bash build-auth.sh", "bash", [buildScript], { cwd });
13377
13893
  timings.push({ label: "docker image build", durationMs: imageResult.durationMs });
13378
13894
  if (!imageResult.ok) {
@@ -13388,49 +13904,49 @@ ${imageResult.stderr}`);
13388
13904
  return;
13389
13905
  }
13390
13906
  const stopStart = Date.now();
13391
- process.stdout.write(` ${pc6.dim("docker stop olam-auth".padEnd(34))}`);
13392
- spawnSync4("docker", ["stop", "olam-auth"], {
13907
+ process.stdout.write(` ${pc7.dim("docker stop olam-auth".padEnd(34))}`);
13908
+ spawnSync6("docker", ["stop", "olam-auth"], {
13393
13909
  encoding: "utf-8",
13394
13910
  stdio: ["ignore", "pipe", "pipe"]
13395
13911
  });
13396
13912
  const stopDurationMs = Date.now() - stopStart;
13397
- process.stdout.write(`${pc6.green("\u2713")} ${(stopDurationMs / 1e3).toFixed(1)}s
13913
+ process.stdout.write(`${pc7.green("\u2713")} ${(stopDurationMs / 1e3).toFixed(1)}s
13398
13914
  `);
13399
13915
  timings.push({ label: "container stop", durationMs: stopDurationMs });
13400
13916
  const rmStart = Date.now();
13401
- process.stdout.write(` ${pc6.dim("docker rm olam-auth".padEnd(34))}`);
13402
- spawnSync4("docker", ["rm", "olam-auth"], {
13917
+ process.stdout.write(` ${pc7.dim("docker rm olam-auth".padEnd(34))}`);
13918
+ spawnSync6("docker", ["rm", "olam-auth"], {
13403
13919
  encoding: "utf-8",
13404
13920
  stdio: ["ignore", "pipe", "pipe"]
13405
13921
  });
13406
13922
  const rmDurationMs = Date.now() - rmStart;
13407
- process.stdout.write(`${pc6.green("\u2713")} ${(rmDurationMs / 1e3).toFixed(1)}s
13923
+ process.stdout.write(`${pc7.green("\u2713")} ${(rmDurationMs / 1e3).toFixed(1)}s
13408
13924
  `);
13409
13925
  timings.push({ label: "container remove", durationMs: rmDurationMs });
13410
13926
  const startStart = Date.now();
13411
- process.stdout.write(` ${pc6.dim("docker run olam-auth:local".padEnd(34))}`);
13927
+ process.stdout.write(` ${pc7.dim("docker run olam-auth:local".padEnd(34))}`);
13412
13928
  try {
13413
13929
  const controller = new AuthContainerController();
13414
13930
  controller.start();
13415
13931
  const startDurationMs = Date.now() - startStart;
13416
- process.stdout.write(`${pc6.green("\u2713")} ${(startDurationMs / 1e3).toFixed(1)}s
13932
+ process.stdout.write(`${pc7.green("\u2713")} ${(startDurationMs / 1e3).toFixed(1)}s
13417
13933
  `);
13418
13934
  timings.push({ label: "container start", durationMs: startDurationMs });
13419
13935
  } catch (err) {
13420
13936
  const startDurationMs = Date.now() - startStart;
13421
- process.stdout.write(`${pc6.red("\u2717")} ${(startDurationMs / 1e3).toFixed(1)}s
13937
+ process.stdout.write(`${pc7.red("\u2717")} ${(startDurationMs / 1e3).toFixed(1)}s
13422
13938
  `);
13423
13939
  timings.push({ label: "container start", durationMs: startDurationMs });
13424
13940
  printError(`Failed to start auth container: ${err instanceof Error ? err.message : String(err)}`);
13425
13941
  process.exitCode = 1;
13426
13942
  return;
13427
13943
  }
13428
- process.stdout.write(` ${pc6.dim("waiting for /health".padEnd(34))}`);
13944
+ process.stdout.write(` ${pc7.dim("waiting for /health".padEnd(34))}`);
13429
13945
  const healthStart = Date.now();
13430
13946
  const healthy = await waitForAuthHealth(1e4);
13431
13947
  const healthDurationMs = Date.now() - healthStart;
13432
13948
  const healthDur = `${(healthDurationMs / 1e3).toFixed(1)}s`;
13433
- process.stdout.write(`${healthy ? pc6.green("\u2713") : pc6.yellow("?")} ${healthDur}
13949
+ process.stdout.write(`${healthy ? pc7.green("\u2713") : pc7.yellow("?")} ${healthDur}
13434
13950
  `);
13435
13951
  timings.push({ label: "/health", durationMs: healthDurationMs });
13436
13952
  if (!healthy) {
@@ -13439,13 +13955,13 @@ ${imageResult.stderr}`);
13439
13955
  printTimings(timings);
13440
13956
  return;
13441
13957
  }
13442
- process.stdout.write(` ${pc6.dim("smoke test: codex provider".padEnd(34))}`);
13958
+ process.stdout.write(` ${pc7.dim("smoke test: codex provider".padEnd(34))}`);
13443
13959
  const smokeStart = Date.now();
13444
13960
  const authSecret = readAuthSecret2();
13445
13961
  const smoke = await smokeTestCodexProvider(authSecret);
13446
13962
  const smokeDurationMs = Date.now() - smokeStart;
13447
13963
  const smokeDur = `${(smokeDurationMs / 1e3).toFixed(1)}s`;
13448
- process.stdout.write(`${smoke.ok ? pc6.green("\u2713") : pc6.red("\u2717")} ${smokeDur}
13964
+ process.stdout.write(`${smoke.ok ? pc7.green("\u2713") : pc7.red("\u2717")} ${smokeDur}
13449
13965
  `);
13450
13966
  timings.push({ label: "smoke test", durationMs: smokeDurationMs });
13451
13967
  if (!smoke.ok) {
@@ -13460,8 +13976,31 @@ ${imageResult.stderr}`);
13460
13976
  printTimings(timings);
13461
13977
  }
13462
13978
  function registerAuthUpgrade(auth) {
13463
- auth.command("upgrade").description("Rebuild the olam-auth image and force-recreate the container").option("-y, --yes", "Skip the confirmation prompt").option("--skip-recreate", "Build the image only; skip container stop/rm/start").action(async (opts) => {
13464
- await handleAuthUpgrade(parseAuthUpgradeOpts(opts));
13979
+ auth.command("upgrade").description(
13980
+ "Upgrade the olam-auth container. Default: pull olam-auth@<digest> from ghcr.io and recreate. Use --from-source to rebuild from monorepo source (requires OLAM_DEV=1)."
13981
+ ).option("-y, --yes", "Skip the confirmation prompt").option("--skip-recreate", "Build the image only; skip container stop/rm/start (only with --from-source)").option(
13982
+ "--from-source",
13983
+ "Build olam-auth from monorepo source (legacy path).\n Requires OLAM_DEV=1 + a `packages/` sibling at the install root."
13984
+ ).action(async (opts) => {
13985
+ const parsed = parseAuthUpgradeOpts(opts);
13986
+ if (parsed.fromSource) {
13987
+ if (!isDevMode()) {
13988
+ printError(
13989
+ new MissingBuildScriptError("packages/adapters/src/docker/build-auth.sh").message
13990
+ );
13991
+ process.exitCode = 1;
13992
+ return;
13993
+ }
13994
+ await handleAuthUpgrade(parsed);
13995
+ return;
13996
+ }
13997
+ try {
13998
+ const result = await runAuthUpgradePullByDigest();
13999
+ process.exitCode = result.exitCode;
14000
+ } catch (err) {
14001
+ printError(err instanceof Error ? err.message : String(err));
14002
+ process.exitCode = EXIT_GENERIC_ERROR;
14003
+ }
13465
14004
  });
13466
14005
  }
13467
14006
 
@@ -13469,7 +14008,7 @@ function registerAuthUpgrade(auth) {
13469
14008
  function openBrowser(url) {
13470
14009
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
13471
14010
  try {
13472
- const child = spawn2(cmd, [url], { detached: true, stdio: "ignore" });
14011
+ const child = spawn3(cmd, [url], { detached: true, stdio: "ignore" });
13473
14012
  child.unref();
13474
14013
  } catch {
13475
14014
  }
@@ -13509,7 +14048,7 @@ function registerAuth(program2) {
13509
14048
  printInfo("Port", String(initial.port));
13510
14049
  printInfo("Volume", "olam-auth-data");
13511
14050
  console.log(`
13512
- ${pc7.dim("Next: olam auth login")}`);
14051
+ ${pc8.dim("Next: olam auth login")}`);
13513
14052
  });
13514
14053
  auth.command("down").description("Stop the auth container (tokens persist in the volume)").action(() => {
13515
14054
  const controller = new AuthContainerController();
@@ -13534,15 +14073,15 @@ ${pc7.dim("Next: olam auth login")}`);
13534
14073
  }
13535
14074
  printHeader(`Credentials (${status.accounts.length})`);
13536
14075
  if (status.accounts.length === 0) {
13537
- console.log(` ${pc7.dim("No credentials \u2014 run: olam auth login --label primary")}`);
14076
+ console.log(` ${pc8.dim("No credentials \u2014 run: olam auth login --label primary")}`);
13538
14077
  return;
13539
14078
  }
13540
14079
  const stateColor = (s) => {
13541
- if (s === "active") return pc7.green("active");
13542
- if (s === "cooldown") return pc7.yellow("cooldown");
13543
- if (s === "expired") return pc7.red("expired");
13544
- if (s === "disabled") return pc7.dim("disabled");
13545
- return pc7.dim(s ?? "unknown");
14080
+ if (s === "active") return pc8.green("active");
14081
+ if (s === "cooldown") return pc8.yellow("cooldown");
14082
+ if (s === "expired") return pc8.red("expired");
14083
+ if (s === "disabled") return pc8.dim("disabled");
14084
+ return pc8.dim(s ?? "unknown");
13546
14085
  };
13547
14086
  for (const a of status.accounts) {
13548
14087
  const label = a.accountLabel ?? a.id;
@@ -13550,7 +14089,7 @@ ${pc7.dim("Next: olam auth login")}`);
13550
14089
  const last429 = a.usage?.last429At ? `last429=${a.usage.last429At}` : "last429=never";
13551
14090
  const reset = a.rateLimitResetsAt ? `resets=${a.rateLimitResetsAt}` : "";
13552
14091
  console.log(
13553
- ` ${pc7.bold(label.padEnd(18))} ${stateColor(a.state).padEnd(18)} ${pc7.dim(`req5h=${reqs}`)} ${pc7.dim(`exp=${a.expiresIn}`)} ${pc7.dim(last429)} ${pc7.yellow(reset)}`
14092
+ ` ${pc8.bold(label.padEnd(18))} ${stateColor(a.state).padEnd(18)} ${pc8.dim(`req5h=${reqs}`)} ${pc8.dim(`exp=${a.expiresIn}`)} ${pc8.dim(last429)} ${pc8.yellow(reset)}`
13554
14093
  );
13555
14094
  }
13556
14095
  });
@@ -13588,7 +14127,7 @@ ${pc7.dim("Next: olam auth login")}`);
13588
14127
  const preflight = await runAuthPreflight({ autoStart: true });
13589
14128
  if (preflight.verdict !== "ok" && preflight.verdict !== "no-accounts") {
13590
14129
  printError(preflight.message);
13591
- console.log(` ${pc7.dim(preflight.remedy)}`);
14130
+ console.log(` ${pc8.dim(preflight.remedy)}`);
13592
14131
  process.exitCode = 1;
13593
14132
  return;
13594
14133
  }
@@ -13621,14 +14160,14 @@ ${pc7.dim("Next: olam auth login")}`);
13621
14160
  }
13622
14161
  printHeader("Claude OAuth \u2014 PKCE flow");
13623
14162
  console.log(`
13624
- ${pc7.bold("1.")} Opening Claude in your default browser\u2026`);
13625
- console.log(` ${pc7.dim(pending.loginUrl)}`);
14163
+ ${pc8.bold("1.")} Opening Claude in your default browser\u2026`);
14164
+ console.log(` ${pc8.dim(pending.loginUrl)}`);
13626
14165
  openBrowser(pending.loginUrl);
13627
14166
  console.log(`
13628
- ${pc7.bold("2.")} After approving, paste the authorization code from the redirect page.`);
13629
- console.log(` ${pc7.dim("(Format: <code>#<state> or just <code>.)")}
14167
+ ${pc8.bold("2.")} After approving, paste the authorization code from the redirect page.`);
14168
+ console.log(` ${pc8.dim("(Format: <code>#<state> or just <code>.)")}
13630
14169
  `);
13631
- const raw = await promptLine(`${pc7.dim("code:")} `);
14170
+ const raw = await promptLine(`${pc8.dim("code:")} `);
13632
14171
  if (!raw) {
13633
14172
  printError("No code provided.");
13634
14173
  process.exitCode = 1;
@@ -13639,7 +14178,7 @@ ${pc7.dim("Next: olam auth login")}`);
13639
14178
  const result = await client.completeLogin(statePart, codePart);
13640
14179
  printSuccess(`Account stored: ${result.account} (${result.expiresIn})`);
13641
14180
  console.log(`
13642
- ${pc7.dim("Next: olam create --name my-world")}`);
14181
+ ${pc8.dim("Next: olam create --name my-world")}`);
13643
14182
  } catch (err) {
13644
14183
  printError(err instanceof Error ? err.message : "token exchange failed");
13645
14184
  process.exitCode = 1;
@@ -13670,16 +14209,16 @@ ${pc7.dim("Next: olam create --name my-world")}`);
13670
14209
 
13671
14210
  // src/commands/create.ts
13672
14211
  init_manager();
13673
- import { spawnSync as spawnSync5 } from "node:child_process";
13674
- import { existsSync as existsSync19 } from "node:fs";
13675
- import { dirname as dirname13, resolve as resolve6 } from "node:path";
13676
- import ora from "ora";
13677
- import pc8 from "picocolors";
14212
+ import { spawnSync as spawnSync7 } from "node:child_process";
14213
+ import { existsSync as existsSync21 } from "node:fs";
14214
+ import { dirname as dirname14, resolve as resolve7 } from "node:path";
14215
+ import ora3 from "ora";
14216
+ import pc9 from "picocolors";
13678
14217
 
13679
14218
  // ../core/src/world/devbox-freshness.ts
13680
14219
  import { execSync as execSync6 } from "node:child_process";
13681
- import { existsSync as existsSync18, statSync as statSync5 } from "node:fs";
13682
- import { join as join25 } from "node:path";
14220
+ import { existsSync as existsSync20, statSync as statSync5 } from "node:fs";
14221
+ import { join as join27 } from "node:path";
13683
14222
  var DEFAULT_DEVBOX_IMAGE = "olam-devbox:latest";
13684
14223
  var DEVBOX_BAKED_SOURCES = [
13685
14224
  "packages/adapters/src/docker/devbox.Dockerfile",
@@ -13714,7 +14253,7 @@ function getDevboxFreshness(deps) {
13714
14253
  }
13715
14254
  const newerSources = [];
13716
14255
  for (const relPath of DEVBOX_BAKED_SOURCES) {
13717
- const absPath = join25(deps.repoRoot, relPath);
14256
+ const absPath = join27(deps.repoRoot, relPath);
13718
14257
  const mtimeMs = statMtime(absPath);
13719
14258
  if (mtimeMs === null) continue;
13720
14259
  if (mtimeMs > imageCreatedAtMs) {
@@ -13768,7 +14307,7 @@ function defaultDockerInspect(image) {
13768
14307
  }
13769
14308
  function defaultStatMtime(absPath) {
13770
14309
  try {
13771
- if (!existsSync18(absPath)) return null;
14310
+ if (!existsSync20(absPath)) return null;
13772
14311
  return statSync5(absPath).mtimeMs;
13773
14312
  } catch {
13774
14313
  return null;
@@ -13955,7 +14494,7 @@ function registerCreate(program2) {
13955
14494
  resolvedName = defaultNameFromPrompt(opts.fromPrompt);
13956
14495
  }
13957
14496
  if (!resolvedWorkspace && !resolvedRepos) {
13958
- const inferenceSpinner = ora("Inferring workspace from prompt\u2026").start();
14497
+ const inferenceSpinner = ora3("Inferring workspace from prompt\u2026").start();
13959
14498
  try {
13960
14499
  const catalog = await fetchHostCpWorkspaces();
13961
14500
  const catalogRepos = Array.from(
@@ -13970,9 +14509,9 @@ function registerCreate(program2) {
13970
14509
  const reason = inferred.repos.length === 0 ? "no repo names extracted from prompt" : `inference confidence ${inferred.confidence.toFixed(2)} below ${PICKER_CONFIDENCE_THRESHOLD}`;
13971
14510
  printError(`Picker needed: ${reason}`);
13972
14511
  if (catalogRepos.length > 0) {
13973
- console.log(pc8.dim(` available repos: ${catalogRepos.join(", ")}`));
14512
+ console.log(pc9.dim(` available repos: ${catalogRepos.join(", ")}`));
13974
14513
  }
13975
- console.log(pc8.dim(" rerun with explicit --workspace <name> or --repos <a> <b> <c>"));
14514
+ console.log(pc9.dim(" rerun with explicit --workspace <name> or --repos <a> <b> <c>"));
13976
14515
  process.exitCode = 1;
13977
14516
  return;
13978
14517
  }
@@ -13990,7 +14529,7 @@ function registerCreate(program2) {
13990
14529
  inferenceSpinner.fail(`Multiple workspaces match (${decision.result})`);
13991
14530
  const cands = decision.result === "exact-N" ? decision.candidates.map((w) => w.name) : decision.candidates.map((c) => c.workspace.name);
13992
14531
  printError(`Picker needed: ${cands.join(", ")}`);
13993
- console.log(pc8.dim(" rerun with explicit --workspace <name>"));
14532
+ console.log(pc9.dim(" rerun with explicit --workspace <name>"));
13994
14533
  process.exitCode = 1;
13995
14534
  return;
13996
14535
  } else {
@@ -14023,10 +14562,24 @@ function registerCreate(program2) {
14023
14562
  const freshness = getDevboxFreshness({ repoRoot });
14024
14563
  if (freshness.isStale) {
14025
14564
  if (opts.rebuildBase) {
14026
- const spinner2 = ora("Rebuilding olam-devbox:latest\u2026").start();
14027
- const rebuild = spawnSync5(
14565
+ const { resolveBuildScript: resolveBuildScript2, MissingBuildScriptError: MissingBuildScriptError2 } = await Promise.resolve().then(() => (init_install_root(), install_root_exports));
14566
+ let buildScript;
14567
+ try {
14568
+ buildScript = resolveBuildScript2({
14569
+ scriptRelPath: "packages/adapters/src/docker/build-devbox.sh"
14570
+ });
14571
+ } catch (err) {
14572
+ if (err instanceof MissingBuildScriptError2) {
14573
+ printError(err.message);
14574
+ process.exitCode = 1;
14575
+ return;
14576
+ }
14577
+ throw err;
14578
+ }
14579
+ const spinner2 = ora3("Rebuilding olam-devbox:latest\u2026").start();
14580
+ const rebuild = spawnSync7(
14028
14581
  "bash",
14029
- [resolve6(repoRoot, "packages/adapters/src/docker/build-devbox.sh")],
14582
+ [buildScript],
14030
14583
  { cwd: repoRoot, stdio: "inherit" }
14031
14584
  );
14032
14585
  if (rebuild.status !== 0) {
@@ -14041,7 +14594,7 @@ function registerCreate(program2) {
14041
14594
  }
14042
14595
  }
14043
14596
  }
14044
- const spinner = ora("Creating world...").start();
14597
+ const spinner = ora3("Creating world...").start();
14045
14598
  try {
14046
14599
  const world = await ctx.worldManager.createWorld({
14047
14600
  name: resolvedName,
@@ -14090,10 +14643,10 @@ function registerCreate(program2) {
14090
14643
  }
14091
14644
  if (world.credentialsInjected?.claude) {
14092
14645
  console.log(`
14093
- ${pc8.green("Credentials injected. World is ready for dispatch.")}`);
14646
+ ${pc9.green("Credentials injected. World is ready for dispatch.")}`);
14094
14647
  } else if (world.dashboardUrl) {
14095
14648
  console.log(`
14096
- ${pc8.yellow("Authenticate at")} ${world.dashboardUrl}`);
14649
+ ${pc9.yellow("Authenticate at")} ${world.dashboardUrl}`);
14097
14650
  }
14098
14651
  if (opts.hostCp !== false) {
14099
14652
  const probeResult = await probeHostCp().catch(() => null);
@@ -14105,14 +14658,14 @@ ${pc8.yellow("Authenticate at")} ${world.dashboardUrl}`);
14105
14658
  process.stderr.write(
14106
14659
  [
14107
14660
  "",
14108
- pc8.red("Host CP probe failed."),
14661
+ pc9.red("Host CP probe failed."),
14109
14662
  ` tried: http://127.0.0.1:19000/api/bootstrap \u2192 ${diag.bootstrapStatus}`,
14110
14663
  ` tried: docker container "olam-host-cp" \u2192 ${diag.containerStatus}`,
14111
14664
  "",
14112
- pc8.yellow("World was created but the SPA inbox will not show it until you:"),
14113
- ` ${pc8.cyan("olam host-cp start")} (start the host CP)`,
14114
- ` ${pc8.cyan(`olam host-cp register --world ${world.id}`)} (register manually)`,
14115
- ` OR pass ${pc8.dim("--no-host-cp")} on next create to suppress this check.`,
14665
+ pc9.yellow("World was created but the SPA inbox will not show it until you:"),
14666
+ ` ${pc9.cyan("olam host-cp start")} (start the host CP)`,
14667
+ ` ${pc9.cyan(`olam host-cp register --world ${world.id}`)} (register manually)`,
14668
+ ` OR pass ${pc9.dim("--no-host-cp")} on next create to suppress this check.`,
14116
14669
  ""
14117
14670
  ].join("\n")
14118
14671
  );
@@ -14144,13 +14697,13 @@ ${pc8.yellow("Authenticate at")} ${world.dashboardUrl}`);
14144
14697
  process.stderr.write(
14145
14698
  [
14146
14699
  "",
14147
- pc8.red("Host CP registry POST failed."),
14700
+ pc9.red("Host CP registry POST failed."),
14148
14701
  ` url: ${hostCpUrl}/api/admin/registry`,
14149
14702
  ` status: ${reg.status}`,
14150
14703
  ` error: ${reg.error}`,
14151
14704
  "",
14152
- pc8.yellow("World was created but not registered. Run manually:"),
14153
- ` ${pc8.cyan(`olam host-cp register --world ${world.id}`)}`,
14705
+ pc9.yellow("World was created but not registered. Run manually:"),
14706
+ ` ${pc9.cyan(`olam host-cp register --world ${world.id}`)}`,
14154
14707
  ""
14155
14708
  ].join("\n")
14156
14709
  );
@@ -14205,7 +14758,7 @@ ${pc8.yellow("Authenticate at")} ${world.dashboardUrl}`);
14205
14758
  }
14206
14759
  const worldUrl = `${hostCpUrl}/world/${encodeURIComponent(world.id)}`;
14207
14760
  console.log(`
14208
- ${pc8.cyan("Host CP UI:")} ${worldUrl}`);
14761
+ ${pc9.cyan("Host CP UI:")} ${worldUrl}`);
14209
14762
  if (opts.open !== false && reg.ok) {
14210
14763
  const openResult = openUrl(worldUrl);
14211
14764
  if (openResult.opened) {
@@ -14219,7 +14772,7 @@ ${pc8.cyan("Host CP UI:")} ${worldUrl}`);
14219
14772
  spinner.fail("Failed to create world");
14220
14773
  if (err instanceof AuthPreflightError) {
14221
14774
  printError(err.message);
14222
- if (err.remedy) console.log(` ${pc8.dim(err.remedy)}`);
14775
+ if (err.remedy) console.log(` ${pc9.dim(err.remedy)}`);
14223
14776
  } else {
14224
14777
  printError(err instanceof Error ? err.message : String(err));
14225
14778
  }
@@ -14230,10 +14783,10 @@ ${pc8.cyan("Host CP UI:")} ${worldUrl}`);
14230
14783
  function resolveRepoRoot(start) {
14231
14784
  let cur = start;
14232
14785
  while (true) {
14233
- if (existsSync19(resolve6(cur, "packages")) && existsSync19(resolve6(cur, "package.json"))) {
14786
+ if (existsSync21(resolve7(cur, "packages")) && existsSync21(resolve7(cur, "package.json"))) {
14234
14787
  return cur;
14235
14788
  }
14236
- const parent = dirname13(cur);
14789
+ const parent = dirname14(cur);
14237
14790
  if (parent === cur) return start;
14238
14791
  cur = parent;
14239
14792
  }
@@ -14292,8 +14845,8 @@ async function fetchHostCpExactMatches(projects) {
14292
14845
 
14293
14846
  // src/commands/dispatch.ts
14294
14847
  init_context();
14295
- import ora2 from "ora";
14296
- import pc9 from "picocolors";
14848
+ import ora4 from "ora";
14849
+ import pc10 from "picocolors";
14297
14850
 
14298
14851
  // ../core/src/orchestrator/dispatch.ts
14299
14852
  var DEEP_MODE_SUFFIX = "\n\nUltrathink and use sub-agents (the Agent tool) to parallelize independent work. Break complex tasks into focused sub-tasks.";
@@ -14319,7 +14872,7 @@ function registerDispatch(program2) {
14319
14872
  process.exitCode = 1;
14320
14873
  return;
14321
14874
  }
14322
- const spinner = ora2("Dispatching...").start();
14875
+ const spinner = ora4("Dispatching...").start();
14323
14876
  try {
14324
14877
  const computeWorld = await ctx.computeProvider.getWorld(worldId);
14325
14878
  if (!computeWorld) {
@@ -14376,7 +14929,7 @@ OLAM_EOF`
14376
14929
  const containerName = `olam-${worldId}-devbox`;
14377
14930
  console.log(
14378
14931
  `
14379
- ${pc9.dim(`Watch live: docker exec -it ${containerName} tmux attach -t claude-main -r`)}`
14932
+ ${pc10.dim(`Watch live: docker exec -it ${containerName} tmux attach -t claude-main -r`)}`
14380
14933
  );
14381
14934
  } catch (err) {
14382
14935
  spinner.fail("Dispatch failed");
@@ -14388,7 +14941,7 @@ ${pc9.dim(`Watch live: docker exec -it ${containerName} tmux attach -t claude-ma
14388
14941
 
14389
14942
  // src/commands/observe.ts
14390
14943
  init_context();
14391
- import pc10 from "picocolors";
14944
+ import pc11 from "picocolors";
14392
14945
  function registerObserve(program2) {
14393
14946
  program2.command("observe").description("Stream thoughts from a world (coming soon)").argument("<world>", "World ID").action(async (worldId) => {
14394
14947
  const { ctx, error } = await loadContext();
@@ -14404,22 +14957,22 @@ function registerObserve(program2) {
14404
14957
  return;
14405
14958
  }
14406
14959
  console.log(
14407
- pc10.yellow("Observation is coming in a future release.")
14960
+ pc11.yellow("Observation is coming in a future release.")
14408
14961
  );
14409
14962
  console.log(
14410
- pc10.dim("This will stream the world's reasoning in real-time.")
14963
+ pc11.dim("This will stream the world's reasoning in real-time.")
14411
14964
  );
14412
14965
  const containerName = `olam-${worldId}-devbox`;
14413
14966
  console.log(
14414
14967
  `
14415
- ${pc10.dim(`For now: docker exec -it ${containerName} tmux attach -t claude-main -r`)}`
14968
+ ${pc11.dim(`For now: docker exec -it ${containerName} tmux attach -t claude-main -r`)}`
14416
14969
  );
14417
14970
  });
14418
14971
  }
14419
14972
 
14420
14973
  // src/commands/list.ts
14421
14974
  init_context();
14422
- import pc11 from "picocolors";
14975
+ import pc12 from "picocolors";
14423
14976
  function registerList(program2) {
14424
14977
  program2.command("list").alias("ls").description("List active worlds").action(async () => {
14425
14978
  const { ctx, error } = await loadContext();
@@ -14430,18 +14983,18 @@ function registerList(program2) {
14430
14983
  }
14431
14984
  const worlds = ctx.worldManager.listWorlds();
14432
14985
  if (worlds.length === 0) {
14433
- console.log(pc11.dim("No worlds. Create one with `olam create --name my-world`."));
14986
+ console.log(pc12.dim("No worlds. Create one with `olam create --name my-world`."));
14434
14987
  return;
14435
14988
  }
14436
- console.log(`${pc11.bold(String(worlds.length))} world(s)
14989
+ console.log(`${pc12.bold(String(worlds.length))} world(s)
14437
14990
  `);
14438
14991
  for (const w of worlds) {
14439
- const statusColor = w.status === "running" ? pc11.green(w.status) : w.status === "error" ? pc11.red(w.status) : pc11.yellow(w.status);
14992
+ const statusColor = w.status === "running" ? pc12.green(w.status) : w.status === "error" ? pc12.red(w.status) : pc12.yellow(w.status);
14440
14993
  const age = formatAge(w.createdAt);
14441
14994
  const cost = `$${w.totalCostUsd.toFixed(2)}`;
14442
- console.log(` ${pc11.bold(w.name)} ${pc11.dim(`(${w.id})`)}`);
14995
+ console.log(` ${pc12.bold(w.name)} ${pc12.dim(`(${w.id})`)}`);
14443
14996
  console.log(
14444
- ` ${statusColor} ${pc11.dim("|")} ${w.repos.join(", ")} ${pc11.dim("|")} ${cost} ${pc11.dim("|")} ${age}`
14997
+ ` ${statusColor} ${pc12.dim("|")} ${w.repos.join(", ")} ${pc12.dim("|")} ${cost} ${pc12.dim("|")} ${age}`
14445
14998
  );
14446
14999
  console.log();
14447
15000
  }
@@ -14493,7 +15046,7 @@ function registerStatus(program2) {
14493
15046
 
14494
15047
  // src/commands/destroy.ts
14495
15048
  init_context();
14496
- import ora3 from "ora";
15049
+ import ora5 from "ora";
14497
15050
  function registerDestroy(program2) {
14498
15051
  program2.command("destroy").description("Destroy a world and clean up resources").argument("<world>", "World ID").option("--skip-crystallize", "Skip thought crystallization").action(async (worldId, opts) => {
14499
15052
  const { ctx, error } = await loadContext();
@@ -14508,7 +15061,7 @@ function registerDestroy(program2) {
14508
15061
  process.exitCode = 1;
14509
15062
  return;
14510
15063
  }
14511
- const spinner = ora3(`Destroying ${world.name}...`).start();
15064
+ const spinner = ora5(`Destroying ${world.name}...`).start();
14512
15065
  try {
14513
15066
  await ctx.worldManager.destroyWorld(worldId, {
14514
15067
  skipCrystallize: opts.skipCrystallize
@@ -14532,7 +15085,7 @@ function registerDestroy(program2) {
14532
15085
  // src/commands/enter.ts
14533
15086
  init_context();
14534
15087
  import { execSync as execSync7 } from "node:child_process";
14535
- import pc12 from "picocolors";
15088
+ import pc13 from "picocolors";
14536
15089
  var SAFE_IDENT3 = /^[a-z0-9][a-z0-9-]{0,63}$/;
14537
15090
  function buildStartClaudeCommands(containerName, sessionName, task) {
14538
15091
  if (!SAFE_IDENT3.test(containerName)) {
@@ -14634,7 +15187,7 @@ function registerEnter(program2) {
14634
15187
  }
14635
15188
  console.log("Run these commands in order to enter the world:\n");
14636
15189
  for (const step of steps) {
14637
- console.log(` ${pc12.dim(`# ${step.description}`)}`);
15190
+ console.log(` ${pc13.dim(`# ${step.description}`)}`);
14638
15191
  if (step.stdin !== void 0) {
14639
15192
  const escaped = step.stdin.replace(/'/g, "'\\''");
14640
15193
  console.log(` printf '%s' '${escaped}' | ${step.command}`);
@@ -14668,11 +15221,11 @@ function registerEnter(program2) {
14668
15221
  return;
14669
15222
  }
14670
15223
  console.log("Run this command to enter the world:\n");
14671
- console.log(` ${pc12.bold(result.command)}`);
15224
+ console.log(` ${pc13.bold(result.command)}`);
14672
15225
  const containerName = `olam-${worldId}-devbox`;
14673
15226
  console.log(
14674
15227
  `
14675
- ${pc12.dim(`Observe dispatch: docker exec -it ${containerName} tmux attach -t olam-dispatch -r`)}`
15228
+ ${pc13.dim(`Observe dispatch: docker exec -it ${containerName} tmux attach -t olam-dispatch -r`)}`
14676
15229
  );
14677
15230
  });
14678
15231
  }
@@ -14681,7 +15234,7 @@ ${pc12.dim(`Observe dispatch: docker exec -it ${containerName} tmux attach -t ol
14681
15234
  init_context();
14682
15235
  import * as fs21 from "node:fs";
14683
15236
  import "node:path";
14684
- import ora4 from "ora";
15237
+ import ora6 from "ora";
14685
15238
  init_world_paths();
14686
15239
  function registerCrystallize(program2, options = {}) {
14687
15240
  const cmd = program2.command("crystallize").description("Crystallize thoughts from a world to Pleri Plane").argument("<world>", "World ID").action(async (worldId) => {
@@ -14717,7 +15270,7 @@ function registerCrystallize(program2, options = {}) {
14717
15270
  process.exitCode = EXIT_GENERIC_ERROR;
14718
15271
  return;
14719
15272
  }
14720
- const spinner = ora4("Crystallizing thoughts...").start();
15273
+ const spinner = ora6("Crystallizing thoughts...").start();
14721
15274
  try {
14722
15275
  const { ThoughtLocalStore: ThoughtLocalStore2 } = await Promise.resolve().then(() => (init_local_store(), local_store_exports));
14723
15276
  const { computeGraphChecksum: computeGraphChecksum2 } = await Promise.resolve().then(() => (init_checksum(), checksum_exports));
@@ -14782,7 +15335,7 @@ function registerCrystallize(program2, options = {}) {
14782
15335
 
14783
15336
  // src/commands/pr.ts
14784
15337
  init_registry();
14785
- import pc13 from "picocolors";
15338
+ import pc14 from "picocolors";
14786
15339
 
14787
15340
  // ../core/src/pr-gate/client.ts
14788
15341
  var HOST_CONTROL_PLANE_BASE2 = 19080;
@@ -14862,26 +15415,26 @@ async function findGate(id) {
14862
15415
  return null;
14863
15416
  }
14864
15417
  function formatStateBadge(state) {
14865
- if (state === "approve") return pc13.green("approve");
14866
- if (state === "block") return pc13.red("block");
14867
- if (state === "denied") return pc13.gray("denied");
14868
- return pc13.yellow("pending");
15418
+ if (state === "approve") return pc14.green("approve");
15419
+ if (state === "block") return pc14.red("block");
15420
+ if (state === "denied") return pc14.gray("denied");
15421
+ return pc14.yellow("pending");
14869
15422
  }
14870
15423
  function registerPr(program2) {
14871
15424
  const pr = program2.command("pr").description("Review and decide PR-gate requests from running worlds");
14872
15425
  pr.command("list").description("List all PR-gate requests across every running world").action(async () => {
14873
15426
  const all = await fanoutList();
14874
15427
  if (all.length === 0) {
14875
- console.log(pc13.dim("No gates open."));
15428
+ console.log(pc14.dim("No gates open."));
14876
15429
  return;
14877
15430
  }
14878
15431
  printHeader(`${all.length} gate(s)`);
14879
15432
  for (const { world, gate } of all) {
14880
15433
  const badge = formatStateBadge(gate.state);
14881
15434
  console.log(
14882
- ` ${pc13.bold(gate.id.slice(0, 8))} ${badge.padEnd(20)} ${pc13.dim(world.name)} ${pc13.dim(gate.branch)}`
15435
+ ` ${pc14.bold(gate.id.slice(0, 8))} ${badge.padEnd(20)} ${pc14.dim(world.name)} ${pc14.dim(gate.branch)}`
14883
15436
  );
14884
- console.log(` ${pc13.dim(gate.command.slice(0, 100))}`);
15437
+ console.log(` ${pc14.dim(gate.command.slice(0, 100))}`);
14885
15438
  }
14886
15439
  });
14887
15440
  pr.command("show").description("Show full gate detail (diff, command, commits)").argument("<id>", "Gate id (prefix match ok)").action(async (id) => {
@@ -14904,9 +15457,9 @@ function registerPr(program2) {
14904
15457
  if (gate.reason) printInfo("Reason", gate.reason);
14905
15458
  }
14906
15459
  printHeader("Commits");
14907
- console.log(gate.commitLog || pc13.dim(" (empty)"));
15460
+ console.log(gate.commitLog || pc14.dim(" (empty)"));
14908
15461
  printHeader("Diff stat");
14909
- console.log(gate.diffStat || pc13.dim(" (empty)"));
15462
+ console.log(gate.diffStat || pc14.dim(" (empty)"));
14910
15463
  });
14911
15464
  function decideCommand(verb, decision) {
14912
15465
  pr.command(verb).description(`${verb[0].toUpperCase()}${verb.slice(1)} a pending gate`).argument("<id>", "Gate id").option("--reason <reason>", "Short free-text reason").option("--by <name>", "Deciding identity (defaults to $USER)", process.env["USER"] ?? "human").action(async (id, opts) => {
@@ -15026,7 +15579,7 @@ function registerLanes(program2) {
15026
15579
  // src/commands/policy-check.ts
15027
15580
  init_loader2();
15028
15581
  import { execSync as execSync8 } from "node:child_process";
15029
- import pc14 from "picocolors";
15582
+ import pc15 from "picocolors";
15030
15583
 
15031
15584
  // ../../node_modules/balanced-match/dist/esm/index.js
15032
15585
  var balanced = (a, b, str) => {
@@ -16890,7 +17443,7 @@ function registerPolicyCheck(program2) {
16890
17443
  const workspaceRoot = opts.workspace ?? process.cwd();
16891
17444
  const policies = loadPolicies(workspaceRoot);
16892
17445
  if (policies.length === 0) {
16893
- console.log(pc14.dim("policy-check: no policies found in .olam/policies/ \u2014 nothing to enforce"));
17446
+ console.log(pc15.dim("policy-check: no policies found in .olam/policies/ \u2014 nothing to enforce"));
16894
17447
  return;
16895
17448
  }
16896
17449
  const diff = getDiff(opts.base, workspaceRoot);
@@ -16899,11 +17452,11 @@ function registerPolicyCheck(program2) {
16899
17452
  for (const result of results) {
16900
17453
  if (result.passed) continue;
16901
17454
  if (result.severity === "error") {
16902
- console.error(`${pc14.red("policy error")} [${result.policyId}]`);
17455
+ console.error(`${pc15.red("policy error")} [${result.policyId}]`);
16903
17456
  console.error(result.message);
16904
17457
  hasErrorFailure = true;
16905
17458
  } else {
16906
- console.warn(`${pc14.yellow("policy warn")} [${result.policyId}]`);
17459
+ console.warn(`${pc15.yellow("policy warn")} [${result.policyId}]`);
16907
17460
  console.warn(result.message);
16908
17461
  }
16909
17462
  }
@@ -16916,14 +17469,15 @@ function registerPolicyCheck(program2) {
16916
17469
  // src/commands/upgrade.ts
16917
17470
  import * as fs24 from "node:fs";
16918
17471
  import * as path28 from "node:path";
16919
- import { spawnSync as spawnSync7 } from "node:child_process";
16920
- import pc15 from "picocolors";
17472
+ import { spawnSync as spawnSync9 } from "node:child_process";
17473
+ import ora7 from "ora";
17474
+ import pc16 from "picocolors";
16921
17475
 
16922
17476
  // src/commands/upgrade-lock.ts
16923
17477
  import * as fs22 from "node:fs";
16924
17478
  import * as os13 from "node:os";
16925
17479
  import * as path26 from "node:path";
16926
- import { spawnSync as spawnSync6 } from "node:child_process";
17480
+ import { spawnSync as spawnSync8 } from "node:child_process";
16927
17481
  var LOCK_FILE_PATH = path26.join(os13.homedir(), ".olam", ".upgrade.lock");
16928
17482
  var STALE_LOCK_TIMEOUT_MS = 5 * 60 * 1e3;
16929
17483
  function readLockFile(lockPath) {
@@ -16948,7 +17502,7 @@ function isPidAlive(pid) {
16948
17502
  }
16949
17503
  var PS_UNAVAILABLE = "__ps_unavailable__";
16950
17504
  function getPidCommand(pid) {
16951
- const result = spawnSync6("ps", ["-p", String(pid), "-o", "comm="], {
17505
+ const result = spawnSync8("ps", ["-p", String(pid), "-o", "comm="], {
16952
17506
  encoding: "utf-8",
16953
17507
  stdio: ["ignore", "pipe", "ignore"]
16954
17508
  });
@@ -17146,6 +17700,7 @@ function handleHistory(opts) {
17146
17700
 
17147
17701
  // src/commands/upgrade.ts
17148
17702
  init_auth();
17703
+ init_install_root();
17149
17704
  var AUTH_HEALTH_URL2 = "http://127.0.0.1:9999/health";
17150
17705
  function isNodeModulesInSync(cwd) {
17151
17706
  const lockPath = path28.join(cwd, "package-lock.json");
@@ -17192,7 +17747,8 @@ function parseUpgradeOpts(raw) {
17192
17747
  noCache: raw.noCache === true,
17193
17748
  history: raw.history === true,
17194
17749
  historyN: Number.isFinite(historyN) && historyN > 0 ? historyN : 10,
17195
- historyJson: raw.json === true
17750
+ historyJson: raw.json === true,
17751
+ fromSource: raw.fromSource === true
17196
17752
  };
17197
17753
  }
17198
17754
  function extractBundleHash(indexHtml) {
@@ -17201,8 +17757,8 @@ function extractBundleHash(indexHtml) {
17201
17757
  }
17202
17758
  function runStep2(label, cmd, args, opts = {}) {
17203
17759
  const start = Date.now();
17204
- process.stdout.write(` ${pc15.dim(label.padEnd(34))}`);
17205
- const result = spawnSync7(cmd, [...args], {
17760
+ process.stdout.write(` ${pc16.dim(label.padEnd(34))}`);
17761
+ const result = spawnSync9(cmd, [...args], {
17206
17762
  encoding: "utf-8",
17207
17763
  stdio: ["ignore", "pipe", "pipe"],
17208
17764
  cwd: opts.cwd ?? process.cwd(),
@@ -17211,7 +17767,7 @@ function runStep2(label, cmd, args, opts = {}) {
17211
17767
  const durationMs = Date.now() - start;
17212
17768
  const ok = result.status === 0 && result.error === void 0;
17213
17769
  const dur = `${(durationMs / 1e3).toFixed(1)}s`;
17214
- process.stdout.write(`${ok ? pc15.green("\u2713") : pc15.red("\u2717")} ${dur}
17770
+ process.stdout.write(`${ok ? pc16.green("\u2713") : pc16.red("\u2717")} ${dur}
17215
17771
  `);
17216
17772
  return {
17217
17773
  ok,
@@ -17221,7 +17777,7 @@ function runStep2(label, cmd, args, opts = {}) {
17221
17777
  };
17222
17778
  }
17223
17779
  function isGitDirty(cwd) {
17224
- const result = spawnSync7("git", ["status", "--porcelain"], {
17780
+ const result = spawnSync9("git", ["status", "--porcelain"], {
17225
17781
  encoding: "utf-8",
17226
17782
  stdio: ["ignore", "pipe", "pipe"],
17227
17783
  cwd
@@ -17229,7 +17785,7 @@ function isGitDirty(cwd) {
17229
17785
  return (result.stdout ?? "").trim().length > 0;
17230
17786
  }
17231
17787
  function hasGitUpstream(cwd) {
17232
- const result = spawnSync7("git", ["rev-parse", "--abbrev-ref", "@{u}"], {
17788
+ const result = spawnSync9("git", ["rev-parse", "--abbrev-ref", "@{u}"], {
17233
17789
  encoding: "utf-8",
17234
17790
  stdio: ["ignore", "pipe", "pipe"],
17235
17791
  cwd
@@ -17237,7 +17793,7 @@ function hasGitUpstream(cwd) {
17237
17793
  return result.status === 0;
17238
17794
  }
17239
17795
  function captureHeadSha(cwd) {
17240
- const result = spawnSync7("git", ["rev-parse", "HEAD"], {
17796
+ const result = spawnSync9("git", ["rev-parse", "HEAD"], {
17241
17797
  encoding: "utf-8",
17242
17798
  stdio: ["ignore", "pipe", "pipe"],
17243
17799
  cwd
@@ -17252,7 +17808,7 @@ function abbreviateSha(sha) {
17252
17808
  }
17253
17809
  function imageExists(tag) {
17254
17810
  try {
17255
- const result = spawnSync7("docker", ["image", "inspect", "--format", "{{.Id}}", tag], {
17811
+ const result = spawnSync9("docker", ["image", "inspect", "--format", "{{.Id}}", tag], {
17256
17812
  encoding: "utf-8",
17257
17813
  stdio: ["ignore", "pipe", "ignore"]
17258
17814
  });
@@ -17267,7 +17823,7 @@ function checkRollbackSetExists(plan) {
17267
17823
  return missing.join(", ");
17268
17824
  }
17269
17825
  function smokeImage(image, targetSha) {
17270
- const createResult = spawnSync7("docker", ["create", "--name", `olam-smoke-${Date.now()}`, image], {
17826
+ const createResult = spawnSync9("docker", ["create", "--name", `olam-smoke-${Date.now()}`, image], {
17271
17827
  encoding: "utf-8",
17272
17828
  stdio: ["ignore", "pipe", "pipe"]
17273
17829
  });
@@ -17280,16 +17836,16 @@ function smokeImage(image, targetSha) {
17280
17836
  };
17281
17837
  }
17282
17838
  const containerId = (createResult.stdout ?? "").trim();
17283
- const inspectResult = spawnSync7(
17839
+ const inspectResult = spawnSync9(
17284
17840
  "docker",
17285
- ["inspect", "--format", '{{index .Config.Labels "olam_build_sha"}}', image],
17841
+ ["inspect", "--format", '{{index .Config.Labels "olam.build.sha"}}', image],
17286
17842
  {
17287
17843
  encoding: "utf-8",
17288
17844
  stdio: ["ignore", "pipe", "pipe"]
17289
17845
  }
17290
17846
  );
17291
17847
  if (containerId.length > 0) {
17292
- spawnSync7("docker", ["rm", "-f", containerId], {
17848
+ spawnSync9("docker", ["rm", "-f", containerId], {
17293
17849
  encoding: "utf-8",
17294
17850
  stdio: ["ignore", "ignore", "ignore"]
17295
17851
  });
@@ -17308,7 +17864,7 @@ function smokeImage(image, targetSha) {
17308
17864
  image,
17309
17865
  ok: false,
17310
17866
  bakedSha: null,
17311
- error: "olam_build_sha label is missing or empty"
17867
+ error: "olam.build.sha label is missing or empty"
17312
17868
  };
17313
17869
  }
17314
17870
  if (bakedSha !== targetSha) {
@@ -17328,7 +17884,7 @@ var PRODUCTION_SWAP_PLAN = [
17328
17884
  ];
17329
17885
  function dockerTag(source, dest) {
17330
17886
  try {
17331
- const result = spawnSync7("docker", ["tag", source, dest], {
17887
+ const result = spawnSync9("docker", ["tag", source, dest], {
17332
17888
  encoding: "utf-8",
17333
17889
  stdio: ["ignore", "ignore", "pipe"]
17334
17890
  });
@@ -17421,10 +17977,10 @@ async function confirm2(message) {
17421
17977
  if (!process.stdin.isTTY) return true;
17422
17978
  const { createInterface: createInterface2 } = await import("node:readline");
17423
17979
  const rl = createInterface2({ input: process.stdin, output: process.stdout });
17424
- return new Promise((resolve7) => {
17980
+ return new Promise((resolve8) => {
17425
17981
  rl.question(`${message} [y/N] `, (answer) => {
17426
17982
  rl.close();
17427
- resolve7(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
17983
+ resolve8(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
17428
17984
  });
17429
17985
  });
17430
17986
  }
@@ -17442,7 +17998,7 @@ async function waitForHealth(timeoutMs = 1e4) {
17442
17998
  }
17443
17999
  return false;
17444
18000
  }
17445
- async function waitForVersionMatch(targetSha, timeoutMs = 6e4, pollIntervalMs = 1e3) {
18001
+ async function waitForVersionMatch(targetSha, timeoutMs = 9e4, pollIntervalMs = 1e3) {
17446
18002
  const deadline = Date.now() + timeoutMs;
17447
18003
  let lastSnapshot = null;
17448
18004
  while (Date.now() < deadline) {
@@ -17491,11 +18047,11 @@ async function waitForAuthHealthLocal(timeoutMs = 15e3) {
17491
18047
  async function recreateAuthService() {
17492
18048
  const start = Date.now();
17493
18049
  try {
17494
- spawnSync7("docker", ["stop", "olam-auth"], {
18050
+ spawnSync9("docker", ["stop", "olam-auth"], {
17495
18051
  encoding: "utf-8",
17496
18052
  stdio: ["ignore", "ignore", "ignore"]
17497
18053
  });
17498
- spawnSync7("docker", ["rm", "olam-auth"], {
18054
+ spawnSync9("docker", ["rm", "olam-auth"], {
17499
18055
  encoding: "utf-8",
17500
18056
  stdio: ["ignore", "ignore", "ignore"]
17501
18057
  });
@@ -17524,6 +18080,163 @@ function readBundleHash(cwd) {
17524
18080
  if (!fs24.existsSync(indexPath)) return null;
17525
18081
  return extractBundleHash(fs24.readFileSync(indexPath, "utf-8"));
17526
18082
  }
18083
+ async function runUpgradePullByDigest(deps = {}) {
18084
+ const docker2 = deps.docker ?? realDocker;
18085
+ const digests = deps.digests ?? loadImageDigests();
18086
+ const registry = deps.registry ?? digests.$registry ?? "ghcr.io/pleri";
18087
+ printHeader("olam upgrade (pull-by-digest)");
18088
+ const infoSpinner = ora7("Checking docker daemon").start();
18089
+ const info = await docker2.info();
18090
+ if (info.exitCode !== 0) {
18091
+ infoSpinner.fail("docker daemon not reachable");
18092
+ process.stderr.write(
18093
+ `${pc16.red("error")} docker info exited with ${info.exitCode}.
18094
+ Ensure Docker Desktop / Colima / Rancher is running, then retry.
18095
+ `
18096
+ );
18097
+ return { exitCode: EXIT_GENERIC_ERROR, summary: "docker daemon not reachable" };
18098
+ }
18099
+ infoSpinner.succeed("docker daemon reachable");
18100
+ const imageRefs = [
18101
+ { name: "host-cp", ref: `${registry}/olam-host-cp@${digests["host-cp"]}` },
18102
+ { name: "auth", ref: `${registry}/olam-auth@${digests.auth}` },
18103
+ { name: "devbox", ref: `${registry}/olam-devbox@${digests.devbox}` }
18104
+ ];
18105
+ const pullSpinner = ora7("Pulling images (3 parallel)").start();
18106
+ const pullStart = Date.now();
18107
+ const pullResults = await Promise.all(
18108
+ imageRefs.map(async ({ name, ref }) => ({
18109
+ name,
18110
+ ref,
18111
+ result: await pullImageWithRetry(ref, docker2)
18112
+ }))
18113
+ );
18114
+ const pullElapsed = ((Date.now() - pullStart) / 1e3).toFixed(1);
18115
+ const failed = pullResults.filter((r) => r.result.exitCode !== 0);
18116
+ if (failed.length > 0) {
18117
+ pullSpinner.fail(`Pull failed for ${failed.map((r) => r.name).join(", ")}`);
18118
+ for (const f of failed) {
18119
+ process.stderr.write(
18120
+ ` ${pc16.red(f.name)} (${f.ref}):
18121
+ exit=${f.result.exitCode}
18122
+ stderr: ${f.result.stderr.split("\n")[0] ?? "(empty)"}
18123
+ `
18124
+ );
18125
+ }
18126
+ process.stderr.write(
18127
+ "\n Remedy: re-run after resolving network / GHCR availability.\n For monorepo dev, `OLAM_DEV=1 olam upgrade --from-source` builds locally.\n"
18128
+ );
18129
+ return {
18130
+ exitCode: EXIT_BOOTSTRAP_PULL_FAILED,
18131
+ summary: `pull failed: ${failed.map((r) => r.name).join(", ")}`
18132
+ };
18133
+ }
18134
+ pullSpinner.succeed(`Pulled 3 images in ${pullElapsed}s`);
18135
+ const handshakeSpinner = ora7("Verifying olam.protocol.versions handshake").start();
18136
+ for (const { name, ref } of imageRefs) {
18137
+ const inspect = await docker2.inspectLabel(ref, "olam.protocol.versions");
18138
+ if (inspect.exitCode !== 0) {
18139
+ handshakeSpinner.fail(`Could not inspect ${name}`);
18140
+ process.stderr.write(
18141
+ `${pc16.red("error")} docker inspect ${ref} failed: ${inspect.stderr}
18142
+ `
18143
+ );
18144
+ return { exitCode: EXIT_GENERIC_ERROR, summary: `inspect failed: ${name}` };
18145
+ }
18146
+ const labelValue = (inspect.stdout || "").trim();
18147
+ const versions = parseProtocolVersionsLabel(
18148
+ labelValue === "<no value>" ? "" : labelValue
18149
+ );
18150
+ const decision = checkProtocolOverlap(versions);
18151
+ if (!decision.compatible) {
18152
+ handshakeSpinner.fail(`Protocol mismatch on ${name}`);
18153
+ process.stderr.write(`${pc16.red("error")} ${decision.remedy}
18154
+ `);
18155
+ return {
18156
+ exitCode: EXIT_PROTOCOL_MISMATCH,
18157
+ summary: `protocol mismatch: ${name}`
18158
+ };
18159
+ }
18160
+ }
18161
+ handshakeSpinner.succeed("Protocol handshake passed (all 3 images)");
18162
+ const tagPlan = [
18163
+ { from: imageRefs[0].ref, to: "olam-host-cp:latest", name: "host-cp" },
18164
+ { from: imageRefs[1].ref, to: "olam-auth:local", name: "auth" },
18165
+ { from: imageRefs[2].ref, to: "olam-devbox:latest", name: "devbox" }
18166
+ ];
18167
+ const tagSpinner = ora7("Tagging digests \u2192 canonical local refs").start();
18168
+ const tagger = deps.tagImpl ?? dockerTag;
18169
+ for (const t of tagPlan) {
18170
+ const r = tagger(t.from, t.to);
18171
+ if (!r.ok) {
18172
+ tagSpinner.fail(`docker tag failed for ${t.name}`);
18173
+ process.stderr.write(`${pc16.red("error")} ${r.error ?? "docker tag failed"}
18174
+ `);
18175
+ return { exitCode: EXIT_GENERIC_ERROR, summary: `tag failed: ${t.name}` };
18176
+ }
18177
+ }
18178
+ tagSpinner.succeed("Re-tagged 3 images to canonical refs");
18179
+ const composeFile = deps.composeFile ?? path28.join(process.cwd(), "packages/host-cp/compose.yaml");
18180
+ const authSecret = deps.authSecret ?? readAuthSecret2();
18181
+ const composeRunner = deps.runComposeImpl ?? runCompose;
18182
+ const composeSpinner = ora7("docker compose recreate host-cp").start();
18183
+ const composeResult = composeRunner(
18184
+ ["up", "-d", "--force-recreate", "host-cp"],
18185
+ composeFile,
18186
+ buildComposeEnv(authSecret)
18187
+ );
18188
+ if (!composeResult.ok) {
18189
+ composeSpinner.fail("compose recreate failed");
18190
+ process.stderr.write(
18191
+ `${pc16.red("error")} docker compose up --force-recreate host-cp failed:
18192
+ ${composeResult.stderr.split("\n").slice(0, 3).join("\n ")}
18193
+ `
18194
+ );
18195
+ return { exitCode: EXIT_GENERIC_ERROR, summary: "compose recreate failed" };
18196
+ }
18197
+ composeSpinner.succeed("host-cp recreated");
18198
+ const authSpinner = ora7("recreate auth-service").start();
18199
+ const authRecreate = deps.recreateAuth ?? defaultRecreateAuthForUpgrade;
18200
+ const authResult = await authRecreate();
18201
+ if (!authResult.ok) {
18202
+ authSpinner.fail("auth-service recreate failed");
18203
+ process.stderr.write(
18204
+ `${pc16.red("error")} ${authResult.error ?? "unknown failure"}
18205
+ `
18206
+ );
18207
+ return { exitCode: EXIT_GENERIC_ERROR, summary: "auth recreate failed" };
18208
+ }
18209
+ authSpinner.succeed("auth-service running on new image");
18210
+ printSuccess("Upgrade complete (pull-by-digest)");
18211
+ printInfo("host-cp", `running (${digests["host-cp"].slice(0, 19)}\u2026)`);
18212
+ printInfo("auth", `running (${digests.auth.slice(0, 19)}\u2026)`);
18213
+ printInfo("devbox", `pulled (${digests.devbox.slice(0, 19)}\u2026)`);
18214
+ return { exitCode: 0, summary: "stack upgraded" };
18215
+ }
18216
+ async function defaultRecreateAuthForUpgrade() {
18217
+ try {
18218
+ spawnSync9("docker", ["stop", "olam-auth"], {
18219
+ encoding: "utf-8",
18220
+ stdio: ["ignore", "ignore", "ignore"]
18221
+ });
18222
+ spawnSync9("docker", ["rm", "olam-auth"], {
18223
+ encoding: "utf-8",
18224
+ stdio: ["ignore", "ignore", "ignore"]
18225
+ });
18226
+ const controller = new AuthContainerController();
18227
+ controller.start();
18228
+ const healthy = await waitForAuthHealthLocal(15e3);
18229
+ if (!healthy) {
18230
+ return { ok: false, error: "auth-service /health did not respond within 15s" };
18231
+ }
18232
+ return { ok: true };
18233
+ } catch (err) {
18234
+ return {
18235
+ ok: false,
18236
+ error: err instanceof Error ? err.message : String(err)
18237
+ };
18238
+ }
18239
+ }
17527
18240
  async function handleUpgrade(opts) {
17528
18241
  const cwd = process.cwd();
17529
18242
  const rootCheck = validateRepoRoot(cwd);
@@ -17648,11 +18361,11 @@ manually inspect images with \`docker images olam-*:olam-rollback\`.`
17648
18361
  process.once("SIGINT", releaseOnSignal);
17649
18362
  process.once("SIGTERM", releaseOnSignal);
17650
18363
  try {
17651
- process.stdout.write(` ${pc15.dim("rollback retag (3 ops)".padEnd(34))}`);
18364
+ process.stdout.write(` ${pc16.dim("rollback retag (3 ops)".padEnd(34))}`);
17652
18365
  const swapStart = Date.now();
17653
18366
  const swapResult = performRollbackSwap(PRODUCTION_SWAP_PLAN);
17654
18367
  const swapDur = `${((Date.now() - swapStart) / 1e3).toFixed(1)}s`;
17655
- process.stdout.write(`${swapResult.ok ? pc15.green("\u2713") : pc15.red("\u2717")} ${swapDur}
18368
+ process.stdout.write(`${swapResult.ok ? pc16.green("\u2713") : pc16.red("\u2717")} ${swapDur}
17656
18369
  `);
17657
18370
  if (!swapResult.ok) {
17658
18371
  printError(`Rollback retag failed: ${swapResult.summary}`);
@@ -17663,11 +18376,11 @@ manually inspect images with \`docker images olam-*:olam-rollback\`.`
17663
18376
  const cwd = process.cwd();
17664
18377
  const composeFile = path28.join(cwd, "packages/host-cp/compose.yaml");
17665
18378
  const authSecret = readAuthSecret2();
17666
- process.stdout.write(` ${pc15.dim("docker compose recreate host-cp".padEnd(34))}`);
18379
+ process.stdout.write(` ${pc16.dim("docker compose recreate host-cp".padEnd(34))}`);
17667
18380
  const composeStart = Date.now();
17668
18381
  const composeResult = runCompose(["up", "-d", "--force-recreate", "host-cp"], composeFile, buildComposeEnv(authSecret));
17669
18382
  const composeDur = `${((Date.now() - composeStart) / 1e3).toFixed(1)}s`;
17670
- process.stdout.write(`${composeResult.ok ? pc15.green("\u2713") : pc15.red("\u2717")} ${composeDur}
18383
+ process.stdout.write(`${composeResult.ok ? pc16.green("\u2713") : pc16.red("\u2717")} ${composeDur}
17671
18384
  `);
17672
18385
  if (!composeResult.ok) {
17673
18386
  printError(
@@ -17678,10 +18391,10 @@ Canonical tags are at :olam-rollback (good); container restart pending. Manually
17678
18391
  process.exitCode = 1;
17679
18392
  return;
17680
18393
  }
17681
- process.stdout.write(` ${pc15.dim("recreate auth-service".padEnd(34))}`);
18394
+ process.stdout.write(` ${pc16.dim("recreate auth-service".padEnd(34))}`);
17682
18395
  const authResult = await recreateAuthService();
17683
18396
  const authDur = `${(authResult.durationMs / 1e3).toFixed(1)}s`;
17684
- process.stdout.write(`${authResult.ok ? pc15.green("\u2713") : pc15.red("\u2717")} ${authDur}
18397
+ process.stdout.write(`${authResult.ok ? pc16.green("\u2713") : pc16.red("\u2717")} ${authDur}
17685
18398
  `);
17686
18399
  if (!authResult.ok) {
17687
18400
  printError(`Auth-service recreate failed: ${authResult.error ?? "unknown"}`);
@@ -17833,13 +18546,24 @@ ${spaResult.stderr}`);
17833
18546
  { label: "bash build-devbox.sh", relPath: "packages/adapters/src/docker/build-devbox.sh", tee: true },
17834
18547
  { label: "bash build-host-cp.sh", relPath: "packages/adapters/src/docker/build-host-cp.sh", tee: false }
17835
18548
  ];
18549
+ const { resolveBuildScript: resolveBuildScript2, MissingBuildScriptError: MissingBuildScriptError2 } = await Promise.resolve().then(() => (init_install_root(), install_root_exports));
17836
18550
  for (const step of buildScripts) {
17837
- const scriptPath = path28.join(cwd, step.relPath);
18551
+ let scriptPath;
18552
+ try {
18553
+ scriptPath = resolveBuildScript2({ scriptRelPath: step.relPath });
18554
+ } catch (err) {
18555
+ if (err instanceof MissingBuildScriptError2) {
18556
+ printError(err.message);
18557
+ process.exitCode = 1;
18558
+ return;
18559
+ }
18560
+ throw err;
18561
+ }
17838
18562
  if (step.tee) {
17839
- process.stdout.write(` ${pc15.dim(step.label.padEnd(34))}
18563
+ process.stdout.write(` ${pc16.dim(step.label.padEnd(34))}
17840
18564
  `);
17841
18565
  const start = Date.now();
17842
- const result = spawnSync7("bash", [scriptPath], {
18566
+ const result = spawnSync9("bash", [scriptPath], {
17843
18567
  stdio: "inherit",
17844
18568
  cwd,
17845
18569
  env: { ...process.env, ...olamTagEnv }
@@ -17847,7 +18571,7 @@ ${spaResult.stderr}`);
17847
18571
  const durationMs = Date.now() - start;
17848
18572
  const ok = result.status === 0 && result.error === void 0;
17849
18573
  const dur = `${(durationMs / 1e3).toFixed(1)}s`;
17850
- process.stdout.write(` ${pc15.dim(step.label.padEnd(34))}${ok ? pc15.green("\u2713") : pc15.red("\u2717")} ${dur}
18574
+ process.stdout.write(` ${pc16.dim(step.label.padEnd(34))}${ok ? pc16.green("\u2713") : pc16.red("\u2717")} ${dur}
17851
18575
  `);
17852
18576
  timings.push({ label: step.label, durationMs });
17853
18577
  if (!ok) {
@@ -17873,7 +18597,7 @@ ${result.stderr.split("\n").slice(-3).join("\n")}`);
17873
18597
  }
17874
18598
  for (const t of timings) logRow.durations_ms[t.label] = t.durationMs;
17875
18599
  const smokeStart = Date.now();
17876
- process.stdout.write(` ${pc15.dim("smoke (docker create + inspect)".padEnd(34))}`);
18600
+ process.stdout.write(` ${pc16.dim("smoke (docker create + inspect)".padEnd(34))}`);
17877
18601
  const smokeImages = [
17878
18602
  "olam-auth:olam-next",
17879
18603
  "olam-devbox:olam-next",
@@ -17883,7 +18607,7 @@ ${result.stderr.split("\n").slice(-3).join("\n")}`);
17883
18607
  const smokeFailures = smokeResults.filter((r) => !r.ok);
17884
18608
  const smokeDurationMs = Date.now() - smokeStart;
17885
18609
  const smokeDur = `${(smokeDurationMs / 1e3).toFixed(1)}s`;
17886
- process.stdout.write(`${smokeFailures.length === 0 ? pc15.green("\u2713") : pc15.red("\u2717")} ${smokeDur}
18610
+ process.stdout.write(`${smokeFailures.length === 0 ? pc16.green("\u2713") : pc16.red("\u2717")} ${smokeDur}
17887
18611
  `);
17888
18612
  timings.push({ label: "smoke", durationMs: smokeDurationMs });
17889
18613
  if (smokeFailures.length > 0) {
@@ -17910,12 +18634,12 @@ Recovery options:
17910
18634
  process.exitCode = 1;
17911
18635
  return;
17912
18636
  }
17913
- process.stdout.write(` ${pc15.dim("atomic 6-tag swap".padEnd(34))}`);
18637
+ process.stdout.write(` ${pc16.dim("atomic 6-tag swap".padEnd(34))}`);
17914
18638
  const swapStart = Date.now();
17915
18639
  const swapResult = performAtomicSwap(PRODUCTION_SWAP_PLAN);
17916
18640
  const swapDurationMs = Date.now() - swapStart;
17917
18641
  const swapDur = `${(swapDurationMs / 1e3).toFixed(1)}s`;
17918
- process.stdout.write(`${swapResult.ok ? pc15.green("\u2713") : pc15.red("\u2717")} ${swapDur}
18642
+ process.stdout.write(`${swapResult.ok ? pc16.green("\u2713") : pc16.red("\u2717")} ${swapDur}
17919
18643
  `);
17920
18644
  timings.push({ label: "atomic swap", durationMs: swapDurationMs });
17921
18645
  if (!swapResult.ok) {
@@ -17925,7 +18649,7 @@ Recovery options:
17925
18649
  }
17926
18650
  printInfo("Swap", swapResult.summary);
17927
18651
  const composeFile = path28.join(cwd, "packages/host-cp/compose.yaml");
17928
- process.stdout.write(` ${pc15.dim("docker compose recreate".padEnd(34))}`);
18652
+ process.stdout.write(` ${pc16.dim("docker compose recreate".padEnd(34))}`);
17929
18653
  const composeStart = Date.now();
17930
18654
  const composeResult = runCompose(
17931
18655
  ["up", "-d", "--force-recreate"],
@@ -17935,7 +18659,7 @@ Recovery options:
17935
18659
  const composeDurationMs = Date.now() - composeStart;
17936
18660
  const composeOk = composeResult.ok;
17937
18661
  const composeDur = `${(composeDurationMs / 1e3).toFixed(1)}s`;
17938
- process.stdout.write(`${composeOk ? pc15.green("\u2713") : pc15.red("\u2717")} ${composeDur}
18662
+ process.stdout.write(`${composeOk ? pc16.green("\u2713") : pc16.red("\u2717")} ${composeDur}
17939
18663
  `);
17940
18664
  timings.push({ label: "container recreate", durationMs: composeDurationMs });
17941
18665
  if (!composeOk) {
@@ -17951,10 +18675,10 @@ Recovery options:
17951
18675
  process.exitCode = 1;
17952
18676
  return;
17953
18677
  }
17954
- process.stdout.write(` ${pc15.dim("recreate auth-service".padEnd(34))}`);
18678
+ process.stdout.write(` ${pc16.dim("recreate auth-service".padEnd(34))}`);
17955
18679
  const authResult = await recreateAuthService();
17956
18680
  const authDur = `${(authResult.durationMs / 1e3).toFixed(1)}s`;
17957
- process.stdout.write(`${authResult.ok ? pc15.green("\u2713") : pc15.red("\u2717")} ${authDur}
18681
+ process.stdout.write(`${authResult.ok ? pc16.green("\u2713") : pc16.red("\u2717")} ${authDur}
17958
18682
  `);
17959
18683
  timings.push({ label: "auth recreate", durationMs: authResult.durationMs });
17960
18684
  if (!authResult.ok) {
@@ -17969,12 +18693,12 @@ Recovery options:
17969
18693
  process.exitCode = 1;
17970
18694
  return;
17971
18695
  }
17972
- process.stdout.write(` ${pc15.dim("waiting for /health".padEnd(34))}`);
18696
+ process.stdout.write(` ${pc16.dim("waiting for /health".padEnd(34))}`);
17973
18697
  const healthStart = Date.now();
17974
18698
  const healthy = await waitForHealth(1e4);
17975
18699
  const healthDurationMs = Date.now() - healthStart;
17976
18700
  const healthDur = `${(healthDurationMs / 1e3).toFixed(1)}s`;
17977
- process.stdout.write(`${healthy ? pc15.green("\u2713") : pc15.yellow("?")} ${healthDur}
18701
+ process.stdout.write(`${healthy ? pc16.green("\u2713") : pc16.yellow("?")} ${healthDur}
17978
18702
  `);
17979
18703
  timings.push({ label: "/health", durationMs: healthDurationMs });
17980
18704
  if (!healthy) {
@@ -17982,12 +18706,12 @@ Recovery options:
17982
18706
  "Host CP started but /health did not respond within 10s.\n \u2022 Check: docker logs olam-host-cp\n \u2022 If the new SHA is broken: `olam upgrade --rollback` restores the prior set in <30s."
17983
18707
  );
17984
18708
  }
17985
- process.stdout.write(` ${pc15.dim("verify /version/status round-trip".padEnd(34))}`);
18709
+ process.stdout.write(` ${pc16.dim("verify /version/status round-trip".padEnd(34))}`);
17986
18710
  const versionStart = Date.now();
17987
- const versionMatch = await waitForVersionMatch(_targetSha, 6e4);
18711
+ const versionMatch = await waitForVersionMatch(_targetSha, 9e4);
17988
18712
  const versionDurationMs = Date.now() - versionStart;
17989
18713
  const versionDur = `${(versionDurationMs / 1e3).toFixed(1)}s`;
17990
- process.stdout.write(`${versionMatch.matched ? pc15.green("\u2713") : pc15.yellow("?")} ${versionDur}
18714
+ process.stdout.write(`${versionMatch.matched ? pc16.green("\u2713") : pc16.yellow("?")} ${versionDur}
17991
18715
  `);
17992
18716
  timings.push({ label: "/version/status round-trip", durationMs: versionDurationMs });
17993
18717
  if (!versionMatch.matched) {
@@ -18011,7 +18735,9 @@ function printTimings2(timings) {
18011
18735
  printInfo("total", `${(total / 1e3).toFixed(1)}s`);
18012
18736
  }
18013
18737
  function registerUpgrade(program2) {
18014
- program2.command("upgrade").description("Self-upgrade the local Olam dev stack (pull + rebuild + restart all three components)").option("-y, --yes", "Skip the confirmation prompt").option("--skip-image", "Skip docker image rebuild + container recreate (source rebuild only)").option(
18738
+ program2.command("upgrade").description(
18739
+ "Upgrade the local Olam stack to the CLI's pinned image digests. Default: pull pre-built images from ghcr.io and recreate containers. Use --from-source for the legacy monorepo build path (requires OLAM_DEV=1)."
18740
+ ).option("-y, --yes", "Skip the confirmation prompt").option("--skip-image", "Skip docker image rebuild + container recreate (source rebuild only)").option(
18015
18741
  "--skip-install",
18016
18742
  "Skip npm install entirely (use existing node_modules as-is). Useful when a native-module build failure blocks the normal upgrade path."
18017
18743
  ).option("--branch <name>", "Switch to this branch before pulling (refuses if working tree is dirty)").option(
@@ -18026,24 +18752,47 @@ function registerUpgrade(program2) {
18026
18752
  ).option(
18027
18753
  "--history",
18028
18754
  "Print the upgrade history (~/.olam/upgrade.log) and exit.\n No upgrade is performed."
18029
- ).option("-n <count>", "Number of history rows to print (default 10)", "10").option("--json", "Emit history as JSONL instead of a table").action(async (opts) => {
18030
- await handleUpgrade(parseUpgradeOpts(opts));
18755
+ ).option("-n <count>", "Number of history rows to print (default 10)", "10").option("--json", "Emit history as JSONL instead of a table").option(
18756
+ "--from-source",
18757
+ "Build host-cp + auth + devbox from monorepo source (legacy path).\n Requires OLAM_DEV=1 + a `packages/` sibling at the install root.\n Default (no flag): pull pre-built images from ghcr.io by digest."
18758
+ ).action(async (opts) => {
18759
+ const parsed = parseUpgradeOpts(opts);
18760
+ if (parsed.fromSource) {
18761
+ if (!isDevMode()) {
18762
+ printError(new MissingBuildScriptError("packages/adapters/src/docker/build-*.sh").message);
18763
+ process.exitCode = 1;
18764
+ return;
18765
+ }
18766
+ await handleUpgrade(parsed);
18767
+ return;
18768
+ }
18769
+ if (parsed.history) {
18770
+ handleHistory(parseHistoryOpts({ n: parsed.historyN, json: parsed.historyJson }));
18771
+ return;
18772
+ }
18773
+ try {
18774
+ const result = await runUpgradePullByDigest();
18775
+ process.exitCode = result.exitCode;
18776
+ } catch (err) {
18777
+ printError(err instanceof Error ? err.message : String(err));
18778
+ process.exitCode = EXIT_GENERIC_ERROR;
18779
+ }
18031
18780
  });
18032
18781
  }
18033
18782
 
18034
18783
  // src/commands/logs.ts
18035
18784
  import * as http3 from "node:http";
18036
- import pc16 from "picocolors";
18785
+ import pc17 from "picocolors";
18037
18786
  init_context();
18038
18787
  var HOST_CP_PORT2 = 19e3;
18039
18788
  function colorLine(line) {
18040
- if (/\bERROR\b/.test(line)) return pc16.red(line);
18041
- if (/\bWARN\b/.test(line)) return pc16.yellow(line);
18042
- if (/\bINFO\b/.test(line)) return pc16.dim(line);
18789
+ if (/\bERROR\b/.test(line)) return pc17.red(line);
18790
+ if (/\bWARN\b/.test(line)) return pc17.yellow(line);
18791
+ if (/\bINFO\b/.test(line)) return pc17.dim(line);
18043
18792
  return line;
18044
18793
  }
18045
18794
  function formatLine(line, service, showService) {
18046
- const prefix = showService && service ? `${pc16.cyan(`[${service}]`)} ` : "";
18795
+ const prefix = showService && service ? `${pc17.cyan(`[${service}]`)} ` : "";
18047
18796
  return prefix + colorLine(line);
18048
18797
  }
18049
18798
  function parseSseEvent(raw) {
@@ -18159,8 +18908,8 @@ function registerLogs(program2) {
18159
18908
 
18160
18909
  // src/commands/ps.ts
18161
18910
  init_context();
18162
- import pc17 from "picocolors";
18163
- import { spawnSync as spawnSync8 } from "node:child_process";
18911
+ import pc18 from "picocolors";
18912
+ import { spawnSync as spawnSync10 } from "node:child_process";
18164
18913
  var SAFE_IDENT4 = /^[a-z0-9][a-z0-9-]{0,63}$/;
18165
18914
  function parseDockerTop(stdout) {
18166
18915
  const trimmed = stdout.trim();
@@ -18220,18 +18969,18 @@ function printTable(rows) {
18220
18969
  const fixedWidth = 5 + 1 + 8 + 1 + 6 + 1 + 6 + 1 + 10 + 1 + 6 + 1;
18221
18970
  const cmdWidth = Math.max(20, cols - fixedWidth);
18222
18971
  const header = [
18223
- pc17.bold(pc17.dim("PID".padEnd(5))),
18224
- pc17.bold(pc17.dim("USER".padEnd(8))),
18225
- pc17.bold(pc17.dim("%CPU".padEnd(6))),
18226
- pc17.bold(pc17.dim("%MEM".padEnd(6))),
18227
- pc17.bold(pc17.dim("STARTED".padEnd(10))),
18228
- pc17.bold(pc17.dim("STATE".padEnd(6))),
18229
- pc17.bold(pc17.dim("COMMAND"))
18972
+ pc18.bold(pc18.dim("PID".padEnd(5))),
18973
+ pc18.bold(pc18.dim("USER".padEnd(8))),
18974
+ pc18.bold(pc18.dim("%CPU".padEnd(6))),
18975
+ pc18.bold(pc18.dim("%MEM".padEnd(6))),
18976
+ pc18.bold(pc18.dim("STARTED".padEnd(10))),
18977
+ pc18.bold(pc18.dim("STATE".padEnd(6))),
18978
+ pc18.bold(pc18.dim("COMMAND"))
18230
18979
  ].join(" ");
18231
18980
  console.log(header);
18232
18981
  for (const row of rows) {
18233
18982
  const cmd = row.command.length > cmdWidth ? row.command.slice(0, cmdWidth - 1) + "\u2026" : row.command;
18234
- const stateFn = row.state.startsWith("R") ? pc17.green : row.state.startsWith("Z") ? pc17.red : pc17.dim;
18983
+ const stateFn = row.state.startsWith("R") ? pc18.green : row.state.startsWith("Z") ? pc18.red : pc18.dim;
18235
18984
  console.log([
18236
18985
  row.pid.padEnd(5),
18237
18986
  row.user.slice(0, 8).padEnd(8),
@@ -18260,7 +19009,7 @@ function registerPs(program2) {
18260
19009
  const containerName = `olam-${worldId}-devbox`;
18261
19010
  let watchInterval;
18262
19011
  function fetchAndPrint() {
18263
- const result = spawnSync8(
19012
+ const result = spawnSync10(
18264
19013
  "docker",
18265
19014
  ["top", containerName, "pid", "user", "pcpu", "pmem", "stime", "stat", "cmd"],
18266
19015
  { encoding: "utf-8", timeout: 3e3 }
@@ -18280,7 +19029,7 @@ function registerPs(program2) {
18280
19029
  printTable(rows);
18281
19030
  if (opts.watch) {
18282
19031
  process.stdout.write(`
18283
- ${pc17.dim(`world: ${worldId} sort: ${sortKey} refresh: 5s Ctrl-C to exit`)}
19032
+ ${pc18.dim(`world: ${worldId} sort: ${sortKey} refresh: 5s Ctrl-C to exit`)}
18284
19033
  `);
18285
19034
  }
18286
19035
  }
@@ -18400,7 +19149,7 @@ function registerKeys(program2) {
18400
19149
  import * as fs27 from "node:fs";
18401
19150
  import * as path31 from "node:path";
18402
19151
  import { execSync as execSync9 } from "node:child_process";
18403
- import pc18 from "picocolors";
19152
+ import pc19 from "picocolors";
18404
19153
 
18405
19154
  // ../core/src/world/snapshot.ts
18406
19155
  import * as crypto6 from "node:crypto";
@@ -18569,7 +19318,7 @@ async function handleCreate2(worldId, kindArg) {
18569
19318
  const label = r.repo ? `${r.kind}/${r.repo}` : r.kind;
18570
19319
  if (r.ok) {
18571
19320
  printSuccess(`${label}`);
18572
- console.log(` ${pc18.dim(r.tarPath)}`);
19321
+ console.log(` ${pc19.dim(r.tarPath)}`);
18573
19322
  } else {
18574
19323
  printWarning(`${label}: ${r.msg ?? "skipped"}`);
18575
19324
  }
@@ -18719,7 +19468,7 @@ function handleList2(worldIdFilter) {
18719
19468
  const entries = listSnapshots(worldIdFilter);
18720
19469
  if (entries.length === 0) {
18721
19470
  const where = worldIdFilter ? ` for world "${worldIdFilter}"` : "";
18722
- console.log(pc18.dim(`No snapshots found${where}. Run \`olam world snapshot create <worldId>\` first.`));
19471
+ console.log(pc19.dim(`No snapshots found${where}. Run \`olam world snapshot create <worldId>\` first.`));
18723
19472
  return;
18724
19473
  }
18725
19474
  printHeader(`${entries.length} snapshot(s)`);
@@ -18728,15 +19477,15 @@ function handleList2(worldIdFilter) {
18728
19477
  for (const entry of entries) {
18729
19478
  const { manifest } = entry;
18730
19479
  if (manifest.worldId !== lastWorldId) {
18731
- console.log(pc18.bold(manifest.worldId));
19480
+ console.log(pc19.bold(manifest.worldId));
18732
19481
  lastWorldId = manifest.worldId;
18733
19482
  }
18734
19483
  const repo = manifest.repo ?? "(all repos)";
18735
19484
  const size = formatBytes(manifest.sizeBytes);
18736
19485
  const age = formatAge2(entry.ageMs);
18737
- const kindColor = manifest.kind === "gems" ? pc18.magenta(manifest.kind) : manifest.kind === "node" ? pc18.cyan(manifest.kind) : pc18.yellow(manifest.kind);
19486
+ const kindColor = manifest.kind === "gems" ? pc19.magenta(manifest.kind) : manifest.kind === "node" ? pc19.cyan(manifest.kind) : pc19.yellow(manifest.kind);
18738
19487
  console.log(
18739
- ` ${kindColor.padEnd(6)} ${pc18.dim(repo.padEnd(24))} ${manifest.fingerprint} ${size.padStart(8)} ${age}`
19488
+ ` ${kindColor.padEnd(6)} ${pc19.dim(repo.padEnd(24))} ${manifest.fingerprint} ${size.padStart(8)} ${age}`
18740
19489
  );
18741
19490
  }
18742
19491
  console.log();
@@ -18773,8 +19522,8 @@ init_context();
18773
19522
  import * as fs29 from "node:fs";
18774
19523
  import * as os17 from "node:os";
18775
19524
  import * as path33 from "node:path";
18776
- import { spawnSync as spawnSync9 } from "node:child_process";
18777
- import ora5 from "ora";
19525
+ import { spawnSync as spawnSync11 } from "node:child_process";
19526
+ import ora8 from "ora";
18778
19527
 
18779
19528
  // src/commands/refresh-helpers.ts
18780
19529
  import * as fs28 from "node:fs";
@@ -18817,7 +19566,7 @@ var RESTART_TIMEOUT_S = 30;
18817
19566
  var HEALTH_POLL_MS = 500;
18818
19567
  var HEALTH_TIMEOUT_MS = 3e4;
18819
19568
  function docker(args) {
18820
- const result = spawnSync9("docker", args, {
19569
+ const result = spawnSync11("docker", args, {
18821
19570
  encoding: "utf-8",
18822
19571
  stdio: ["ignore", "pipe", "pipe"]
18823
19572
  });
@@ -18957,7 +19706,7 @@ Run \`olam refresh\` from the olam repo root.`
18957
19706
  process.stdout.write("\n");
18958
19707
  const results = [];
18959
19708
  for (const world of worldsToRefresh) {
18960
- const spinner = ora5(`${world.name}: copying CP source...`).start();
19709
+ const spinner = ora8(`${world.name}: copying CP source...`).start();
18961
19710
  try {
18962
19711
  const result = await refreshWorld(
18963
19712
  world.id,
@@ -19022,7 +19771,7 @@ function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
19022
19771
  var program = new Command();
19023
19772
  function readCliVersion() {
19024
19773
  try {
19025
- const here = path35.dirname(fileURLToPath3(import.meta.url));
19774
+ const here = path35.dirname(fileURLToPath4(import.meta.url));
19026
19775
  for (const candidate of [
19027
19776
  path35.join(here, "package.json"),
19028
19777
  path35.join(here, "..", "package.json"),
@@ -19060,4 +19809,5 @@ registerPs(program);
19060
19809
  registerKeys(program);
19061
19810
  registerWorldSnapshot(program);
19062
19811
  registerRefresh(program);
19812
+ registerBootstrap(program);
19063
19813
  program.parse();