@pleri/olam-cli 0.1.210 → 0.1.212

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/README.md CHANGED
@@ -53,11 +53,17 @@ olam setup \
53
53
  --remote-memory-url=<memory-url> \
54
54
  --remote-kg-url=<kg-url> \
55
55
  --remote-dispatch-url=<dispatch-url> \
56
- --credentials=gcp # pull bearers from gs://olam-credentials
56
+ --credentials=gcp \
57
+ --gcp-bucket=<gs://your-bucket[/prefix]> # explicit — no implicit default
57
58
  ```
58
59
 
59
- - **Admin (once):** `olam credentials push` uploads the team's bearers to the
60
- bucket (auto-created, uniform bucket-level access). Grant teammates
60
+ The credentials bucket has no implicit default: pass `--gcp-bucket`, set
61
+ `OLAM_CREDENTIALS_BUCKET`, or persist it with
62
+ `olam config set credentials.bucket <gs://bucket[/prefix]>`.
63
+
64
+ - **Admin (once):** `olam credentials push --gcp-bucket <name>` uploads the
65
+ team's bearers to the bucket (auto-created, uniform bucket-level access).
66
+ Grant teammates
61
67
  `roles/storage.objectViewer`.
62
68
  - **Teammate:** `--credentials=gcp` runs `olam credentials pull` — `gcloud`
63
69
  downloads the bearers with the teammate's own ADC and writes them `0600`.
@@ -1,12 +1,12 @@
1
1
  {
2
- "auth": "sha256:90c00c3d75cc697539a0d6663fdf30d67fac787171ff1c53a3c1fa1755fcecb3",
3
- "devbox": "sha256:6d8eccfb38c5379a8977bbd79e59c36ce7d45b4cb7f834d76c7b0bdbc7c27c43",
4
- "devbox-base": "sha256:e9ddfc1305549e76608d4da12d2930e8c10be1e3c198db04b7b3b21e4bffc284",
5
- "host-cp": "sha256:5d8726cbe667359e64d2abe53150c80c870a2d71960c2f41833a3c8719abee12",
6
- "kg-service": "sha256:829de080754fe0728b0c0368b6083a6679baff33745dd81c68fadc4ccea7bf7d",
7
- "memory-service": "sha256:2b40d835b807fa49316a9db0215ee4ac6b36e2403c8170cfb4a70067115ad292",
8
- "mcp-auth": "sha256:c7041e093e23acdad36eb2a611e66e925061b79e41a5b8a3be28bba57d6624c5",
2
+ "auth": "sha256:7a206b619cd92d39b2550a09e270e9999a6c0b1a70e391e72b46c2cfbbf0be9c",
3
+ "devbox": "sha256:d9d1635ba112c00f3f722f2f19c272263f3187b7667751839c33307ee79fef6b",
4
+ "devbox-base": "sha256:e09f5646a9434fb7b19dcaa70f7efca92e5e884b1a3395146856e7087046fa3a",
5
+ "host-cp": "sha256:1818b62ee1475cf42f8d55c3ba3cbda9c27b799dc99abcff6c63f02d54574893",
6
+ "kg-service": "sha256:b74d2099752a0299317c95feab19893764a291db375c4ce0fd96d06691defb9f",
7
+ "memory-service": "sha256:847d97e6970158f5037821c5664836a1781949750ce69caab08128e1c9c6a157",
8
+ "mcp-auth": "sha256:9e1b11d9a67005a1a3c65f63b5c4c94d311a35f6b424e576d63bba82290f86cf",
9
9
  "$schema_version": 1,
10
- "$published_version": "0.1.210",
10
+ "$published_version": "0.1.212",
11
11
  "$registry": "ghcr.io/pleri"
12
12
  }
package/dist/index.js CHANGED
@@ -5742,7 +5742,11 @@ function writeConfig(updates, opts = {}) {
5742
5742
  ...current,
5743
5743
  "config.schema": 1,
5744
5744
  host: { ...current.host, ...updates.host ?? {} },
5745
- install_id: current.install_id
5745
+ install_id: current.install_id,
5746
+ // Only materialise `credentials` when the update sets it or it already
5747
+ // exists — avoids writing an empty `credentials: {}` on every host-only
5748
+ // write.
5749
+ ...updates.credentials || current.credentials ? { credentials: { ...current.credentials, ...updates.credentials ?? {} } } : {}
5746
5750
  };
5747
5751
  atomicWrite(configPath, next, stderr);
5748
5752
  return next;
