@pleri/olam-cli 0.1.110 → 0.1.111

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.
package/dist/index.js CHANGED
@@ -487,8 +487,8 @@ var init_parseUtil = __esm({
487
487
  init_errors();
488
488
  init_en();
489
489
  makeIssue = (params) => {
490
- const { data, path: path53, errorMaps, issueData } = params;
491
- const fullPath = [...path53, ...issueData.path || []];
490
+ const { data, path: path55, errorMaps, issueData } = params;
491
+ const fullPath = [...path55, ...issueData.path || []];
492
492
  const fullIssue = {
493
493
  ...issueData,
494
494
  path: fullPath
@@ -796,11 +796,11 @@ var init_types = __esm({
796
796
  init_parseUtil();
797
797
  init_util();
798
798
  ParseInputLazyPath = class {
799
- constructor(parent, value, path53, key) {
799
+ constructor(parent, value, path55, key) {
800
800
  this._cachedPath = [];
801
801
  this.parent = parent;
802
802
  this.data = value;
803
- this._path = path53;
803
+ this._path = path55;
804
804
  this._key = key;
805
805
  }
806
806
  get path() {
@@ -4281,7 +4281,7 @@ import YAML from "yaml";
4281
4281
  function bootstrapStepCmd(entry) {
4282
4282
  return typeof entry === "string" ? entry : entry.cmd;
4283
4283
  }
4284
- function refineForbiddenKeys(value, path53, ctx, rejectSource) {
4284
+ function refineForbiddenKeys(value, path55, ctx, rejectSource) {
4285
4285
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
4286
4286
  return;
4287
4287
  }
@@ -4289,12 +4289,12 @@ function refineForbiddenKeys(value, path53, ctx, rejectSource) {
4289
4289
  if (FORBIDDEN_KEYS.has(key)) {
4290
4290
  ctx.addIssue({
4291
4291
  code: external_exports.ZodIssueCode.custom,
4292
- path: [...path53, key],
4292
+ path: [...path55, key],
4293
4293
  message: `forbidden key "${key}" (prototype-pollution surface)`
4294
4294
  });
4295
4295
  continue;
4296
4296
  }
4297
- if (rejectSource && path53.length === 0 && key === "source") {
4297
+ if (rejectSource && path55.length === 0 && key === "source") {
4298
4298
  ctx.addIssue({
4299
4299
  code: external_exports.ZodIssueCode.custom,
4300
4300
  path: ["source"],
@@ -4302,21 +4302,21 @@ function refineForbiddenKeys(value, path53, ctx, rejectSource) {
4302
4302
  });
4303
4303
  continue;
4304
4304
  }
4305
- refineForbiddenKeys(value[key], [...path53, key], ctx, false);
4305
+ refineForbiddenKeys(value[key], [...path55, key], ctx, false);
4306
4306
  }
4307
4307
  }
4308
- function rejectForbiddenKeys(value, path53, rejectSource) {
4308
+ function rejectForbiddenKeys(value, path55, rejectSource) {
4309
4309
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
4310
4310
  return;
4311
4311
  }
4312
4312
  for (const key of Object.keys(value)) {
4313
4313
  if (FORBIDDEN_KEYS.has(key)) {
4314
- throw new Error(`[manifest] ${path53}: forbidden key "${key}" (prototype-pollution surface)`);
4314
+ throw new Error(`[manifest] ${path55}: forbidden key "${key}" (prototype-pollution surface)`);
4315
4315
  }
4316
4316
  if (rejectSource && key === "source") {
4317
- throw new Error(`[manifest] ${path53}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
4317
+ throw new Error(`[manifest] ${path55}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
4318
4318
  }
4319
- rejectForbiddenKeys(value[key], `${path53}.${key}`, false);
4319
+ rejectForbiddenKeys(value[key], `${path55}.${key}`, false);
4320
4320
  }
4321
4321
  }
4322
4322
  function unknownTopLevelKeys(parsed) {
@@ -5309,8 +5309,8 @@ var init_client = __esm({
5309
5309
  throw new Error(`failed to report rate-limit for ${accountId} (HTTP ${res.status})`);
5310
5310
  }
5311
5311
  }
5312
- async request(method, path53, body, attempt = 0) {
5313
- const url = `${this.baseUrl}${path53}`;
5312
+ async request(method, path55, body, attempt = 0) {
5313
+ const url = `${this.baseUrl}${path55}`;
5314
5314
  const controller = new AbortController();
5315
5315
  const timer = setTimeout(() => controller.abort(), this.timeoutMs);
5316
5316
  const headers = {};
@@ -5328,7 +5328,7 @@ var init_client = __esm({
5328
5328
  } catch (err) {
5329
5329
  if (attempt < RETRY_COUNT && isTransient(err)) {
5330
5330
  await sleep(RETRY_BACKOFF_MS * (attempt + 1));
5331
- return this.request(method, path53, body, attempt + 1);
5331
+ return this.request(method, path55, body, attempt + 1);
5332
5332
  }
5333
5333
  throw err;
5334
5334
  } finally {
@@ -6877,8 +6877,8 @@ var init_provider3 = __esm({
6877
6877
  // -----------------------------------------------------------------------
6878
6878
  // Internal fetch helper
6879
6879
  // -----------------------------------------------------------------------
6880
- async request(path53, method, body) {
6881
- const url = `${this.config.workerUrl}${path53}`;
6880
+ async request(path55, method, body) {
6881
+ const url = `${this.config.workerUrl}${path55}`;
6882
6882
  const bearer = await this.config.mintToken();
6883
6883
  const headers = {
6884
6884
  Authorization: `Bearer ${bearer}`
@@ -8170,8 +8170,8 @@ import { execFileSync as execFileSync3 } from "node:child_process";
8170
8170
  import * as fs14 from "node:fs";
8171
8171
  import * as os9 from "node:os";
8172
8172
  import * as path15 from "node:path";
8173
- function expandHome(p, homedir29) {
8174
- return p.replace(/^~(?=$|\/|\\)/, homedir29());
8173
+ function expandHome(p, homedir30) {
8174
+ return p.replace(/^~(?=$|\/|\\)/, homedir30());
8175
8175
  }
8176
8176
  function sanitizeRepoFilename(name) {
8177
8177
  const sanitized = name.replace(/[^A-Za-z0-9._-]/g, "_");
@@ -8194,7 +8194,7 @@ ${stderr}`;
8194
8194
  }
8195
8195
  function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
8196
8196
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync3(cmd, args, opts));
8197
- const homedir29 = deps.homedir ?? (() => os9.homedir());
8197
+ const homedir30 = deps.homedir ?? (() => os9.homedir());
8198
8198
  const baselineDir = path15.join(workspacePath, ".olam", "baseline");
8199
8199
  try {
8200
8200
  fs14.mkdirSync(baselineDir, { recursive: true });
@@ -8210,7 +8210,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
8210
8210
  continue;
8211
8211
  const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
8212
8212
  const outPath = path15.join(baselineDir, filename);
8213
- const repoPath = expandHome(repo.path, homedir29);
8213
+ const repoPath = expandHome(repo.path, homedir30);
8214
8214
  if (!fs14.existsSync(repoPath)) {
8215
8215
  writeBaselineFile(outPath, `# repo: ${repo.name}
8216
8216
  # (skipped: path ${repoPath} does not exist)
@@ -13822,10 +13822,10 @@ async function readHostCpToken2() {
13822
13822
  if (!fs25.existsSync(tp)) return null;
13823
13823
  return fs25.readFileSync(tp, "utf-8").trim();
13824
13824
  }
13825
- async function callHostCpProxy(method, worldId, path53, body) {
13825
+ async function callHostCpProxy(method, worldId, path55, body) {
13826
13826
  const token = await readHostCpToken2();
13827
13827
  if (!token) return { ok: false, status: 0, error: "no token (host CP not started)" };
13828
- const url = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path53}`;
13828
+ const url = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path55}`;
13829
13829
  try {
13830
13830
  const headers = {
13831
13831
  Authorization: `Bearer ${token}`
@@ -14285,7 +14285,7 @@ __export(machine_schema_exports, {
14285
14285
  writeMachineConfig: () => writeMachineConfig
14286
14286
  });
14287
14287
  import * as fs41 from "node:fs";
14288
- import * as path45 from "node:path";
14288
+ import * as path47 from "node:path";
14289
14289
  import * as os24 from "node:os";
14290
14290
  import { parse as parseYaml5, stringify as stringifyYaml5 } from "yaml";
14291
14291
  function readMachineConfig(configPath) {
@@ -14302,7 +14302,7 @@ function readMachineConfig(configPath) {
14302
14302
  }
14303
14303
  function writeMachineConfig(config, configPath) {
14304
14304
  const p = configPath ?? DEFAULT_CONFIG_PATH;
14305
- fs41.mkdirSync(path45.dirname(p), { recursive: true });
14305
+ fs41.mkdirSync(path47.dirname(p), { recursive: true });
14306
14306
  fs41.writeFileSync(p, stringifyYaml5({ ...config }), { mode: 420 });
14307
14307
  }
14308
14308
  function initMachineConfig(opts = {}) {
@@ -14326,9 +14326,9 @@ var init_machine_schema = __esm({
14326
14326
  channel: external_exports.enum(["stable", "beta", "edge"]).default("stable"),
14327
14327
  auto_update: external_exports.boolean().default(true),
14328
14328
  telemetry: external_exports.boolean().default(true),
14329
- worlds_dir: external_exports.string().default(() => path45.join(os24.homedir(), ".olam", "worlds"))
14329
+ worlds_dir: external_exports.string().default(() => path47.join(os24.homedir(), ".olam", "worlds"))
14330
14330
  });
14331
- DEFAULT_CONFIG_PATH = path45.join(os24.homedir(), ".olam", "config.yaml");
14331
+ DEFAULT_CONFIG_PATH = path47.join(os24.homedir(), ".olam", "config.yaml");
14332
14332
  }
14333
14333
  });
14334
14334
 
@@ -14710,9 +14710,9 @@ var UnknownArchetypeError = class extends Error {
14710
14710
  };
14711
14711
  var ArchetypeCycleError = class extends Error {
14712
14712
  path;
14713
- constructor(path53) {
14714
- super(`Archetype inheritance cycle detected: ${path53.join(" \u2192 ")} \u2192 ${path53[0] ?? "?"}`);
14715
- this.path = path53;
14713
+ constructor(path55) {
14714
+ super(`Archetype inheritance cycle detected: ${path55.join(" \u2192 ")} \u2192 ${path55[0] ?? "?"}`);
14715
+ this.path = path55;
14716
14716
  this.name = "ArchetypeCycleError";
14717
14717
  }
14718
14718
  };
@@ -15359,8 +15359,8 @@ function runStep(label, cmd, args, opts = {}) {
15359
15359
  }
15360
15360
  async function confirm(message) {
15361
15361
  if (!process.stdin.isTTY) return true;
15362
- const { createInterface: createInterface5 } = await import("node:readline");
15363
- const rl = createInterface5({ input: process.stdin, output: process.stdout });
15362
+ const { createInterface: createInterface6 } = await import("node:readline");
15363
+ const rl = createInterface6({ input: process.stdin, output: process.stdout });
15364
15364
  return new Promise((resolve11) => {
15365
15365
  rl.question(`${message} [y/N] `, (answer) => {
15366
15366
  rl.close();
@@ -16093,9 +16093,9 @@ function formatFreshnessWarning(result, image = DEFAULT_DEVBOX_IMAGE) {
16093
16093
  "These source files have changed since the image was built; the",
16094
16094
  "changes will NOT take effect in fresh worlds until you rebuild:"
16095
16095
  ];
16096
- for (const { path: path53, mtimeMs } of result.newerSources) {
16096
+ for (const { path: path55, mtimeMs } of result.newerSources) {
16097
16097
  const when = new Date(mtimeMs).toISOString();
16098
- lines.push(` \u2022 ${path53} (modified ${when})`);
16098
+ lines.push(` \u2022 ${path55} (modified ${when})`);
16099
16099
  }
16100
16100
  lines.push("");
16101
16101
  lines.push("Rebuild with:");
@@ -16256,9 +16256,9 @@ async function readHostCpTokenForCreate() {
16256
16256
  try {
16257
16257
  const { default: fs50 } = await import("node:fs");
16258
16258
  const { default: os28 } = await import("node:os");
16259
- const { default: path53 } = await import("node:path");
16260
- const tp = path53.join(
16261
- process.env.OLAM_HOME ?? path53.join(os28.homedir(), ".olam"),
16259
+ const { default: path55 } = await import("node:path");
16260
+ const tp = path55.join(
16261
+ process.env.OLAM_HOME ?? path55.join(os28.homedir(), ".olam"),
16262
16262
  "host-cp.token"
16263
16263
  );
16264
16264
  if (!fs50.existsSync(tp)) return null;
@@ -16627,8 +16627,8 @@ async function readHostCpToken3() {
16627
16627
  try {
16628
16628
  const { default: fs50 } = await import("node:fs");
16629
16629
  const { default: os28 } = await import("node:os");
16630
- const { default: path53 } = await import("node:path");
16631
- const tp = path53.join(os28.homedir(), ".olam", "host-cp.token");
16630
+ const { default: path55 } = await import("node:path");
16631
+ const tp = path55.join(os28.homedir(), ".olam", "host-cp.token");
16632
16632
  if (!fs50.existsSync(tp)) return null;
16633
16633
  const raw = fs50.readFileSync(tp, "utf-8").trim();
16634
16634
  return raw.length > 0 ? raw : null;
@@ -20361,11 +20361,11 @@ function zodIssueToError(issue, doc, lineCounter) {
20361
20361
  suggestion: deriveSuggestion(issue)
20362
20362
  };
20363
20363
  }
20364
- function formatJsonPath(path53) {
20365
- if (path53.length === 0)
20364
+ function formatJsonPath(path55) {
20365
+ if (path55.length === 0)
20366
20366
  return "<root>";
20367
20367
  let out = "";
20368
- for (const seg of path53) {
20368
+ for (const seg of path55) {
20369
20369
  if (typeof seg === "number") {
20370
20370
  out += `[${seg}]`;
20371
20371
  } else {
@@ -20374,11 +20374,11 @@ function formatJsonPath(path53) {
20374
20374
  }
20375
20375
  return out;
20376
20376
  }
20377
- function resolveYamlLocation(path53, doc, lineCounter) {
20377
+ function resolveYamlLocation(path55, doc, lineCounter) {
20378
20378
  let bestLine = 0;
20379
20379
  let bestColumn = 0;
20380
- for (let depth = path53.length; depth >= 0; depth -= 1) {
20381
- const segment = path53.slice(0, depth);
20380
+ for (let depth = path55.length; depth >= 0; depth -= 1) {
20381
+ const segment = path55.slice(0, depth);
20382
20382
  try {
20383
20383
  const node = doc.getIn(segment, true);
20384
20384
  if (node && typeof node === "object" && "range" in node) {
@@ -20596,11 +20596,11 @@ function topoSort(nodes) {
20596
20596
  }
20597
20597
  function traceCycle(start, byId) {
20598
20598
  const seen = /* @__PURE__ */ new Set();
20599
- const path53 = [];
20599
+ const path55 = [];
20600
20600
  let current = start;
20601
20601
  while (current && !seen.has(current)) {
20602
20602
  seen.add(current);
20603
- path53.push(current);
20603
+ path55.push(current);
20604
20604
  const node = byId.get(current);
20605
20605
  const next = node?.dependsOn[0];
20606
20606
  if (next === void 0)
@@ -20608,10 +20608,10 @@ function traceCycle(start, byId) {
20608
20608
  current = next;
20609
20609
  }
20610
20610
  if (current && seen.has(current)) {
20611
- const idx = path53.indexOf(current);
20612
- return [...path53.slice(idx), current];
20611
+ const idx = path55.indexOf(current);
20612
+ return [...path55.slice(idx), current];
20613
20613
  }
20614
- return path53;
20614
+ return path55;
20615
20615
  }
20616
20616
 
20617
20617
  // ../core/dist/executor/types.js
@@ -23018,8 +23018,8 @@ function performRollbackSwap(plan) {
23018
23018
  }
23019
23019
  async function confirm2(message) {
23020
23020
  if (!process.stdin.isTTY) return true;
23021
- const { createInterface: createInterface5 } = await import("node:readline");
23022
- const rl = createInterface5({ input: process.stdin, output: process.stdout });
23021
+ const { createInterface: createInterface6 } = await import("node:readline");
23022
+ const rl = createInterface6({ input: process.stdin, output: process.stdout });
23023
23023
  return new Promise((resolve11) => {
23024
23024
  rl.question(`${message} [y/N] `, (answer) => {
23025
23025
  rl.close();
@@ -25493,16 +25493,318 @@ function registerCompletion(program2) {
25493
25493
  });
25494
25494
  }
25495
25495
 
25496
+ // src/commands/setup.ts
25497
+ init_cli_version();
25498
+ import { spawn as spawn5 } from "node:child_process";
25499
+ import { existsSync as existsSync45 } from "node:fs";
25500
+ import { homedir as homedir23 } from "node:os";
25501
+ import path45 from "node:path";
25502
+ import { createInterface as createInterface3 } from "node:readline";
25503
+
25504
+ // src/lib/shell-rc.ts
25505
+ import { copyFileSync as copyFileSync5, existsSync as existsSync44, readFileSync as readFileSync31, renameSync as renameSync4, writeFileSync as writeFileSync20 } from "node:fs";
25506
+ import path44 from "node:path";
25507
+ function appendIdempotent(opts) {
25508
+ const { rcPath, marker, contentLine, clock = () => /* @__PURE__ */ new Date() } = opts;
25509
+ if (!existsSync44(rcPath)) {
25510
+ return { status: "no-rc-file", backupPath: null };
25511
+ }
25512
+ const content = readFileSync31(rcPath, "utf-8");
25513
+ if (content.includes(marker)) {
25514
+ return { status: "already-present", backupPath: null };
25515
+ }
25516
+ const timestamp = clock().toISOString().replace(/[:.]/g, "-");
25517
+ const backupPath = `${rcPath}.olam-bak.${timestamp}`;
25518
+ copyFileSync5(rcPath, backupPath);
25519
+ const separator = content.length === 0 || content.endsWith("\n") ? "" : "\n";
25520
+ const trailing = contentLine.endsWith("\n") ? "" : "\n";
25521
+ const nextContent = `${content}${separator}${contentLine}${trailing}`;
25522
+ const tmpPath = `${rcPath}.olam-tmp.${process.pid}`;
25523
+ writeFileSync20(tmpPath, nextContent, { encoding: "utf-8" });
25524
+ renameSync4(tmpPath, rcPath);
25525
+ return { status: "appended", backupPath };
25526
+ }
25527
+ function resolveShellRc(home, shellEnv) {
25528
+ if (!shellEnv) return null;
25529
+ const basename6 = path44.basename(shellEnv);
25530
+ if (basename6 === "zsh") return path44.join(home, ".zshrc");
25531
+ if (basename6 === "bash") return path44.join(home, ".bashrc");
25532
+ return null;
25533
+ }
25534
+
25535
+ // src/commands/setup.ts
25536
+ init_output();
25537
+ var REQUIRED_NODE_MAJOR = 20;
25538
+ var NEXT_STEPS_DOCS = [
25539
+ "docs/architecture/devbox-contract.md \u2014 image contract",
25540
+ "docs/architecture/manifest-spec.md \u2014 per-repo .adb.yaml schema",
25541
+ "docs/architecture/config-spec.md \u2014 workspace .olam/config.yaml schema"
25542
+ ];
25543
+ var defaultSpawn = (cmd, args) => new Promise((resolve11) => {
25544
+ const child = spawn5(cmd, [...args], { stdio: "inherit" });
25545
+ child.on("exit", (code) => resolve11({ status: code }));
25546
+ child.on("error", () => resolve11({ status: 1 }));
25547
+ });
25548
+ var defaultPrompt = (question, defaultYes) => {
25549
+ if (!process.stdin.isTTY) {
25550
+ process.stderr.write(
25551
+ `[olam setup] non-TTY stdin detected; using default answer (${defaultYes ? "yes" : "no"}). Re-run with \`--yes\` for explicit non-interactive mode.
25552
+ `
25553
+ );
25554
+ return Promise.resolve(defaultYes);
25555
+ }
25556
+ return new Promise((resolve11) => {
25557
+ const rl = createInterface3({ input: process.stdin, output: process.stdout });
25558
+ const suffix = defaultYes ? " [Y/n]: " : " [y/N]: ";
25559
+ rl.question(`${question}${suffix}`, (answer) => {
25560
+ rl.close();
25561
+ const t = answer.trim().toLowerCase();
25562
+ if (t === "") resolve11(defaultYes);
25563
+ else if (t === "y" || t === "yes") resolve11(true);
25564
+ else if (t === "n" || t === "no") resolve11(false);
25565
+ else resolve11(defaultYes);
25566
+ });
25567
+ rl.on("close", () => resolve11(defaultYes));
25568
+ });
25569
+ };
25570
+ async function phase1SystemCheck(deps) {
25571
+ const dockerProbe = await probeDockerDaemon(deps.dockerExec);
25572
+ if (!dockerProbe.ok) {
25573
+ return phaseFromProbe(dockerProbe);
25574
+ }
25575
+ const nodeVersion = deps.nodeVersion ?? process.version;
25576
+ const nodeMajor = parseNodeMajor(nodeVersion);
25577
+ if (nodeMajor === null || nodeMajor < REQUIRED_NODE_MAJOR) {
25578
+ return {
25579
+ ok: false,
25580
+ message: `Node.js ${nodeVersion} is too old (need \u2265${REQUIRED_NODE_MAJOR})`,
25581
+ remedy: `Install Node.js ${REQUIRED_NODE_MAJOR}+ LTS via nvm/fnm/asdf and re-run \`olam setup\`.`
25582
+ };
25583
+ }
25584
+ return {
25585
+ ok: true,
25586
+ message: `${dockerProbe.message}; node ${nodeVersion}`
25587
+ };
25588
+ }
25589
+ function parseNodeMajor(version) {
25590
+ const m = version.match(/^v?(\d+)\./);
25591
+ if (!m) return null;
25592
+ const n = Number.parseInt(m[1], 10);
25593
+ return Number.isFinite(n) ? n : null;
25594
+ }
25595
+ function phaseFromProbe(probe) {
25596
+ if (probe.ok) return { ok: true, message: probe.message };
25597
+ return { ok: false, message: probe.message, remedy: probe.remedy };
25598
+ }
25599
+ async function phase2CliSanity(deps) {
25600
+ const version = deps.olamCliVersion ?? safeReadCliVersion();
25601
+ if (!version || version === "unknown") {
25602
+ return {
25603
+ ok: false,
25604
+ message: "olam CLI version not detectable",
25605
+ remedy: "Re-install `olam` via `npm install -g @pleri/olam-cli@stable` and re-run."
25606
+ };
25607
+ }
25608
+ return { ok: true, message: `olam ${version}` };
25609
+ }
25610
+ function safeReadCliVersion() {
25611
+ try {
25612
+ return readCliVersion();
25613
+ } catch {
25614
+ return null;
25615
+ }
25616
+ }
25617
+ async function phase3Bootstrap(deps) {
25618
+ const spawnFn = deps.spawnSubprocess ?? defaultSpawn;
25619
+ const r = await spawnFn("olam", ["bootstrap", "--skip-auth-login"]);
25620
+ if (r.status === 0) {
25621
+ return { ok: true, message: "olam bootstrap succeeded" };
25622
+ }
25623
+ return {
25624
+ ok: false,
25625
+ message: `olam bootstrap exited ${r.status}`,
25626
+ remedy: "Re-run `olam setup` after inspecting the bootstrap error above (bootstrap is idempotent)."
25627
+ };
25628
+ }
25629
+ async function phase4ShellInit(opts, deps) {
25630
+ if (opts.skipShellInit) {
25631
+ return { ok: true, skipped: true, message: "skipped via --skip-shell-init" };
25632
+ }
25633
+ const home = deps.home ?? homedir23();
25634
+ const shellEnv = deps.shellEnv ?? process.env.SHELL;
25635
+ const rcPath = resolveShellRc(home, shellEnv);
25636
+ if (rcPath === null) {
25637
+ return {
25638
+ ok: true,
25639
+ skipped: true,
25640
+ message: `unsupported $SHELL (${shellEnv ?? "unset"}); add \`eval "$(olam completion <shell>)"\` to your shell rc manually`
25641
+ };
25642
+ }
25643
+ const shellBasename = path45.basename(shellEnv);
25644
+ const evalLine = `eval "$(olam completion ${shellBasename})"`;
25645
+ const result = appendIdempotent({
25646
+ rcPath,
25647
+ marker: "olam completion",
25648
+ contentLine: evalLine,
25649
+ clock: deps.clock
25650
+ });
25651
+ if (result.status === "no-rc-file") {
25652
+ return {
25653
+ ok: true,
25654
+ skipped: true,
25655
+ message: `${rcPath} not present; skipped (add \`${evalLine}\` to your shell rc manually)`
25656
+ };
25657
+ }
25658
+ if (result.status === "already-present") {
25659
+ return { ok: true, message: `${rcPath}: already configured (no change)` };
25660
+ }
25661
+ return {
25662
+ ok: true,
25663
+ message: `${rcPath}: appended (backup: ${result.backupPath})`
25664
+ };
25665
+ }
25666
+ async function phase5InitProject(opts, deps) {
25667
+ const cwd = deps.cwd ?? process.cwd();
25668
+ const projectRoot = findProjectRoot(cwd);
25669
+ const configPath = path45.join(projectRoot, ".olam", "config.yaml");
25670
+ if (existsSync45(configPath)) {
25671
+ return { ok: true, message: `${configPath} present (no change)` };
25672
+ }
25673
+ const promptFn = deps.prompt ?? defaultPrompt;
25674
+ const shouldInit = opts.yes ? true : await promptFn(`No .olam/config.yaml in ${cwd}. Initialise project here?`, false);
25675
+ if (!shouldInit) {
25676
+ return {
25677
+ ok: true,
25678
+ skipped: true,
25679
+ message: "declined; run `olam init` later when ready"
25680
+ };
25681
+ }
25682
+ const spawnFn = deps.spawnSubprocess ?? defaultSpawn;
25683
+ const r = await spawnFn("olam", ["init"]);
25684
+ if (r.status === 0) {
25685
+ return { ok: true, message: "olam init completed" };
25686
+ }
25687
+ return {
25688
+ ok: false,
25689
+ message: `olam init exited ${r.status}`,
25690
+ remedy: "Inspect the init error above and re-run `olam setup`."
25691
+ };
25692
+ }
25693
+ async function phase6Auth(opts, deps) {
25694
+ if (opts.skipAuth) {
25695
+ return {
25696
+ ok: true,
25697
+ skipped: true,
25698
+ message: "skipped via --skip-auth (run `olam auth login` later)"
25699
+ };
25700
+ }
25701
+ const promptFn = deps.prompt ?? defaultPrompt;
25702
+ const shouldLaunch = opts.yes ? true : await promptFn(
25703
+ "`olam auth login` is interactive (PKCE browser flow, 5 min timeout). Launch now?",
25704
+ false
25705
+ );
25706
+ if (!shouldLaunch) {
25707
+ return {
25708
+ ok: true,
25709
+ skipped: true,
25710
+ message: "declined; run `olam auth login` later when ready"
25711
+ };
25712
+ }
25713
+ const spawnFn = deps.spawnSubprocess ?? defaultSpawn;
25714
+ const r = await spawnFn("olam", ["auth", "login"]);
25715
+ if (r.status === 0) {
25716
+ return { ok: true, message: "olam auth login succeeded" };
25717
+ }
25718
+ return {
25719
+ ok: true,
25720
+ skipped: true,
25721
+ message: `olam auth login exited ${r.status}; re-run \`olam auth login\` after resolving`
25722
+ };
25723
+ }
25724
+ async function phase7Verify(deps) {
25725
+ const spawnFn = deps.spawnSubprocess ?? defaultSpawn;
25726
+ const r = await spawnFn("olam", ["doctor"]);
25727
+ if (r.status === 0) {
25728
+ return { ok: true, message: "olam doctor: all probes green" };
25729
+ }
25730
+ return {
25731
+ ok: false,
25732
+ message: `olam doctor exited ${r.status}`,
25733
+ remedy: "Inspect doctor output above; the specific failing probe names its remedy."
25734
+ };
25735
+ }
25736
+ var PHASE_TITLES = [
25737
+ "Phase 1: System check",
25738
+ "Phase 2: olam CLI sanity",
25739
+ "Phase 3: Bootstrap",
25740
+ "Phase 4: Shell init",
25741
+ "Phase 5: Init project",
25742
+ "Phase 6: Auth prompt",
25743
+ "Phase 7: Final verification"
25744
+ ];
25745
+ async function runSetup(opts, deps = {}) {
25746
+ printHeader("olam setup");
25747
+ const phaseFns = [
25748
+ () => phase1SystemCheck(deps),
25749
+ () => phase2CliSanity(deps),
25750
+ () => phase3Bootstrap(deps),
25751
+ () => phase4ShellInit(opts, deps),
25752
+ () => phase5InitProject(opts, deps),
25753
+ () => phase6Auth(opts, deps),
25754
+ () => phase7Verify(deps)
25755
+ ];
25756
+ const results = [];
25757
+ let failureAt = null;
25758
+ for (let i = 0; i < phaseFns.length; i += 1) {
25759
+ const name = PHASE_TITLES[i];
25760
+ process.stdout.write(`
25761
+ ${name}
25762
+ `);
25763
+ const result = await phaseFns[i]();
25764
+ results.push({ name, result });
25765
+ if (result.ok && result.skipped) {
25766
+ printWarning(` \u2298 ${result.message}`);
25767
+ } else if (result.ok) {
25768
+ printSuccess(` \u2713 ${result.message}`);
25769
+ } else {
25770
+ printError(` \u2717 ${result.message}`);
25771
+ if (result.remedy) printWarning(` remedy: ${result.remedy}`);
25772
+ failureAt = i + 1;
25773
+ break;
25774
+ }
25775
+ }
25776
+ process.stdout.write("\n");
25777
+ if (failureAt !== null) {
25778
+ printError(`Setup FAILED at Phase ${failureAt}`);
25779
+ return { phases: results, failureAt, exitCode: 1 };
25780
+ }
25781
+ printSuccess("Setup complete.");
25782
+ process.stdout.write("\nNext steps \u2014 read these in order for the 3-contract pattern:\n");
25783
+ for (const line of NEXT_STEPS_DOCS) {
25784
+ printInfo("docs", line);
25785
+ }
25786
+ process.stdout.write("\n");
25787
+ return { phases: results, failureAt: null, exitCode: 0 };
25788
+ }
25789
+ function registerSetup(program2) {
25790
+ program2.command("setup").description(
25791
+ "Fresh-host onboarding wizard. Runs 7 phases (system check \u2192 bootstrap \u2192 shell init \u2192 init project \u2192 auth prompt \u2192 doctor verification). Idempotent; safe to re-run."
25792
+ ).option("--skip-shell-init", "Skip Phase 4 (do not append to ~/.zshrc / ~/.bashrc)").option("--skip-auth", "Skip Phase 6 (do not prompt for `olam auth login`)").option("-y, --yes", "Auto-affirm every prompt (non-interactive)").action(async (opts) => {
25793
+ const report = await runSetup(opts);
25794
+ if (report.exitCode !== 0) process.exitCode = report.exitCode;
25795
+ });
25796
+ }
25797
+
25496
25798
  // src/commands/update.ts
25497
25799
  import * as fs42 from "node:fs";
25498
25800
  import * as os25 from "node:os";
25499
- import * as path46 from "node:path";
25801
+ import * as path48 from "node:path";
25500
25802
  import { execSync as execSync13 } from "node:child_process";
25501
25803
  import pc23 from "picocolors";
25502
25804
 
25503
25805
  // src/lib/symlink-reconcile.ts
25504
25806
  import * as fs40 from "node:fs";
25505
- import * as path44 from "node:path";
25807
+ import * as path46 from "node:path";
25506
25808
  var realFs = {
25507
25809
  readdirSync: (p) => fs40.readdirSync(p),
25508
25810
  existsSync: (p) => fs40.existsSync(p),
@@ -25521,8 +25823,8 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir, _fs = realFs) {
25521
25823
  _fs.mkdirSync(claudeSkillsDir, { recursive: true });
25522
25824
  const sourceSkills = _fs.existsSync(npmSkillsDir) ? _fs.readdirSync(npmSkillsDir).filter((d) => d.startsWith("olam-")) : [];
25523
25825
  for (const skill of sourceSkills) {
25524
- const linkPath = path44.join(claudeSkillsDir, skill);
25525
- const target = path44.join(npmSkillsDir, skill);
25826
+ const linkPath = path46.join(claudeSkillsDir, skill);
25827
+ const target = path46.join(npmSkillsDir, skill);
25526
25828
  if (!_fs.existsSync(linkPath)) {
25527
25829
  try {
25528
25830
  _fs.symlinkSync(target, linkPath);
@@ -25535,7 +25837,7 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir, _fs = realFs) {
25535
25837
  }
25536
25838
  const deployedEntries = _fs.existsSync(claudeSkillsDir) ? _fs.readdirSync(claudeSkillsDir).filter((d) => d.startsWith("olam-")) : [];
25537
25839
  for (const entry of deployedEntries) {
25538
- const linkPath = path44.join(claudeSkillsDir, entry);
25840
+ const linkPath = path46.join(claudeSkillsDir, entry);
25539
25841
  let isSymlink = false;
25540
25842
  try {
25541
25843
  isSymlink = _fs.lstatSync(linkPath).isSymbolicLink();
@@ -25560,9 +25862,9 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir, _fs = realFs) {
25560
25862
 
25561
25863
  // src/commands/update.ts
25562
25864
  var PACKAGE_NAME = "@pleri/olam-cli";
25563
- var CACHE_DIR2 = path46.join(os25.homedir(), ".olam", "cache");
25564
- var LOG_DIR2 = path46.join(os25.homedir(), ".olam", "log");
25565
- var LAST_STABLE_FILE = path46.join(CACHE_DIR2, "last-stable.txt");
25865
+ var CACHE_DIR2 = path48.join(os25.homedir(), ".olam", "cache");
25866
+ var LOG_DIR2 = path48.join(os25.homedir(), ".olam", "log");
25867
+ var LAST_STABLE_FILE = path48.join(CACHE_DIR2, "last-stable.txt");
25566
25868
  function defaultExec(cmd) {
25567
25869
  try {
25568
25870
  const stdout = execSync13(cmd, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
@@ -25591,12 +25893,12 @@ function readLastStable(file = LAST_STABLE_FILE) {
25591
25893
  }
25592
25894
  }
25593
25895
  function writeLastStable(version, file = LAST_STABLE_FILE) {
25594
- fs42.mkdirSync(path46.dirname(file), { recursive: true });
25896
+ fs42.mkdirSync(path48.dirname(file), { recursive: true });
25595
25897
  fs42.writeFileSync(file, version, { mode: 420 });
25596
25898
  }
25597
25899
  function logUpdateFailure(stderr) {
25598
25900
  const ts = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
25599
- const logFile = path46.join(LOG_DIR2, `update-${ts}.log`);
25901
+ const logFile = path48.join(LOG_DIR2, `update-${ts}.log`);
25600
25902
  try {
25601
25903
  fs42.mkdirSync(LOG_DIR2, { recursive: true });
25602
25904
  fs42.appendFileSync(logFile, `[update-failure ${(/* @__PURE__ */ new Date()).toISOString()}]
@@ -25686,8 +25988,8 @@ async function doUpdate(opts, _exec = defaultExec, _reconcile = reconcileSkillSy
25686
25988
  let symlinkResult = { added: [], removed: [] };
25687
25989
  if (npmRootResult.exitCode === 0) {
25688
25990
  const npmRoot = npmRootResult.stdout.trim();
25689
- const npmSkillsDir = path46.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills");
25690
- const claudeSkillsDir = path46.join(os25.homedir(), ".claude", "skills");
25991
+ const npmSkillsDir = path48.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills");
25992
+ const claudeSkillsDir = path48.join(os25.homedir(), ".claude", "skills");
25691
25993
  const rec = _reconcile(npmSkillsDir, claudeSkillsDir);
25692
25994
  symlinkResult = { added: rec.added, removed: rec.removed };
25693
25995
  if (!quiet && (rec.added.length > 0 || rec.removed.length > 0)) {
@@ -25733,8 +26035,8 @@ async function doRollback(_exec = defaultExec, _reconcile = reconcileSkillSymlin
25733
26035
  if (npmRootResult.exitCode === 0) {
25734
26036
  const npmRoot = npmRootResult.stdout.trim();
25735
26037
  _reconcile(
25736
- path46.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills"),
25737
- path46.join(os25.homedir(), ".claude", "skills")
26038
+ path48.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills"),
26039
+ path48.join(os25.homedir(), ".claude", "skills")
25738
26040
  );
25739
26041
  }
25740
26042
  return { action: "rolled-back", restoredVersion: prev, exitCode: 0 };
@@ -25826,10 +26128,10 @@ init_store2();
25826
26128
  init_store2();
25827
26129
  import * as fs43 from "node:fs";
25828
26130
  import * as os26 from "node:os";
25829
- import * as path47 from "node:path";
26131
+ import * as path49 from "node:path";
25830
26132
  function expandPath(p) {
25831
26133
  if (p === "~" || p.startsWith("~/")) {
25832
- return path47.join(os26.homedir(), p.slice(1));
26134
+ return path49.join(os26.homedir(), p.slice(1));
25833
26135
  }
25834
26136
  return p;
25835
26137
  }
@@ -26238,8 +26540,8 @@ var SECRET = process.env["OLAM_MCP_AUTH_SECRET"] ?? "";
26238
26540
  function authHeaders() {
26239
26541
  return SECRET ? { "X-Olam-Mcp-Secret": SECRET } : {};
26240
26542
  }
26241
- async function apiFetch(path53, init = {}) {
26242
- const res = await fetch(`${BASE_URL}${path53}`, {
26543
+ async function apiFetch(path55, init = {}) {
26544
+ const res = await fetch(`${BASE_URL}${path55}`, {
26243
26545
  ...init,
26244
26546
  headers: {
26245
26547
  "Content-Type": "application/json",
@@ -26294,11 +26596,11 @@ function getMcpAuthClient() {
26294
26596
  }
26295
26597
 
26296
26598
  // src/commands/mcp/login.ts
26297
- import { spawn as spawn5 } from "node:child_process";
26599
+ import { spawn as spawn6 } from "node:child_process";
26298
26600
  function openBrowser2(url) {
26299
26601
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
26300
26602
  try {
26301
- const child = spawn5(cmd, [url], { detached: true, stdio: "ignore" });
26603
+ const child = spawn6(cmd, [url], { detached: true, stdio: "ignore" });
26302
26604
  child.unref();
26303
26605
  } catch {
26304
26606
  }
@@ -26501,7 +26803,7 @@ import pc29 from "picocolors";
26501
26803
  // src/commands/mcp/import-discovery.ts
26502
26804
  import * as fs45 from "node:fs";
26503
26805
  import * as os27 from "node:os";
26504
- import * as path48 from "node:path";
26806
+ import * as path50 from "node:path";
26505
26807
  function readJsonFile(filePath) {
26506
26808
  try {
26507
26809
  const raw = fs45.readFileSync(filePath, "utf-8");
@@ -26533,18 +26835,18 @@ function extractMcpServers(obj, source, sourceLabel) {
26533
26835
  }
26534
26836
  function getClaudeDesktopPath() {
26535
26837
  if (process.platform === "darwin") {
26536
- return path48.join(os27.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
26838
+ return path50.join(os27.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
26537
26839
  }
26538
26840
  if (process.platform === "win32") {
26539
- const appData = process.env["APPDATA"] ?? path48.join(os27.homedir(), "AppData", "Roaming");
26540
- return path48.join(appData, "Claude", "claude_desktop_config.json");
26841
+ const appData = process.env["APPDATA"] ?? path50.join(os27.homedir(), "AppData", "Roaming");
26842
+ return path50.join(appData, "Claude", "claude_desktop_config.json");
26541
26843
  }
26542
- return path48.join(os27.homedir(), ".config", "Claude", "claude_desktop_config.json");
26844
+ return path50.join(os27.homedir(), ".config", "Claude", "claude_desktop_config.json");
26543
26845
  }
26544
26846
  function getOlamRepoPaths() {
26545
26847
  const configPaths = [
26546
- path48.join(os27.homedir(), ".olam", "config.yaml"),
26547
- path48.join(process.cwd(), ".olam", "config.yaml")
26848
+ path50.join(os27.homedir(), ".olam", "config.yaml"),
26849
+ path50.join(process.cwd(), ".olam", "config.yaml")
26548
26850
  ];
26549
26851
  const paths = [];
26550
26852
  for (const configPath of configPaths) {
@@ -26566,7 +26868,7 @@ async function discoverMcpSources(repoPaths) {
26566
26868
  const sources = [];
26567
26869
  const sourceDefs = [
26568
26870
  {
26569
- path: path48.join(os27.homedir(), ".claude.json"),
26871
+ path: path50.join(os27.homedir(), ".claude.json"),
26570
26872
  label: "Claude Code (~/.claude.json)"
26571
26873
  },
26572
26874
  {
@@ -26574,19 +26876,19 @@ async function discoverMcpSources(repoPaths) {
26574
26876
  label: "Claude Desktop"
26575
26877
  },
26576
26878
  {
26577
- path: path48.join(os27.homedir(), ".cursor", "mcp.json"),
26879
+ path: path50.join(os27.homedir(), ".cursor", "mcp.json"),
26578
26880
  label: "Cursor (~/.cursor/mcp.json)"
26579
26881
  },
26580
26882
  {
26581
- path: path48.join(os27.homedir(), ".codeium", "windsurf", "mcp_config.json"),
26883
+ path: path50.join(os27.homedir(), ".codeium", "windsurf", "mcp_config.json"),
26582
26884
  label: "Windsurf (~/.codeium/windsurf/mcp_config.json)"
26583
26885
  }
26584
26886
  ];
26585
26887
  const resolvedRepoPaths = repoPaths ?? getOlamRepoPaths();
26586
26888
  for (const repoPath of resolvedRepoPaths) {
26587
26889
  sourceDefs.push({
26588
- path: path48.join(repoPath, ".mcp.json"),
26589
- label: `.mcp.json (${path48.basename(repoPath)})`
26890
+ path: path50.join(repoPath, ".mcp.json"),
26891
+ label: `.mcp.json (${path50.basename(repoPath)})`
26590
26892
  });
26591
26893
  }
26592
26894
  const reads = await Promise.all(
@@ -26616,7 +26918,7 @@ async function discoverMcpSources(repoPaths) {
26616
26918
  }
26617
26919
 
26618
26920
  // src/commands/mcp/import-validate.ts
26619
- import { spawn as spawn6 } from "node:child_process";
26921
+ import { spawn as spawn7 } from "node:child_process";
26620
26922
  var VALIDATION_TIMEOUT_MS = 5e3;
26621
26923
  async function validateMcpEntry(entry) {
26622
26924
  return new Promise((resolve11) => {
@@ -26624,7 +26926,7 @@ async function validateMcpEntry(entry) {
26624
26926
  let timedOut = false;
26625
26927
  let child;
26626
26928
  try {
26627
- child = spawn6(entry.command, [...entry.args ?? []], {
26929
+ child = spawn7(entry.command, [...entry.args ?? []], {
26628
26930
  stdio: ["ignore", "pipe", "ignore"],
26629
26931
  env: { ...process.env, ...entry.env ?? {} }
26630
26932
  });
@@ -26818,10 +27120,10 @@ function registerMcp(program2) {
26818
27120
  // src/commands/kg-build.ts
26819
27121
  import { spawnSync as spawnSync15 } from "node:child_process";
26820
27122
  import fs48 from "node:fs";
26821
- import path51 from "node:path";
27123
+ import path53 from "node:path";
26822
27124
 
26823
27125
  // ../core/dist/kg/storage-paths.js
26824
- import { homedir as homedir27 } from "node:os";
27126
+ import { homedir as homedir28 } from "node:os";
26825
27127
  import { join as join48, resolve as resolve10 } from "node:path";
26826
27128
 
26827
27129
  // ../core/dist/world/workspace-name.js
@@ -26843,7 +27145,7 @@ function validateWorkspaceName(name) {
26843
27145
 
26844
27146
  // ../core/dist/kg/storage-paths.js
26845
27147
  function olamHome3() {
26846
- return process.env.OLAM_HOME ?? join48(homedir27(), ".olam");
27148
+ return process.env.OLAM_HOME ?? join48(homedir28(), ".olam");
26847
27149
  }
26848
27150
  function kgRoot() {
26849
27151
  return join48(olamHome3(), "kg");
@@ -26851,17 +27153,17 @@ function kgRoot() {
26851
27153
  function worldsRoot() {
26852
27154
  return join48(olamHome3(), "worlds");
26853
27155
  }
26854
- function assertWithinPrefix(path53, prefix, label) {
26855
- if (!path53.startsWith(prefix + "/")) {
26856
- throw new Error(`${label} escape: ${path53} not under ${prefix}/`);
27156
+ function assertWithinPrefix(path55, prefix, label) {
27157
+ if (!path55.startsWith(prefix + "/")) {
27158
+ throw new Error(`${label} escape: ${path55} not under ${prefix}/`);
26857
27159
  }
26858
27160
  }
26859
27161
  function kgPristinePath(workspace) {
26860
27162
  validateWorkspaceName(workspace);
26861
27163
  const root = kgRoot();
26862
- const path53 = resolve10(join48(root, workspace));
26863
- assertWithinPrefix(path53, root, "kgPristinePath");
26864
- return path53;
27164
+ const path55 = resolve10(join48(root, workspace));
27165
+ assertWithinPrefix(path55, root, "kgPristinePath");
27166
+ return path55;
26865
27167
  }
26866
27168
  var KG_PATHS_INTERNALS = Object.freeze({
26867
27169
  olamHome: olamHome3,
@@ -26874,17 +27176,17 @@ init_output();
26874
27176
 
26875
27177
  // src/commands/kg-status.ts
26876
27178
  import fs46 from "node:fs";
26877
- import { homedir as homedir28 } from "node:os";
26878
- import path49 from "node:path";
27179
+ import { homedir as homedir29 } from "node:os";
27180
+ import path51 from "node:path";
26879
27181
  init_output();
26880
27182
  function olamHome4() {
26881
- return process.env.OLAM_HOME ?? path49.join(homedir28(), ".olam");
27183
+ return process.env.OLAM_HOME ?? path51.join(homedir29(), ".olam");
26882
27184
  }
26883
27185
  function kgRoot2() {
26884
- return path49.join(olamHome4(), "kg");
27186
+ return path51.join(olamHome4(), "kg");
26885
27187
  }
26886
27188
  function worldsRoot2() {
26887
- return path49.join(olamHome4(), "worlds");
27189
+ return path51.join(olamHome4(), "worlds");
26888
27190
  }
26889
27191
  function dirSizeBytes2(dir) {
26890
27192
  if (!fs46.existsSync(dir)) return 0;
@@ -26899,7 +27201,7 @@ function dirSizeBytes2(dir) {
26899
27201
  continue;
26900
27202
  }
26901
27203
  for (const entry of entries) {
26902
- const full = path49.join(cur, entry.name);
27204
+ const full = path51.join(cur, entry.name);
26903
27205
  if (entry.isSymbolicLink()) continue;
26904
27206
  if (entry.isDirectory()) {
26905
27207
  stack.push(full);
@@ -26920,7 +27222,7 @@ function formatBytes5(n) {
26920
27222
  return `${(n / 1024 / 1024 / 1024).toFixed(2)} GB`;
26921
27223
  }
26922
27224
  function readFreshness(workspace) {
26923
- const file = path49.join(kgPristinePath(workspace), "freshness.json");
27225
+ const file = path51.join(kgPristinePath(workspace), "freshness.json");
26924
27226
  if (!fs46.existsSync(file)) return null;
26925
27227
  try {
26926
27228
  const raw = JSON.parse(fs46.readFileSync(file, "utf-8"));
@@ -26931,7 +27233,7 @@ function readFreshness(workspace) {
26931
27233
  }
26932
27234
  }
26933
27235
  function readOverlayNodeCount(graphifyOutDir) {
26934
- const graphPath = path49.join(graphifyOutDir, "graph.json");
27236
+ const graphPath = path51.join(graphifyOutDir, "graph.json");
26935
27237
  if (!fs46.existsSync(graphPath)) return null;
26936
27238
  try {
26937
27239
  const raw = JSON.parse(fs46.readFileSync(graphPath, "utf-8"));
@@ -26957,7 +27259,7 @@ function listOverlays() {
26957
27259
  for (const worldEntry of worldDirs) {
26958
27260
  if (!worldEntry.isDirectory()) continue;
26959
27261
  const worldId = worldEntry.name;
26960
- const worldDir = path49.join(root, worldId);
27262
+ const worldDir = path51.join(root, worldId);
26961
27263
  let cloneDirs;
26962
27264
  try {
26963
27265
  cloneDirs = fs46.readdirSync(worldDir, { withFileTypes: true });
@@ -26966,7 +27268,7 @@ function listOverlays() {
26966
27268
  }
26967
27269
  for (const cloneEntry of cloneDirs) {
26968
27270
  if (!cloneEntry.isDirectory()) continue;
26969
- const graphifyOut = path49.join(worldDir, cloneEntry.name, "graphify-out");
27271
+ const graphifyOut = path51.join(worldDir, cloneEntry.name, "graphify-out");
26970
27272
  if (!fs46.existsSync(graphifyOut)) continue;
26971
27273
  records.push({
26972
27274
  world_id: worldId,
@@ -26998,7 +27300,7 @@ function listPristines(overlays) {
26998
27300
  continue;
26999
27301
  }
27000
27302
  const fresh = readFreshness(workspace);
27001
- const graphifyOut = path49.join(kgPristinePath(workspace), "graphify-out");
27303
+ const graphifyOut = path51.join(kgPristinePath(workspace), "graphify-out");
27002
27304
  const size = dirSizeBytes2(graphifyOut);
27003
27305
  const worldCount = overlays.filter((o) => o.clone_dir === workspace).length;
27004
27306
  records.push({
@@ -27130,12 +27432,12 @@ function registerKgStatusCommand(kg) {
27130
27432
  }
27131
27433
 
27132
27434
  // src/commands/kg-watch.ts
27133
- import { spawn as spawn7 } from "node:child_process";
27435
+ import { spawn as spawn8 } from "node:child_process";
27134
27436
  import fs47 from "node:fs";
27135
- import path50 from "node:path";
27437
+ import path52 from "node:path";
27136
27438
  init_output();
27137
27439
  function pidFilePath(workspace) {
27138
- return path50.join(kgPristinePath(workspace), ".watch.pid");
27440
+ return path52.join(kgPristinePath(workspace), ".watch.pid");
27139
27441
  }
27140
27442
  function isPidAlive3(pid) {
27141
27443
  if (!Number.isInteger(pid) || pid <= 0) return false;
@@ -27169,7 +27471,7 @@ function readAndClassifyPid(workspace) {
27169
27471
  }
27170
27472
  function writePidFile(workspace, pid) {
27171
27473
  const file = pidFilePath(workspace);
27172
- const dir = path50.dirname(file);
27474
+ const dir = path52.dirname(file);
27173
27475
  fs47.mkdirSync(dir, { recursive: true });
27174
27476
  fs47.writeFileSync(file, String(pid), { encoding: "utf-8" });
27175
27477
  }
@@ -27182,7 +27484,7 @@ function removePidFile(workspace) {
27182
27484
  }
27183
27485
  async function runKgWatch(workspaceArg, opts, deps = {}) {
27184
27486
  const cwd = deps.cwd ?? opts.cwd ?? process.cwd();
27185
- const name = workspaceArg ?? path50.basename(cwd).toLowerCase();
27487
+ const name = workspaceArg ?? path52.basename(cwd).toLowerCase();
27186
27488
  try {
27187
27489
  validateWorkspaceName(name);
27188
27490
  } catch (err) {
@@ -27190,7 +27492,7 @@ async function runKgWatch(workspaceArg, opts, deps = {}) {
27190
27492
  return { exitCode: 1, pidWritten: false };
27191
27493
  }
27192
27494
  const pristinePath = kgPristinePath(name);
27193
- const graphPath = path50.join(pristinePath, "graphify-out", "graph.json");
27495
+ const graphPath = path52.join(pristinePath, "graphify-out", "graph.json");
27194
27496
  const pidState = readAndClassifyPid(name);
27195
27497
  if (pidState.status === "active") {
27196
27498
  printError(
@@ -27201,7 +27503,7 @@ async function runKgWatch(workspaceArg, opts, deps = {}) {
27201
27503
  if (pidState.status === "stale-reclaimed") {
27202
27504
  printInfo("stale-pid", `reclaimed dead PID file at ${pidFilePath(name)}`);
27203
27505
  }
27204
- const spawnFn = deps.spawnImpl ?? spawn7;
27506
+ const spawnFn = deps.spawnImpl ?? spawn8;
27205
27507
  const child = spawnFn(
27206
27508
  "graphify",
27207
27509
  [cwd, "--watch", "--update", "--graph", graphPath],
@@ -27256,7 +27558,7 @@ function registerKgWatchCommand(kg) {
27256
27558
  var DEFAULT_DEVBOX_IMAGE2 = "olam-devbox:latest";
27257
27559
  function resolveWorkspace(arg) {
27258
27560
  const cwd = process.cwd();
27259
- const name = arg ?? path51.basename(cwd).toLowerCase();
27561
+ const name = arg ?? path53.basename(cwd).toLowerCase();
27260
27562
  validateWorkspaceName(name);
27261
27563
  return { name, sourcePath: cwd };
27262
27564
  }
@@ -27278,7 +27580,7 @@ function copyWorkspaceToScratch(source, scratch) {
27278
27580
  return "cp-r";
27279
27581
  }
27280
27582
  function parseNodeCount(graphifyOutDir) {
27281
- const graphPath = path51.join(graphifyOutDir, "graph.json");
27583
+ const graphPath = path53.join(graphifyOutDir, "graph.json");
27282
27584
  if (!fs48.existsSync(graphPath)) return null;
27283
27585
  try {
27284
27586
  const content = fs48.readFileSync(graphPath, "utf-8");
@@ -27315,7 +27617,7 @@ async function runKgBuild(workspaceArg, options = {}) {
27315
27617
  return { exitCode: 2 };
27316
27618
  }
27317
27619
  const outDir = kgPristinePath(workspace.name);
27318
- const scratchDir = path51.join(outDir, "scratch");
27620
+ const scratchDir = path53.join(outDir, "scratch");
27319
27621
  fs48.mkdirSync(outDir, { recursive: true });
27320
27622
  if (fs48.existsSync(scratchDir)) fs48.rmSync(scratchDir, { recursive: true, force: true });
27321
27623
  fs48.mkdirSync(scratchDir);
@@ -27346,8 +27648,8 @@ async function runKgBuild(workspaceArg, options = {}) {
27346
27648
  printError(`graphify update failed (exit ${r.status})`);
27347
27649
  return { exitCode: r.status ?? 1 };
27348
27650
  }
27349
- const scratchOut = path51.join(scratchDir, "graphify-out");
27350
- const finalOut = path51.join(outDir, "graphify-out");
27651
+ const scratchOut = path53.join(scratchDir, "graphify-out");
27652
+ const finalOut = path53.join(outDir, "graphify-out");
27351
27653
  if (!fs48.existsSync(scratchOut)) {
27352
27654
  printError(`graphify produced no graphify-out/ in scratch (${scratchOut})`);
27353
27655
  return { exitCode: 1 };
@@ -27366,7 +27668,7 @@ async function runKgBuild(workspaceArg, options = {}) {
27366
27668
  scratch_strategy: scratchStrategy
27367
27669
  };
27368
27670
  fs48.writeFileSync(
27369
- path51.join(outDir, "freshness.json"),
27671
+ path53.join(outDir, "freshness.json"),
27370
27672
  JSON.stringify(freshness, null, 2) + "\n",
27371
27673
  "utf-8"
27372
27674
  );
@@ -27399,12 +27701,12 @@ function registerKg(program2) {
27399
27701
 
27400
27702
  // src/pleri-config.ts
27401
27703
  import * as fs49 from "node:fs";
27402
- import * as path52 from "node:path";
27704
+ import * as path54 from "node:path";
27403
27705
  function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
27404
27706
  if (process.env.PLERI_BASE_URL) {
27405
27707
  return true;
27406
27708
  }
27407
- const configPath = path52.join(configDir, "config.yaml");
27709
+ const configPath = path54.join(configDir, "config.yaml");
27408
27710
  if (!fs49.existsSync(configPath)) {
27409
27711
  return false;
27410
27712
  }
@@ -27448,6 +27750,7 @@ registerBootstrap(program);
27448
27750
  registerDiagnose(program);
27449
27751
  registerDoctor(program);
27450
27752
  registerCompletion(program);
27753
+ registerSetup(program);
27451
27754
  registerUpdate(program);
27452
27755
  registerBegin(program);
27453
27756
  registerStop(program);