@pleri/olam-cli 0.1.195 → 0.1.196

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
@@ -7751,6 +7751,19 @@ import { spawnSync as spawnSync3 } from "node:child_process";
7751
7751
  import { existsSync as existsSync14, readdirSync as readdirSync2, readFileSync as readFileSync14, statSync } from "node:fs";
7752
7752
  import { homedir as homedir9 } from "node:os";
7753
7753
  import path14 from "node:path";
7754
+ function resolveAnthropicBaseUrl(olamHomeOverride) {
7755
+ const envFirst = process.env.OLAM_ANTHROPIC_BASE_URL ?? process.env.ANTHROPIC_BASE_URL;
7756
+ if (envFirst && envFirst.trim().length > 0) return envFirst.trim();
7757
+ try {
7758
+ const olamHome6 = olamHomeOverride ?? process.env.OLAM_HOME ?? path14.join(homedir9(), ".olam");
7759
+ const filePath = path14.join(olamHome6, "anthropic-base-url");
7760
+ if (!existsSync14(filePath)) return null;
7761
+ const body = readFileSync14(filePath, "utf-8").trim();
7762
+ return body.length > 0 ? body : null;
7763
+ } catch {
7764
+ return null;
7765
+ }
7766
+ }
7754
7767
  async function probeDockerDaemon(dockerExec = defaultDockerExec) {
7755
7768
  const r = dockerExec("docker", ["info", "--format", "{{.ServerVersion}}"]);
7756
7769
  if (r.status === 0 && r.stdout.trim().length > 0) {
@@ -7854,6 +7867,11 @@ function isHostCpHealthEnvelope(body) {
7854
7867
  return true;
7855
7868
  }
7856
7869
  async function probeAuthVault(olamHomeOverride) {
7870
+ const remoteUrl = resolveAnthropicBaseUrl(olamHomeOverride);
7871
+ if (remoteUrl !== null) {
7872
+ const safeUrl = remoteUrl.replace(/\/\/[^@/]*@/, "//<redacted>@");
7873
+ return { ok: true, message: `remote auth-worker configured (${safeUrl})` };
7874
+ }
7857
7875
  const vaultPath = resolveAccountsPath(olamHomeOverride);
7858
7876
  if (!existsSync14(vaultPath)) {
7859
7877
  return {
@@ -11210,14 +11228,14 @@ var init_olam_yaml = __esm({
11210
11228
  // ../core/dist/policies/loader.js
11211
11229
  import * as fs20 from "node:fs";
11212
11230
  import * as path23 from "node:path";
11213
- import { parse as parseYaml3 } from "yaml";
11231
+ import { parse as parseYaml4 } from "yaml";
11214
11232
  function parseFrontmatter(content) {
11215
11233
  const match2 = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/m.exec(content);
11216
11234
  if (!match2)
11217
11235
  return null;
11218
11236
  const [, yamlText = "", body = ""] = match2;
11219
11237
  try {
11220
- const frontmatter = parseYaml3(yamlText);
11238
+ const frontmatter = parseYaml4(yamlText);
11221
11239
  return { frontmatter, body };
11222
11240
  } catch {
11223
11241
  return null;
@@ -11477,7 +11495,17 @@ var init_source_config_schema = __esm({
11477
11495
  * `SkillSourceSchema.prefixScope`. Operators inherit this when their
11478
11496
  * `~/.olam/config.json` has no explicit `prefixScope` override.
11479
11497
  */
11480
- prefixScope: external_exports.array(external_exports.enum(["skill", "agent"])).optional()
11498
+ prefixScope: external_exports.array(external_exports.enum(["skill", "agent"])).optional(),
11499
+ /**
11500
+ * Source's RECOMMENDED prefixTarget patterns. Same semantics as
11501
+ * operator-side `SkillSourceSchema.prefixTarget`: an array of glob
11502
+ * patterns (only `*` wildcard) that restrict which canonical names are
11503
+ * renamed. Operators inherit this when their `~/.olam/config.json` has
11504
+ * no explicit `prefixTarget` override.
11505
+ *
11506
+ * See: docs/decisions/022-prefix-target-name-patterns.md.
11507
+ */
11508
+ prefixTarget: external_exports.array(external_exports.string().min(1, "prefixTarget pattern must be a non-empty string")).optional()
11481
11509
  }).strict();
11482
11510
  SourceConfigSnapshotSchema = SourceConfigSchema;
11483
11511
  }
@@ -11523,6 +11551,29 @@ var init_schema3 = __esm({
11523
11551
  * NOT applicable when `prefix` is undefined.
11524
11552
  */
11525
11553
  prefixScope: external_exports.array(external_exports.enum(["skill", "agent"])).optional(),
11554
+ /**
11555
+ * Restrict prefix renaming to canonical names matching at least one glob
11556
+ * pattern. Patterns support `*` as a wildcard (zero or more chars); no
11557
+ * other metacharacters. Examples:
11558
+ *
11559
+ * `['*']` — rename ALL skills/agents (DEFAULT — today's behavior)
11560
+ * `['10x:*']` — rename only canonicals that start with `10x:`
11561
+ * `['10x:*', 'atl:*']`— match either namespace
11562
+ * `['plan-*']` — match a name-family prefix
11563
+ *
11564
+ * When `prefixTarget` is undefined OR `['*']`, all kind-allowed artifacts are
11565
+ * renamed (identical to the pre-ADR-022 behavior — full backward compat).
11566
+ *
11567
+ * When set, artifacts whose canonical name does NOT match ANY pattern are
11568
+ * deployed WITHOUT a prefix (canonical-only). No error is raised; `sync`
11569
+ * output emits a `[prefix-target: <n> skipped]` warning so operators can
11570
+ * detect misconfigured patterns.
11571
+ *
11572
+ * NOT applicable when `prefix` is undefined.
11573
+ *
11574
+ * See: docs/decisions/022-prefix-target-name-patterns.md.
11575
+ */
11576
+ prefixTarget: external_exports.array(external_exports.string().min(1, "prefixTarget pattern must be a non-empty string")).optional(),
11526
11577
  /**
11527
11578
  * Snapshot of the LAST source-config.yaml content this operator saw +
11528
11579
  * consented to (ADR-021). Trust-gate state: when the live source-config
@@ -16818,11 +16869,11 @@ var init_home_override = __esm({
16818
16869
  // ../core/dist/world/world-yaml.js
16819
16870
  import * as fs40 from "node:fs";
16820
16871
  import * as path41 from "node:path";
16821
- import { parse as parseYaml4, stringify as stringifyYaml4 } from "yaml";
16872
+ import { parse as parseYaml5, stringify as stringifyYaml5 } from "yaml";
16822
16873
  function writeWorldYaml(worldPath, data) {
16823
16874
  const olamDir = path41.join(worldPath, ".olam");
16824
16875
  fs40.mkdirSync(olamDir, { recursive: true });
16825
- fs40.writeFileSync(path41.join(olamDir, "world.yaml"), stringifyYaml4(data), "utf-8");
16876
+ fs40.writeFileSync(path41.join(olamDir, "world.yaml"), stringifyYaml5(data), "utf-8");
16826
16877
  }
16827
16878
  function readWorldYaml(worldPath) {
16828
16879
  const yamlPath = path41.join(worldPath, ".olam", "world.yaml");
@@ -16830,7 +16881,7 @@ function readWorldYaml(worldPath) {
16830
16881
  return null;
16831
16882
  try {
16832
16883
  const raw = fs40.readFileSync(yamlPath, "utf-8");
16833
- const parsed = parseYaml4(raw);
16884
+ const parsed = parseYaml5(raw);
16834
16885
  return WorldYamlSchema.parse(parsed);
16835
16886
  } catch {
16836
16887
  return null;
@@ -17151,6 +17202,18 @@ function updateSkillSource(id, patch) {
17151
17202
  } else if (patch.prefixScope !== void 0) {
17152
17203
  working = { ...working, prefixScope: [...patch.prefixScope] };
17153
17204
  }
17205
+ if (patch.prefixTarget === null) {
17206
+ const { prefixTarget: _t, ...rest } = working;
17207
+ void _t;
17208
+ working = rest;
17209
+ } else if (patch.prefixTarget !== void 0) {
17210
+ for (const p of patch.prefixTarget) {
17211
+ if (typeof p !== "string" || p.length === 0) {
17212
+ throw new Error(`prefixTarget patterns must be non-empty strings \u2014 got ${JSON.stringify(p)}`);
17213
+ }
17214
+ }
17215
+ working = { ...working, prefixTarget: [...patch.prefixTarget] };
17216
+ }
17154
17217
  if (patch.lastSeenSourcePrefix === null) {
17155
17218
  const { lastSeenSourcePrefix: _l, ...rest } = working;
17156
17219
  void _l;
@@ -18482,7 +18545,7 @@ var init_schema5 = __esm({
18482
18545
  import { execFileSync as execFileSync16 } from "node:child_process";
18483
18546
  import * as fs68 from "node:fs";
18484
18547
  import * as path67 from "node:path";
18485
- import { parse as parseYaml5 } from "yaml";
18548
+ import { parse as parseYaml6 } from "yaml";
18486
18549
  function findProjectOverride(startDir) {
18487
18550
  let dir = path67.resolve(startDir);
18488
18551
  const root = path67.parse(dir).root;
@@ -18492,7 +18555,7 @@ function findProjectOverride(startDir) {
18492
18555
  const raw = fs68.readFileSync(candidate, "utf-8");
18493
18556
  let parsed;
18494
18557
  try {
18495
- parsed = parseYaml5(raw);
18558
+ parsed = parseYaml6(raw);
18496
18559
  } catch (err) {
18497
18560
  const msg = err instanceof Error ? err.message : String(err);
18498
18561
  throw new Error(`failed to parse "${candidate}" as YAML: ${msg}`);
@@ -19588,6 +19651,55 @@ function validateCanonical(filenameBasename, content, registeredPrefixes) {
19588
19651
  }
19589
19652
  return { ok: true };
19590
19653
  }
19654
+ function matchesSinglePattern(candidate, pattern) {
19655
+ const cacheKey = `${candidate}\0${pattern}`;
19656
+ const cached = _matchCache.get(cacheKey);
19657
+ if (cached !== void 0)
19658
+ return cached;
19659
+ const result = _matchesSinglePatternRaw(candidate, pattern);
19660
+ _matchCache.set(cacheKey, result);
19661
+ return result;
19662
+ }
19663
+ function _matchesSinglePatternRaw(candidate, pattern) {
19664
+ if (pattern === "*")
19665
+ return true;
19666
+ if (!pattern.includes("*"))
19667
+ return candidate === pattern;
19668
+ const segments = pattern.split("*");
19669
+ let pos = 0;
19670
+ for (let i = 0; i < segments.length; i++) {
19671
+ const seg = segments[i];
19672
+ if (seg.length === 0)
19673
+ continue;
19674
+ if (i === 0) {
19675
+ if (!candidate.startsWith(seg))
19676
+ return false;
19677
+ pos = seg.length;
19678
+ } else if (i === segments.length - 1) {
19679
+ if (!candidate.endsWith(seg))
19680
+ return false;
19681
+ if (pos > candidate.length - seg.length)
19682
+ return false;
19683
+ } else {
19684
+ const found = candidate.indexOf(seg, pos);
19685
+ if (found === -1)
19686
+ return false;
19687
+ pos = found + seg.length;
19688
+ }
19689
+ }
19690
+ return true;
19691
+ }
19692
+ function matchesPrefixTarget(canonical, patterns) {
19693
+ if (patterns === void 0 || patterns.length === 0)
19694
+ return true;
19695
+ if (patterns.length === 1 && patterns[0] === "*")
19696
+ return true;
19697
+ for (const pattern of patterns) {
19698
+ if (matchesSinglePattern(canonical, pattern))
19699
+ return true;
19700
+ }
19701
+ return false;
19702
+ }
19591
19703
  function formatCanonicalViolation(filePath, violation) {
19592
19704
  const surface = violation.kind === "filename" ? "filename" : "frontmatter `name:` field";
19593
19705
  const stripped = violation.value.replace(new RegExp(`^${violation.prefix}:`), "");
@@ -19598,10 +19710,12 @@ function formatCanonicalViolation(filePath, violation) {
19598
19710
  `See docs/plans/skill-prefix-rules/README.md \xA7 Bidirectional invariant.`
19599
19711
  ].join("\n ");
19600
19712
  }
19713
+ var _matchCache;
19601
19714
  var init_prefix_rules = __esm({
19602
19715
  "../core/dist/skill-sync/prefix-rules.js"() {
19603
19716
  "use strict";
19604
19717
  init_markdown_merger();
19718
+ _matchCache = /* @__PURE__ */ new Map();
19605
19719
  }
19606
19720
  });
19607
19721
 
@@ -19611,17 +19725,20 @@ import * as path73 from "node:path";
19611
19725
  function buildSourcePrefixMap(sources) {
19612
19726
  const byId = /* @__PURE__ */ new Map();
19613
19727
  const scopeById = /* @__PURE__ */ new Map();
19728
+ const targetById = /* @__PURE__ */ new Map();
19614
19729
  const prefixes = /* @__PURE__ */ new Set();
19615
19730
  for (const s of sources) {
19616
19731
  if (s.prefix !== void 0 && s.prefix.length > 0) {
19617
19732
  byId.set(s.id, s.prefix);
19618
19733
  scopeById.set(s.id, s.prefixScope ?? DEFAULT_SCOPE);
19734
+ targetById.set(s.id, s.prefixTarget);
19619
19735
  prefixes.add(s.prefix);
19620
19736
  }
19621
19737
  }
19622
19738
  return {
19623
19739
  get: (sourceId) => byId.get(sourceId),
19624
19740
  getScope: (sourceId) => scopeById.get(sourceId) ?? DEFAULT_SCOPE,
19741
+ getPrefixTarget: (sourceId) => targetById.get(sourceId),
19625
19742
  registeredPrefixes: Array.from(prefixes)
19626
19743
  };
19627
19744
  }
@@ -19637,6 +19754,9 @@ function applyPrefixRewrites(baseArtifacts, sourceMap, claudeDir2, dryRun) {
19637
19754
  if (!scope.includes(artifact.kind))
19638
19755
  continue;
19639
19756
  const canonical = artifact.deployBasename;
19757
+ const prefixTarget = sourceMap.getPrefixTarget(artifact.sourceId);
19758
+ if (!matchesPrefixTarget(canonical, prefixTarget))
19759
+ continue;
19640
19760
  const otherPrefixes = sourceMap.registeredPrefixes.filter((p) => p !== prefix);
19641
19761
  const renamed = applyPrefix(canonical, prefix, otherPrefixes);
19642
19762
  if (renamed === canonical)
@@ -19715,7 +19835,7 @@ var init_prefix_deploy = __esm({
19715
19835
  // ../core/dist/skill-sync/resolve-source-config.js
19716
19836
  import { readFileSync as readFileSync72, existsSync as existsSync81 } from "node:fs";
19717
19837
  import { join as join81 } from "node:path";
19718
- import { parse as parseYaml6 } from "yaml";
19838
+ import { parse as parseYaml7 } from "yaml";
19719
19839
  function sourceConfigPath(clonePath) {
19720
19840
  return join81(clonePath, "shared", "source-config.yaml");
19721
19841
  }
@@ -19732,7 +19852,7 @@ function readSourceConfig(clonePath, sourceId) {
19732
19852
  }
19733
19853
  let parsed;
19734
19854
  try {
19735
- parsed = parseYaml6(raw);
19855
+ parsed = parseYaml7(raw);
19736
19856
  } catch (err) {
19737
19857
  emitMalformedWarning(sourceId, `YAML parse failed: ${errToMsg(err)}`);
19738
19858
  return void 0;
@@ -19756,18 +19876,23 @@ function errToMsg(err) {
19756
19876
  function resolveEffectivePrefix(operatorSource, sourceConfig) {
19757
19877
  const opPrefix = operatorSource.prefix;
19758
19878
  const opScope = operatorSource.prefixScope;
19879
+ const opTarget = operatorSource.prefixTarget;
19759
19880
  const srcPrefix = sourceConfig?.prefix;
19760
19881
  const srcScope = sourceConfig?.prefixScope;
19882
+ const srcTarget = sourceConfig?.prefixTarget;
19761
19883
  const effectivePrefix = opPrefix ?? srcPrefix;
19762
19884
  const effectiveScope = opScope ?? srcScope;
19763
- const operatorHasAny = opPrefix !== void 0 || opScope !== void 0 && opScope.length > 0;
19764
- const sourceHasAny = srcPrefix !== void 0 || srcScope !== void 0 && srcScope.length > 0;
19885
+ const effectiveTarget = opTarget ?? srcTarget;
19886
+ const operatorHasAny = opPrefix !== void 0 || opScope !== void 0 && opScope.length > 0 || opTarget !== void 0 && opTarget.length > 0;
19887
+ const sourceHasAny = srcPrefix !== void 0 || srcScope !== void 0 && srcScope.length > 0 || srcTarget !== void 0 && srcTarget.length > 0;
19765
19888
  const origin = operatorHasAny ? "operator" : sourceHasAny ? "source" : "none";
19766
19889
  const result = { origin };
19767
19890
  if (effectivePrefix !== void 0)
19768
19891
  result.prefix = effectivePrefix;
19769
19892
  if (effectiveScope !== void 0)
19770
19893
  result.prefixScope = effectiveScope;
19894
+ if (effectiveTarget !== void 0)
19895
+ result.prefixTarget = effectiveTarget;
19771
19896
  return result;
19772
19897
  }
19773
19898
  function sourceConfigsEqual(a, b) {
@@ -19780,6 +19905,9 @@ function sourceConfigsEqual(a, b) {
19780
19905
  if (c.prefixScope !== void 0 && c.prefixScope.length > 0) {
19781
19906
  out.prefixScope = [...c.prefixScope];
19782
19907
  }
19908
+ if (c.prefixTarget !== void 0 && c.prefixTarget.length > 0) {
19909
+ out.prefixTarget = [...c.prefixTarget];
19910
+ }
19783
19911
  return out;
19784
19912
  };
19785
19913
  const na = normalize(a);
@@ -19794,6 +19922,14 @@ function sourceConfigsEqual(a, b) {
19794
19922
  if (sa[i] !== sb[i])
19795
19923
  return false;
19796
19924
  }
19925
+ const ta = na.prefixTarget ?? [];
19926
+ const tb = nb.prefixTarget ?? [];
19927
+ if (ta.length !== tb.length)
19928
+ return false;
19929
+ for (let i = 0; i < ta.length; i++) {
19930
+ if (ta[i] !== tb[i])
19931
+ return false;
19932
+ }
19797
19933
  return true;
19798
19934
  }
19799
19935
  var init_resolve_source_config = __esm({
@@ -19876,6 +20012,8 @@ async function syncSkills(opts = {}) {
19876
20012
  entry.prefix = eff.prefix;
19877
20013
  if (eff.prefixScope !== void 0)
19878
20014
  entry.prefixScope = eff.prefixScope;
20015
+ if (eff.prefixTarget !== void 0)
20016
+ entry.prefixTarget = eff.prefixTarget;
19879
20017
  return entry;
19880
20018
  });
19881
20019
  const sourcePrefixGateOutcomes = [];
@@ -19934,6 +20072,7 @@ async function syncSkills(opts = {}) {
19934
20072
  } else {
19935
20073
  delete eff.prefix;
19936
20074
  delete eff.prefixScope;
20075
+ delete eff.prefixTarget;
19937
20076
  eff.origin = "none";
19938
20077
  const isNonTty = opts.sourcePrefixPrompt === void 0;
19939
20078
  sourcePrefixGateOutcomes.push({
@@ -21082,14 +21221,14 @@ __export(machine_schema_exports, {
21082
21221
  import * as fs82 from "node:fs";
21083
21222
  import * as path83 from "node:path";
21084
21223
  import * as os45 from "node:os";
21085
- import { parse as parseYaml7, stringify as stringifyYaml5 } from "yaml";
21224
+ import { parse as parseYaml8, stringify as stringifyYaml6 } from "yaml";
21086
21225
  function readMachineConfig(configPath) {
21087
21226
  const p = configPath ?? DEFAULT_CONFIG_PATH;
21088
21227
  if (!fs82.existsSync(p))
21089
21228
  return null;
21090
21229
  try {
21091
21230
  const raw = fs82.readFileSync(p, "utf-8");
21092
- const parsed = parseYaml7(raw);
21231
+ const parsed = parseYaml8(raw);
21093
21232
  return MachineConfigSchema.parse(parsed);
21094
21233
  } catch {
21095
21234
  return null;
@@ -21098,7 +21237,7 @@ function readMachineConfig(configPath) {
21098
21237
  function writeMachineConfig(config, configPath) {
21099
21238
  const p = configPath ?? DEFAULT_CONFIG_PATH;
21100
21239
  fs82.mkdirSync(path83.dirname(p), { recursive: true });
21101
- fs82.writeFileSync(p, stringifyYaml5({ ...config }), { mode: 420 });
21240
+ fs82.writeFileSync(p, stringifyYaml6({ ...config }), { mode: 420 });
21102
21241
  }
21103
21242
  function initMachineConfig(opts = {}) {
21104
21243
  const configPath = opts.configPath ?? DEFAULT_CONFIG_PATH;
@@ -21325,14 +21464,25 @@ import {
21325
21464
  import { homedir as homedir3, tmpdir } from "node:os";
21326
21465
  import { join as join7, dirname as dirname3 } from "node:path";
21327
21466
  import { randomUUID } from "node:crypto";
21467
+ import { parse as parseYaml3, stringify as stringifyYaml3 } from "yaml";
21328
21468
  var OLAM_HOME = join7(homedir3(), ".olam");
21329
21469
  var OLAM_STATE_DIR = join7(OLAM_HOME, "state");
21330
- var OLAM_CONFIG_PATH = join7(OLAM_HOME, "config.json");
21470
+ function resolveConfigPath(home = OLAM_HOME) {
21471
+ const jsonPath = join7(home, "config.json");
21472
+ const yamlPath = join7(home, "config.yaml");
21473
+ if (existsSync6(jsonPath)) return jsonPath;
21474
+ if (existsSync6(yamlPath)) return yamlPath;
21475
+ return jsonPath;
21476
+ }
21477
+ var OLAM_CONFIG_PATH = resolveConfigPath();
21331
21478
  function defaultConfigPath() {
21332
21479
  if (process.env["VITEST"]) {
21333
21480
  return join7(tmpdir(), `olam-vitest-config-${process.pid}.json`);
21334
21481
  }
21335
- return OLAM_CONFIG_PATH;
21482
+ return resolveConfigPath();
21483
+ }
21484
+ function isYamlPath(p) {
21485
+ return p.endsWith(".yaml") || p.endsWith(".yml");
21336
21486
  }
21337
21487
  var DEFAULT_SUBSTRATE = "kubernetes";
21338
21488
  function makeDefaultConfig() {
@@ -21381,6 +21531,37 @@ function atomicWriteJSON(path103, value, stderr = process.stderr) {
21381
21531
  throw err;
21382
21532
  }
21383
21533
  }
21534
+ function atomicWriteYaml(path103, value, stderr = process.stderr) {
21535
+ ensureStateDir();
21536
+ const dir = dirname3(path103);
21537
+ if (!existsSync6(dir)) {
21538
+ mkdirSync2(dir, { recursive: true });
21539
+ }
21540
+ const tmp = `${path103}.tmp.${process.pid}`;
21541
+ try {
21542
+ writeFileSync2(tmp, stringifyYaml3(value), { encoding: "utf8" });
21543
+ renameSync2(tmp, path103);
21544
+ } catch (err) {
21545
+ if (existsSync6(tmp)) {
21546
+ try {
21547
+ unlinkSync2(tmp);
21548
+ } catch {
21549
+ }
21550
+ }
21551
+ stderr.write(
21552
+ `[WARN] olam config write failed: ${err instanceof Error ? err.message : String(err)}
21553
+ `
21554
+ );
21555
+ throw err;
21556
+ }
21557
+ }
21558
+ function atomicWrite(path103, value, stderr = process.stderr) {
21559
+ if (isYamlPath(path103)) {
21560
+ atomicWriteYaml(path103, value, stderr);
21561
+ } else {
21562
+ atomicWriteJSON(path103, value, stderr);
21563
+ }
21564
+ }
21384
21565
  function readConfig(opts = {}) {
21385
21566
  const configPath = opts.configPath ?? defaultConfigPath();
21386
21567
  const stateDir = opts.stateDir ?? OLAM_STATE_DIR;
@@ -21388,20 +21569,20 @@ function readConfig(opts = {}) {
21388
21569
  ensureStateDir(stateDir);
21389
21570
  if (!existsSync6(configPath)) {
21390
21571
  const fresh = makeDefaultConfig();
21391
- atomicWriteJSON(configPath, fresh, stderr);
21572
+ atomicWrite(configPath, fresh, stderr);
21392
21573
  return fresh;
21393
21574
  }
21394
21575
  let parsed;
21395
21576
  try {
21396
21577
  const raw = readFileSync6(configPath, "utf8");
21397
- parsed = JSON.parse(raw);
21578
+ parsed = isYamlPath(configPath) ? parseYaml3(raw) : JSON.parse(raw);
21398
21579
  } catch (err) {
21399
21580
  stderr.write(
21400
21581
  `[WARN] olam config malformed at ${configPath}: ${err instanceof Error ? err.message : String(err)}; falling back to defaults
21401
21582
  `
21402
21583
  );
21403
21584
  const fresh = makeDefaultConfig();
21404
- atomicWriteJSON(configPath, fresh, stderr);
21585
+ atomicWrite(configPath, fresh, stderr);
21405
21586
  return fresh;
21406
21587
  }
21407
21588
  if (!isValidConfig(parsed)) {
@@ -21410,7 +21591,7 @@ function readConfig(opts = {}) {
21410
21591
  `
21411
21592
  );
21412
21593
  const fresh = makeDefaultConfig();
21413
- atomicWriteJSON(configPath, fresh, stderr);
21594
+ atomicWrite(configPath, fresh, stderr);
21414
21595
  return fresh;
21415
21596
  }
21416
21597
  return parsed;
@@ -21425,7 +21606,7 @@ function writeConfig(updates, opts = {}) {
21425
21606
  host: { ...current.host, ...updates.host ?? {} },
21426
21607
  install_id: current.install_id
21427
21608
  };
21428
- atomicWriteJSON(configPath, next, stderr);
21609
+ atomicWrite(configPath, next, stderr);
21429
21610
  return next;
21430
21611
  }
21431
21612
 
@@ -21688,7 +21869,7 @@ import * as fs7 from "node:fs";
21688
21869
  import * as os3 from "node:os";
21689
21870
  import * as path7 from "node:path";
21690
21871
  import pc4 from "picocolors";
21691
- import { stringify as stringifyYaml3 } from "yaml";
21872
+ import { stringify as stringifyYaml4 } from "yaml";
21692
21873
 
21693
21874
  // ../core/dist/archetypes/capabilities.js
21694
21875
  var CAPABILITY_NAMES = [
@@ -21854,7 +22035,7 @@ function readRoleFile() {
21854
22035
  }
21855
22036
  function writeRoleFile(role) {
21856
22037
  fs7.mkdirSync(path7.dirname(ROLE_FILE_PATH), { recursive: true });
21857
- const yaml = stringifyYaml3({
22038
+ const yaml = stringifyYaml4({
21858
22039
  archetype: role.archetype,
21859
22040
  customCapabilities: [...role.customCapabilities],
21860
22041
  installedAt: role.installedAt
@@ -24583,6 +24764,7 @@ import { existsSync as existsSync35, mkdtempSync as mkdtempSync2, readFileSync a
24583
24764
  import { tmpdir as tmpdir4 } from "node:os";
24584
24765
  import { join as join42, resolve as resolve13 } from "node:path";
24585
24766
  import { fileURLToPath as fileURLToPath6 } from "node:url";
24767
+ init_install_root();
24586
24768
  var SECRET_NAME2 = "olam-host-cp-tls";
24587
24769
  var NAMESPACE = "olam";
24588
24770
  var SAN_LIST = ["olam.local", "127.0.0.1", "::1"];
@@ -24620,6 +24802,12 @@ function isMkcertRootTrusted(mkcertPath, spawn13) {
24620
24802
  }
24621
24803
  return true;
24622
24804
  }
24805
+ function resolveHostCpManifestDir() {
24806
+ const installed = join42(installRoot(), "host-cp", "k8s", "manifests");
24807
+ if (existsSync35(installed)) return installed;
24808
+ const here3 = fileURLToPath6(import.meta.url);
24809
+ return resolve13(here3, "..", "..", "..", "..", "host-cp", "k8s", "manifests");
24810
+ }
24623
24811
  function readCertNotAfter(pemBytes, spawnImpl) {
24624
24812
  const r = spawnImpl("openssl", ["x509", "-noout", "-enddate"], { input: pemBytes });
24625
24813
  if (r.status !== 0) return null;
@@ -24881,9 +25069,7 @@ function tlsSecretExists(spawnArg, context) {
24881
25069
  return r.status === 0 && r.stdout.trim().length > 0;
24882
25070
  }
24883
25071
  function applyIngressManifests(context) {
24884
- const here3 = fileURLToPath6(import.meta.url);
24885
- const manifestDir = resolve13(here3, "..", "..", "..", "..", "host-cp", "k8s", "manifests");
24886
- const ingressManifest = join42(manifestDir, "70-ingressroute.yaml");
25072
+ const ingressManifest = join42(resolveHostCpManifestDir(), "70-ingressroute.yaml");
24887
25073
  try {
24888
25074
  execFileSync8("kubectl", [
24889
25075
  "--context",
@@ -29993,6 +30179,7 @@ Top-level commands (run \`olam <command> --help\` for flags and subcommands):
29993
30179
  - \`olam services\` \u2014 Manage Olam service containers (up/down/status/logs)
29994
30180
  - \`olam set-prefix\` \u2014 Set the deploy prefix for a registered skill source (skills+agents deploy as <prefix>:<canonical-name>)
29995
30181
  - \`olam set-prefix-scope\` \u2014 Set which artifact kinds are renamed by the prefix (comma-separated: skill, agent, or skill,agent)
30182
+ - \`olam set-prefix-target\` \u2014 Restrict prefix renaming to canonical names matching the given glob patterns (only * wildcard supported).
29996
30183
  - \`olam setup\` \u2014 Fresh-host onboarding wizard (k3d cluster + services, idempotent)
29997
30184
  - \`olam setup-linux-gate-status\` \u2014 Check whether the Linux platform expansion gate has been triggered
29998
30185
  - \`olam setup-metrics\` \u2014 Query trust-audit-log for setup dogfood statistics
@@ -30011,6 +30198,7 @@ Top-level commands (run \`olam <command> --help\` for flags and subcommands):
30011
30198
  - \`olam uninstall-hook\` \u2014 Remove kg-service PreToolUse hook from .claude/settings.json (sentinel-matched; surgical)
30012
30199
  - \`olam unset-prefix\` \u2014 Remove the deploy prefix from a registered skill source (reverts to canonical deploy names)
30013
30200
  - \`olam unset-prefix-scope\` \u2014 Remove the prefix-scope override from a registered skill source (reverts to default: both skill and agent are renamed)
30201
+ - \`olam unset-prefix-target\` \u2014 Remove the prefix-target override from a registered skill source (reverts to default: all canonical names are renamed)
30014
30202
  - \`olam up\` \u2014 [deprecated] Start the auth container \u2014 use
30015
30203
  - \`olam update\` \u2014 Update a registered repo
30016
30204
  - \`olam upgrade\` \u2014 Upgrade the olam-auth container. Default: pull olam-auth@<digest> from ghcr.io and recreate.
@@ -42683,13 +42871,22 @@ async function phase1SystemCheck(substrate, deps) {
42683
42871
  if (!kubectlProbe.ok) {
42684
42872
  return phaseFromProbe(kubectlProbe);
42685
42873
  }
42686
- const dockerProbe2 = await probeDockerDaemon(deps.dockerExec);
42687
- if (!dockerProbe2.ok) {
42688
- return {
42689
- ok: false,
42690
- message: "docker daemon required for k3d: " + dockerProbe2.message,
42691
- remedy: dockerProbe2.remedy
42692
- };
42874
+ const ctx = resolveKubectlContext(deps.configPath);
42875
+ const isK3dManaged = ctx.context?.startsWith("k3d-") ?? false;
42876
+ if (isK3dManaged) {
42877
+ const dockerProbe2 = await probeDockerDaemon(deps.dockerExec);
42878
+ if (!dockerProbe2.ok) {
42879
+ return {
42880
+ ok: false,
42881
+ message: "docker daemon required for k3d-managed cluster: " + dockerProbe2.message,
42882
+ remedy: dockerProbe2.remedy
42883
+ };
42884
+ }
42885
+ } else if (ctx.context !== void 0) {
42886
+ process.stdout.write(
42887
+ ` \u2139 skipped docker check \u2014 kubectl context "${ctx.context}" is not k3d-managed
42888
+ `
42889
+ );
42693
42890
  }
42694
42891
  if (!nodeOk) {
42695
42892
  return {
@@ -42705,7 +42902,8 @@ async function phase1SystemCheck(substrate, deps) {
42705
42902
  const lintWithWarn = colimaLint;
42706
42903
  printWarning(` \u26A0 ${lintWithWarn.remedy}`);
42707
42904
  }
42708
- return { ok: true, message: `kubectl on PATH; docker ready; node ${nodeVersion}` };
42905
+ const dockerNote = isK3dManaged ? "; docker ready" : "";
42906
+ return { ok: true, message: `kubectl on PATH${dockerNote}; node ${nodeVersion}` };
42709
42907
  }
42710
42908
  const dockerProbe = await probeDockerDaemon(deps.dockerExec);
42711
42909
  if (!dockerProbe.ok) {
@@ -42738,6 +42936,15 @@ async function phase1_5InstallSubstrate(substrate, opts, deps, reuseContext) {
42738
42936
  message: `skipped k3d install (reusing context ${reuseContext})`
42739
42937
  };
42740
42938
  }
42939
+ const ctx = resolveKubectlContext(deps.configPath);
42940
+ const isK3dManaged = ctx.context?.startsWith("k3d-") ?? false;
42941
+ if (!isK3dManaged && ctx.context !== void 0) {
42942
+ return {
42943
+ ok: true,
42944
+ skipped: true,
42945
+ message: `skipped k3d install \u2014 kubectl context "${ctx.context}" is not k3d-managed`
42946
+ };
42947
+ }
42741
42948
  const spawnFn = deps.spawnSubprocess ?? defaultSpawn2;
42742
42949
  const promptFn = deps.prompt ?? defaultPrompt;
42743
42950
  const k3dProbe = await probeK3d(deps.dockerExec);
@@ -44456,9 +44663,11 @@ function registerSkillsSource(program2) {
44456
44663
  clonePath,
44457
44664
  prefix: s.prefix ?? null,
44458
44665
  prefixScope: s.prefixScope ? [...s.prefixScope] : null,
44666
+ prefixTarget: s.prefixTarget ? [...s.prefixTarget] : null,
44459
44667
  effective: {
44460
44668
  prefix: eff.prefix ?? null,
44461
44669
  prefixScope: eff.prefixScope ? [...eff.prefixScope] : null,
44670
+ prefixTarget: eff.prefixTarget ? [...eff.prefixTarget] : null,
44462
44671
  origin: eff.origin
44463
44672
  }
44464
44673
  };
@@ -44878,15 +45087,21 @@ function registerSkillsSource(program2) {
44878
45087
  lastPulledSha: entry.lastPulledSha ?? null,
44879
45088
  clonePath
44880
45089
  },
44881
- sourceConfig: srcCfg === void 0 ? null : { prefix: srcCfg.prefix ?? null, prefixScope: srcCfg.prefixScope ? [...srcCfg.prefixScope] : null },
45090
+ sourceConfig: srcCfg === void 0 ? null : {
45091
+ prefix: srcCfg.prefix ?? null,
45092
+ prefixScope: srcCfg.prefixScope ? [...srcCfg.prefixScope] : null,
45093
+ prefixTarget: srcCfg.prefixTarget ? [...srcCfg.prefixTarget] : null
45094
+ },
44882
45095
  operator: {
44883
45096
  prefix: entry.prefix ?? null,
44884
45097
  prefixScope: entry.prefixScope ? [...entry.prefixScope] : null,
45098
+ prefixTarget: entry.prefixTarget ? [...entry.prefixTarget] : null,
44885
45099
  lastSeenSourcePrefix: entry.lastSeenSourcePrefix ?? null
44886
45100
  },
44887
45101
  effective: {
44888
45102
  prefix: effJson.prefix ?? null,
44889
45103
  prefixScope: effJson.prefixScope ? [...effJson.prefixScope] : null,
45104
+ prefixTarget: effJson.prefixTarget ? [...effJson.prefixTarget] : null,
44890
45105
  origin: effJson.origin
44891
45106
  }
44892
45107
  };
@@ -44913,15 +45128,18 @@ function registerSkillsSource(program2) {
44913
45128
  } else {
44914
45129
  console.log(` ${pc36.bold("prefix:")} ${sourceConfig.prefix ?? pc36.dim("\u2014")}`);
44915
45130
  console.log(` ${pc36.bold("prefixScope:")} ${sourceConfig.prefixScope?.join(",") ?? pc36.dim("\u2014")}`);
45131
+ console.log(` ${pc36.bold("prefixTarget:")} ${sourceConfig.prefixTarget?.join(" ") ?? pc36.dim("\u2014")}`);
44916
45132
  }
44917
45133
  console.log(pc36.bold("\u25B8 operator overrides"));
44918
45134
  console.log(` ${pc36.bold("prefix:")} ${entry.prefix ?? pc36.dim("\u2014")}`);
44919
45135
  console.log(` ${pc36.bold("prefixScope:")} ${entry.prefixScope?.join(",") ?? pc36.dim("\u2014")}`);
45136
+ console.log(` ${pc36.bold("prefixTarget:")} ${entry.prefixTarget?.join(" ") ?? pc36.dim("\u2014")}`);
44920
45137
  console.log(` ${pc36.bold("lastSeen:")} ${entry.lastSeenSourcePrefix ? JSON.stringify(entry.lastSeenSourcePrefix) : pc36.dim("\u2014")}`);
44921
45138
  const eff = resolveEffectivePrefix(entry, sourceConfig);
44922
45139
  console.log(pc36.bold(`\u25B8 effective ${pc36.dim(`(origin: ${eff.origin})`)}`));
44923
45140
  console.log(` ${pc36.bold("prefix:")} ${eff.prefix ?? pc36.dim("\u2014")}`);
44924
45141
  console.log(` ${pc36.bold("prefixScope:")} ${eff.prefixScope?.join(",") ?? pc36.dim("\u2014")}`);
45142
+ console.log(` ${pc36.bold("prefixTarget:")} ${eff.prefixTarget?.join(" ") ?? pc36.dim("\u2014")}`);
44925
45143
  });
44926
45144
  source.command("set-prefix").description(
44927
45145
  "Set the deploy prefix for a registered skill source (skills+agents deploy as <prefix>:<canonical-name>)"
@@ -45006,6 +45224,57 @@ function registerSkillsSource(program2) {
45006
45224
  process.exitCode = 1;
45007
45225
  }
45008
45226
  });
45227
+ source.command("set-prefix-target").description(
45228
+ 'Restrict prefix renaming to canonical names matching the given glob patterns (only * wildcard supported). E.g. "10x:*" renames only skills whose canonical name starts with "10x:". Pass multiple patterns as separate arguments.'
45229
+ ).argument("<name>", 'Display name of the skill source (from "olam skills source list")').argument("<patterns...>", 'One or more glob patterns (e.g. "10x:*" "atl:*" "plan-*")').action((name, patterns) => {
45230
+ const entry = getSkillSourceByName(name);
45231
+ if (entry === null) {
45232
+ printError(
45233
+ `skill source "${name}" is not registered. Run "olam skills source list" to see registered sources.`
45234
+ );
45235
+ process.exitCode = 1;
45236
+ return;
45237
+ }
45238
+ for (const p of patterns) {
45239
+ if (p.length === 0) {
45240
+ printError("prefixTarget patterns must be non-empty strings");
45241
+ process.exitCode = 1;
45242
+ return;
45243
+ }
45244
+ }
45245
+ if (patterns.length === 0) {
45246
+ printError('at least one pattern is required \u2014 use "unset-prefix-target" to revert to match-all');
45247
+ process.exitCode = 1;
45248
+ return;
45249
+ }
45250
+ try {
45251
+ updateSkillSource(entry.id, { prefixTarget: patterns });
45252
+ const display = patterns.map((p) => `"${p}"`).join(" ");
45253
+ printSuccess(`set prefix-target ${display} on source "${name}" (${entry.id})`);
45254
+ } catch (err) {
45255
+ printError(asMessage3(err));
45256
+ process.exitCode = 1;
45257
+ }
45258
+ });
45259
+ source.command("unset-prefix-target").description(
45260
+ "Remove the prefix-target override from a registered skill source (reverts to default: all canonical names are renamed)"
45261
+ ).argument("<name>", 'Display name of the skill source (from "olam skills source list")').action((name) => {
45262
+ const entry = getSkillSourceByName(name);
45263
+ if (entry === null) {
45264
+ printError(
45265
+ `skill source "${name}" is not registered. Run "olam skills source list" to see registered sources.`
45266
+ );
45267
+ process.exitCode = 1;
45268
+ return;
45269
+ }
45270
+ try {
45271
+ updateSkillSource(entry.id, { prefixTarget: null });
45272
+ printSuccess(`unset prefix-target on source "${name}" (${entry.id}) \u2014 reverted to default (match all)`);
45273
+ } catch (err) {
45274
+ printError(asMessage3(err));
45275
+ process.exitCode = 1;
45276
+ }
45277
+ });
45009
45278
  }
45010
45279
 
45011
45280
  // src/commands/skills.ts
@@ -48583,7 +48852,7 @@ init_output();
48583
48852
  import { existsSync as existsSync108, readFileSync as readFileSync91, writeFileSync as writeFileSync55 } from "node:fs";
48584
48853
  import { join as join102 } from "node:path";
48585
48854
  import * as readline7 from "node:readline/promises";
48586
- import { parse as parseYaml8, stringify as stringifyYaml6 } from "yaml";
48855
+ import { parse as parseYaml9, stringify as stringifyYaml7 } from "yaml";
48587
48856
  var CONFIG_REL = ".olam/config.yaml";
48588
48857
  function locateConfig(cwd) {
48589
48858
  const absPath = join102(cwd, CONFIG_REL);
@@ -48596,14 +48865,14 @@ function locateConfig(cwd) {
48596
48865
  }
48597
48866
  function readConfigYaml(absPath) {
48598
48867
  const raw = readFileSync91(absPath, "utf-8");
48599
- const parsed = parseYaml8(raw) ?? {};
48868
+ const parsed = parseYaml9(raw) ?? {};
48600
48869
  if (typeof parsed !== "object" || parsed === null) {
48601
48870
  throw new Error(`${absPath} is not a YAML object`);
48602
48871
  }
48603
48872
  return { raw, parsed };
48604
48873
  }
48605
48874
  function writeConfigYaml(absPath, parsed) {
48606
- const out = stringifyYaml6(parsed, { aliasDuplicateObjects: false });
48875
+ const out = stringifyYaml7(parsed, { aliasDuplicateObjects: false });
48607
48876
  writeFileSync55(absPath, out, "utf-8");
48608
48877
  }
48609
48878
  async function defaultPromptText(question) {