@@ -23497,6 +23501,41 @@ import { existsSync as existsSync97, mkdtempSync as mkdtempSync5, readFileSync a
23497
23501
  import { spawnSync as spawnSync29 } from "node:child_process";
23498
23502
  import { homedir as homedir56, tmpdir as tmpdir7 } from "node:os";
23499
23503
  import { join as join104 } from "node:path";
23504
+ function parseBucketSpec(spec) {
23505
+ const trimmed = spec.trim().replace(/^gs:\/\//i, "").replace(/\/+$/, "");
23506
+ if (!trimmed) return null;
23507
+ const slash = trimmed.indexOf("/");
23508
+ if (slash === -1) return { bucket: trimmed };
23509
+ const bucket = trimmed.slice(0, slash);
23510
+ const prefix = trimmed.slice(slash + 1).replace(/^\/+/, "");
23511
+ if (!bucket) return null;
23512
+ return prefix ? { bucket, prefix } : { bucket };
23513
+ }
23514
+ function readConfiguredBucketDefault() {
23515
+ try {
23516
+ const cfg = readConfig();
23517
+ return cfg.credentials?.bucket;
23518
+ } catch {
23519
+ return void 0;
23520
+ }
23521
+ }
23522
+ function resolveCredentialsBucket(explicit, deps = {}) {
23523
+ const env = deps.env ?? process.env;
23524
+ const readConfigured = deps.readConfiguredBucket ?? readConfiguredBucketDefault;
23525
+ const candidates2 = [
23526
+ { value: explicit, source: "flag" },
23527
+ { value: env[CREDENTIALS_BUCKET_ENV], source: "env" },
23528
+ { value: readConfigured(), source: "config" }
23529
+ ];
23530
+ for (const { value, source } of candidates2) {
23531
+ if (value && value.trim()) {
23532
+ const spec = parseBucketSpec(value);
23533
+ if (!spec) return { ok: false, error: `invalid credentials bucket spec: "${value}"`, remedy: NO_BUCKET_REMEDY };
23534
+ return { ok: true, bucket: spec.bucket, prefix: spec.prefix, source };
23535
+ }
23536
+ }
23537
+ return { ok: false, error: "no credentials bucket configured", remedy: NO_BUCKET_REMEDY };
23538
+ }
23500
23539
  function preflightGcp(project, deps = {}) {
23501
23540
  const run = deps.run ?? defaultRun;
23502
23541
  const version = run("gcloud", ["--version"]);
@@ -23531,8 +23570,9 @@ function preflightGcp(project, deps = {}) {
23531
23570
  }
23532
23571
  return { ok: true, project: resolvedProject, account };
23533
23572
  }
23534
- function bucketUri(bucket, object) {
23535
- return object ? `gs://${bucket}/${object}` : `gs://${bucket}`;
23573
+ function bucketUri(bucket, object, prefix) {
23574
+ const parts = [prefix, object].filter((p) => !!p && p.length > 0);
23575
+ return parts.length > 0 ? `gs://${bucket}/${parts.join("/")}` : `gs://${bucket}`;
23536
23576
  }
23537
23577
  function olamDir(deps) {
23538
23578
  return join104(deps.home ?? homedir56(), ".olam");
@@ -23550,7 +23590,9 @@ function resolveLocalSecretValue(obj, deps = {}) {
23550
23590
  }
23551
23591
  function pushCredentials(opts, deps = {}) {
23552
23592
  const run = deps.run ?? defaultRun;
23553
- const bucket = opts.bucket ?? DEFAULT_CREDENTIALS_BUCKET;
23593
+ const bucket = opts.bucket;
23594
+ if (!bucket) return { ok: false, error: "no credentials bucket specified" };
23595
+ const prefix = opts.prefix;
23554
23596
  const project = opts.project;
23555
23597
  const describe2 = run("gcloud", ["storage", "buckets", "describe", bucketUri(bucket), "--format=value(name)"]);
23556
23598
  if (describe2.status !== 0) {
@@ -23573,7 +23615,7 @@ function pushCredentials(opts, deps = {}) {
23573
23615
  }
23574
23616
  const tmp = join104(staging, obj.object);
23575
23617
  writeSecretAtPath(tmp, value);
23576
- const cp = run("gcloud", ["storage", "cp", tmp, bucketUri(bucket, obj.object)]);
23618
+ const cp = run("gcloud", ["storage", "cp", tmp, bucketUri(bucket, obj.object, prefix)]);
23577
23619
  if (cp.status !== 0) {
23578
23620
  return { ok: false, pushed, error: `upload ${obj.object} failed: ${cp.stderr.trim()}` };
23579
23621
  }
@@ -23586,14 +23628,16 @@ function pushCredentials(opts, deps = {}) {
23586
23628
  }
23587
23629
  function pullCredentials(opts, deps = {}) {
23588
23630
  const run = deps.run ?? defaultRun;
23589
- const bucket = opts.bucket ?? DEFAULT_CREDENTIALS_BUCKET;
23631
+ const bucket = opts.bucket;
23632
+ if (!bucket) return { ok: false, error: "no credentials bucket specified" };
23633
+ const prefix = opts.prefix;
23590
23634
  const pulled = [];
23591
23635
  const skipped = [];
23592
23636
  const staging = mkdtempSync5(join104(tmpdir7(), "olam-cred-pull-"));
23593
23637
  try {
23594
23638
  for (const obj of CREDENTIAL_OBJECTS) {
23595
23639
  const tmp = join104(staging, obj.object);
23596
- const cp = run("gcloud", ["storage", "cp", bucketUri(bucket, obj.object), tmp]);
23640
+ const cp = run("gcloud", ["storage", "cp", bucketUri(bucket, obj.object, prefix), tmp]);
23597
23641
  if (cp.status !== 0 || !existsSync97(tmp)) {
23598
23642
  skipped.push(obj.object);
23599
23643
  continue;
@@ -23607,17 +23651,19 @@ function pullCredentials(opts, deps = {}) {
23607
23651
  rmSync12(staging, { recursive: true, force: true });
23608
23652
  }
23609
23653
  if (pulled.length === 0) {
23610
- return { ok: false, pulled, skipped, error: `no credential objects found in ${bucketUri(bucket)} (check bucket name + IAM access)` };
23654
+ return { ok: false, pulled, skipped, error: `no credential objects found in ${bucketUri(bucket, void 0, prefix)} (check bucket name + IAM access)` };
23611
23655
  }
23612
23656
  return { ok: true, pulled, skipped };
23613
23657
  }
23614
- var DEFAULT_CREDENTIALS_BUCKET, CREDENTIAL_OBJECTS, defaultRun;
23658
+ var CREDENTIALS_BUCKET_ENV, NO_BUCKET_REMEDY, CREDENTIAL_OBJECTS, defaultRun;
23615
23659
  var init_gcp_credentials = __esm({
23616
23660
  "src/lib/gcp-credentials.ts"() {
23617
23661
  "use strict";
23618
23662
  init_memory_secret();
23619
23663
  init_remote_connection();
23620
- DEFAULT_CREDENTIALS_BUCKET = "olam-credentials";
23664
+ init_config();
23665
+ CREDENTIALS_BUCKET_ENV = "OLAM_CREDENTIALS_BUCKET";
23666
+ NO_BUCKET_REMEDY = `set one: olam config set credentials.bucket <gs://bucket[/prefix]> \xB7 or pass --gcp-bucket <name> \xB7 or export ${CREDENTIALS_BUCKET_ENV}=<name>`;
23621
23667
  CREDENTIAL_OBJECTS = [
23622
23668
  { local: "secrets/cloud-memory-secret", object: "cloud-memory-secret" },
23623
23669
  { local: "kg-proxy-bearer", object: "kg-proxy-bearer" },
@@ -23734,14 +23780,20 @@ async function runCloudFirstSetup(opts, deps = {}) {
23734
23780
  }
23735
23781
  if (usingGcp) {
23736
23782
  printInfo("5. Credentials", "pull team bearers from GCS (IAM-gated)");
23783
+ const resolvedBucket = resolveCredentialsBucket(opts.gcpBucket);
23737
23784
  const preflight2 = (deps.gcpPreflightFn ?? preflightGcp)(opts.gcpProject);
23738
- if (!preflight2.ok) {
23785
+ if (!resolvedBucket.ok) {
23786
+ printError(` ${resolvedBucket.error}`);
23787
+ printWarning(` remedy: ${resolvedBucket.remedy}`);
23788
+ steps.push({ name: "credentials", status: "error" });
23789
+ } else if (!preflight2.ok) {
23739
23790
  printError(` GCP preflight failed: ${preflight2.error}`);
23740
23791
  if (preflight2.remedy) printWarning(` remedy: ${preflight2.remedy}`);
23741
23792
  steps.push({ name: "credentials", status: "error" });
23742
23793
  } else {
23743
23794
  const pull = (deps.gcpPullFn ?? ((o) => pullCredentials(o)))({
23744
- bucket: opts.gcpBucket,
23795
+ bucket: resolvedBucket.bucket,
23796
+ prefix: resolvedBucket.prefix,
23745
23797
  project: preflight2.project
23746
23798
  });
23747
23799
  if (pull.ok) {
@@ -47669,7 +47721,7 @@ function registerSetup(program2) {
47669
47721
  ).option(
47670
47722
  "--skip-inbox-hook",
47671
47723
  "Skip Phase 10 (do not install question-inbox hook; run `olam inbox install-hook` later)"
47672
- ).option("--verbose", "[k3s] stream all bootstrap phase output sequentially instead of collapsing to live spinner lines").option("--skip-prepull", "[k3s] skip pre-pulling olam-* images into the k3d node (pods cold-pull on demand)").option("--cloud-first", "Run the guided cloud-first onboarding (skills/memory/kg/remote); skips docker/k3s").option("--local-mode", "Run the legacy local (docker/k3s) bootstrap pipeline and reveal local commands").option("--skills-source <git-url>", "Cloud-first: register + sync this skill source (trusted)").option("--memory-url <url>", "Cloud-first: non-interactive memory service URL").option("--remote-memory-url <url>", "Cloud-first: alias of --memory-url").option("--memory-secret <bearer>", "Cloud-first: memory bearer secret (stored 0600; prefer --credentials=gcp)").option("--kg-url <url>", "Cloud-first: non-interactive KG mirror URL").option("--remote-kg-url <url>", "Cloud-first: alias of --kg-url").option("--kg-bearer <token>", "Cloud-first: KG mirror bearer (stored 0600; prefer --credentials=gcp)").option("--remote-url <url>", "Cloud-first: non-interactive plan-agent backend URL").option("--remote-dispatch-url <url>", "Cloud-first: alias of --remote-url (cloud dispatch backend)").option("--remote-password <pw>", "Cloud-first: plan-DO showcase password (stored 0600; prefer --credentials=gcp)").option("--credentials <source>", 'Cloud-first: secret source \u2014 "gcp" pulls bearers from the shared GCS bucket (no secrets on the CLI)').option("--gcp-bucket <name>", "Cloud-first: GCS bucket for --credentials=gcp (default: olam-credentials)").option("--gcp-project <id>", "Cloud-first: GCP project for --credentials=gcp (default: gcloud active project)").option("--allow-local-dev", "Cloud-first: allow http:// / private-IP connect endpoints").action(async (rawOpts) => {
47724
+ ).option("--verbose", "[k3s] stream all bootstrap phase output sequentially instead of collapsing to live spinner lines").option("--skip-prepull", "[k3s] skip pre-pulling olam-* images into the k3d node (pods cold-pull on demand)").option("--cloud-first", "Run the guided cloud-first onboarding (skills/memory/kg/remote); skips docker/k3s").option("--local-mode", "Run the legacy local (docker/k3s) bootstrap pipeline and reveal local commands").option("--skills-source <git-url>", "Cloud-first: register + sync this skill source (trusted)").option("--memory-url <url>", "Cloud-first: non-interactive memory service URL").option("--remote-memory-url <url>", "Cloud-first: alias of --memory-url").option("--memory-secret <bearer>", "Cloud-first: memory bearer secret (stored 0600; prefer --credentials=gcp)").option("--kg-url <url>", "Cloud-first: non-interactive KG mirror URL").option("--remote-kg-url <url>", "Cloud-first: alias of --kg-url").option("--kg-bearer <token>", "Cloud-first: KG mirror bearer (stored 0600; prefer --credentials=gcp)").option("--remote-url <url>", "Cloud-first: non-interactive plan-agent backend URL").option("--remote-dispatch-url <url>", "Cloud-first: alias of --remote-url (cloud dispatch backend)").option("--remote-password <pw>", "Cloud-first: plan-DO showcase password (stored 0600; prefer --credentials=gcp)").option("--credentials <source>", 'Cloud-first: secret source \u2014 "gcp" pulls bearers from the shared GCS bucket (no secrets on the CLI)').option("--gcp-bucket <name>", "Cloud-first: GCS bucket or gs://bucket/prefix for --credentials=gcp (overrides OLAM_CREDENTIALS_BUCKET / config; required \u2014 no implicit default)").option("--gcp-project <id>", "Cloud-first: GCP project for --credentials=gcp (default: gcloud active project)").option("--allow-local-dev", "Cloud-first: allow http:// / private-IP connect endpoints").action(async (rawOpts) => {
47673
47725
  const { resolveSetupPath: resolveSetupPath2, runCloudFirstSetup: runCloudFirstSetup2 } = await Promise.resolve().then(() => (init_setup_cloud_first(), setup_cloud_first_exports));
47674
47726
  const isTty = Boolean(process.stdin.isTTY);
47675
47727
  const hasCloudArg = Boolean(
@@ -48281,7 +48333,8 @@ var SETTABLE_KEYS = [
48281
48333
  "host.substrate",
48282
48334
  "host.mode",
48283
48335
  "host.kubectl_context_pinned",
48284
- "host.gh_token"
48336
+ "host.gh_token",
48337
+ "credentials.bucket"
48285
48338
  ];
48286
48339
  var SECRET_KEYS = /* @__PURE__ */ new Set(["host.gh_token"]);
48287
48340
  function hostConfigPath() {
@@ -48396,6 +48449,14 @@ function registerConfig(program2) {
48396
48449
  process.exit(1);
48397
48450
  }
48398
48451
  writeConfig({ host: { gh_token: value } }, { configPath });
48452
+ } else if (key === "credentials.bucket") {
48453
+ if (value.length === 0) {
48454
+ process.stderr.write(
48455
+ "credentials.bucket must be a non-empty bucket name or gs://bucket[/prefix] path\n"
48456
+ );
48457
+ process.exit(1);
48458
+ }
48459
+ writeConfig({ credentials: { bucket: value } }, { configPath });
48399
48460
  } else {
48400
48461
  process.stderr.write(
48401
48462
  `unknown config key: "${key}"
@@ -56410,28 +56471,34 @@ function fail(message, remedy) {
56410
56471
  }
56411
56472
  function registerCredentials(program2) {
56412
56473
  const credentials = program2.command("credentials").description("Distribute team secret bearers through a GCS bucket (IAM-gated)");
56413
- credentials.command("push").description("Upload local secret bearers to the shared GCS bucket (admin)").option("--gcp-bucket <name>", `GCS bucket name (default: ${DEFAULT_CREDENTIALS_BUCKET})`).option("--gcp-project <id>", "GCP project (default: gcloud active project)").action((opts) => {
56474
+ credentials.command("push").description("Upload local secret bearers to the shared GCS bucket (admin)").option("--gcp-bucket <name>", "GCS bucket or gs://bucket/prefix path (overrides OLAM_CREDENTIALS_BUCKET / config)").option("--gcp-project <id>", "GCP project (default: gcloud active project)").action((opts) => {
56475
+ const resolved = resolveCredentialsBucket(opts.gcpBucket);
56476
+ if (!resolved.ok) fail(resolved.error, resolved.remedy);
56477
+ const { bucket, prefix } = resolved;
56414
56478
  const pre = preflightGcp(opts.gcpProject);
56415
56479
  if (!pre.ok) fail(pre.error ?? "gcloud preflight failed", pre.remedy);
56416
- const bucket = opts.gcpBucket ?? DEFAULT_CREDENTIALS_BUCKET;
56480
+ const uri = prefix ? `gs://${bucket}/${prefix}` : `gs://${bucket}`;
56417
56481
  printInfo("account", pre.account ?? "?");
56418
56482
  printInfo("project", pre.project ?? "?");
56419
- printInfo("bucket", `gs://${bucket}`);
56420
- const result = pushCredentials({ bucket, project: pre.project });
56483
+ printInfo("bucket", `${uri} (${resolved.source})`);
56484
+ const result = pushCredentials({ bucket, prefix, project: pre.project });
56421
56485
  if (!result.ok) fail(result.error ?? "push failed");
56422
- printSuccess(`pushed ${result.pushed?.length ?? 0} secret(s) to gs://${bucket}`);
56486
+ printSuccess(`pushed ${result.pushed?.length ?? 0} secret(s) to ${uri}`);
56423
56487
  for (const o of result.pushed ?? []) printInfo("\u2191", o);
56424
56488
  if (result.skipped && result.skipped.length > 0) {
56425
56489
  printWarning(`skipped (not present locally): ${result.skipped.join(", ")}`);
56426
56490
  }
56427
56491
  });
56428
- credentials.command("pull").description("Download secret bearers from the shared GCS bucket into ~/.olam/ (0600)").option("--gcp-bucket <name>", `GCS bucket name (default: ${DEFAULT_CREDENTIALS_BUCKET})`).option("--gcp-project <id>", "GCP project (default: gcloud active project)").action((opts) => {
56492
+ credentials.command("pull").description("Download secret bearers from the shared GCS bucket into ~/.olam/ (0600)").option("--gcp-bucket <name>", "GCS bucket or gs://bucket/prefix path (overrides OLAM_CREDENTIALS_BUCKET / config)").option("--gcp-project <id>", "GCP project (default: gcloud active project)").action((opts) => {
56493
+ const resolved = resolveCredentialsBucket(opts.gcpBucket);
56494
+ if (!resolved.ok) fail(resolved.error, resolved.remedy);
56495
+ const { bucket, prefix } = resolved;
56429
56496
  const pre = preflightGcp(opts.gcpProject);
56430
56497
  if (!pre.ok) fail(pre.error ?? "gcloud preflight failed", pre.remedy);
56431
- const bucket = opts.gcpBucket ?? DEFAULT_CREDENTIALS_BUCKET;
56498
+ const uri = prefix ? `gs://${bucket}/${prefix}` : `gs://${bucket}`;
56432
56499
  printInfo("account", pre.account ?? "?");
56433
- printInfo("bucket", `gs://${bucket}`);
56434
- const result = pullCredentials({ bucket, project: pre.project });
56500
+ printInfo("bucket", `${uri} (${resolved.source})`);
56501
+ const result = pullCredentials({ bucket, prefix, project: pre.project });
56435
56502
  if (!result.ok) fail(result.error ?? "pull failed", "verify the bucket name and your IAM access (roles/storage.objectViewer)");
56436
56503
  printSuccess(`pulled ${result.pulled?.length ?? 0} secret(s) into ~/.olam/ (0600)`);
56437
56504
  for (const o of result.pulled ?? []) printInfo("\u2193", o);
@@ -10909,37 +10909,37 @@ var require_dist = __commonJS({
10909
10909
  });
10910
10910
 
10911
10911
  // ../core/dist/paths/olam-paths.js
10912
- import { homedir } from "node:os";
10913
- import { join as join2 } from "node:path";
10912
+ import { homedir as homedir2 } from "node:os";
10913
+ import { join as join3 } from "node:path";
10914
10914
  function olamHome() {
10915
10915
  const fromEnv = process.env["OLAM_HOME"];
10916
10916
  if (fromEnv && fromEnv.length > 0)
10917
10917
  return fromEnv;
10918
- return join2(homedir(), ".olam");
10918
+ return join3(homedir2(), ".olam");
10919
10919
  }
10920
10920
  function claudeDir() {
10921
10921
  const fromEnv = process.env["OLAM_CLAUDE_DIR"];
10922
10922
  if (fromEnv && fromEnv.length > 0)
10923
10923
  return fromEnv;
10924
- return join2(homedir(), ".claude");
10924
+ return join3(homedir2(), ".claude");
10925
10925
  }
10926
10926
  function globalConfigPath() {
10927
10927
  const override = process.env["OLAM_GLOBAL_CONFIG_PATH"];
10928
10928
  if (override && override.length > 0)
10929
10929
  return override;
10930
- return join2(olamHome(), "config.json");
10930
+ return join3(olamHome(), "config.json");
10931
10931
  }
10932
10932
  function stateDir() {
10933
10933
  const override = process.env["OLAM_STATE_DIR"];
10934
10934
  if (override && override.length > 0)
10935
10935
  return override;
10936
- return join2(olamHome(), "state");
10936
+ return join3(olamHome(), "state");
10937
10937
  }
10938
10938
  function skillSourcesDir() {
10939
10939
  const override = process.env["OLAM_SKILL_SOURCES_DIR"];
10940
10940
  if (override && override.length > 0)
10941
10941
  return override;
10942
- return join2(stateDir(), "skill-sources");
10942
+ return join3(stateDir(), "skill-sources");
10943
10943
  }
10944
10944
  var init_olam_paths = __esm({
10945
10945
  "../core/dist/paths/olam-paths.js"() {
@@ -11086,8 +11086,8 @@ var init_version2 = __esm({
11086
11086
  });
11087
11087
 
11088
11088
  // ../core/dist/world/repo-manifest.js
11089
- import { existsSync as existsSync5, lstatSync, readFileSync as readFileSync3 } from "node:fs";
11090
- import { join as join6, resolve as resolve3, sep } from "node:path";
11089
+ import { existsSync as existsSync6, lstatSync, readFileSync as readFileSync4 } from "node:fs";
11090
+ import { join as join7, resolve as resolve3, sep } from "node:path";
11091
11091
  import YAML from "yaml";
11092
11092
  function bootstrapStepCmd(entry) {
11093
11093
  return typeof entry === "string" ? entry : entry.cmd;
@@ -11151,14 +11151,14 @@ function isPlainObject3(value) {
11151
11151
  return value !== null && typeof value === "object" && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
11152
11152
  }
11153
11153
  function loadRepoManifest(repoDir) {
11154
- const olamPath = join6(repoDir, ".olam.yaml");
11155
- const adbPath = join6(repoDir, ".adb.yaml");
11154
+ const olamPath = join7(repoDir, ".olam.yaml");
11155
+ const adbPath = join7(repoDir, ".adb.yaml");
11156
11156
  let manifestPath2;
11157
11157
  let source;
11158
- if (existsSync5(olamPath)) {
11158
+ if (existsSync6(olamPath)) {
11159
11159
  manifestPath2 = olamPath;
11160
11160
  source = "olam";
11161
- } else if (existsSync5(adbPath)) {
11161
+ } else if (existsSync6(adbPath)) {
11162
11162
  manifestPath2 = adbPath;
11163
11163
  source = "adb";
11164
11164
  } else {
@@ -11168,10 +11168,10 @@ function loadRepoManifest(repoDir) {
11168
11168
  if (stat2.isSymbolicLink()) {
11169
11169
  throw new Error(`[manifest] ${manifestPath2}: symbolic links are not permitted`);
11170
11170
  }
11171
- const raw = readFileSync3(manifestPath2, "utf-8");
11171
+ const raw = readFileSync4(manifestPath2, "utf-8");
11172
11172
  const parsed = YAML.parse(raw, { maxAliasCount: 100 });
11173
11173
  if (parsed === null || parsed === void 0) {
11174
- if (source === "olam" && existsSync5(adbPath)) {
11174
+ if (source === "olam" && existsSync6(adbPath)) {
11175
11175
  console.warn(`[manifest] ${manifestPath2}: file is empty; .adb.yaml is NOT consulted (delete .olam.yaml to fall back)`);
11176
11176
  }
11177
11177
  return null;
@@ -11191,14 +11191,14 @@ function loadRepoManifest(repoDir) {
11191
11191
  if (!inheritedAbs.startsWith(repoDirAbs + sep) && inheritedAbs !== repoDirAbs) {
11192
11192
  throw new Error(`[manifest] ${manifestPath2}: inherits target "${inheritsRaw}" escapes repo dir`);
11193
11193
  }
11194
- if (!existsSync5(inheritedAbs)) {
11194
+ if (!existsSync6(inheritedAbs)) {
11195
11195
  throw new Error(`[manifest] ${manifestPath2}: inherits target "${inheritsRaw}" not found`);
11196
11196
  }
11197
11197
  const inheritedStat = lstatSync(inheritedAbs);
11198
11198
  if (inheritedStat.isSymbolicLink()) {
11199
11199
  throw new Error(`[manifest] ${manifestPath2}: inherits target "${inheritsRaw}" is a symlink (not permitted)`);
11200
11200
  }
11201
- const inheritedRaw = readFileSync3(inheritedAbs, "utf-8");
11201
+ const inheritedRaw = readFileSync4(inheritedAbs, "utf-8");
11202
11202
  const inheritedParsed = YAML.parse(inheritedRaw, { maxAliasCount: 100 });
11203
11203
  if (inheritedParsed !== null && inheritedParsed !== void 0) {
11204
11204
  if (typeof inheritedParsed !== "object" || Array.isArray(inheritedParsed)) {
@@ -11417,7 +11417,7 @@ var init_path = __esm({
11417
11417
  import * as fs5 from "node:fs";
11418
11418
  import * as os4 from "node:os";
11419
11419
  import * as path7 from "node:path";
11420
- import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
11420
+ import { parse as parseYaml2, stringify as stringifyYaml } from "yaml";
11421
11421
  function workspacesDir() {
11422
11422
  const override = process.env["OLAM_WORKSPACES_DIR"];
11423
11423
  if (override && override.length > 0)
@@ -11441,7 +11441,7 @@ function listWorkspaces() {
11441
11441
  for (const entry of entries) {
11442
11442
  try {
11443
11443
  const raw = fs5.readFileSync(path7.join(dir, entry), "utf-8");
11444
- const parsed = parseYaml(raw);
11444
+ const parsed = parseYaml2(raw);
11445
11445
  const ws = WorkspaceSchema.parse(parsed);
11446
11446
  result.push(ws);
11447
11447
  } catch (err) {
@@ -11466,7 +11466,7 @@ function readWorkspace(name) {
11466
11466
  if (!fs5.existsSync(file2))
11467
11467
  return null;
11468
11468
  const raw = fs5.readFileSync(file2, "utf-8");
11469
- return WorkspaceSchema.parse(parseYaml(raw));
11469
+ return WorkspaceSchema.parse(parseYaml2(raw));
11470
11470
  }
11471
11471
  function writeWorkspace(ws, options = {}) {
11472
11472
  validateName(ws.name);
@@ -12392,7 +12392,7 @@ __export(loader_exports, {
12392
12392
  });
12393
12393
  import * as fs8 from "node:fs";
12394
12394
  import * as path9 from "node:path";
12395
- import { parse as parseYaml2 } from "yaml";
12395
+ import { parse as parseYaml3 } from "yaml";
12396
12396
  function findConfigFile(startDir) {
12397
12397
  const searched = [];
12398
12398
  let current = path9.resolve(startDir);
@@ -12432,7 +12432,7 @@ function loadConfig(startDir) {
12432
12432
  }
12433
12433
  let parsed;
12434
12434
  try {
12435
- parsed = parseYaml2(rawContent);
12435
+ parsed = parseYaml3(rawContent);
12436
12436
  } catch (err) {
12437
12437
  const message = err instanceof Error ? err.message : String(err);
12438
12438
  throw new Error(`Invalid YAML in ${found.path}: ${message}`);
@@ -13387,7 +13387,7 @@ var init_cleanup = __esm({
13387
13387
 
13388
13388
  // ../adapters/dist/ssh/connection.js
13389
13389
  import { Client as SSHClient } from "ssh2";
13390
- import { readFileSync as readFileSync10 } from "node:fs";
13390
+ import { readFileSync as readFileSync11 } from "node:fs";
13391
13391
  var SSHConnectionPool;
13392
13392
  var init_connection = __esm({
13393
13393
  "../adapters/dist/ssh/connection.js"() {
@@ -13482,7 +13482,7 @@ var init_connection = __esm({
13482
13482
  host: config2.host,
13483
13483
  port: config2.port ?? 22,
13484
13484
  username: config2.user,
13485
- ...config2.key ? { privateKey: readFileSync10(config2.key) } : {},
13485
+ ...config2.key ? { privateKey: readFileSync11(config2.key) } : {},
13486
13486
  ...config2.password ? { password: config2.password } : {}
13487
13487
  });
13488
13488
  });
@@ -16305,9 +16305,9 @@ var init_model_router = __esm({
16305
16305
  });
16306
16306
 
16307
16307
  // ../core/dist/meta-hooks/model-router-deploy.js
16308
- import { existsSync as existsSync32, mkdirSync as mkdirSync16, readFileSync as readFileSync23, writeFileSync as writeFileSync15 } from "node:fs";
16309
- import { homedir as homedir14 } from "node:os";
16310
- import { dirname as dirname13, join as join30, resolve as resolve7 } from "node:path";
16308
+ import { existsSync as existsSync33, mkdirSync as mkdirSync16, readFileSync as readFileSync24, writeFileSync as writeFileSync15 } from "node:fs";
16309
+ import { homedir as homedir15 } from "node:os";
16310
+ import { dirname as dirname13, join as join31, resolve as resolve7 } from "node:path";
16311
16311
  import { fileURLToPath as fileURLToPath3 } from "node:url";
16312
16312
  function resolveModelRouterSourcePath() {
16313
16313
  const here = dirname13(fileURLToPath3(import.meta.url));
@@ -16321,21 +16321,21 @@ function resolveModelRouterSourcePath() {
16321
16321
  resolve7(here, "..", "..", "hooks", MODEL_ROUTER_SCRIPT_BASENAME)
16322
16322
  ];
16323
16323
  for (const candidate of candidates) {
16324
- if (existsSync32(candidate))
16324
+ if (existsSync33(candidate))
16325
16325
  return candidate;
16326
16326
  }
16327
16327
  return candidates[0];
16328
16328
  }
16329
16329
  function deployModelRouterScript(opts = {}) {
16330
- const targetDir = opts.targetDir ?? join30(homedir14(), ".claude", "hooks");
16331
- const targetPath = join30(targetDir, MODEL_ROUTER_SCRIPT_BASENAME);
16330
+ const targetDir = opts.targetDir ?? join31(homedir15(), ".claude", "hooks");
16331
+ const targetPath = join31(targetDir, MODEL_ROUTER_SCRIPT_BASENAME);
16332
16332
  const sourcePath = opts.sourcePath ?? resolveModelRouterSourcePath();
16333
- if (!existsSync32(sourcePath)) {
16333
+ if (!existsSync33(sourcePath)) {
16334
16334
  return { basename: MODEL_ROUTER_SCRIPT_BASENAME, action: "source-missing", targetPath };
16335
16335
  }
16336
- const newContent = readFileSync23(sourcePath, "utf8");
16337
- if (existsSync32(targetPath)) {
16338
- const existing = readFileSync23(targetPath, "utf8");
16336
+ const newContent = readFileSync24(sourcePath, "utf8");
16337
+ if (existsSync33(targetPath)) {
16338
+ const existing = readFileSync24(targetPath, "utf8");
16339
16339
  if (existing === newContent) {
16340
16340
  return { basename: MODEL_ROUTER_SCRIPT_BASENAME, action: "unchanged", targetPath };
16341
16341
  }
@@ -16613,7 +16613,7 @@ var init_schema5 = __esm({
16613
16613
  import { execFileSync as execFileSync4 } from "node:child_process";
16614
16614
  import * as fs30 from "node:fs";
16615
16615
  import * as path28 from "node:path";
16616
- import { parse as parseYaml3 } from "yaml";
16616
+ import { parse as parseYaml4 } from "yaml";
16617
16617
  function findProjectOverride(startDir) {
16618
16618
  let dir = path28.resolve(startDir);
16619
16619
  const root = path28.parse(dir).root;
@@ -16623,7 +16623,7 @@ function findProjectOverride(startDir) {
16623
16623
  const raw = fs30.readFileSync(candidate, "utf-8");
16624
16624
  let parsed;
16625
16625
  try {
16626
- parsed = parseYaml3(raw);
16626
+ parsed = parseYaml4(raw);
16627
16627
  } catch (err) {
16628
16628
  const msg = err instanceof Error ? err.message : String(err);
16629
16629
  throw new Error(`failed to parse "${candidate}" as YAML: ${msg}`);
@@ -16854,13 +16854,13 @@ var init_file_lock = __esm({
16854
16854
  });
16855
16855
 
16856
16856
  // ../core/dist/lib/min-version-filter.js
16857
- import { existsSync as existsSync35, readFileSync as readFileSync27 } from "node:fs";
16857
+ import { existsSync as existsSync36, readFileSync as readFileSync28 } from "node:fs";
16858
16858
  function readOlamMinVersion(filepath) {
16859
- if (!existsSync35(filepath))
16859
+ if (!existsSync36(filepath))
16860
16860
  return void 0;
16861
16861
  let text;
16862
16862
  try {
16863
- text = readFileSync27(filepath, "utf8");
16863
+ text = readFileSync28(filepath, "utf8");
16864
16864
  } catch {
16865
16865
  return void 0;
16866
16866
  }
@@ -17536,7 +17536,7 @@ var init_meta_hook_injector = __esm({
17536
17536
 
17537
17537
  // ../core/dist/lib/markdown-merger.js
17538
17538
  import { createHash as createHash5 } from "node:crypto";
17539
- import { readFileSync as readFileSync31, existsSync as existsSync38, statSync as statSync10 } from "node:fs";
17539
+ import { readFileSync as readFileSync32, existsSync as existsSync39, statSync as statSync10 } from "node:fs";
17540
17540
  function parseFrontmatter(text) {
17541
17541
  const match = FM_RE2.exec(text);
17542
17542
  if (match === null)
@@ -17665,9 +17665,9 @@ function mergeMarkdown(upstreamText, overlayText, labelForError, upstreamPath, o
17665
17665
  return { merged: fmBlock !== "" ? fmBlock + mergedBody : mergedBody };
17666
17666
  }
17667
17667
  function sha256OfPath(p) {
17668
- if (!existsSync38(p) || !statSync10(p).isFile())
17668
+ if (!existsSync39(p) || !statSync10(p).isFile())
17669
17669
  return "MISSING";
17670
- return createHash5("sha256").update(readFileSync31(p)).digest("hex");
17670
+ return createHash5("sha256").update(readFileSync32(p)).digest("hex");
17671
17671
  }
17672
17672
  var FM_RE2, H2_RE;
17673
17673
  var init_markdown_merger = __esm({
@@ -17935,26 +17935,26 @@ var init_prefix_deploy = __esm({
17935
17935
  });
17936
17936
 
17937
17937
  // ../core/dist/skill-sync/resolve-source-config.js
17938
- import { readFileSync as readFileSync33, existsSync as existsSync39 } from "node:fs";
17939
- import { join as join39 } from "node:path";
17940
- import { parse as parseYaml4 } from "yaml";
17938
+ import { readFileSync as readFileSync34, existsSync as existsSync40 } from "node:fs";
17939
+ import { join as join40 } from "node:path";
17940
+ import { parse as parseYaml5 } from "yaml";
17941
17941
  function sourceConfigPath(clonePath) {
17942
- return join39(clonePath, "shared", "source-config.yaml");
17942
+ return join40(clonePath, "shared", "source-config.yaml");
17943
17943
  }
17944
17944
  function readSourceConfig(clonePath, sourceId) {
17945
17945
  const path62 = sourceConfigPath(clonePath);
17946
- if (!existsSync39(path62))
17946
+ if (!existsSync40(path62))
17947
17947
  return void 0;
17948
17948
  let raw;
17949
17949
  try {
17950
- raw = readFileSync33(path62, "utf-8");
17950
+ raw = readFileSync34(path62, "utf-8");
17951
17951
  } catch (err) {
17952
17952
  emitMalformedWarning(sourceId, `read failed: ${errToMsg(err)}`);
17953
17953
  return void 0;
17954
17954
  }
17955
17955
  let parsed;
17956
17956
  try {
17957
- parsed = parseYaml4(raw);
17957
+ parsed = parseYaml5(raw);
17958
17958
  } catch (err) {
17959
17959
  emitMalformedWarning(sourceId, `YAML parse failed: ${errToMsg(err)}`);
17960
17960
  return void 0;
@@ -39602,6 +39602,68 @@ var EMPTY_COMPLETION_RESULT = {
39602
39602
  }
39603
39603
  };
39604
39604
 
39605
+ // ../mcp-server/src/cloud-visibility.ts
39606
+ import { existsSync, readFileSync } from "node:fs";
39607
+ import { homedir } from "node:os";
39608
+ import { join } from "node:path";
39609
+ import { parse as parseYaml } from "yaml";
39610
+ var DEFAULT_MCP_MODE = "cloud";
39611
+ var SHOW_ALL_TOOLS_ENV = "OLAM_MCP_SHOW_ALL_TOOLS";
39612
+ var MCP_LOCAL_ONLY_TOOLS = /* @__PURE__ */ new Set([
39613
+ "olam_enter",
39614
+ // world-enter — literal `docker exec -it … tmux attach`
39615
+ "olam_observe",
39616
+ // world-observe — local better-sqlite3 world DB read
39617
+ "olam_web_task",
39618
+ // web-task — host venv `spawn(python -m webwright)`
39619
+ "olam_create_lane",
39620
+ // lane-create — in-container .exec curl (CF exec unsupported)
39621
+ "olam_list_lanes",
39622
+ // lane-list — in-container .exec curl
39623
+ "olam_dispatch_lane",
39624
+ // lane-dispatch — in-container .exec curl
39625
+ "olam_destroy_lane",
39626
+ // lane-destroy — in-container .exec curl
39627
+ "olam_merge_lane"
39628
+ // lane-merge — in-container .exec curl
39629
+ ]);
39630
+ function resolveConfigPath() {
39631
+ const override = process.env["OLAM_CONFIG_PATH"];
39632
+ if (override && override.trim() !== "") return override;
39633
+ const home = join(homedir(), ".olam");
39634
+ const jsonPath = join(home, "config.json");
39635
+ const yamlPath = join(home, "config.yaml");
39636
+ if (existsSync(jsonPath)) return jsonPath;
39637
+ if (existsSync(yamlPath)) return yamlPath;
39638
+ return jsonPath;
39639
+ }
39640
+ function isYamlPath(p) {
39641
+ return p.endsWith(".yaml") || p.endsWith(".yml");
39642
+ }
39643
+ function readMcpMode(opts = {}) {
39644
+ try {
39645
+ const configPath = opts.configPath ?? resolveConfigPath();
39646
+ if (!existsSync(configPath)) return DEFAULT_MCP_MODE;
39647
+ const raw = readFileSync(configPath, "utf8");
39648
+ const parsed = isYamlPath(configPath) ? parseYaml(raw) : JSON.parse(raw);
39649
+ const mode = parsed?.host?.mode;
39650
+ return mode === "local" ? "local" : DEFAULT_MCP_MODE;
39651
+ } catch {
39652
+ return DEFAULT_MCP_MODE;
39653
+ }
39654
+ }
39655
+ function isCloudMode(opts = {}) {
39656
+ return readMcpMode(opts) === "cloud";
39657
+ }
39658
+ function showAllToolsForced() {
39659
+ return process.env[SHOW_ALL_TOOLS_ENV] === "1";
39660
+ }
39661
+ function resolveDeniedTools(opts = {}) {
39662
+ if (opts.showAll || showAllToolsForced()) return /* @__PURE__ */ new Set();
39663
+ if (!isCloudMode({ configPath: opts.configPath })) return /* @__PURE__ */ new Set();
39664
+ return MCP_LOCAL_ONLY_TOOLS;
39665
+ }
39666
+
39605
39667
  // ../mcp-server/src/tool-filter.ts
39606
39668
  function getToolFilterContextFromEnv() {
39607
39669
  const raw = process.env.OLAM_ALLOWED_TOOLS;
@@ -39616,20 +39678,29 @@ function getToolFilterContextFromEnv() {
39616
39678
  context.allowedTools = allowedTools;
39617
39679
  }
39618
39680
  }
39681
+ const denied = resolveDeniedTools();
39682
+ if (denied.size > 0) {
39683
+ context.deniedTools = denied;
39684
+ }
39619
39685
  return context;
39620
39686
  }
39621
39687
  function withFilteredTools(server, context) {
39622
39688
  const allowed = context.allowedTools;
39623
- if (!allowed || allowed.length === 0) {
39689
+ const denied = context.deniedTools;
39690
+ const hasAllow = !!allowed && allowed.length > 0;
39691
+ const hasDeny = !!denied && denied.size > 0;
39692
+ if (!hasAllow && !hasDeny) {
39624
39693
  return { server, finalize: () => {
39625
39694
  } };
39626
39695
  }
39627
- const allowedSet = new Set(allowed);
39696
+ const allowedSet = hasAllow ? new Set(allowed) : null;
39628
39697
  const registered = /* @__PURE__ */ new Set();
39629
39698
  const host = server;
39630
39699
  const original = host.tool;
39631
39700
  const filtered = function(name, ...rest) {
39632
- if (typeof name === "string" && allowedSet.has(name)) {
39701
+ const passesAllow = typeof name === "string" && (!allowedSet || allowedSet.has(name));
39702
+ const passesDeny = !hasDeny || !denied.has(name);
39703
+ if (passesAllow && passesDeny) {
39633
39704
  registered.add(name);
39634
39705
  return original.apply(
39635
39706
  server,
@@ -39643,12 +39714,14 @@ function withFilteredTools(server, context) {
39643
39714
  server,
39644
39715
  finalize: () => {
39645
39716
  host.tool = original;
39646
- for (const name of allowedSet) {
39647
- if (!registered.has(name)) {
39648
- process.stderr.write(
39649
- `[tool-filter] warning: unknown tool name in OLAM_ALLOWED_TOOLS: "${name}"
39717
+ if (allowedSet) {
39718
+ for (const name of allowedSet) {
39719
+ if (!registered.has(name) && !(hasDeny && denied.has(name))) {
39720
+ process.stderr.write(
39721
+ `[tool-filter] warning: unknown tool name in OLAM_ALLOWED_TOOLS: "${name}"
39650
39722
  `
39651
- );
39723
+ );
39724
+ }
39652
39725
  }
39653
39726
  }
39654
39727
  }
@@ -40171,7 +40244,7 @@ function sleep(ms) {
40171
40244
 
40172
40245
  // ../core/dist/auth/container.js
40173
40246
  import { execFileSync, spawnSync } from "node:child_process";
40174
- import { chmodSync as chmodSync3, existsSync as existsSync4, mkdtempSync, rmSync, writeFileSync as writeFileSync3 } from "node:fs";
40247
+ import { chmodSync as chmodSync3, existsSync as existsSync5, mkdtempSync, rmSync, writeFileSync as writeFileSync3 } from "node:fs";
40175
40248
  import { tmpdir } from "node:os";
40176
40249
  import * as path4 from "node:path";
40177
40250
  import { fileURLToPath } from "node:url";
@@ -40240,7 +40313,7 @@ var AuthContainerController = class {
40240
40313
  */
40241
40314
  buildImage() {
40242
40315
  const dockerfileDir = resolveAuthServicePath();
40243
- if (!existsSync4(path4.join(dockerfileDir, "Dockerfile"))) {
40316
+ if (!existsSync5(path4.join(dockerfileDir, "Dockerfile"))) {
40244
40317
  throw new Error(`auth image '${this.imageTag}' is not present locally and no Dockerfile is available at ${dockerfileDir} to build from. Run \`olam bootstrap\` to pull the published image, or check out the olam source tree.`);
40245
40318
  }
40246
40319
  execFileSync("docker", ["build", "--tag", this.imageTag, dockerfileDir], { stdio: "inherit" });
@@ -41390,12 +41463,12 @@ var logger = {
41390
41463
  // ../mcp-server/src/utils/profile-sync.ts
41391
41464
  import { execFile } from "node:child_process";
41392
41465
  import { promisify } from "node:util";
41393
- import { readFileSync as readFileSync5, existsSync as existsSync7, statSync } from "node:fs";
41394
- import { homedir as homedir5 } from "node:os";
41395
- import { join as join9 } from "node:path";
41466
+ import { readFileSync as readFileSync6, existsSync as existsSync8, statSync } from "node:fs";
41467
+ import { homedir as homedir6 } from "node:os";
41468
+ import { join as join10 } from "node:path";
41396
41469
  var execFileP = promisify(execFile);
41397
41470
  async function tarSkillsDir(skillsDir) {
41398
- if (!existsSync7(skillsDir) || !statSync(skillsDir).isDirectory()) {
41471
+ if (!existsSync8(skillsDir) || !statSync(skillsDir).isDirectory()) {
41399
41472
  return null;
41400
41473
  }
41401
41474
  const { stdout } = await execFileP(
@@ -41406,12 +41479,12 @@ async function tarSkillsDir(skillsDir) {
41406
41479
  return stdout;
41407
41480
  }
41408
41481
  function extractMcpConfig(claudeJsonPath) {
41409
- if (!existsSync7(claudeJsonPath)) {
41482
+ if (!existsSync8(claudeJsonPath)) {
41410
41483
  return { mcpServers: {}, secrets: {} };
41411
41484
  }
41412
41485
  let parsed;
41413
41486
  try {
41414
- const raw = readFileSync5(claudeJsonPath, "utf8");
41487
+ const raw = readFileSync6(claudeJsonPath, "utf8");
41415
41488
  parsed = JSON.parse(raw);
41416
41489
  } catch (err) {
41417
41490
  logger.warn("Failed to parse ~/.claude.json", {
@@ -41449,19 +41522,19 @@ function extractMcpConfig(claudeJsonPath) {
41449
41522
  return { mcpServers, secrets };
41450
41523
  }
41451
41524
  function readOptional(path62) {
41452
- if (!existsSync7(path62)) return null;
41525
+ if (!existsSync8(path62)) return null;
41453
41526
  try {
41454
- return readFileSync5(path62, "utf8");
41527
+ return readFileSync6(path62, "utf8");
41455
41528
  } catch {
41456
41529
  return null;
41457
41530
  }
41458
41531
  }
41459
41532
  async function syncProfileToCloudflare(opts) {
41460
- const home = opts.homeDir ?? homedir5();
41461
- const skillsDir = join9(home, ".claude", "skills");
41462
- const claudeJsonPath = join9(home, ".claude.json");
41463
- const claudeMdPath = join9(home, ".claude", "CLAUDE.md");
41464
- const agentsMdPath = join9(home, ".claude", "AGENTS.md");
41533
+ const home = opts.homeDir ?? homedir6();
41534
+ const skillsDir = join10(home, ".claude", "skills");
41535
+ const claudeJsonPath = join10(home, ".claude.json");
41536
+ const claudeMdPath = join10(home, ".claude", "CLAUDE.md");
41537
+ const agentsMdPath = join10(home, ".claude", "AGENTS.md");
41465
41538
  const form = new FormData();
41466
41539
  const skillsBuf = await tarSkillsDir(skillsDir);
41467
41540
  if (skillsBuf) {
@@ -43618,7 +43691,7 @@ __export(world_observe_exports, {
43618
43691
  register: () => register9
43619
43692
  });
43620
43693
  import { createRequire as createRequire3 } from "node:module";
43621
- import { existsSync as existsSync12 } from "node:fs";
43694
+ import { existsSync as existsSync13 } from "node:fs";
43622
43695
 
43623
43696
  // ../skill-runtime/dist/skills/world-observe.js
43624
43697
  init_v3();
@@ -43669,7 +43742,7 @@ function readWorldChunks(dbPath, params) {
43669
43742
  limit
43670
43743
  }
43671
43744
  });
43672
- if (!existsSync12(dbPath)) return empty();
43745
+ if (!existsSync13(dbPath)) return empty();
43673
43746
  const Sqlite = require2("better-sqlite3");
43674
43747
  const db = new Sqlite(dbPath, { readonly: true, fileMustExist: true });
43675
43748
  try {
@@ -44582,12 +44655,12 @@ __export(capture_view_exports, {
44582
44655
  });
44583
44656
  init_v3();
44584
44657
  import { mkdir } from "node:fs/promises";
44585
- import { join as join16, resolve as resolvePath } from "node:path";
44658
+ import { join as join17, resolve as resolvePath } from "node:path";
44586
44659
 
44587
44660
  // ../mcp-server/src/tools/_capture/manifest.ts
44588
44661
  import { createHash as createHash3 } from "node:crypto";
44589
44662
  import { readFile, writeFile } from "node:fs/promises";
44590
- import { basename as basename2, join as join15 } from "node:path";
44663
+ import { basename as basename2, join as join16 } from "node:path";
44591
44664
  function redactUrl(url3) {
44592
44665
  if (url3.startsWith("world://")) return url3;
44593
44666
  let parsed;
@@ -44630,7 +44703,7 @@ async function writeManifest(args) {
44630
44703
  capturedAt: args.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
44631
44704
  shots: entries
44632
44705
  };
44633
- const path62 = join15(args.outDir, "manifest.json");
44706
+ const path62 = join16(args.outDir, "manifest.json");
44634
44707
  await writeFile(path62, `${JSON.stringify(manifest, null, 2)}
44635
44708
  `, "utf8");
44636
44709
  return { path: path62, manifest };
@@ -45428,7 +45501,7 @@ function releaseLaunchSlot() {
45428
45501
  function resolveShootsRoot() {
45429
45502
  const fromEnv = process.env.OLAM_SHOOTS_ROOT;
45430
45503
  if (fromEnv && fromEnv.length > 0) return resolvePath(fromEnv);
45431
- return resolvePath(join16(process.cwd(), ".olam", "shoots"));
45504
+ return resolvePath(join17(process.cwd(), ".olam", "shoots"));
45432
45505
  }
45433
45506
  function isUnderRoot(absPath, root) {
45434
45507
  if (absPath === root) return true;
@@ -45729,7 +45802,7 @@ async function runShot(browser, shot, outDir, format, jpegQuality, allowEval, as
45729
45802
  await page.waitForTimeout(shot.afterLoadMs);
45730
45803
  }
45731
45804
  const ext = format === "jpeg" ? "jpg" : "png";
45732
- const path62 = join16(outDir, `${shot.name}.${ext}`);
45805
+ const path62 = join17(outDir, `${shot.name}.${ext}`);
45733
45806
  await page.screenshot({
45734
45807
  path: path62,
45735
45808
  type: format,
@@ -46041,20 +46114,20 @@ var webTaskShape = external_exports2.object(webTaskInput);
46041
46114
 
46042
46115
  // ../mcp-server/src/tools/_web_task/provision.ts
46043
46116
  import { spawn as spawn3 } from "node:child_process";
46044
- import { existsSync as existsSync14 } from "node:fs";
46045
- import { homedir as homedir9 } from "node:os";
46046
- import { join as join17 } from "node:path";
46117
+ import { existsSync as existsSync15 } from "node:fs";
46118
+ import { homedir as homedir10 } from "node:os";
46119
+ import { join as join18 } from "node:path";
46047
46120
  var WEBWRIGHT_SETUP_COMMAND = "olam webwright setup";
46048
46121
  function resolveVenvPath(cfg) {
46049
46122
  if (cfg?.venvPath && cfg.venvPath.length > 0) return cfg.venvPath;
46050
- return join17(homedir9(), ".olam", "venvs", "webwright");
46123
+ return join18(homedir10(), ".olam", "venvs", "webwright");
46051
46124
  }
46052
46125
  function resolveConfigDir(cfg) {
46053
46126
  if (cfg?.configDir && cfg.configDir.length > 0) {
46054
- return existsSync14(cfg.configDir) ? cfg.configDir : null;
46127
+ return existsSync15(cfg.configDir) ? cfg.configDir : null;
46055
46128
  }
46056
- const candidate = join17(
46057
- homedir9(),
46129
+ const candidate = join18(
46130
+ homedir10(),
46058
46131
  ".claude",
46059
46132
  "plugins",
46060
46133
  "marketplaces",
@@ -46063,7 +46136,7 @@ function resolveConfigDir(cfg) {
46063
46136
  "webwright",
46064
46137
  "config"
46065
46138
  );
46066
- return existsSync14(candidate) ? candidate : null;
46139
+ return existsSync15(candidate) ? candidate : null;
46067
46140
  }
46068
46141
  function isWebwrightEnabled(cfg) {
46069
46142
  const env = process.env.OLAM_WEBWRIGHT_ENABLED;
@@ -46071,10 +46144,10 @@ function isWebwrightEnabled(cfg) {
46071
46144
  return cfg?.enabled === true;
46072
46145
  }
46073
46146
  function venvPython(venvPath) {
46074
- const posix = join17(venvPath, "bin", "python");
46075
- if (existsSync14(posix)) return posix;
46076
- const win = join17(venvPath, "Scripts", "python.exe");
46077
- if (existsSync14(win)) return win;
46147
+ const posix = join18(venvPath, "bin", "python");
46148
+ if (existsSync15(posix)) return posix;
46149
+ const win = join18(venvPath, "Scripts", "python.exe");
46150
+ if (existsSync15(win)) return win;
46078
46151
  return null;
46079
46152
  }
46080
46153
  async function probeWebwrightImportable(pythonPath, opts = {}) {
@@ -46120,7 +46193,7 @@ async function checkWebwrightProvisioned(cfg, probe = probeWebwrightImportable)
46120
46193
  };
46121
46194
  }
46122
46195
  const venvPath = resolveVenvPath(cfg);
46123
- if (!existsSync14(venvPath)) {
46196
+ if (!existsSync15(venvPath)) {
46124
46197
  return {
46125
46198
  ok: false,
46126
46199
  reason: "venv_missing",
@@ -46157,14 +46230,14 @@ async function checkWebwrightProvisioned(cfg, probe = probeWebwrightImportable)
46157
46230
  // ../mcp-server/src/tools/_web_task/spawn-executor.ts
46158
46231
  import { spawn as spawn4 } from "node:child_process";
46159
46232
  import { mkdir as mkdir2, mkdtemp, readFile as readFile3, readdir, rm, writeFile as writeFile2 } from "node:fs/promises";
46160
- import { existsSync as existsSync15 } from "node:fs";
46233
+ import { existsSync as existsSync16 } from "node:fs";
46161
46234
  import { tmpdir as tmpdir2 } from "node:os";
46162
- import { join as join19, resolve as resolvePath2 } from "node:path";
46235
+ import { join as join20, resolve as resolvePath2 } from "node:path";
46163
46236
 
46164
46237
  // ../mcp-server/src/tools/_web_task/model-config.ts
46165
46238
  import { readFile as readFile2 } from "node:fs/promises";
46166
- import { homedir as homedir10 } from "node:os";
46167
- import { join as join18 } from "node:path";
46239
+ import { homedir as homedir11 } from "node:os";
46240
+ import { join as join19 } from "node:path";
46168
46241
  var PLACEHOLDER_ANTHROPIC_API_KEY = "olam-vault-routed-placeholder-stripped-by-proxy";
46169
46242
  var DEFAULT_WEB_TASK_MODEL = "claude-opus-4-7";
46170
46243
  var AnthropicBaseUrlMissingError = class extends Error {
@@ -46179,7 +46252,7 @@ async function resolveVaultBaseUrl(opts = {}) {
46179
46252
  const env = opts.env ?? process.env;
46180
46253
  const fromEnv = env.OLAM_ANTHROPIC_BASE_URL;
46181
46254
  if (fromEnv && fromEnv.trim().length > 0) return fromEnv.trim();
46182
- const file2 = opts.baseUrlFile ?? join18(homedir10(), ".olam", "anthropic-base-url");
46255
+ const file2 = opts.baseUrlFile ?? join19(homedir11(), ".olam", "anthropic-base-url");
46183
46256
  let raw;
46184
46257
  try {
46185
46258
  raw = await readFile2(file2, "utf-8");
@@ -46229,7 +46302,7 @@ var WebTaskSpawnError = class extends Error {
46229
46302
  function resolveWebTaskRoot() {
46230
46303
  const fromEnv = process.env.OLAM_WEB_TASK_ROOT;
46231
46304
  if (fromEnv && fromEnv.length > 0) return resolvePath2(fromEnv);
46232
- return resolvePath2(join19(process.cwd(), ".olam", "web-tasks"));
46305
+ return resolvePath2(join20(process.cwd(), ".olam", "web-tasks"));
46233
46306
  }
46234
46307
  function isUnderRoot2(absPath, root) {
46235
46308
  if (absPath === root) return true;
@@ -46292,7 +46365,7 @@ async function runWebwright(pythonPath, args, spawnEnv, timeoutMs, deps) {
46292
46365
  });
46293
46366
  }
46294
46367
  async function locateRunDir(outDir) {
46295
- if (existsSync15(join19(outDir, "trajectory.json"))) return outDir;
46368
+ if (existsSync16(join20(outDir, "trajectory.json"))) return outDir;
46296
46369
  let entries = [];
46297
46370
  try {
46298
46371
  entries = await readdir(outDir);
@@ -46301,8 +46374,8 @@ async function locateRunDir(outDir) {
46301
46374
  }
46302
46375
  const candidates = [];
46303
46376
  for (const name of entries) {
46304
- const sub = join19(outDir, name);
46305
- if (existsSync15(join19(sub, "trajectory.json"))) candidates.push({ dir: sub });
46377
+ const sub = join20(outDir, name);
46378
+ if (existsSync16(join20(sub, "trajectory.json"))) candidates.push({ dir: sub });
46306
46379
  }
46307
46380
  if (candidates.length === 0) return outDir;
46308
46381
  candidates.sort((a, b) => a.dir < b.dir ? 1 : -1);
@@ -46315,14 +46388,14 @@ async function collectScreenshots(runDir) {
46315
46388
  } catch {
46316
46389
  return [];
46317
46390
  }
46318
- const shots = entries.filter((n) => /\.(png|jpe?g)$/i.test(n)).sort().map((n, i) => ({ step: i, path: join19(runDir, n) }));
46391
+ const shots = entries.filter((n) => /\.(png|jpe?g)$/i.test(n)).sort().map((n, i) => ({ step: i, path: join20(runDir, n) }));
46319
46392
  return shots;
46320
46393
  }
46321
46394
  async function readTrajectoryFacts(runDir, stdoutTail) {
46322
46395
  let answer = null;
46323
46396
  let modelCalls = null;
46324
46397
  try {
46325
- const raw = await readFile3(join19(runDir, "trajectory.json"), "utf-8");
46398
+ const raw = await readFile3(join20(runDir, "trajectory.json"), "utf-8");
46326
46399
  const parsed = JSON.parse(raw);
46327
46400
  answer = extractFinalAnswer(parsed);
46328
46401
  modelCalls = extractModelCalls(parsed);
@@ -46455,11 +46528,11 @@ async function runSpawnExecutor(spec, ctx, provision, deps = { spawn: spawn4 })
46455
46528
  } catch (err) {
46456
46529
  throw new WebTaskSpawnError("vault_base_url_missing", err.message);
46457
46530
  }
46458
- const tmpDirRoot = await mkdtemp(join19(tmpdir2(), "olam-web-task-"));
46459
- const modelYamlPath = join19(tmpDirRoot, "model_olam.yaml");
46531
+ const tmpDirRoot = await mkdtemp(join20(tmpdir2(), "olam-web-task-"));
46532
+ const modelYamlPath = join20(tmpDirRoot, "model_olam.yaml");
46460
46533
  await writeFile2(modelYamlPath, modelYaml.yaml, "utf-8");
46461
46534
  try {
46462
- const baseYaml = join19(provision.configDir, "base.yaml");
46535
+ const baseYaml = join20(provision.configDir, "base.yaml");
46463
46536
  const args = [
46464
46537
  "-m",
46465
46538
  "webwright.run.cli",
@@ -46513,10 +46586,10 @@ ${tail}` : ""}`
46513
46586
  );
46514
46587
  }
46515
46588
  const runDir = await locateRunDir(absOutDir);
46516
- const trajectoryPath = join19(runDir, "trajectory.json");
46589
+ const trajectoryPath = join20(runDir, "trajectory.json");
46517
46590
  const screenshots = await collectScreenshots(runDir);
46518
46591
  const facts = await readTrajectoryFacts(runDir, outcome.stdout);
46519
- const scriptPath = existsSync15(join19(runDir, "final_script.py")) ? join19(runDir, "final_script.py") : void 0;
46592
+ const scriptPath = existsSync16(join20(runDir, "final_script.py")) ? join20(runDir, "final_script.py") : void 0;
46520
46593
  return {
46521
46594
  result: facts.answer,
46522
46595
  trajectoryPath,
@@ -50238,8 +50311,14 @@ var toolModules = [
50238
50311
  memory_reinforce_exports,
50239
50312
  cloud_dispatch_exports
50240
50313
  ];
50241
- function registerAllTools(server, ctx, initError) {
50314
+ function registerAllTools(server, ctx, initError, options = {}) {
50242
50315
  const filterContext = getToolFilterContextFromEnv();
50316
+ if (options.showAll) {
50317
+ delete filterContext.deniedTools;
50318
+ } else {
50319
+ const denied = resolveDeniedTools();
50320
+ if (denied.size > 0) filterContext.deniedTools = denied;
50321
+ }
50243
50322
  const { server: filtered, finalize: finalize2 } = withFilteredTools(server, filterContext);
50244
50323
  try {
50245
50324
  for (const mod of toolModules) {
@@ -50596,7 +50675,8 @@ function describeParam(schema) {
50596
50675
  constrained: isConstrained(base)
50597
50676
  };
50598
50677
  }
50599
- function extractToolCatalog() {
50678
+ function extractToolCatalog(opts = {}) {
50679
+ const showAll = opts.showAll ?? true;
50600
50680
  const captured = [];
50601
50681
  const recordingServer = {
50602
50682
  tool(name, description, inputSchema, _handler) {
@@ -50609,7 +50689,12 @@ function extractToolCatalog() {
50609
50689
  captured.push({ name, description: description ?? "", params });
50610
50690
  }
50611
50691
  };
50612
- registerAllTools(recordingServer, void 0, void 0);
50692
+ registerAllTools(
50693
+ recordingServer,
50694
+ void 0,
50695
+ void 0,
50696
+ { showAll }
50697
+ );
50613
50698
  return [...captured].sort((a, b) => a.name.localeCompare(b.name));
50614
50699
  }
50615
50700
 
@@ -50637,7 +50722,7 @@ function buildToolsCatalogPayload(catalog) {
50637
50722
  };
50638
50723
  }
50639
50724
  function createToolsCatalogResource(deps = {}) {
50640
- const extract = deps.extract ?? extractToolCatalog;
50725
+ const extract = deps.extract ?? (() => extractToolCatalog({ showAll: false }));
50641
50726
  let cachedPayload = null;
50642
50727
  return {
50643
50728
  name: "olam-tools",
@@ -52269,8 +52354,8 @@ import * as fs51 from "node:fs";
52269
52354
  import * as path50 from "node:path";
52270
52355
 
52271
52356
  // ../core/dist/kg/storage-paths.js
52272
- import { homedir as homedir26 } from "node:os";
52273
- import { join as join53, resolve as resolve11 } from "node:path";
52357
+ import { homedir as homedir27 } from "node:os";
52358
+ import { join as join54, resolve as resolve11 } from "node:path";
52274
52359
 
52275
52360
  // ../core/dist/world/workspace-name.js
52276
52361
  var InvalidWorkspaceNameError = class extends Error {
@@ -52291,13 +52376,13 @@ function validateWorkspaceName(name) {
52291
52376
 
52292
52377
  // ../core/dist/kg/storage-paths.js
52293
52378
  function olamHome3() {
52294
- return process.env.OLAM_HOME ?? join53(homedir26(), ".olam");
52379
+ return process.env.OLAM_HOME ?? join54(homedir27(), ".olam");
52295
52380
  }
52296
52381
  function kgRoot() {
52297
- return join53(olamHome3(), "kg");
52382
+ return join54(olamHome3(), "kg");
52298
52383
  }
52299
52384
  function worldsRoot() {
52300
- return join53(olamHome3(), "worlds");
52385
+ return join54(olamHome3(), "worlds");
52301
52386
  }
52302
52387
  function assertWithinPrefix(path62, prefix, label) {
52303
52388
  if (!path62.startsWith(prefix + "/")) {
@@ -52307,7 +52392,7 @@ function assertWithinPrefix(path62, prefix, label) {
52307
52392
  function kgPristinePath(workspace) {
52308
52393
  validateWorkspaceName(workspace);
52309
52394
  const root = kgRoot();
52310
- const path62 = resolve11(join53(root, workspace));
52395
+ const path62 = resolve11(join54(root, workspace));
52311
52396
  assertWithinPrefix(path62, root, "kgPristinePath");
52312
52397
  return path62;
52313
52398
  }
@@ -52408,8 +52493,8 @@ import * as fs52 from "node:fs";
52408
52493
  import * as os26 from "node:os";
52409
52494
  import * as path51 from "node:path";
52410
52495
  var DEFAULT_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
52411
- function expandHome2(p, homedir33) {
52412
- return p.replace(/^~(?=$|\/|\\)/, homedir33());
52496
+ function expandHome2(p, homedir34) {
52497
+ return p.replace(/^~(?=$|\/|\\)/, homedir34());
52413
52498
  }
52414
52499
  function sanitizeRepoFilename(name) {
52415
52500
  const sanitized = name.replace(/[^A-Za-z0-9._-]/g, "_");
@@ -52432,7 +52517,7 @@ ${stderr}`;
52432
52517
  }
52433
52518
  function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
52434
52519
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync7(cmd, args, opts));
52435
- const homedir33 = deps.homedir ?? (() => os26.homedir());
52520
+ const homedir34 = deps.homedir ?? (() => os26.homedir());
52436
52521
  const baselineDir = path51.join(workspacePath, ".olam", "baseline");
52437
52522
  try {
52438
52523
  fs52.mkdirSync(baselineDir, { recursive: true });
@@ -52448,7 +52533,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
52448
52533
  continue;
52449
52534
  const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
52450
52535
  const outPath = path51.join(baselineDir, filename);
52451
- const repoPath = expandHome2(repo.path, homedir33);
52536
+ const repoPath = expandHome2(repo.path, homedir34);
52452
52537
  if (!fs52.existsSync(repoPath)) {
52453
52538
  writeBaselineFile(outPath, `# repo: ${repo.name}
52454
52539
  # (skipped: path ${repoPath} does not exist)
@@ -52584,8 +52669,8 @@ function extractStderr(err) {
52584
52669
  }
52585
52670
  function carryUncommittedEdits(repos, workspacePath, deps = {}) {
52586
52671
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync7(cmd, args, opts));
52587
- const homedir33 = deps.homedir ?? (() => os26.homedir());
52588
- const existsSync61 = deps.existsSync ?? ((p) => fs52.existsSync(p));
52672
+ const homedir34 = deps.homedir ?? (() => os26.homedir());
52673
+ const existsSync62 = deps.existsSync ?? ((p) => fs52.existsSync(p));
52589
52674
  const copyFileSync10 = deps.copyFileSync ?? ((src, dest) => fs52.copyFileSync(src, dest));
52590
52675
  const mkdirSync34 = deps.mkdirSync ?? ((dirPath, opts) => {
52591
52676
  fs52.mkdirSync(dirPath, opts);
@@ -52594,11 +52679,11 @@ function carryUncommittedEdits(repos, workspacePath, deps = {}) {
52594
52679
  for (const repo of repos) {
52595
52680
  if (!repo.path)
52596
52681
  continue;
52597
- const repoPath = expandHome2(repo.path, homedir33);
52682
+ const repoPath = expandHome2(repo.path, homedir34);
52598
52683
  const worktreePath = path51.join(workspacePath, repo.name);
52599
- if (!existsSync61(repoPath))
52684
+ if (!existsSync62(repoPath))
52600
52685
  continue;
52601
- if (!existsSync61(worktreePath)) {
52686
+ if (!existsSync62(worktreePath)) {
52602
52687
  console.warn(`[carry] ${repo.name}: world worktree ${worktreePath} missing; skipping carry for this repo`);
52603
52688
  continue;
52604
52689
  }
@@ -52658,7 +52743,7 @@ function carryUncommittedEdits(repos, workspacePath, deps = {}) {
52658
52743
  for (const rel of plan.diff.untracked) {
52659
52744
  const src = path51.join(plan.repoPath, rel);
52660
52745
  const dest = path51.join(plan.worktreePath, rel);
52661
- if (!existsSync61(src))
52746
+ if (!existsSync62(src))
52662
52747
  continue;
52663
52748
  try {
52664
52749
  mkdirSync34(path51.dirname(dest), { recursive: true });
@@ -53917,14 +54002,14 @@ function enrichReposWithManifests(repos, workspacePath) {
53917
54002
  // ../core/dist/policies/loader.js
53918
54003
  import * as fs55 from "node:fs";
53919
54004
  import * as path55 from "node:path";
53920
- import { parse as parseYaml5 } from "yaml";
54005
+ import { parse as parseYaml6 } from "yaml";
53921
54006
  function parseFrontmatter2(content) {
53922
54007
  const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/m.exec(content);
53923
54008
  if (!match)
53924
54009
  return null;
53925
54010
  const [, yamlText = "", body = ""] = match;
53926
54011
  try {
53927
- const frontmatter = parseYaml5(yamlText);
54012
+ const frontmatter = parseYaml6(yamlText);
53928
54013
  return { frontmatter, body };
53929
54014
  } catch {
53930
54015
  return null;
@@ -57385,8 +57470,8 @@ var PleriClient = class {
57385
57470
  };
57386
57471
 
57387
57472
  // ../mcp-server/src/env-loader.ts
57388
- import { readFileSync as readFileSync47, existsSync as existsSync60, statSync as statSync16 } from "node:fs";
57389
- import { join as join65, dirname as dirname31, resolve as resolve15 } from "node:path";
57473
+ import { readFileSync as readFileSync48, existsSync as existsSync61, statSync as statSync16 } from "node:fs";
57474
+ import { join as join66, dirname as dirname31, resolve as resolve15 } from "node:path";
57390
57475
  var PROJECT_MARKERS = [
57391
57476
  ".olam/config.yaml",
57392
57477
  ".olam/config.yml",
@@ -57398,12 +57483,12 @@ function findProjectRoot2(startDir) {
57398
57483
  const root = resolve15("/");
57399
57484
  while (true) {
57400
57485
  for (const marker of PROJECT_MARKERS) {
57401
- if (existsSync60(join65(dir, marker))) return dir;
57486
+ if (existsSync61(join66(dir, marker))) return dir;
57402
57487
  }
57403
- const pkg = join65(dir, "package.json");
57404
- if (existsSync60(pkg)) {
57488
+ const pkg = join66(dir, "package.json");
57489
+ if (existsSync61(pkg)) {
57405
57490
  try {
57406
- const json2 = JSON.parse(readFileSync47(pkg, "utf8"));
57491
+ const json2 = JSON.parse(readFileSync48(pkg, "utf8"));
57407
57492
  const isOlamWorkspace = typeof json2.name === "string" && json2.name.startsWith("@olam/");
57408
57493
  const hasOlamDep = json2.dependencies && Object.keys(json2.dependencies).some((k) => k.startsWith("@olam/")) || json2.devDependencies && Object.keys(json2.devDependencies).some((k) => k.startsWith("@olam/"));
57409
57494
  if (isOlamWorkspace || hasOlamDep) return dir;
@@ -57417,7 +57502,7 @@ function findProjectRoot2(startDir) {
57417
57502
  }
57418
57503
  function parseEnvFile(path62) {
57419
57504
  const out = {};
57420
- const raw = readFileSync47(path62, "utf8");
57505
+ const raw = readFileSync48(path62, "utf8");
57421
57506
  for (const line of raw.split(/\r?\n/)) {
57422
57507
  const trimmed = line.trim();
57423
57508
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -57440,8 +57525,8 @@ function loadProjectEnv(startDir = process.cwd()) {
57440
57525
  const filesRead = [];
57441
57526
  const merged = {};
57442
57527
  for (const name of [".env", ".env.local"]) {
57443
- const p = join65(root, name);
57444
- if (existsSync60(p) && statSync16(p).isFile()) {
57528
+ const p = join66(root, name);
57529
+ if (existsSync61(p) && statSync16(p).isFile()) {
57445
57530
  Object.assign(merged, parseEnvFile(p));
57446
57531
  filesRead.push(p);
57447
57532
  }
@@ -1,4 +1,4 @@
1
1
  {
2
- "bundledAt": "2026-06-03T07:06:37.421Z",
2
+ "bundledAt": "2026-06-03T07:50:57.230Z",
3
3
  "kgFirstSha": "29a9ccce1b115d049e375c4a90eb5cf7c123e610e2d0590270a4db2cdbc64a28"
4
4
  }
@@ -118,7 +118,7 @@ spec:
118
118
  # k3d), started by `olam upgrade` Step 0.7 — not inside this Pod.
119
119
  containers:
120
120
  - name: olam-host-cp
121
- image: ghcr.io/pleri/olam-host-cp@sha256:5d8726cbe667359e64d2abe53150c80c870a2d71960c2f41833a3c8719abee12
121
+ image: ghcr.io/pleri/olam-host-cp@sha256:1818b62ee1475cf42f8d55c3ba3cbda9c27b799dc99abcff6c63f02d54574893
122
122
  imagePullPolicy: IfNotPresent
123
123
  securityContext:
124
124
  runAsNonRoot: true
@@ -70,7 +70,7 @@ spec:
70
70
  mountPath: /data
71
71
  containers:
72
72
  - name: olam-auth-service
73
- image: ghcr.io/pleri/olam-auth@sha256:90c00c3d75cc697539a0d6663fdf30d67fac787171ff1c53a3c1fa1755fcecb3
73
+ image: ghcr.io/pleri/olam-auth@sha256:7a206b619cd92d39b2550a09e270e9999a6c0b1a70e391e72b46c2cfbbf0be9c
74
74
  imagePullPolicy: IfNotPresent
75
75
  securityContext:
76
76
  runAsNonRoot: true
@@ -61,7 +61,7 @@ spec:
61
61
  mountPath: /data
62
62
  containers:
63
63
  - name: olam-kg-service
64
- image: ghcr.io/pleri/olam-kg-service@sha256:829de080754fe0728b0c0368b6083a6679baff33745dd81c68fadc4ccea7bf7d
64
+ image: ghcr.io/pleri/olam-kg-service@sha256:b74d2099752a0299317c95feab19893764a291db375c4ce0fd96d06691defb9f
65
65
  imagePullPolicy: IfNotPresent
66
66
  securityContext:
67
67
  runAsNonRoot: true
@@ -68,7 +68,7 @@ spec:
68
68
  mountPath: /data
69
69
  containers:
70
70
  - name: olam-mcp-auth-service
71
- image: ghcr.io/pleri/olam-mcp-auth@sha256:c7041e093e23acdad36eb2a611e66e925061b79e41a5b8a3be28bba57d6624c5
71
+ image: ghcr.io/pleri/olam-mcp-auth@sha256:9e1b11d9a67005a1a3c65f63b5c4c94d311a35f6b424e576d63bba82290f86cf
72
72
  imagePullPolicy: IfNotPresent
73
73
  securityContext:
74
74
  runAsNonRoot: true
@@ -70,7 +70,7 @@ spec:
70
70
  # bootstrap-placeholder comment + run `npm run refresh:manifest-digests`
71
71
  # once ghcr.io/pleri/olam-memory-service has a real published digest.
72
72
  # bootstrap-placeholder: pre-publish; refresh after first release
73
- image: ghcr.io/pleri/olam-memory-service@sha256:2b40d835b807fa49316a9db0215ee4ac6b36e2403c8170cfb4a70067115ad292
73
+ image: ghcr.io/pleri/olam-memory-service@sha256:847d97e6970158f5037821c5664836a1781949750ce69caab08128e1c9c6a157
74
74
  imagePullPolicy: IfNotPresent
75
75
  securityContext:
76
76
  runAsNonRoot: true
@@ -3308,8 +3308,14 @@ const server = http.createServer(instrumentHandler('host-cp', async (req, res) =
3308
3308
  // binding hops (plan-DO) because those bypass the CF Access edge; a CF
3309
3309
  // Access app in front of plan-DO would still not receive service-binding
3310
3310
  // traffic. See docs/runbooks/cf-access-service-token.md.
3311
+ // Phase B (cloud-plan-execute-split): a `mode: 'plan'` dispatch routes to
3312
+ // plan-DO's /v1/plan endpoint (the light Sandbox pool, no-push planning
3313
+ // role) instead of /v1/dispatch (the execute/world path). Any other value
3314
+ // (incl. absent) keeps the existing /v1/dispatch route — zero behaviour
3315
+ // change for execute dispatches. The SPA opts in by setting body.mode.
3316
+ const dispatchPath = parsed.mode === 'plan' ? '/v1/plan' : '/v1/dispatch';
3311
3317
  const upstream = await fetch(
3312
- `${cloudUrl.replace(/\/+$/, '')}/v1/dispatch?plan_id=${encodeURIComponent(planId)}`,
3318
+ `${cloudUrl.replace(/\/+$/, '')}${dispatchPath}?plan_id=${encodeURIComponent(planId)}`,
3313
3319
  {
3314
3320
  method: 'POST',
3315
3321
  headers: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pleri/olam-cli",
3
- "version": "0.1.210",
3
+ "version": "0.1.212",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "olam": "./bin/olam.cjs"