@pleri/olam-cli 0.1.36 → 0.1.37

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
@@ -421,8 +421,8 @@ var init_parseUtil = __esm({
421
421
  init_errors();
422
422
  init_en();
423
423
  makeIssue = (params) => {
424
- const { data, path: path36, errorMaps, issueData } = params;
425
- const fullPath = [...path36, ...issueData.path || []];
424
+ const { data, path: path40, errorMaps, issueData } = params;
425
+ const fullPath = [...path40, ...issueData.path || []];
426
426
  const fullIssue = {
427
427
  ...issueData,
428
428
  path: fullPath
@@ -730,11 +730,11 @@ var init_types = __esm({
730
730
  init_parseUtil();
731
731
  init_util();
732
732
  ParseInputLazyPath = class {
733
- constructor(parent, value, path36, key) {
733
+ constructor(parent, value, path40, key) {
734
734
  this._cachedPath = [];
735
735
  this.parent = parent;
736
736
  this.data = value;
737
- this._path = path36;
737
+ this._path = path40;
738
738
  this._key = key;
739
739
  }
740
740
  get path() {
@@ -2812,33 +2812,33 @@ var init_types = __esm({
2812
2812
  ...processCreateParams(params)
2813
2813
  });
2814
2814
  };
2815
- getDiscriminator = (type) => {
2816
- if (type instanceof ZodLazy) {
2817
- return getDiscriminator(type.schema);
2818
- } else if (type instanceof ZodEffects) {
2819
- return getDiscriminator(type.innerType());
2820
- } else if (type instanceof ZodLiteral) {
2821
- return [type.value];
2822
- } else if (type instanceof ZodEnum) {
2823
- return type.options;
2824
- } else if (type instanceof ZodNativeEnum) {
2825
- return util.objectValues(type.enum);
2826
- } else if (type instanceof ZodDefault) {
2827
- return getDiscriminator(type._def.innerType);
2828
- } else if (type instanceof ZodUndefined) {
2815
+ getDiscriminator = (type2) => {
2816
+ if (type2 instanceof ZodLazy) {
2817
+ return getDiscriminator(type2.schema);
2818
+ } else if (type2 instanceof ZodEffects) {
2819
+ return getDiscriminator(type2.innerType());
2820
+ } else if (type2 instanceof ZodLiteral) {
2821
+ return [type2.value];
2822
+ } else if (type2 instanceof ZodEnum) {
2823
+ return type2.options;
2824
+ } else if (type2 instanceof ZodNativeEnum) {
2825
+ return util.objectValues(type2.enum);
2826
+ } else if (type2 instanceof ZodDefault) {
2827
+ return getDiscriminator(type2._def.innerType);
2828
+ } else if (type2 instanceof ZodUndefined) {
2829
2829
  return [void 0];
2830
- } else if (type instanceof ZodNull) {
2830
+ } else if (type2 instanceof ZodNull) {
2831
2831
  return [null];
2832
- } else if (type instanceof ZodOptional) {
2833
- return [void 0, ...getDiscriminator(type.unwrap())];
2834
- } else if (type instanceof ZodNullable) {
2835
- return [null, ...getDiscriminator(type.unwrap())];
2836
- } else if (type instanceof ZodBranded) {
2837
- return getDiscriminator(type.unwrap());
2838
- } else if (type instanceof ZodReadonly) {
2839
- return getDiscriminator(type.unwrap());
2840
- } else if (type instanceof ZodCatch) {
2841
- return getDiscriminator(type._def.innerType);
2832
+ } else if (type2 instanceof ZodOptional) {
2833
+ return [void 0, ...getDiscriminator(type2.unwrap())];
2834
+ } else if (type2 instanceof ZodNullable) {
2835
+ return [null, ...getDiscriminator(type2.unwrap())];
2836
+ } else if (type2 instanceof ZodBranded) {
2837
+ return getDiscriminator(type2.unwrap());
2838
+ } else if (type2 instanceof ZodReadonly) {
2839
+ return getDiscriminator(type2.unwrap());
2840
+ } else if (type2 instanceof ZodCatch) {
2841
+ return getDiscriminator(type2._def.innerType);
2842
2842
  } else {
2843
2843
  return [];
2844
2844
  }
@@ -2898,8 +2898,8 @@ var init_types = __esm({
2898
2898
  */
2899
2899
  static create(discriminator, options, params) {
2900
2900
  const optionsMap = /* @__PURE__ */ new Map();
2901
- for (const type of options) {
2902
- const discriminatorValues = getDiscriminator(type.shape[discriminator]);
2901
+ for (const type2 of options) {
2902
+ const discriminatorValues = getDiscriminator(type2.shape[discriminator]);
2903
2903
  if (!discriminatorValues.length) {
2904
2904
  throw new Error(`A discriminator value for key \`${discriminator}\` could not be extracted from all schema options`);
2905
2905
  }
@@ -2907,7 +2907,7 @@ var init_types = __esm({
2907
2907
  if (optionsMap.has(value)) {
2908
2908
  throw new Error(`Discriminator property ${String(discriminator)} has duplicate value ${String(value)}`);
2909
2909
  }
2910
- optionsMap.set(value, type);
2910
+ optionsMap.set(value, type2);
2911
2911
  }
2912
2912
  }
2913
2913
  return new _ZodDiscriminatedUnion({
@@ -3673,9 +3673,9 @@ var init_types = __esm({
3673
3673
  return this._def.innerType;
3674
3674
  }
3675
3675
  };
3676
- ZodOptional.create = (type, params) => {
3676
+ ZodOptional.create = (type2, params) => {
3677
3677
  return new ZodOptional({
3678
- innerType: type,
3678
+ innerType: type2,
3679
3679
  typeName: ZodFirstPartyTypeKind.ZodOptional,
3680
3680
  ...processCreateParams(params)
3681
3681
  });
@@ -3692,9 +3692,9 @@ var init_types = __esm({
3692
3692
  return this._def.innerType;
3693
3693
  }
3694
3694
  };
3695
- ZodNullable.create = (type, params) => {
3695
+ ZodNullable.create = (type2, params) => {
3696
3696
  return new ZodNullable({
3697
- innerType: type,
3697
+ innerType: type2,
3698
3698
  typeName: ZodFirstPartyTypeKind.ZodNullable,
3699
3699
  ...processCreateParams(params)
3700
3700
  });
@@ -3716,9 +3716,9 @@ var init_types = __esm({
3716
3716
  return this._def.innerType;
3717
3717
  }
3718
3718
  };
3719
- ZodDefault.create = (type, params) => {
3719
+ ZodDefault.create = (type2, params) => {
3720
3720
  return new ZodDefault({
3721
- innerType: type,
3721
+ innerType: type2,
3722
3722
  typeName: ZodFirstPartyTypeKind.ZodDefault,
3723
3723
  defaultValue: typeof params.default === "function" ? params.default : () => params.default,
3724
3724
  ...processCreateParams(params)
@@ -3769,9 +3769,9 @@ var init_types = __esm({
3769
3769
  return this._def.innerType;
3770
3770
  }
3771
3771
  };
3772
- ZodCatch.create = (type, params) => {
3772
+ ZodCatch.create = (type2, params) => {
3773
3773
  return new ZodCatch({
3774
- innerType: type,
3774
+ innerType: type2,
3775
3775
  typeName: ZodFirstPartyTypeKind.ZodCatch,
3776
3776
  catchValue: typeof params.catch === "function" ? params.catch : () => params.catch,
3777
3777
  ...processCreateParams(params)
@@ -3883,9 +3883,9 @@ var init_types = __esm({
3883
3883
  return this._def.innerType;
3884
3884
  }
3885
3885
  };
3886
- ZodReadonly.create = (type, params) => {
3886
+ ZodReadonly.create = (type2, params) => {
3887
3887
  return new ZodReadonly({
3888
- innerType: type,
3888
+ innerType: type2,
3889
3889
  typeName: ZodFirstPartyTypeKind.ZodReadonly,
3890
3890
  ...processCreateParams(params)
3891
3891
  });
@@ -4221,7 +4221,7 @@ import YAML from "yaml";
4221
4221
  function bootstrapStepCmd(entry) {
4222
4222
  return typeof entry === "string" ? entry : entry.cmd;
4223
4223
  }
4224
- function refineForbiddenKeys(value, path36, ctx, rejectSource) {
4224
+ function refineForbiddenKeys(value, path40, ctx, rejectSource) {
4225
4225
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
4226
4226
  return;
4227
4227
  }
@@ -4229,12 +4229,12 @@ function refineForbiddenKeys(value, path36, ctx, rejectSource) {
4229
4229
  if (FORBIDDEN_KEYS.has(key)) {
4230
4230
  ctx.addIssue({
4231
4231
  code: external_exports.ZodIssueCode.custom,
4232
- path: [...path36, key],
4232
+ path: [...path40, key],
4233
4233
  message: `forbidden key "${key}" (prototype-pollution surface)`
4234
4234
  });
4235
4235
  continue;
4236
4236
  }
4237
- if (rejectSource && path36.length === 0 && key === "source") {
4237
+ if (rejectSource && path40.length === 0 && key === "source") {
4238
4238
  ctx.addIssue({
4239
4239
  code: external_exports.ZodIssueCode.custom,
4240
4240
  path: ["source"],
@@ -4244,30 +4244,30 @@ function refineForbiddenKeys(value, path36, ctx, rejectSource) {
4244
4244
  }
4245
4245
  refineForbiddenKeys(
4246
4246
  value[key],
4247
- [...path36, key],
4247
+ [...path40, key],
4248
4248
  ctx,
4249
4249
  false
4250
4250
  );
4251
4251
  }
4252
4252
  }
4253
- function rejectForbiddenKeys(value, path36, rejectSource) {
4253
+ function rejectForbiddenKeys(value, path40, rejectSource) {
4254
4254
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
4255
4255
  return;
4256
4256
  }
4257
4257
  for (const key of Object.keys(value)) {
4258
4258
  if (FORBIDDEN_KEYS.has(key)) {
4259
4259
  throw new Error(
4260
- `[manifest] ${path36}: forbidden key "${key}" (prototype-pollution surface)`
4260
+ `[manifest] ${path40}: forbidden key "${key}" (prototype-pollution surface)`
4261
4261
  );
4262
4262
  }
4263
4263
  if (rejectSource && key === "source") {
4264
4264
  throw new Error(
4265
- `[manifest] ${path36}: top-level "source" is loader-stamped \u2014 manifests must not author it`
4265
+ `[manifest] ${path40}: top-level "source" is loader-stamped \u2014 manifests must not author it`
4266
4266
  );
4267
4267
  }
4268
4268
  rejectForbiddenKeys(
4269
4269
  value[key],
4270
- `${path36}.${key}`,
4270
+ `${path40}.${key}`,
4271
4271
  false
4272
4272
  );
4273
4273
  }
@@ -5208,8 +5208,8 @@ var init_client = __esm({
5208
5208
  throw new Error(`failed to report rate-limit for ${accountId} (HTTP ${res.status})`);
5209
5209
  }
5210
5210
  }
5211
- async request(method, path36, body, attempt = 0) {
5212
- const url = `${this.baseUrl}${path36}`;
5211
+ async request(method, path40, body, attempt = 0) {
5212
+ const url = `${this.baseUrl}${path40}`;
5213
5213
  const controller = new AbortController();
5214
5214
  const timer = setTimeout(() => controller.abort(), this.timeoutMs);
5215
5215
  const headers = {};
@@ -5225,7 +5225,7 @@ var init_client = __esm({
5225
5225
  } catch (err) {
5226
5226
  if (attempt < RETRY_COUNT && isTransient(err)) {
5227
5227
  await sleep(RETRY_BACKOFF_MS * (attempt + 1));
5228
- return this.request(method, path36, body, attempt + 1);
5228
+ return this.request(method, path40, body, attempt + 1);
5229
5229
  }
5230
5230
  throw err;
5231
5231
  } finally {
@@ -5644,7 +5644,7 @@ var init_container2 = __esm({
5644
5644
  init_volume();
5645
5645
  serviceContainerName = (worldId, serviceName) => `olam-${sanitizeContainerName(worldId)}-${sanitizeContainerName(serviceName)}`;
5646
5646
  worldContainerName = (worldId) => `olam-${sanitizeContainerName(worldId)}-devbox`;
5647
- miseCacheVolumeName = (arch = process.arch) => `olam-mise-cache-${arch}`;
5647
+ miseCacheVolumeName = (arch2 = process.arch) => `olam-mise-cache-${arch2}`;
5648
5648
  PACKAGE_MANAGER_CACHE_DIRS = [
5649
5649
  { name: "bundle", hostSubpath: ".olam/cache/bundle", containerPath: "/home/olam/.bundle/cache" },
5650
5650
  { name: "npm", hostSubpath: ".olam/cache/npm", containerPath: "/home/olam/.npm" },
@@ -6715,8 +6715,8 @@ var init_provider3 = __esm({
6715
6715
  // -----------------------------------------------------------------------
6716
6716
  // Internal fetch helper
6717
6717
  // -----------------------------------------------------------------------
6718
- async request(path36, method, body) {
6719
- const url = `${this.config.workerUrl}${path36}`;
6718
+ async request(path40, method, body) {
6719
+ const url = `${this.config.workerUrl}${path40}`;
6720
6720
  const bearer = await this.config.mintToken();
6721
6721
  const headers = {
6722
6722
  Authorization: `Bearer ${bearer}`
@@ -6817,8 +6817,8 @@ var init_provider3 = __esm({
6817
6817
  /**
6818
6818
  * Submit thumbs-up / thumbs-down feedback for a session.
6819
6819
  */
6820
- async submitFeedback(sessionId, type, comment) {
6821
- const body = { sessionId, type, comment };
6820
+ async submitFeedback(sessionId, type2, comment) {
6821
+ const body = { sessionId, type: type2, comment };
6822
6822
  const res = await this.request("/feedback", "POST", body);
6823
6823
  await assertOk(res, `submitFeedback ${sessionId}`);
6824
6824
  }
@@ -7570,8 +7570,8 @@ function copyDirRecursive(src, dest, depth = 0, skipFiles = /* @__PURE__ */ new
7570
7570
  }
7571
7571
  }
7572
7572
  async function copyClaudeConfigIntoContainer(containerName) {
7573
- const { execSync: execSync10 } = await import("node:child_process");
7574
- const dockerExec = (cmd) => execSync10(`docker exec ${containerName} sh -c '${cmd}'`, { stdio: "pipe" });
7573
+ const { execSync: execSync12 } = await import("node:child_process");
7574
+ const dockerExec = (cmd) => execSync12(`docker exec ${containerName} sh -c '${cmd}'`, { stdio: "pipe" });
7575
7575
  dockerExec("mkdir -p /home/olam/.claude");
7576
7576
  dockerExec("test -f /home/olam/workspace/.claude-host-config/settings.json && cp /home/olam/workspace/.claude-host-config/settings.json /home/olam/.claude/settings.json || true");
7577
7577
  dockerExec("test -f /home/olam/workspace/.claude-host-config/CLAUDE.md && cp /home/olam/workspace/.claude-host-config/CLAUDE.md /home/olam/.claude/CLAUDE.md || true");
@@ -7589,7 +7589,7 @@ async function copyClaudeConfigIntoContainer(containerName) {
7589
7589
  await sanitizeContainerClaudeHooks(containerName);
7590
7590
  }
7591
7591
  async function sanitizeContainerClaudeHooks(containerName) {
7592
- const { execSync: execSync10 } = await import("node:child_process");
7592
+ const { execSync: execSync12 } = await import("node:child_process");
7593
7593
  const script = `
7594
7594
  const fs = require('fs');
7595
7595
  const p = '/home/olam/.claude/settings.json';
@@ -7633,7 +7633,7 @@ if (changed) {
7633
7633
  }
7634
7634
  `;
7635
7635
  try {
7636
- execSync10(
7636
+ execSync12(
7637
7637
  `docker exec ${containerName} /usr/local/bin/node -e ${shQuote(script)}`,
7638
7638
  { stdio: "pipe" }
7639
7639
  );
@@ -7870,8 +7870,8 @@ import { execFileSync as execFileSync3 } from "node:child_process";
7870
7870
  import * as fs13 from "node:fs";
7871
7871
  import * as os9 from "node:os";
7872
7872
  import * as path14 from "node:path";
7873
- function expandHome(p, homedir17) {
7874
- return p.replace(/^~(?=$|\/|\\)/, homedir17());
7873
+ function expandHome(p, homedir20) {
7874
+ return p.replace(/^~(?=$|\/|\\)/, homedir20());
7875
7875
  }
7876
7876
  function sanitizeRepoFilename(name) {
7877
7877
  const sanitized = name.replace(/[^A-Za-z0-9._-]/g, "_");
@@ -7892,7 +7892,7 @@ ${stderr}`;
7892
7892
  }
7893
7893
  function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
7894
7894
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync3(cmd, args, opts));
7895
- const homedir17 = deps.homedir ?? (() => os9.homedir());
7895
+ const homedir20 = deps.homedir ?? (() => os9.homedir());
7896
7896
  const baselineDir = path14.join(workspacePath, ".olam", "baseline");
7897
7897
  try {
7898
7898
  fs13.mkdirSync(baselineDir, { recursive: true });
@@ -7907,7 +7907,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
7907
7907
  if (!repo.path) continue;
7908
7908
  const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
7909
7909
  const outPath = path14.join(baselineDir, filename);
7910
- const repoPath = expandHome(repo.path, homedir17);
7910
+ const repoPath = expandHome(repo.path, homedir20);
7911
7911
  if (!fs13.existsSync(repoPath)) {
7912
7912
  writeBaselineFile(outPath, `# repo: ${repo.name}
7913
7913
  # (skipped: path ${repoPath} does not exist)
@@ -9960,7 +9960,7 @@ var init_manager = __esm({
9960
9960
  console.warn(`[WorldManager] container git setup failed: ${msg}`);
9961
9961
  }
9962
9962
  try {
9963
- const safeExec = makeContainerExecFn(containerName);
9963
+ const safeExec2 = makeContainerExecFn(containerName);
9964
9964
  let stacks;
9965
9965
  if (preDetectedStacks.size > 0) {
9966
9966
  stacks = preDetectedStacks;
@@ -9971,12 +9971,12 @@ var init_manager = __esm({
9971
9971
  if (repo.stack && Object.keys(repo.stack).length > 0) {
9972
9972
  stacks.set(repo.name, { repoName: repo.name, versions: repo.stack });
9973
9973
  } else {
9974
- const detected = await detectRepoStack(safeExec, repoDir, repo.name);
9974
+ const detected = await detectRepoStack(safeExec2, repoDir, repo.name);
9975
9975
  stacks.set(repo.name, detected);
9976
9976
  }
9977
9977
  }
9978
9978
  }
9979
- const stackResult = await installStack(safeExec, enrichedRepos, stacks);
9979
+ const stackResult = await installStack(safeExec2, enrichedRepos, stacks);
9980
9980
  if (stackResult.installed.length > 0) {
9981
9981
  const summary = stackResult.installed.map((r) => `${r.runtime}@${r.version}`).join(", ");
9982
9982
  console.log(`[WorldManager] installed runtimes: ${summary}`);
@@ -10564,8 +10564,8 @@ var init_local_store = __esm({
10564
10564
  const rows = this.db.prepare("SELECT * FROM thought_edges").all();
10565
10565
  return rows.map(rowToEdge);
10566
10566
  }
10567
- getNodesByType(type) {
10568
- const rows = this.db.prepare("SELECT * FROM thought_nodes WHERE node_type = ? ORDER BY sequence_num").all(type);
10567
+ getNodesByType(type2) {
10568
+ const rows = this.db.prepare("SELECT * FROM thought_nodes WHERE node_type = ? ORDER BY sequence_num").all(type2);
10569
10569
  return rows.map(rowToNode);
10570
10570
  }
10571
10571
  getChainToRoot(nodeId) {
@@ -12118,10 +12118,64 @@ var init_checksum = __esm({
12118
12118
  }
12119
12119
  });
12120
12120
 
12121
+ // ../core/src/config/machine-schema.ts
12122
+ var machine_schema_exports = {};
12123
+ __export(machine_schema_exports, {
12124
+ MachineConfigSchema: () => MachineConfigSchema,
12125
+ initMachineConfig: () => initMachineConfig,
12126
+ readMachineConfig: () => readMachineConfig,
12127
+ writeMachineConfig: () => writeMachineConfig
12128
+ });
12129
+ import * as fs32 from "node:fs";
12130
+ import * as path36 from "node:path";
12131
+ import * as os19 from "node:os";
12132
+ import { parse as parseYaml4, stringify as stringifyYaml4 } from "yaml";
12133
+ function readMachineConfig(configPath) {
12134
+ const p = configPath ?? DEFAULT_CONFIG_PATH;
12135
+ if (!fs32.existsSync(p)) return null;
12136
+ try {
12137
+ const raw = fs32.readFileSync(p, "utf-8");
12138
+ const parsed = parseYaml4(raw);
12139
+ return MachineConfigSchema.parse(parsed);
12140
+ } catch {
12141
+ return null;
12142
+ }
12143
+ }
12144
+ function writeMachineConfig(config, configPath) {
12145
+ const p = configPath ?? DEFAULT_CONFIG_PATH;
12146
+ fs32.mkdirSync(path36.dirname(p), { recursive: true });
12147
+ fs32.writeFileSync(p, stringifyYaml4({ ...config }), { mode: 420 });
12148
+ }
12149
+ function initMachineConfig(opts = {}) {
12150
+ const configPath = opts.configPath ?? DEFAULT_CONFIG_PATH;
12151
+ const existing = readMachineConfig(configPath);
12152
+ if (existing) return existing;
12153
+ const config = MachineConfigSchema.parse({
12154
+ telemetry: opts.telemetry ?? true
12155
+ });
12156
+ writeMachineConfig(config, configPath);
12157
+ return config;
12158
+ }
12159
+ var MachineConfigSchema, DEFAULT_CONFIG_PATH;
12160
+ var init_machine_schema = __esm({
12161
+ "../core/src/config/machine-schema.ts"() {
12162
+ "use strict";
12163
+ init_zod();
12164
+ MachineConfigSchema = external_exports.object({
12165
+ schema_version: external_exports.literal(1).default(1),
12166
+ channel: external_exports.enum(["stable", "beta", "edge"]).default("stable"),
12167
+ auto_update: external_exports.boolean().default(true),
12168
+ telemetry: external_exports.boolean().default(true),
12169
+ worlds_dir: external_exports.string().default(() => path36.join(os19.homedir(), ".olam", "worlds"))
12170
+ });
12171
+ DEFAULT_CONFIG_PATH = path36.join(os19.homedir(), ".olam", "config.yaml");
12172
+ }
12173
+ });
12174
+
12121
12175
  // src/index.ts
12122
12176
  import { Command } from "commander";
12123
- import * as fs31 from "node:fs";
12124
- import * as path35 from "node:path";
12177
+ import * as fs35 from "node:fs";
12178
+ import * as path39 from "node:path";
12125
12179
  import { fileURLToPath as fileURLToPath4 } from "node:url";
12126
12180
 
12127
12181
  // src/commands/init.ts
@@ -12529,11 +12583,11 @@ var UnknownArchetypeError = class extends Error {
12529
12583
  known;
12530
12584
  };
12531
12585
  var ArchetypeCycleError = class extends Error {
12532
- constructor(path36) {
12586
+ constructor(path40) {
12533
12587
  super(
12534
- `Archetype inheritance cycle detected: ${path36.join(" \u2192 ")} \u2192 ${path36[0] ?? "?"}`
12588
+ `Archetype inheritance cycle detected: ${path40.join(" \u2192 ")} \u2192 ${path40[0] ?? "?"}`
12535
12589
  );
12536
- this.path = path36;
12590
+ this.path = path40;
12537
12591
  this.name = "ArchetypeCycleError";
12538
12592
  }
12539
12593
  path;
@@ -12547,15 +12601,15 @@ function walk(name, acc, stack) {
12547
12601
  if (stack.includes(name)) {
12548
12602
  throw new ArchetypeCycleError([...stack, name]);
12549
12603
  }
12550
- const arch = getArchetype(name);
12551
- if (!arch) {
12604
+ const arch2 = getArchetype(name);
12605
+ if (!arch2) {
12552
12606
  throw new UnknownArchetypeError(name, listArchetypeNames());
12553
12607
  }
12554
12608
  const nextStack = [...stack, name];
12555
- for (const parent of arch.inherits ?? []) {
12609
+ for (const parent of arch2.inherits ?? []) {
12556
12610
  walk(parent, acc, nextStack);
12557
12611
  }
12558
- for (const cap of arch.capabilities) {
12612
+ for (const cap of arch2.capabilities) {
12559
12613
  acc.add(cap);
12560
12614
  }
12561
12615
  }
@@ -12659,8 +12713,8 @@ function registerInstall(program2) {
12659
12713
  }
12660
12714
  if (!opts.as) {
12661
12715
  printError("Missing --as <archetype>. Known archetypes:");
12662
- for (const arch of ARCHETYPES) {
12663
- console.log(` ${pc4.bold(arch.name.padEnd(20))} ${pc4.dim(arch.description)}`);
12716
+ for (const arch2 of ARCHETYPES) {
12717
+ console.log(` ${pc4.bold(arch2.name.padEnd(20))} ${pc4.dim(arch2.description)}`);
12664
12718
  }
12665
12719
  process.exitCode = 1;
12666
12720
  return;
@@ -13374,10 +13428,10 @@ async function readHostCpToken2() {
13374
13428
  if (!fs19.existsSync(tp)) return null;
13375
13429
  return fs19.readFileSync(tp, "utf-8").trim();
13376
13430
  }
13377
- async function callHostCpProxy(method, worldId, path36, body) {
13431
+ async function callHostCpProxy(method, worldId, path40, body) {
13378
13432
  const token = await readHostCpToken2();
13379
13433
  if (!token) return { ok: false, status: 0, error: "no token (host CP not started)" };
13380
- const url = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path36}`;
13434
+ const url = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path40}`;
13381
13435
  try {
13382
13436
  const headers = {
13383
13437
  Authorization: `Bearer ${token}`
@@ -14450,9 +14504,9 @@ function formatFreshnessWarning(result, image = DEFAULT_DEVBOX_IMAGE) {
14450
14504
  "These source files have changed since the image was built; the",
14451
14505
  "changes will NOT take effect in fresh worlds until you rebuild:"
14452
14506
  ];
14453
- for (const { path: path36, mtimeMs } of result.newerSources) {
14507
+ for (const { path: path40, mtimeMs } of result.newerSources) {
14454
14508
  const when = new Date(mtimeMs).toISOString();
14455
- lines.push(` \u2022 ${path36} (modified ${when})`);
14509
+ lines.push(` \u2022 ${path40} (modified ${when})`);
14456
14510
  }
14457
14511
  lines.push("");
14458
14512
  lines.push("Rebuild with:");
@@ -14612,15 +14666,15 @@ init_context();
14612
14666
  var HOST_CP_URL = "http://127.0.0.1:19000";
14613
14667
  async function readHostCpTokenForCreate() {
14614
14668
  try {
14615
- const { default: fs32 } = await import("node:fs");
14616
- const { default: os18 } = await import("node:os");
14617
- const { default: path36 } = await import("node:path");
14618
- const tp = path36.join(
14619
- process.env.OLAM_HOME ?? path36.join(os18.homedir(), ".olam"),
14669
+ const { default: fs36 } = await import("node:fs");
14670
+ const { default: os21 } = await import("node:os");
14671
+ const { default: path40 } = await import("node:path");
14672
+ const tp = path40.join(
14673
+ process.env.OLAM_HOME ?? path40.join(os21.homedir(), ".olam"),
14620
14674
  "host-cp.token"
14621
14675
  );
14622
- if (!fs32.existsSync(tp)) return null;
14623
- return fs32.readFileSync(tp, "utf-8").trim();
14676
+ if (!fs36.existsSync(tp)) return null;
14677
+ return fs36.readFileSync(tp, "utf-8").trim();
14624
14678
  } catch {
14625
14679
  return null;
14626
14680
  }
@@ -14982,12 +15036,12 @@ function defaultNameFromPrompt(prompt) {
14982
15036
  }
14983
15037
  async function readHostCpToken3() {
14984
15038
  try {
14985
- const { default: fs32 } = await import("node:fs");
14986
- const { default: os18 } = await import("node:os");
14987
- const { default: path36 } = await import("node:path");
14988
- const tp = path36.join(os18.homedir(), ".olam", "host-cp.token");
14989
- if (!fs32.existsSync(tp)) return null;
14990
- const raw = fs32.readFileSync(tp, "utf-8").trim();
15039
+ const { default: fs36 } = await import("node:fs");
15040
+ const { default: os21 } = await import("node:os");
15041
+ const { default: path40 } = await import("node:path");
15042
+ const tp = path40.join(os21.homedir(), ".olam", "host-cp.token");
15043
+ if (!fs36.existsSync(tp)) return null;
15044
+ const raw = fs36.readFileSync(tp, "utf-8").trim();
14991
15045
  return raw.length > 0 ? raw : null;
14992
15046
  } catch {
14993
15047
  return null;
@@ -16200,15 +16254,15 @@ var AST = class {
16200
16254
  parts: this.#parts
16201
16255
  };
16202
16256
  }
16203
- constructor(type, parent, options = {}) {
16204
- this.type = type;
16205
- if (type)
16257
+ constructor(type2, parent, options = {}) {
16258
+ this.type = type2;
16259
+ if (type2)
16206
16260
  this.#hasMagic = true;
16207
16261
  this.#parent = parent;
16208
16262
  this.#root = this.#parent ? this.#parent.#root : this;
16209
16263
  this.#options = this.#root === this ? options : this.#root.#options;
16210
16264
  this.#negs = this.#root === this ? [] : this.#root.#negs;
16211
- if (type === "!" && !this.#root.#filledNegs)
16265
+ if (type2 === "!" && !this.#root.#filledNegs)
16212
16266
  this.#negs.push(this);
16213
16267
  this.#parentIndex = this.#parent ? this.#parent.#parts.length : 0;
16214
16268
  }
@@ -16851,8 +16905,8 @@ var defaults = (def) => {
16851
16905
  },
16852
16906
  AST: class AST extends orig.AST {
16853
16907
  /* c8 ignore start */
16854
- constructor(type, parent, options = {}) {
16855
- super(type, parent, ext(def, options));
16908
+ constructor(type2, parent, options = {}) {
16909
+ super(type2, parent, ext(def, options));
16856
16910
  }
16857
16911
  /* c8 ignore stop */
16858
16912
  static fromGlob(pattern, options = {}) {
@@ -19936,19 +19990,477 @@ Run \`olam refresh\` from the olam repo root.`
19936
19990
  });
19937
19991
  }
19938
19992
 
19939
- // src/pleri-config.ts
19993
+ // src/commands/diagnose.ts
19940
19994
  import * as fs30 from "node:fs";
19995
+ import * as os18 from "node:os";
19941
19996
  import * as path34 from "node:path";
19997
+ import { execFileSync as execFileSync5, execSync as execSync10 } from "node:child_process";
19998
+ import pc20 from "picocolors";
19999
+
20000
+ // ../core/src/diagnose/secret-stripper.ts
20001
+ var SECRET_PATTERNS = [
20002
+ { name: "anthropic-key", re: /sk-ant-[A-Za-z0-9\-_]{8,}/g },
20003
+ { name: "github-pat", re: /gh[pourstu]_[A-Za-z0-9]{20,}/g },
20004
+ { name: "github-pat-fgp", re: /github_pat_[A-Za-z0-9_]{22,}/g },
20005
+ { name: "aws-access-key", re: /AKIA[A-Z0-9]{16}/g },
20006
+ { name: "bearer-header", re: /Bearer\s+[A-Za-z0-9._\-+/=]{16,}/g },
20007
+ { name: "slack-token", re: /xox[bpsa]-[A-Za-z0-9-]{10,}/g },
20008
+ { name: "host-cp-token", re: /(?:host[-_.]?cp[-_.]?token|"token")\s*[:=]\s*"?([A-Za-z0-9._\-]{16,})"?/gi },
20009
+ { name: "generic-hex-key", re: /\bkey\s*[:=]\s*[0-9a-f]{32,}/gi },
20010
+ { name: "db-url", re: /(?:postgres|mysql|redis|mongodb):\/\/[^:]+:[^@]+@[^\s'"]+/gi },
20011
+ { name: "env-secret", re: /(?:API_KEY|SECRET_KEY|AUTH_TOKEN|ACCESS_TOKEN|PRIVATE_KEY|DATABASE_URL|REDIS_URL)\s*[=:]\s*\S+/gi },
20012
+ { name: "pem-key", re: /-----BEGIN (?:RSA |EC )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC )?PRIVATE KEY-----/g }
20013
+ ];
20014
+ var REDACTED = "[REDACTED]";
20015
+ function stripSecrets(input) {
20016
+ let out = input;
20017
+ for (const { re } of SECRET_PATTERNS) {
20018
+ re.lastIndex = 0;
20019
+ out = out.replace(re, (match2) => {
20020
+ const colonOrEq = match2.indexOf(":") !== -1 ? match2.indexOf(":") : match2.indexOf("=");
20021
+ if (colonOrEq !== -1 && (match2.includes("token") || match2.includes("key") || match2.includes("KEY"))) {
20022
+ return match2.slice(0, colonOrEq + 1) + " " + REDACTED;
20023
+ }
20024
+ return REDACTED;
20025
+ });
20026
+ }
20027
+ return out;
20028
+ }
20029
+
20030
+ // src/commands/diagnose.ts
20031
+ var DIAGNOSTICS_DIR = path34.join(os18.homedir(), ".olam", "diagnostics");
20032
+ var LOG_DIR = path34.join(os18.homedir(), ".olam", "log");
20033
+ var CACHE_DIR = path34.join(os18.homedir(), ".olam", "cache");
20034
+ var LOG_TAIL_LINES = 200;
20035
+ function safeExec(cmd) {
20036
+ try {
20037
+ return execSync10(cmd, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
20038
+ } catch {
20039
+ return "";
20040
+ }
20041
+ }
20042
+ function defaultZip(zipPath, files) {
20043
+ execFileSync5("zip", ["-j", zipPath, ...files]);
20044
+ }
20045
+ async function buildDiagnosticsZip(_exec = (cmd) => safeExec(cmd), _outDir = DIAGNOSTICS_DIR, _logDir = LOG_DIR, _zip = defaultZip) {
20046
+ const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 23);
20047
+ const zipPath = path34.join(_outDir, `olam-diag-${ts}.zip`);
20048
+ const tmpDir = fs30.mkdtempSync(path34.join(os18.tmpdir(), "olam-diag-"));
20049
+ try {
20050
+ fs30.mkdirSync(_outDir, { recursive: true });
20051
+ const entries = [];
20052
+ const version = process.env["OLAM_CLI_VERSION"] ?? "unknown";
20053
+ const nodeVersion = process.version;
20054
+ const platform = `${process.platform}/${process.arch}`;
20055
+ const versionContent = `olam: ${version}
20056
+ node: ${nodeVersion}
20057
+ platform: ${platform}
20058
+ `;
20059
+ _writeEntry(tmpDir, "version.txt", stripSecrets(versionContent), entries);
20060
+ const osContent = [
20061
+ `os: ${os18.type()} ${os18.release()}`,
20062
+ `arch: ${os18.arch()}`,
20063
+ `uptime: ${os18.uptime()}s`
20064
+ ].join("\n") + "\n";
20065
+ _writeEntry(tmpDir, "os-info.txt", stripSecrets(osContent), entries);
20066
+ const depsFile = path34.join(CACHE_DIR, "deps.json");
20067
+ if (fs30.existsSync(depsFile)) {
20068
+ const deps = fs30.readFileSync(depsFile, "utf-8");
20069
+ _writeEntry(tmpDir, "deps.json", stripSecrets(deps), entries);
20070
+ }
20071
+ const latestLog = _latestLog(_logDir);
20072
+ if (latestLog) {
20073
+ const lines = fs30.readFileSync(latestLog, "utf-8").split("\n");
20074
+ const tail = lines.slice(-LOG_TAIL_LINES).join("\n");
20075
+ _writeEntry(tmpDir, "log-tail.txt", stripSecrets(tail), entries);
20076
+ }
20077
+ const statusOut = _exec("olam status --json");
20078
+ if (statusOut) {
20079
+ _writeEntry(tmpDir, "status.json", stripSecrets(statusOut), entries);
20080
+ }
20081
+ const authAudit = _exec("npm run audit:auth-callers --if-present 2>&1");
20082
+ if (authAudit) {
20083
+ _writeEntry(tmpDir, "audit-auth-callers.txt", stripSecrets(authAudit), entries);
20084
+ }
20085
+ const fileArgs = entries.map((e) => path34.join(tmpDir, e));
20086
+ try {
20087
+ _zip(zipPath, fileArgs);
20088
+ } catch (err) {
20089
+ throw new Error(`zip command produced no output file. zip stderr: ${err.message}`);
20090
+ }
20091
+ if (!fs30.existsSync(zipPath)) {
20092
+ throw new Error("zip command produced no output file.");
20093
+ }
20094
+ return { zipPath, entries };
20095
+ } finally {
20096
+ try {
20097
+ fs30.rmSync(tmpDir, { recursive: true, force: true });
20098
+ } catch {
20099
+ }
20100
+ }
20101
+ }
20102
+ function _writeEntry(dir, name, content, entries) {
20103
+ fs30.writeFileSync(path34.join(dir, name), content, { mode: 420 });
20104
+ entries.push(name);
20105
+ }
20106
+ function _latestLog(logDir) {
20107
+ if (!fs30.existsSync(logDir)) return null;
20108
+ const files = fs30.readdirSync(logDir).filter((f) => f.startsWith("host-")).sort().reverse();
20109
+ return files.length > 0 ? path34.join(logDir, files[0]) : null;
20110
+ }
20111
+ async function buildTelemetryPayload() {
20112
+ const channel = "stable";
20113
+ const manifestFile = path34.join(CACHE_DIR, "manifest.json");
20114
+ let manifestAgeHours = null;
20115
+ if (fs30.existsSync(manifestFile)) {
20116
+ const mtime = fs30.statSync(manifestFile).mtime.getTime();
20117
+ manifestAgeHours = Math.round((Date.now() - mtime) / 36e5);
20118
+ }
20119
+ return {
20120
+ version: process.env["OLAM_CLI_VERSION"] ?? "unknown",
20121
+ os: process.platform,
20122
+ arch: process.arch,
20123
+ channel,
20124
+ manifest_age_hours: manifestAgeHours
20125
+ // No userid, no project, no path — privacy per design doc
20126
+ };
20127
+ }
20128
+ function registerDiagnose(program2) {
20129
+ program2.command("diagnose").description("Bundle diagnostics into a zip file for sharing with maintainers").option("--show-telemetry", "Print the telemetry payload that would be sent (no endpoint yet)").option("--no-telemetry", "Suppress telemetry payload (future opt-out)").option("--upload", "Share zip with maintainers (endpoint not yet provisioned)").option("--quiet", "Suppress progress output").action(async (opts) => {
20130
+ if (opts.showTelemetry) {
20131
+ const payload = await buildTelemetryPayload();
20132
+ console.log(JSON.stringify(payload, null, 2));
20133
+ return;
20134
+ }
20135
+ if (!opts.quiet) {
20136
+ console.log(pc20.cyan("Building diagnostics zip\u2026"));
20137
+ }
20138
+ try {
20139
+ const { zipPath, entries } = await buildDiagnosticsZip();
20140
+ if (!opts.quiet) {
20141
+ console.log(pc20.green(`Done: ${zipPath}`));
20142
+ console.log(pc20.dim(`Contents: ${entries.join(", ")}`));
20143
+ }
20144
+ if (opts.upload) {
20145
+ console.log(pc20.yellow(
20146
+ `Telemetry endpoint not yet provisioned. Share the zip manually:
20147
+ File: ${zipPath}
20148
+ See docs/runbooks/share-diagnostics.md for instructions.`
20149
+ ));
20150
+ }
20151
+ } catch (err) {
20152
+ console.error(pc20.red(`Diagnose failed: ${err.message}`));
20153
+ process.exitCode = 1;
20154
+ }
20155
+ });
20156
+ }
20157
+
20158
+ // src/commands/update.ts
20159
+ import * as fs33 from "node:fs";
20160
+ import * as os20 from "node:os";
20161
+ import * as path37 from "node:path";
20162
+ import { execSync as execSync11 } from "node:child_process";
20163
+ import pc21 from "picocolors";
20164
+
20165
+ // src/lib/symlink-reconcile.ts
20166
+ import * as fs31 from "node:fs";
20167
+ import * as path35 from "node:path";
20168
+ var realFs = {
20169
+ readdirSync: (p) => fs31.readdirSync(p),
20170
+ existsSync: (p) => fs31.existsSync(p),
20171
+ lstatSync: (p) => fs31.lstatSync(p),
20172
+ readlinkSync: (p) => fs31.readlinkSync(p),
20173
+ symlinkSync: (t, l) => fs31.symlinkSync(t, l),
20174
+ unlinkSync: (p) => fs31.unlinkSync(p),
20175
+ mkdirSync: (p, o) => {
20176
+ fs31.mkdirSync(p, o);
20177
+ }
20178
+ };
20179
+ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir, _fs = realFs) {
20180
+ const added = [];
20181
+ const removed = [];
20182
+ const kept = [];
20183
+ _fs.mkdirSync(claudeSkillsDir, { recursive: true });
20184
+ const sourceSkills = _fs.existsSync(npmSkillsDir) ? _fs.readdirSync(npmSkillsDir).filter((d) => d.startsWith("olam-")) : [];
20185
+ for (const skill of sourceSkills) {
20186
+ const linkPath = path35.join(claudeSkillsDir, skill);
20187
+ const target = path35.join(npmSkillsDir, skill);
20188
+ if (!_fs.existsSync(linkPath)) {
20189
+ try {
20190
+ _fs.symlinkSync(target, linkPath);
20191
+ added.push(skill);
20192
+ } catch (e) {
20193
+ if (e.code !== "EEXIST") throw e;
20194
+ kept.push(skill);
20195
+ }
20196
+ }
20197
+ }
20198
+ const deployedEntries = _fs.existsSync(claudeSkillsDir) ? _fs.readdirSync(claudeSkillsDir).filter((d) => d.startsWith("olam-")) : [];
20199
+ for (const entry of deployedEntries) {
20200
+ const linkPath = path35.join(claudeSkillsDir, entry);
20201
+ let isSymlink = false;
20202
+ try {
20203
+ isSymlink = _fs.lstatSync(linkPath).isSymbolicLink();
20204
+ } catch {
20205
+ continue;
20206
+ }
20207
+ if (!isSymlink) continue;
20208
+ const target = _fs.readlinkSync(linkPath);
20209
+ if (!target.includes("@pleri/olam-cli")) {
20210
+ kept.push(entry);
20211
+ continue;
20212
+ }
20213
+ if (_fs.existsSync(target)) {
20214
+ kept.push(entry);
20215
+ } else {
20216
+ _fs.unlinkSync(linkPath);
20217
+ removed.push(entry);
20218
+ }
20219
+ }
20220
+ return { added, removed, kept };
20221
+ }
20222
+
20223
+ // src/commands/update.ts
20224
+ var PACKAGE_NAME = "@pleri/olam-cli";
20225
+ var CACHE_DIR2 = path37.join(os20.homedir(), ".olam", "cache");
20226
+ var LOG_DIR2 = path37.join(os20.homedir(), ".olam", "log");
20227
+ var LAST_STABLE_FILE = path37.join(CACHE_DIR2, "last-stable.txt");
20228
+ function defaultExec(cmd) {
20229
+ try {
20230
+ const stdout = execSync11(cmd, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
20231
+ return { exitCode: 0, stdout, stderr: "" };
20232
+ } catch (err) {
20233
+ const e = err;
20234
+ return { exitCode: e.status ?? 1, stdout: e.stdout ?? "", stderr: e.stderr ?? "" };
20235
+ }
20236
+ }
20237
+ function getCurrentVersion(_exec = defaultExec) {
20238
+ const result = _exec(`npm ls -g ${PACKAGE_NAME} --json --depth=0`);
20239
+ if (result.exitCode !== 0) return null;
20240
+ try {
20241
+ const parsed = JSON.parse(result.stdout);
20242
+ return parsed.dependencies?.[PACKAGE_NAME]?.version ?? null;
20243
+ } catch {
20244
+ return null;
20245
+ }
20246
+ }
20247
+ function readLastStable(file = LAST_STABLE_FILE) {
20248
+ try {
20249
+ const v = fs33.readFileSync(file, "utf-8").trim();
20250
+ return v || null;
20251
+ } catch {
20252
+ return null;
20253
+ }
20254
+ }
20255
+ function writeLastStable(version, file = LAST_STABLE_FILE) {
20256
+ fs33.mkdirSync(path37.dirname(file), { recursive: true });
20257
+ fs33.writeFileSync(file, version, { mode: 420 });
20258
+ }
20259
+ function logUpdateFailure(stderr) {
20260
+ const ts = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
20261
+ const logFile = path37.join(LOG_DIR2, `update-${ts}.log`);
20262
+ try {
20263
+ fs33.mkdirSync(LOG_DIR2, { recursive: true });
20264
+ fs33.appendFileSync(logFile, `[update-failure ${(/* @__PURE__ */ new Date()).toISOString()}]
20265
+ ${stderr}
20266
+ `, "utf-8");
20267
+ } catch {
20268
+ }
20269
+ }
20270
+ var SAFE_VERSION_RE = /^[a-zA-Z0-9._-]{1,64}$/;
20271
+ function isUpgradeBlocked(channelOrVersion, _exec = defaultExec) {
20272
+ if (!SAFE_VERSION_RE.test(channelOrVersion)) return false;
20273
+ const result = _exec(`npm view ${PACKAGE_NAME}@${channelOrVersion} olam.upgrade_blocked --json`);
20274
+ if (result.exitCode !== 0) return false;
20275
+ try {
20276
+ const val = JSON.parse(result.stdout.trim());
20277
+ return val === true;
20278
+ } catch {
20279
+ return false;
20280
+ }
20281
+ }
20282
+ async function doUpdate(opts, _exec = defaultExec, _reconcile = reconcileSkillSymlinks, _readConfig, _getNpmRoot = defaultExec) {
20283
+ const readConfig = _readConfig ?? (async () => {
20284
+ const { readMachineConfig: readMachineConfig2 } = await Promise.resolve().then(() => (init_machine_schema(), machine_schema_exports));
20285
+ return readMachineConfig2();
20286
+ });
20287
+ const config = await readConfig();
20288
+ const channel = opts.channel ?? config?.channel ?? "stable";
20289
+ const quiet = opts.quiet ?? false;
20290
+ const force = opts.force ?? false;
20291
+ if (!SAFE_VERSION_RE.test(channel)) {
20292
+ if (!quiet) console.error(`Invalid channel/version: ${channel}`);
20293
+ return { action: "failed", exitCode: 11 };
20294
+ }
20295
+ if (!force && config && config.auto_update === false) {
20296
+ if (!quiet) {
20297
+ console.log("Updates frozen. Run `olam update --force` to override or `olam update --freeze` to manage.");
20298
+ }
20299
+ return { action: "failed", exitCode: 11 };
20300
+ }
20301
+ if (!force) {
20302
+ const blocked = isUpgradeBlocked(channel, _exec);
20303
+ if (blocked) {
20304
+ if (!quiet) {
20305
+ console.error(`Version @${channel} has upgrade_blocked: true. Run with --force to override.`);
20306
+ }
20307
+ return { action: "failed", exitCode: 11 };
20308
+ }
20309
+ }
20310
+ const prevVersion = getCurrentVersion(_exec);
20311
+ if (prevVersion) {
20312
+ writeLastStable(prevVersion);
20313
+ }
20314
+ if (!quiet) {
20315
+ console.log(pc21.cyan(`Installing ${PACKAGE_NAME}@${channel}\u2026`));
20316
+ }
20317
+ const installResult = _exec(`npm install -g ${PACKAGE_NAME}@${channel}`);
20318
+ if (installResult.exitCode !== 0) {
20319
+ logUpdateFailure(installResult.stderr);
20320
+ if (!quiet) {
20321
+ console.error(pc21.red("Update failed."));
20322
+ }
20323
+ const prev = readLastStable();
20324
+ if (prev) {
20325
+ if (!quiet) {
20326
+ console.log(pc21.yellow(`Restoring to ${prev}\u2026`));
20327
+ }
20328
+ const restoreResult = _exec(`npm install -g ${PACKAGE_NAME}@${prev}`);
20329
+ if (restoreResult.exitCode !== 0) {
20330
+ if (!quiet) {
20331
+ console.error(pc21.red(
20332
+ `Restore also failed. Run: npm install -g ${PACKAGE_NAME}@${prev} manually.`
20333
+ ));
20334
+ }
20335
+ } else if (!quiet) {
20336
+ console.log(pc21.yellow(`Restored to ${prev}.`));
20337
+ }
20338
+ } else if (!quiet) {
20339
+ console.error(pc21.red("No previous version cached; cannot auto-restore."));
20340
+ }
20341
+ return { action: "restored", prevVersion: prev ?? void 0, exitCode: 11 };
20342
+ }
20343
+ const newVersion = getCurrentVersion(_exec) ?? void 0;
20344
+ if (!quiet && newVersion) {
20345
+ console.log(pc21.green(`Updated to ${newVersion}.`));
20346
+ }
20347
+ const npmRootResult = _getNpmRoot("npm root -g");
20348
+ let symlinkResult = { added: [], removed: [] };
20349
+ if (npmRootResult.exitCode === 0) {
20350
+ const npmRoot = npmRootResult.stdout.trim();
20351
+ const npmSkillsDir = path37.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills");
20352
+ const claudeSkillsDir = path37.join(os20.homedir(), ".claude", "skills");
20353
+ const rec = _reconcile(npmSkillsDir, claudeSkillsDir);
20354
+ symlinkResult = { added: rec.added, removed: rec.removed };
20355
+ if (!quiet && (rec.added.length > 0 || rec.removed.length > 0)) {
20356
+ if (rec.added.length > 0) {
20357
+ console.log(pc21.dim(`Skills added: ${rec.added.join(", ")}`));
20358
+ }
20359
+ if (rec.removed.length > 0) {
20360
+ console.log(pc21.dim(`Skills removed (dangling): ${rec.removed.join(", ")}`));
20361
+ }
20362
+ }
20363
+ }
20364
+ return {
20365
+ action: "installed",
20366
+ version: newVersion,
20367
+ prevVersion: prevVersion ?? void 0,
20368
+ exitCode: 0,
20369
+ symlinks: symlinkResult
20370
+ };
20371
+ }
20372
+ async function doCheck(_exec = defaultExec) {
20373
+ const current = getCurrentVersion(_exec);
20374
+ const viewResult = _exec(`npm view ${PACKAGE_NAME} dist-tags.stable`);
20375
+ const latest = viewResult.exitCode === 0 ? viewResult.stdout.trim() || null : null;
20376
+ if (current && latest && current === latest) {
20377
+ return { action: "already-current", current, latest, exitCode: 10 };
20378
+ }
20379
+ return { action: "update-available", current, latest, exitCode: 0 };
20380
+ }
20381
+ async function doRollback(_exec = defaultExec, _reconcile = reconcileSkillSymlinks, _getNpmRoot = defaultExec) {
20382
+ const prev = readLastStable();
20383
+ if (!prev) {
20384
+ return { action: "nothing-to-rollback", exitCode: 14 };
20385
+ }
20386
+ const current = getCurrentVersion(_exec);
20387
+ if (current && current === prev) {
20388
+ return { action: "already-at-cached", restoredVersion: prev, exitCode: 0 };
20389
+ }
20390
+ const result = _exec(`npm install -g ${PACKAGE_NAME}@${prev}`);
20391
+ if (result.exitCode !== 0) {
20392
+ return { action: "failed", restoredVersion: prev, exitCode: 11 };
20393
+ }
20394
+ const npmRootResult = _getNpmRoot("npm root -g");
20395
+ if (npmRootResult.exitCode === 0) {
20396
+ const npmRoot = npmRootResult.stdout.trim();
20397
+ _reconcile(
20398
+ path37.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills"),
20399
+ path37.join(os20.homedir(), ".claude", "skills")
20400
+ );
20401
+ }
20402
+ return { action: "rolled-back", restoredVersion: prev, exitCode: 0 };
20403
+ }
20404
+ function registerUpdate(program2) {
20405
+ program2.command("update").description("Update @pleri/olam-cli to the latest version on the configured channel").option("--to <version>", "Install a specific version").option("--rollback", "Restore the previously installed version").option("--check", "Check if a newer version is available (read-only)").option("--channel <channel>", "Switch to channel and install (stable|beta|edge)").option("--freeze", "Disable automatic updates (sets auto_update: false)").option("--force", "Override freeze and upgrade_blocked checks").option("--quiet", "Suppress output").action(async (opts) => {
20406
+ if (opts.freeze) {
20407
+ const { readMachineConfig: readMachineConfig2, writeMachineConfig: writeMachineConfig2, MachineConfigSchema: MachineConfigSchema2 } = await Promise.resolve().then(() => (init_machine_schema(), machine_schema_exports));
20408
+ const cfg = readMachineConfig2() ?? MachineConfigSchema2.parse({});
20409
+ writeMachineConfig2({ ...cfg, auto_update: false });
20410
+ if (!opts.quiet) console.log("Updates frozen. Run `olam update --force` to override.");
20411
+ return;
20412
+ }
20413
+ if (opts.check) {
20414
+ const r = await doCheck();
20415
+ if (!opts.quiet) {
20416
+ if (r.action === "already-current") {
20417
+ console.log(`Already on latest: ${r.current}`);
20418
+ } else {
20419
+ console.log(`Current: ${r.current ?? "unknown"}, Latest: ${r.latest ?? "unknown"}`);
20420
+ }
20421
+ }
20422
+ process.exitCode = r.exitCode;
20423
+ return;
20424
+ }
20425
+ if (opts.rollback) {
20426
+ const r = await doRollback();
20427
+ if (!opts.quiet) {
20428
+ if (r.action === "nothing-to-rollback") {
20429
+ console.error("Nothing to roll back. Use --to=<version> for a specific target.");
20430
+ } else if (r.action === "already-at-cached") {
20431
+ console.log(`Already at cached version ${r.restoredVersion}. Use --to=<v> for older targets.`);
20432
+ } else if (r.action === "rolled-back") {
20433
+ console.log(`Rolled back to ${r.restoredVersion}.`);
20434
+ } else {
20435
+ console.error(`Rollback failed.`);
20436
+ }
20437
+ }
20438
+ process.exitCode = r.exitCode;
20439
+ return;
20440
+ }
20441
+ if (opts.channel) {
20442
+ const { readMachineConfig: readMachineConfig2, writeMachineConfig: writeMachineConfig2, MachineConfigSchema: MachineConfigSchema2 } = await Promise.resolve().then(() => (init_machine_schema(), machine_schema_exports));
20443
+ const cfg = readMachineConfig2() ?? MachineConfigSchema2.parse({});
20444
+ writeMachineConfig2({ ...cfg, channel: opts.channel });
20445
+ }
20446
+ const result = await doUpdate({ channel: opts.to ?? opts.channel, quiet: opts.quiet, force: opts.force });
20447
+ process.exitCode = result.exitCode;
20448
+ });
20449
+ }
20450
+
20451
+ // src/pleri-config.ts
20452
+ import * as fs34 from "node:fs";
20453
+ import * as path38 from "node:path";
19942
20454
  function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
19943
20455
  if (process.env.PLERI_BASE_URL) {
19944
20456
  return true;
19945
20457
  }
19946
- const configPath = path34.join(configDir, "config.yaml");
19947
- if (!fs30.existsSync(configPath)) {
20458
+ const configPath = path38.join(configDir, "config.yaml");
20459
+ if (!fs34.existsSync(configPath)) {
19948
20460
  return false;
19949
20461
  }
19950
20462
  try {
19951
- const contents = fs30.readFileSync(configPath, "utf8");
20463
+ const contents = fs34.readFileSync(configPath, "utf8");
19952
20464
  return /^[^#\n]*\bpleri:/m.test(contents);
19953
20465
  } catch {
19954
20466
  return false;
@@ -19959,14 +20471,14 @@ function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
19959
20471
  var program = new Command();
19960
20472
  function readCliVersion() {
19961
20473
  try {
19962
- const here = path35.dirname(fileURLToPath4(import.meta.url));
20474
+ const here = path39.dirname(fileURLToPath4(import.meta.url));
19963
20475
  for (const candidate of [
19964
- path35.join(here, "package.json"),
19965
- path35.join(here, "..", "package.json"),
19966
- path35.join(here, "..", "..", "package.json")
20476
+ path39.join(here, "package.json"),
20477
+ path39.join(here, "..", "package.json"),
20478
+ path39.join(here, "..", "..", "package.json")
19967
20479
  ]) {
19968
- if (fs31.existsSync(candidate)) {
19969
- const pkg = JSON.parse(fs31.readFileSync(candidate, "utf-8"));
20480
+ if (fs35.existsSync(candidate)) {
20481
+ const pkg = JSON.parse(fs35.readFileSync(candidate, "utf-8"));
19970
20482
  if (typeof pkg.version === "string" && pkg.version.length > 0) return pkg.version;
19971
20483
  }
19972
20484
  }
@@ -19998,4 +20510,6 @@ registerKeys(program);
19998
20510
  registerWorldSnapshot(program);
19999
20511
  registerRefresh(program);
20000
20512
  registerBootstrap(program);
20513
+ registerDiagnose(program);
20514
+ registerUpdate(program);
20001
20515
  program.parse();