@intentius/behold 0.29.15 → 0.29.17

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/cli.js CHANGED
@@ -9291,8 +9291,8 @@ __export(tree_exports, {
9291
9291
  workingTree: () => workingTree
9292
9292
  });
9293
9293
  import { execFileSync as execFileSync2 } from "node:child_process";
9294
- import { readdirSync as readdirSync11, readFileSync as readFileSync21, statSync as statSync9 } from "node:fs";
9295
- import { join as join28 } from "node:path";
9294
+ import { readdirSync as readdirSync12, readFileSync as readFileSync22, statSync as statSync9 } from "node:fs";
9295
+ import { join as join29 } from "node:path";
9296
9296
  function joinPath(...parts) {
9297
9297
  return parts.filter((p) => p !== "" && p !== ".").join("/");
9298
9298
  }
@@ -9301,7 +9301,7 @@ function workingTree(root) {
9301
9301
  label: "",
9302
9302
  stat(path) {
9303
9303
  try {
9304
- const s = statSync9(join28(root, path));
9304
+ const s = statSync9(join29(root, path));
9305
9305
  return s.isDirectory() ? "dir" : s.isFile() ? "file" : void 0;
9306
9306
  } catch {
9307
9307
  return void 0;
@@ -9310,7 +9310,7 @@ function workingTree(root) {
9310
9310
  list(path) {
9311
9311
  let dirents;
9312
9312
  try {
9313
- dirents = readdirSync11(join28(root, path), { withFileTypes: true });
9313
+ dirents = readdirSync12(join29(root, path), { withFileTypes: true });
9314
9314
  } catch {
9315
9315
  return void 0;
9316
9316
  }
@@ -9319,7 +9319,7 @@ function workingTree(root) {
9319
9319
  let type = d.isDirectory() ? "dir" : d.isFile() ? "file" : void 0;
9320
9320
  if (!type && d.isSymbolicLink()) {
9321
9321
  try {
9322
- const s = statSync9(join28(root, path, d.name));
9322
+ const s = statSync9(join29(root, path, d.name));
9323
9323
  type = s.isDirectory() ? "dir" : s.isFile() ? "file" : void 0;
9324
9324
  } catch {
9325
9325
  }
@@ -9329,10 +9329,10 @@ function workingTree(root) {
9329
9329
  return out;
9330
9330
  },
9331
9331
  read(path) {
9332
- return readFileSync21(join28(root, path), "utf-8");
9332
+ return readFileSync22(join29(root, path), "utf-8");
9333
9333
  },
9334
9334
  bytes(path) {
9335
- return readFileSync21(join28(root, path));
9335
+ return readFileSync22(join29(root, path));
9336
9336
  }
9337
9337
  };
9338
9338
  }
@@ -9934,12 +9934,12 @@ var init_identity_gate_rule = __esm({
9934
9934
  });
9935
9935
 
9936
9936
  // node_modules/@intentius/chant/src/workspace/class-data.ts
9937
- import { existsSync as existsSync18, readFileSync as readFileSync22, statSync as statSync10 } from "node:fs";
9938
- import { dirname as dirname7, join as join29, posix as posix2, resolve as resolve15 } from "node:path";
9937
+ import { existsSync as existsSync19, readFileSync as readFileSync23, statSync as statSync10 } from "node:fs";
9938
+ import { dirname as dirname7, join as join30, posix as posix2, resolve as resolve15 } from "node:path";
9939
9939
  function diskFiles(dir) {
9940
9940
  return (path) => {
9941
9941
  try {
9942
- return readFileSync22(join29(dir, ...path.split("/")), "utf-8");
9942
+ return readFileSync23(join30(dir, ...path.split("/")), "utf-8");
9943
9943
  } catch {
9944
9944
  return void 0;
9945
9945
  }
@@ -9947,9 +9947,9 @@ function diskFiles(dir) {
9947
9947
  }
9948
9948
  function findInstalledPackage(name, fromDir) {
9949
9949
  for (let dir = resolve15(fromDir); ; dir = dirname7(dir)) {
9950
- const candidate = join29(dir, "node_modules", ...name.split("/"));
9950
+ const candidate = join30(dir, "node_modules", ...name.split("/"));
9951
9951
  try {
9952
- if (statSync10(candidate).isDirectory() && existsSync18(join29(candidate, "package.json"))) return candidate;
9952
+ if (statSync10(candidate).isDirectory() && existsSync19(join30(candidate, "package.json"))) return candidate;
9953
9953
  } catch {
9954
9954
  }
9955
9955
  if (dirname7(dir) === dir) return void 0;
@@ -10399,10 +10399,10 @@ var init_jsonc = __esm({
10399
10399
  });
10400
10400
 
10401
10401
  // node_modules/@intentius/chant/src/package-version.ts
10402
- import { readFileSync as readFileSync23 } from "node:fs";
10402
+ import { readFileSync as readFileSync24 } from "node:fs";
10403
10403
  import { fileURLToPath as fileURLToPath4 } from "node:url";
10404
10404
  function readChantPackageVersion() {
10405
- return JSON.parse(readFileSync23(fileURLToPath4(new URL("../package.json", import.meta.url)), "utf-8")).version;
10405
+ return JSON.parse(readFileSync24(fileURLToPath4(new URL("../package.json", import.meta.url)), "utf-8")).version;
10406
10406
  }
10407
10407
  var init_package_version = __esm({
10408
10408
  "node_modules/@intentius/chant/src/package-version.ts"() {
@@ -11201,8 +11201,8 @@ var init_declaration = __esm({
11201
11201
  });
11202
11202
 
11203
11203
  // src/cli.ts
11204
- import { resolve as resolve35, dirname as dirname21, join as join53 } from "node:path";
11205
- import { realpathSync as realpathSync3, existsSync as existsSync32, readFileSync as readFileSync41, rmSync as rmSync4 } from "node:fs";
11204
+ import { resolve as resolve35, dirname as dirname21, join as join54 } from "node:path";
11205
+ import { realpathSync as realpathSync3, existsSync as existsSync33, readFileSync as readFileSync42, rmSync as rmSync4 } from "node:fs";
11206
11206
  import { fileURLToPath as fileURLToPath12 } from "node:url";
11207
11207
  import { spawn as spawn9, spawnSync as spawnSync4 } from "node:child_process";
11208
11208
 
@@ -11260,8 +11260,8 @@ import { serve } from "@hono/node-server";
11260
11260
  import { fileURLToPath as fileURLToPath10 } from "node:url";
11261
11261
  import { execFile as execFile5 } from "node:child_process";
11262
11262
  import { promisify as promisify3 } from "node:util";
11263
- import { existsSync as existsSync29, readFileSync as readFileSync37 } from "node:fs";
11264
- import { basename as basename5, dirname as dirname18, join as join49, relative as relative11, resolve as resolve32, sep as sep10 } from "node:path";
11263
+ import { existsSync as existsSync30, readFileSync as readFileSync38 } from "node:fs";
11264
+ import { basename as basename5, dirname as dirname18, join as join50, relative as relative11, resolve as resolve32, sep as sep10 } from "node:path";
11265
11265
 
11266
11266
  // src/recents.ts
11267
11267
  import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
@@ -13667,10 +13667,10 @@ function joinNamespaceBindings(members, isDir = realIsDir) {
13667
13667
  if (!winner || tied) continue;
13668
13668
  const prev = best.get(winner.dir);
13669
13669
  if (prev === "ambiguous") continue;
13670
- const join54 = { dir: winner.dir, namespace: b.namespace, path: b.path, declaredBy: b.declaredBy };
13671
- if (!prev) best.set(winner.dir, { score: winner.score, join: join54 });
13670
+ const join55 = { dir: winner.dir, namespace: b.namespace, path: b.path, declaredBy: b.declaredBy };
13671
+ if (!prev) best.set(winner.dir, { score: winner.score, join: join55 });
13672
13672
  else if (prev.join.namespace !== b.namespace) best.set(winner.dir, "ambiguous");
13673
- else if (winner.score > prev.score) best.set(winner.dir, { score: winner.score, join: join54 });
13673
+ else if (winner.score > prev.score) best.set(winner.dir, { score: winner.score, join: join55 });
13674
13674
  }
13675
13675
  return [...best.values()].filter((v) => v !== "ambiguous").map((v) => v.join);
13676
13676
  }
@@ -15149,6 +15149,135 @@ function resourcesByRoot(ir, rootOf2) {
15149
15149
  return byComponent;
15150
15150
  }
15151
15151
 
15152
+ // src/pipeline-marks.ts
15153
+ init_yaml();
15154
+ init_terragrunt_units();
15155
+ import { existsSync as existsSync11, readdirSync as readdirSync9, readFileSync as readFileSync12 } from "node:fs";
15156
+ import { extname, join as join17 } from "node:path";
15157
+ var PIPELINE_FORGES = ["forgejo", "github", "gitlab"];
15158
+ var WORKFLOW_PLACES = [
15159
+ ["forgejo", ".forgejo/workflows"],
15160
+ ["github", ".github/workflows"],
15161
+ ["gitlab", ".gitlab-ci.yml"]
15162
+ ];
15163
+ function forgeOfName(name) {
15164
+ const s = typeof name === "string" ? name.trim().toLowerCase() : "";
15165
+ return PIPELINE_FORGES.find((f) => s === f || s.startsWith(`${f} `) || s.startsWith(`${f}-`));
15166
+ }
15167
+ function forgeOfPipelinePath(path) {
15168
+ const p = path.replace(/\\/g, "/").replace(/^\.\/+/, "");
15169
+ if (/(^|\/)\.forgejo\/workflows(\/|$)/.test(p)) return "forgejo";
15170
+ if (/(^|\/)\.github\/workflows(\/|$)/.test(p)) return "github";
15171
+ if (/(^|\/)\.gitlab-ci\.ya?ml$/.test(p)) return "gitlab";
15172
+ return void 0;
15173
+ }
15174
+ function toolOfBinary(binary) {
15175
+ const b = typeof binary === "string" ? binary.trim().toLowerCase().split("/").pop() ?? "" : "";
15176
+ if (b === "tofu" || b === "opentofu") return "opentofu";
15177
+ if (b === "terraform") return "terraform";
15178
+ if (b === "choudoufu") return "choudoufu";
15179
+ return void 0;
15180
+ }
15181
+ function configKeys(file) {
15182
+ if (!file) return {};
15183
+ let text2;
15184
+ try {
15185
+ text2 = readFileSync12(file, "utf8");
15186
+ } catch {
15187
+ return {};
15188
+ }
15189
+ if (extname(file) === ".ts") {
15190
+ const pick = (k) => new RegExp(`(^|[\\s,{])${k}\\s*:\\s*["']([^"']+)["']`).exec(text2)?.[2];
15191
+ const out = {};
15192
+ const forge = pick("forge");
15193
+ const binary = pick("binary");
15194
+ if (forge) out.forge = forge;
15195
+ if (binary) out.binary = binary;
15196
+ return out;
15197
+ }
15198
+ let doc;
15199
+ try {
15200
+ doc = parseYAMLDocument(text2);
15201
+ } catch {
15202
+ return {};
15203
+ }
15204
+ if (!doc || typeof doc !== "object" || Array.isArray(doc)) return {};
15205
+ const d = doc;
15206
+ return {
15207
+ ...typeof d.forge === "string" ? { forge: d.forge } : {},
15208
+ ...typeof d.binary === "string" ? { binary: d.binary } : {}
15209
+ };
15210
+ }
15211
+ function pipelineForge(decl, dir, config) {
15212
+ const declared = forgeOfName(decl?.pipeline.forge);
15213
+ if (declared) return { forge: declared, from: "declared" };
15214
+ const configured = forgeOfName(configKeys(config).forge);
15215
+ if (configured) return { forge: configured, from: "config" };
15216
+ const byPath = decl?.pipeline.path ? forgeOfPipelinePath(decl.pipeline.path) : void 0;
15217
+ if (byPath) return { forge: byPath, from: "pipeline-path" };
15218
+ const present2 = WORKFLOW_PLACES.filter(([, p]) => existsSync11(join17(dir, p))).map(([f]) => f);
15219
+ return present2.length === 1 ? { forge: present2[0], from: "workflow-dir" } : void 0;
15220
+ }
15221
+ function chantWorkspaceWithMembers(dir) {
15222
+ try {
15223
+ const doc = JSON.parse(readFileSync12(join17(dir, "chant.workspace.json"), "utf8"));
15224
+ return Array.isArray(doc.members) && doc.members.length > 0;
15225
+ } catch {
15226
+ return false;
15227
+ }
15228
+ }
15229
+ function atmosRepo(dir) {
15230
+ if (existsSync11(join17(dir, "atmos.yaml")) || existsSync11(join17(dir, "atmos.yml"))) return true;
15231
+ return existsSync11(join17(dir, "stacks")) && existsSync11(join17(dir, "components", "terraform"));
15232
+ }
15233
+ function sqlYodelerRepo(dir) {
15234
+ if (existsSync11(join17(dir, "yodel.config.ts"))) return true;
15235
+ if (!existsSync11(join17(dir, "migrations"))) return false;
15236
+ try {
15237
+ const pkg = JSON.parse(readFileSync12(join17(dir, "package.json"), "utf8"));
15238
+ return ["dependencies", "devDependencies"].some((k) => !!pkg[k]?.["@intentius/sql-yodeler"]);
15239
+ } catch {
15240
+ return false;
15241
+ }
15242
+ }
15243
+ function repoTools(dir, config, has = {}) {
15244
+ const out = [];
15245
+ if ((has.terragrunt ?? hasTerragruntUnits)(dir)) out.push("terragrunt");
15246
+ else if (existsSync11(join17(dir, "cdktf.json")) || existsSync11(join17(dir, "cdktn.json"))) out.push("cdk-terrain");
15247
+ else if (atmosRepo(dir)) out.push("atmos");
15248
+ else if (chantWorkspaceWithMembers(dir)) out.push("chant");
15249
+ if (sqlYodelerRepo(dir)) out.push("sql-yodeler");
15250
+ const engine = toolOfBinary(configKeys(config).binary);
15251
+ if (engine) out.push(engine);
15252
+ return out;
15253
+ }
15254
+ function sqlYodelerProjectIn(dir) {
15255
+ if (existsSync11(join17(dir, "yodel.config.ts")) || existsSync11(join17(dir, "yodel-waves.json"))) return true;
15256
+ return existsSync11(join17(dir, "migrations")) && (existsSync11(join17(dir, "chant.config.ts")) || sqlYodelerRepo(dir));
15257
+ }
15258
+ var SKIP_DIRS4 = /* @__PURE__ */ new Set(["node_modules", ".terraform", ".terragrunt-cache", ".git"]);
15259
+ function rootTools(repo, rootDir) {
15260
+ const top = join17(repo, rootDir);
15261
+ const dirs = [top];
15262
+ const kids = (d) => {
15263
+ try {
15264
+ return readdirSync9(d, { withFileTypes: true }).filter((e) => e.isDirectory() && !SKIP_DIRS4.has(e.name) && e.name !== "migrations").map((e) => join17(d, e.name));
15265
+ } catch {
15266
+ return [];
15267
+ }
15268
+ };
15269
+ for (const k of kids(top)) dirs.push(k, ...kids(k));
15270
+ return dirs.some(sqlYodelerProjectIn) ? ["sql-yodeler"] : [];
15271
+ }
15272
+ function declaredRootTools(repo, roots) {
15273
+ const out = {};
15274
+ for (const [name, r] of Object.entries(roots)) {
15275
+ const tools = rootTools(repo, r.dir.replace(/^\.\/+/, "").replace(/\/+$/, "") || ".");
15276
+ if (tools.length) out[name] = tools;
15277
+ }
15278
+ return out;
15279
+ }
15280
+
15152
15281
  // src/server.ts
15153
15282
  init_terragucci_components();
15154
15283
  init_terragrunt_units();
@@ -15238,10 +15367,10 @@ import {
15238
15367
  } from "@intentius/pinhole";
15239
15368
 
15240
15369
  // src/icon-packs.ts
15241
- import { readFileSync as readFileSync12 } from "node:fs";
15242
- import { dirname as dirname5, join as join17 } from "node:path";
15370
+ import { readFileSync as readFileSync13 } from "node:fs";
15371
+ import { dirname as dirname5, join as join18 } from "node:path";
15243
15372
  import { fileURLToPath as fileURLToPath3 } from "node:url";
15244
- var ICON_ROOT = join17(dirname5(fileURLToPath3(import.meta.url)), "..", "web", "icons");
15373
+ var ICON_ROOT = join18(dirname5(fileURLToPath3(import.meta.url)), "..", "web", "icons");
15245
15374
  var cache4 = /* @__PURE__ */ new Map();
15246
15375
  function unprefix(body) {
15247
15376
  return body.replace(/\s(?:inkscape|sodipodi):[\w-]+\s*=\s*(["'])[\s\S]*?\1/g, "").replace(/\sxlink:href\s*=/g, " href=");
@@ -15263,7 +15392,7 @@ function plate(glyph) {
15263
15392
  function loadIcon(rel) {
15264
15393
  const hit = cache4.get(rel);
15265
15394
  if (hit) return hit;
15266
- const raw = readFileSync12(join17(ICON_ROOT, `${rel}.svg`), "utf8");
15395
+ const raw = readFileSync13(join18(ICON_ROOT, `${rel}.svg`), "utf8");
15267
15396
  const open = raw.indexOf("<svg");
15268
15397
  const openEnd = raw.indexOf(">", open);
15269
15398
  const close = raw.lastIndexOf("</svg");
@@ -17398,12 +17527,12 @@ init_carve_manifest();
17398
17527
 
17399
17528
  // src/carve-actions.ts
17400
17529
  init_chant();
17401
- import { existsSync as existsSync13, mkdirSync as mkdirSync5, readFileSync as readFileSync15, readdirSync as readdirSync9, statSync as statSync7 } from "node:fs";
17402
- import { isAbsolute as isAbsolute3, join as join20, relative as relative5, resolve as resolve12, sep as sep6 } from "node:path";
17530
+ import { existsSync as existsSync14, mkdirSync as mkdirSync5, readFileSync as readFileSync16, readdirSync as readdirSync10, statSync as statSync7 } from "node:fs";
17531
+ import { isAbsolute as isAbsolute3, join as join21, relative as relative5, resolve as resolve12, sep as sep6 } from "node:path";
17403
17532
 
17404
17533
  // src/layout.ts
17405
- import { existsSync as existsSync11, mkdirSync as mkdirSync4, readFileSync as readFileSync13, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync4, accessSync, constants } from "node:fs";
17406
- import { join as join18 } from "node:path";
17534
+ import { existsSync as existsSync12, mkdirSync as mkdirSync4, readFileSync as readFileSync14, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync4, accessSync, constants } from "node:fs";
17535
+ import { join as join19 } from "node:path";
17407
17536
  var LAYOUT_DIR = ".behold";
17408
17537
  var LAYOUT_FILE = "layout.json";
17409
17538
  var MAX_BODY_BYTES = 64 * 1024;
@@ -17444,10 +17573,10 @@ function lensFromQuery(params) {
17444
17573
  return [slug2(zoom), params.get("radial") === "1" ? "radial" : null, stack ? slug2(`stack-${stack}`) : null].filter(Boolean).join("+");
17445
17574
  }
17446
17575
  function layoutPath(projectDir) {
17447
- return join18(projectDir, LAYOUT_DIR, LAYOUT_FILE);
17576
+ return join19(projectDir, LAYOUT_DIR, LAYOUT_FILE);
17448
17577
  }
17449
17578
  function unwritableReason(projectDir) {
17450
- if (!projectDir || !existsSync11(projectDir)) return `no such project directory: ${projectDir || "(none)"}`;
17579
+ if (!projectDir || !existsSync12(projectDir)) return `no such project directory: ${projectDir || "(none)"}`;
17451
17580
  try {
17452
17581
  accessSync(projectDir, constants.W_OK);
17453
17582
  } catch {
@@ -17459,8 +17588,8 @@ function readLayoutFile(projectDir) {
17459
17588
  const empty = { version: 1, lenses: {} };
17460
17589
  const file = layoutPath(projectDir);
17461
17590
  try {
17462
- if (!existsSync11(file)) return empty;
17463
- const raw = readFileSync13(file, "utf8");
17591
+ if (!existsSync12(file)) return empty;
17592
+ const raw = readFileSync14(file, "utf8");
17464
17593
  if (raw.length > MAX_FILE_BYTES) return empty;
17465
17594
  const parsed = JSON.parse(raw);
17466
17595
  if (!parsed || typeof parsed !== "object" || !parsed.lenses || typeof parsed.lenses !== "object") return empty;
@@ -17500,7 +17629,7 @@ function writeLens(projectDir, lens, deltas) {
17500
17629
  }
17501
17630
  const body = JSON.stringify({ version: 1, lenses }, null, 2) + "\n";
17502
17631
  if (body.length > MAX_FILE_BYTES) throw new LayoutTooLarge(`a layout sidecar is capped at ${MAX_FILE_BYTES} bytes`);
17503
- mkdirSync4(join18(projectDir, LAYOUT_DIR), { recursive: true });
17632
+ mkdirSync4(join19(projectDir, LAYOUT_DIR), { recursive: true });
17504
17633
  const tmp = `${file}.tmp`;
17505
17634
  writeFileSync4(tmp, body, "utf8");
17506
17635
  renameSync(tmp, file);
@@ -17586,8 +17715,8 @@ function reanchorEdges(svg, moved) {
17586
17715
  // src/carve-live.ts
17587
17716
  init_scratch();
17588
17717
  import { spawn as spawn4 } from "node:child_process";
17589
- import { readFileSync as readFileSync14, writeFileSync as writeFileSync5, existsSync as existsSync12 } from "node:fs";
17590
- import { join as join19 } from "node:path";
17718
+ import { readFileSync as readFileSync15, writeFileSync as writeFileSync5, existsSync as existsSync13 } from "node:fs";
17719
+ import { join as join20 } from "node:path";
17591
17720
  var LIVE_CONTAINER = "behold-carve-floci";
17592
17721
  var LIVE_PORT = 4602;
17593
17722
  var LIVE_IMAGE = "floci/floci:1.5.34";
@@ -17647,9 +17776,9 @@ async function teardownScratchFloci() {
17647
17776
  await capture("docker", ["rm", "-f", LIVE_CONTAINER], process.cwd()).catch(() => void 0);
17648
17777
  }
17649
17778
  async function applyIntoFloci(fromDir, step) {
17650
- const template = join19(fromDir, "floci-override.tf.disabled");
17651
- if (!existsSync12(template)) return `no floci-override.tf.disabled in ${fromDir} \u2014 this estate wasn't authored for the live tier`;
17652
- writeFileSync5(join19(fromDir, "floci_override.tf"), armOverride(readFileSync14(template, "utf8"), LIVE_PORT));
17779
+ const template = join20(fromDir, "floci-override.tf.disabled");
17780
+ if (!existsSync13(template)) return `no floci-override.tf.disabled in ${fromDir} \u2014 this estate wasn't authored for the live tier`;
17781
+ writeFileSync5(join20(fromDir, "floci_override.tf"), armOverride(readFileSync15(template, "utf8"), LIVE_PORT));
17653
17782
  const init = await step("terraform", ["init", "-input=false", "-no-color"], fromDir);
17654
17783
  if (init !== 0) return `terraform init exited ${init} (provider downloads need network)`;
17655
17784
  const apply = await step(
@@ -17699,7 +17828,7 @@ async function runCarveObserve(demo, select) {
17699
17828
  "run `behold demo carve --live` (needs docker + terraform)"
17700
17829
  );
17701
17830
  }
17702
- if (!existsSync13(join20(demo.out, "src"))) {
17831
+ if (!existsSync14(join21(demo.out, "src"))) {
17703
17832
  return refuse6("carve-action", "nothing has been emitted yet", "run Emit first \u2014 observe reads the carveout emit writes");
17704
17833
  }
17705
17834
  const args = ["lifecycle", "diff", "prod", "--live", "--json"];
@@ -17780,7 +17909,7 @@ function carveWriteBlock(demo) {
17780
17909
  if (!demo) {
17781
17910
  return "this server isn't running a carve demo \u2014 the carve actions only exist inside a `behold demo carve` copy";
17782
17911
  }
17783
- if (!existsSync13(demo.from)) return `the demo copy has no Terraform estate at ${demo.from}`;
17912
+ if (!existsSync14(demo.from)) return `the demo copy has no Terraform estate at ${demo.from}`;
17784
17913
  if (!insideDemo(demo.root, demo.out)) return "the carve output directory is outside the demo copy";
17785
17914
  return unwritableReason(demo.root);
17786
17915
  }
@@ -17790,14 +17919,14 @@ function readArtifacts(demo, dir, filter) {
17790
17919
  if (out.length >= MAX_ARTIFACTS || depth > 2) return;
17791
17920
  let entries;
17792
17921
  try {
17793
- entries = readdirSync9(d).sort();
17922
+ entries = readdirSync10(d).sort();
17794
17923
  } catch {
17795
17924
  return;
17796
17925
  }
17797
17926
  for (const name of entries) {
17798
17927
  if (out.length >= MAX_ARTIFACTS) return;
17799
17928
  if (name === "node_modules" || name.startsWith(".")) continue;
17800
- const full = join20(d, name);
17929
+ const full = join21(d, name);
17801
17930
  let st;
17802
17931
  try {
17803
17932
  st = statSync7(full);
@@ -17812,7 +17941,7 @@ function readArtifacts(demo, dir, filter) {
17812
17941
  if (!filter(rel)) continue;
17813
17942
  let text2 = "";
17814
17943
  try {
17815
- text2 = readFileSync15(full, "utf8");
17944
+ text2 = readFileSync16(full, "utf8");
17816
17945
  } catch {
17817
17946
  continue;
17818
17947
  }
@@ -17844,7 +17973,7 @@ async function runCarveEmit(demo, select) {
17844
17973
  const block = carveWriteBlock(demo);
17845
17974
  if (block) return refuse6("read-only", block, "Start the walkthrough with `behold demo carve`.");
17846
17975
  mkdirSync5(demo.out, { recursive: true });
17847
- const reportFile = join20(demo.out, `${carveSlug(select)}-boundary.json`);
17976
+ const reportFile = join21(demo.out, `${carveSlug(select)}-boundary.json`);
17848
17977
  const args = [
17849
17978
  "carve",
17850
17979
  "emit",
@@ -17873,10 +18002,10 @@ async function runCarveEmit(demo, select) {
17873
18002
  }
17874
18003
  let boundary = null;
17875
18004
  try {
17876
- boundary = JSON.parse(readFileSync15(reportFile, "utf8"));
18005
+ boundary = JSON.parse(readFileSync16(reportFile, "utf8"));
17877
18006
  } catch {
17878
18007
  }
17879
- const lintPath = relative5(demo.project, join20(demo.out, "src")).split(sep6).join("/");
18008
+ const lintPath = relative5(demo.project, join21(demo.out, "src")).split(sep6).join("/");
17880
18009
  const lintArgs = ["lint", lintPath];
17881
18010
  const lint = await runChantRaw(lintArgs, demo.project).catch((err) => ({
17882
18011
  code: 127,
@@ -17939,8 +18068,8 @@ async function runCarveBridge(demo, select) {
17939
18068
  }
17940
18069
 
17941
18070
  // src/ops.ts
17942
- import { readdirSync as readdirSync10, readFileSync as readFileSync16, existsSync as existsSync14 } from "node:fs";
17943
- import { join as join21 } from "node:path";
18071
+ import { readdirSync as readdirSync11, readFileSync as readFileSync17, existsSync as existsSync15 } from "node:fs";
18072
+ import { join as join22 } from "node:path";
17944
18073
  var APPLY_TARGET_LEXICON = {
17945
18074
  cloudformation: "aws",
17946
18075
  kubectl: "k8s",
@@ -17962,11 +18091,11 @@ function discoverOps(projectDir) {
17962
18091
  const seen = /* @__PURE__ */ new Set();
17963
18092
  const out = [];
17964
18093
  for (const sub of ["ops", "src", "."]) {
17965
- const dir = join21(projectDir, sub);
17966
- if (!existsSync14(dir)) continue;
17967
- for (const f of readdirSync10(dir)) {
18094
+ const dir = join22(projectDir, sub);
18095
+ if (!existsSync15(dir)) continue;
18096
+ for (const f of readdirSync11(dir)) {
17968
18097
  if (!f.endsWith(".op.ts")) continue;
17969
- const content = readFileSync16(join21(dir, f), "utf8");
18098
+ const content = readFileSync17(join22(dir, f), "utf8");
17970
18099
  const name = content.match(/name:\s*["'`]([^"'`]+)["'`]/)?.[1];
17971
18100
  if (!name || seen.has(name)) continue;
17972
18101
  seen.add(name);
@@ -17982,25 +18111,25 @@ function discoverOps(projectDir) {
17982
18111
  ...gate ? { gate } : {},
17983
18112
  ...env ? { env } : {},
17984
18113
  ...substrate ? { substrate } : {},
17985
- ...existsSync14(irPath) ? { irPath } : {}
18114
+ ...existsSync15(irPath) ? { irPath } : {}
17986
18115
  });
17987
18116
  }
17988
18117
  }
17989
18118
  return out.sort((a, b) => a.name.localeCompare(b.name));
17990
18119
  }
17991
18120
  function opIrPath(projectDir, name) {
17992
- return join21(projectDir, "dist", "ops", name, "op.json");
18121
+ return join22(projectDir, "dist", "ops", name, "op.json");
17993
18122
  }
17994
18123
  function discoverOpIrs(projectDirs) {
17995
18124
  const seen = /* @__PURE__ */ new Set();
17996
18125
  const out = [];
17997
18126
  for (const dir of projectDirs) {
17998
- const root = join21(dir, "dist", "ops");
17999
- if (!existsSync14(root)) continue;
18000
- for (const name of readdirSync10(root)) {
18127
+ const root = join22(dir, "dist", "ops");
18128
+ if (!existsSync15(root)) continue;
18129
+ for (const name of readdirSync11(root)) {
18001
18130
  if (seen.has(name)) continue;
18002
18131
  const path = opIrPath(dir, name);
18003
- if (!existsSync14(path)) continue;
18132
+ if (!existsSync15(path)) continue;
18004
18133
  seen.add(name);
18005
18134
  out.push({ name, dir, path });
18006
18135
  }
@@ -18235,11 +18364,11 @@ var RAN = { ok: "ok", fail: "failed", skipped: "skipped" };
18235
18364
  function tookLabel(ms) {
18236
18365
  return ms < 1e3 ? `${ms}ms` : `${(ms / 1e3).toFixed(1)}s`;
18237
18366
  }
18238
- function paintPlayhead(ir, join54, gate) {
18239
- if (!join54.byNode.size && !join54.at) return ir;
18367
+ function paintPlayhead(ir, join55, gate) {
18368
+ if (!join55.byNode.size && !join55.at) return ir;
18240
18369
  const nodes = ir.nodes.map((node) => {
18241
- const run3 = join54.byNode.get(node.id);
18242
- const here = join54.at === node.id;
18370
+ const run3 = join55.byNode.get(node.id);
18371
+ const here = join55.at === node.id;
18243
18372
  if (!run3 && !here) return node;
18244
18373
  const isGate = node.attrs?._step === "gate";
18245
18374
  const attrs = { ...node.attrs };
@@ -18254,7 +18383,7 @@ function paintPlayhead(ir, join54, gate) {
18254
18383
  if (here) {
18255
18384
  attrs._playhead = true;
18256
18385
  attrs._status = isGate && gate ? "warn" : "accent";
18257
- attrs.run = isGate && gate ? `waiting for approval since ${gate.since}` : join54.atReason ?? "here";
18386
+ attrs.run = isGate && gate ? `waiting for approval since ${gate.since}` : join55.atReason ?? "here";
18258
18387
  if (isGate && gate?.description) attrs.gateDescription = gate.description;
18259
18388
  }
18260
18389
  return { ...node, attrs };
@@ -18276,11 +18405,11 @@ function pendingGateCard(op, gate, ir) {
18276
18405
  }
18277
18406
  };
18278
18407
  }
18279
- function playheadNote(state, join54) {
18408
+ function playheadNote(state, join55) {
18280
18409
  if (!state.op) {
18281
18410
  return "No run state: nothing has been run from this behold session, so every step paints as declared.";
18282
18411
  }
18283
- const settled = join54 ? join54.byNode.size : state.records.length;
18412
+ const settled = join55 ? join55.byNode.size : state.records.length;
18284
18413
  const bits = [];
18285
18414
  const head = state.status === "idle" ? `Run state for ${state.op}: no per-step records \u2014 this behold session didn't start the run, so only the gate query answers` : `Run: ${state.op} (${state.mode === "temporal" ? "durable" : "local executor"}) \u2014 ${settled} step${settled === 1 ? "" : "s"} settled`;
18286
18415
  if (state.status === "running") {
@@ -18296,9 +18425,9 @@ function playheadNote(state, join54) {
18296
18425
  } else if (state.gateNote) {
18297
18426
  bits.push(`gate state unavailable \u2014 ${state.gateNote}`);
18298
18427
  }
18299
- if (join54?.unplaced.length) {
18428
+ if (join55?.unplaced.length) {
18300
18429
  bits.push(
18301
- `${join54.unplaced.length} record${join54.unplaced.length === 1 ? "" : "s"} matched no declared step and ${join54.unplaced.length === 1 ? "is" : "are"} not painted`
18430
+ `${join55.unplaced.length} record${join55.unplaced.length === 1 ? "" : "s"} matched no declared step and ${join55.unplaced.length === 1 ? "is" : "are"} not painted`
18302
18431
  );
18303
18432
  }
18304
18433
  if (!bits.length) return `${head}.`;
@@ -18969,8 +19098,8 @@ var OpRunner = class {
18969
19098
  };
18970
19099
 
18971
19100
  // src/public-mode.ts
18972
- import { readFileSync as readFileSync17 } from "node:fs";
18973
- import { join as join22 } from "node:path";
19101
+ import { readFileSync as readFileSync18 } from "node:fs";
19102
+ import { join as join23 } from "node:path";
18974
19103
  var ReadOnlyRunner = class {
18975
19104
  running = null;
18976
19105
  applyProgress = initialApplyProgress;
@@ -19033,7 +19162,7 @@ function publicReadRefusal(path, query) {
19033
19162
  }
19034
19163
  var PUBLIC_FLAG = "<script>window.__BEHOLD_PUBLIC__ = true;</script>";
19035
19164
  function publicPage(webRoot2) {
19036
- const html = readFileSync17(join22(webRoot2, "index.html"), "utf8");
19165
+ const html = readFileSync18(join23(webRoot2, "index.html"), "utf8");
19037
19166
  return html.replace("</head>", ` ${PUBLIC_FLAG}
19038
19167
  </head>`);
19039
19168
  }
@@ -19050,8 +19179,8 @@ function publicRoutes(app, webRoot2) {
19050
19179
 
19051
19180
  // src/substrates.ts
19052
19181
  import { spawn as spawn5 } from "node:child_process";
19053
- import { existsSync as existsSync15, readFileSync as readFileSync18 } from "node:fs";
19054
- import { join as join23 } from "node:path";
19182
+ import { existsSync as existsSync16, readFileSync as readFileSync19 } from "node:fs";
19183
+ import { join as join24 } from "node:path";
19055
19184
  import { platform } from "node:os";
19056
19185
  var DOCKER_DOWN_DETAIL = "docker is down";
19057
19186
  function probe(cmd, args) {
@@ -19080,11 +19209,11 @@ async function dockerRunning(run3, nameFilter) {
19080
19209
  return out.split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
19081
19210
  }
19082
19211
  function scriptBringUp(projectDir, relPath, label) {
19083
- return existsSync15(join23(projectDir, relPath)) ? { label, cmd: "bash", args: [relPath] } : void 0;
19212
+ return existsSync16(join24(projectDir, relPath)) ? { label, cmd: "bash", args: [relPath] } : void 0;
19084
19213
  }
19085
19214
  function projectLexicons(projectDir) {
19086
19215
  try {
19087
- const src = readFileSync18(join23(projectDir, "chant.config.ts"), "utf-8");
19216
+ const src = readFileSync19(join24(projectDir, "chant.config.ts"), "utf-8");
19088
19217
  const m = src.match(/lexicons\s*:\s*\[([^\]]*)\]/);
19089
19218
  if (!m) return [];
19090
19219
  return [...m[1].matchAll(/["']([^"']+)["']/g)].map((x) => x[1]);
@@ -19136,7 +19265,7 @@ async function detectSubstrates(projectDir, preview = false, boundContext, probe
19136
19265
  ["forgejo", "Forgejo", ".forgejo", "test/forgejo-runtime-e2e.sh"]
19137
19266
  ];
19138
19267
  for (const [name, label, marker, script] of forges) {
19139
- if (!existsSync15(join23(projectDir, marker))) continue;
19268
+ if (!existsSync16(join24(projectDir, marker))) continue;
19140
19269
  const c = docker ? await dockerRunning(run3, name) : [];
19141
19270
  const d = dep(c.length > 0, "container up", "on-demand (pipeline run)");
19142
19271
  subs.push({
@@ -19170,7 +19299,7 @@ async function detectSubstrates(projectDir, preview = false, boundContext, probe
19170
19299
  detail: endpoint ? `targeting ${endpoint}` : "real Fly (FLY_FLAPS_BASE_URL unset)"
19171
19300
  });
19172
19301
  }
19173
- if (existsSync15(join23(projectDir, ".github", "workflows"))) {
19302
+ if (existsSync16(join24(projectDir, ".github", "workflows"))) {
19174
19303
  const gh = await run3("gh", ["auth", "status"]);
19175
19304
  const ready = gh.code === 0;
19176
19305
  subs.push({
@@ -19183,7 +19312,7 @@ async function detectSubstrates(projectDir, preview = false, boundContext, probe
19183
19312
  if (lexicons.includes("temporal")) {
19184
19313
  let hasProfiles = false;
19185
19314
  try {
19186
- hasProfiles = /temporal\s*:\s*\{[\s\S]{0,400}?profiles\s*:/.test(readFileSync18(join23(projectDir, "chant.config.ts"), "utf-8"));
19315
+ hasProfiles = /temporal\s*:\s*\{[\s\S]{0,400}?profiles\s*:/.test(readFileSync19(join24(projectDir, "chant.config.ts"), "utf-8"));
19187
19316
  } catch {
19188
19317
  }
19189
19318
  subs.push({
@@ -19326,8 +19455,8 @@ function statusVocabulary(kinds) {
19326
19455
  }
19327
19456
 
19328
19457
  // src/behaviour.ts
19329
- import { readFileSync as readFileSync19 } from "node:fs";
19330
- import { join as join24 } from "node:path";
19458
+ import { readFileSync as readFileSync20 } from "node:fs";
19459
+ import { join as join25 } from "node:path";
19331
19460
  var rec5 = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
19332
19461
  var str6 = (v) => typeof v === "string" && v.trim().length > 0 ? v : void 0;
19333
19462
  var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
@@ -19434,7 +19563,7 @@ var FIRST_TOTAL_SHOWN = "two members stated an estate total; the first is shown"
19434
19563
  var behaviourFileName = (env) => `behaviour.${env}.json`;
19435
19564
  var realRead = (path) => {
19436
19565
  try {
19437
- return readFileSync19(path, "utf8");
19566
+ return readFileSync20(path, "utf8");
19438
19567
  } catch {
19439
19568
  return void 0;
19440
19569
  }
@@ -19492,7 +19621,7 @@ function attachBehaviour(ir, members, env, readFile2 = realRead) {
19492
19621
  }
19493
19622
  const file = behaviourFileName(env);
19494
19623
  looked.push(`${label}/${file}`);
19495
- const raw = readFile2(join24(m.dir, file));
19624
+ const raw = readFile2(join25(m.dir, file));
19496
19625
  if (raw === void 0) {
19497
19626
  sources.set(label, "none");
19498
19627
  continue;
@@ -19928,7 +20057,7 @@ init_choudoufu_live();
19928
20057
  init_choudoufu_member();
19929
20058
  import { mkdtempSync, rmSync as rmSync3 } from "node:fs";
19930
20059
  import { tmpdir as tmpdir2 } from "node:os";
19931
- import { join as join25 } from "node:path";
20060
+ import { join as join26 } from "node:path";
19932
20061
  var isRecord10 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
19933
20062
  var refuse7 = (error, remedy) => ({ ok: false, refusal: { error, code: "choudoufu-live-check", remedy } });
19934
20063
  var CREDS2 = "Give behold the ambient read-only AWS credentials the estate's `plan` needs (AWS_PROFILE, or AWS_ENDPOINT_URL for an emulator), then re-check live with plan.";
@@ -20002,8 +20131,8 @@ var planArgv = (out) => ({
20002
20131
  show: ["show", "-json", out]
20003
20132
  });
20004
20133
  async function readChoudoufuPlan(dir, run3 = captureChoudoufu) {
20005
- const scratch = mkdtempSync(join25(tmpdir2(), "behold-choudoufu-plan-"));
20006
- const file = join25(scratch, "plan.tfplan");
20134
+ const scratch = mkdtempSync(join26(tmpdir2(), "behold-choudoufu-plan-"));
20135
+ const file = join26(scratch, "plan.tfplan");
20007
20136
  const argv = planArgv(file);
20008
20137
  try {
20009
20138
  const planRun = await run3(argv.plan, dir);
@@ -20035,8 +20164,8 @@ init_choudoufu_refs();
20035
20164
  // src/choudoufu-moves.ts
20036
20165
  init_choudoufu_member();
20037
20166
  init_choudoufu_live();
20038
- import { existsSync as existsSync16, readFileSync as readFileSync20 } from "node:fs";
20039
- import { join as join26, relative as relative6 } from "node:path";
20167
+ import { existsSync as existsSync17, readFileSync as readFileSync21 } from "node:fs";
20168
+ import { join as join27, relative as relative6 } from "node:path";
20040
20169
  var isRecord11 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
20041
20170
  var refuse8 = (error, remedy) => ({ ok: false, refusal: { error, code: "choudoufu-live-check", remedy } });
20042
20171
  var HOW_TO_GET_ONE2 = "A plan is the live-mv workbench's carve.json: `{from, estates[], moves[{address, from, to}]}` \u2014 the workbench's plan phase writes one, or write it by hand.";
@@ -20056,7 +20185,7 @@ function parseCarvePlan(value) {
20056
20185
  }
20057
20186
  };
20058
20187
  }
20059
- function readCarvePlan(path, readFile2 = (p) => readFileSync20(p, "utf8")) {
20188
+ function readCarvePlan(path, readFile2 = (p) => readFileSync21(p, "utf8")) {
20060
20189
  let text2;
20061
20190
  try {
20062
20191
  text2 = readFile2(path);
@@ -20072,8 +20201,8 @@ function readCarvePlan(path, readFile2 = (p) => readFileSync20(p, "utf8")) {
20072
20201
  function discoverCarvePlans(memberDirs, base) {
20073
20202
  const out = [];
20074
20203
  for (const dir of memberDirs) {
20075
- const p = join26(dir, "carve.json");
20076
- if (existsSync16(p)) out.push(relative6(base, p));
20204
+ const p = join27(dir, "carve.json");
20205
+ if (existsSync17(p)) out.push(relative6(base, p));
20077
20206
  }
20078
20207
  return out;
20079
20208
  }
@@ -20302,27 +20431,27 @@ function getRuntime() {
20302
20431
  }
20303
20432
 
20304
20433
  // node_modules/@intentius/chant/src/lifecycle/member-ledger.ts
20305
- import { existsSync as existsSync19 } from "node:fs";
20306
- import { dirname as dirname8, join as join30, relative as relative7, resolve as resolve16, sep as sep7 } from "node:path";
20434
+ import { existsSync as existsSync20 } from "node:fs";
20435
+ import { dirname as dirname8, join as join31, relative as relative7, resolve as resolve16, sep as sep7 } from "node:path";
20307
20436
 
20308
20437
  // node_modules/@intentius/chant/src/project-root.ts
20309
- import { existsSync as existsSync17 } from "fs";
20310
- import { dirname as dirname6, join as join27, resolve as resolve14 } from "path";
20438
+ import { existsSync as existsSync18 } from "fs";
20439
+ import { dirname as dirname6, join as join28, resolve as resolve14 } from "path";
20311
20440
  var WORKSPACE_DECLARATION_FILES = ["chant.workspace.json", "chant.workspace.jsonc"];
20312
20441
  function findWorkspaceRoot(startDir) {
20313
20442
  const start = resolve14(startDir);
20314
20443
  let top;
20315
20444
  for (let dir = start; ; dir = dirname6(dir)) {
20316
- if (existsSync17(join27(dir, ".git"))) {
20445
+ if (existsSync18(join28(dir, ".git"))) {
20317
20446
  top = dir;
20318
20447
  break;
20319
20448
  }
20320
20449
  if (dirname6(dir) === dir) break;
20321
20450
  }
20322
20451
  for (let dir = start; ; dir = dirname6(dir)) {
20323
- const [json2, jsonc] = WORKSPACE_DECLARATION_FILES.map((name) => join27(dir, name));
20324
- const hasJson = existsSync17(json2);
20325
- const hasJsonc = existsSync17(jsonc);
20452
+ const [json2, jsonc] = WORKSPACE_DECLARATION_FILES.map((name) => join28(dir, name));
20453
+ const hasJson = existsSync18(json2);
20454
+ const hasJsonc = existsSync18(jsonc);
20326
20455
  if (hasJson && hasJsonc) return { dir, file: json2, conflicting: jsonc };
20327
20456
  if (hasJson) return { dir, file: json2 };
20328
20457
  if (hasJsonc) return { dir, file: jsonc };
@@ -20382,7 +20511,7 @@ async function ledgerIn(root, dir) {
20382
20511
  }
20383
20512
  let outer = FLAT;
20384
20513
  const parent = dirname8(root);
20385
- if (parent !== root && !existsSync19(join30(root, ".git"))) {
20514
+ if (parent !== root && !existsSync20(join31(root, ".git"))) {
20386
20515
  const outerFound = findWorkspaceRoot(parent);
20387
20516
  if (outerFound) outer = await ledgerIn(outerFound.dir, root);
20388
20517
  }
@@ -20936,8 +21065,8 @@ function decideOverride(input) {
20936
21065
  }
20937
21066
 
20938
21067
  // src/terragucci-repo.ts
20939
- import { existsSync as existsSync20 } from "node:fs";
20940
- import { dirname as dirname9, join as join31, resolve as resolve17 } from "node:path";
21068
+ import { existsSync as existsSync21 } from "node:fs";
21069
+ import { dirname as dirname9, join as join32, resolve as resolve17 } from "node:path";
20941
21070
  var TERRAGUCCI_CONFIG_NAMES = ["terragucci.yml", "terragucci.yaml", "terragucci.json", "terragucci.ts"];
20942
21071
  function terragucciConfig(dir) {
20943
21072
  return walkUp(dir, TERRAGUCCI_CONFIG_NAMES);
@@ -20946,10 +21075,10 @@ function walkUp(dir, names) {
20946
21075
  let at2 = resolve17(dir);
20947
21076
  for (; ; ) {
20948
21077
  for (const name of names) {
20949
- const file = join31(at2, name);
20950
- if (existsSync20(file)) return file;
21078
+ const file = join32(at2, name);
21079
+ if (existsSync21(file)) return file;
20951
21080
  }
20952
- if (existsSync20(join31(at2, ".git"))) return void 0;
21081
+ if (existsSync21(join32(at2, ".git"))) return void 0;
20953
21082
  const up = dirname9(at2);
20954
21083
  if (up === at2) return void 0;
20955
21084
  at2 = up;
@@ -21752,8 +21881,8 @@ init_read_stats();
21752
21881
  init_foreign();
21753
21882
 
21754
21883
  // src/events.ts
21755
- import { watch, existsSync as existsSync21 } from "node:fs";
21756
- import { join as join32 } from "node:path";
21884
+ import { watch, existsSync as existsSync22 } from "node:fs";
21885
+ import { join as join33 } from "node:path";
21757
21886
  var Broadcaster = class {
21758
21887
  listeners = /* @__PURE__ */ new Set();
21759
21888
  subscribe(fn) {
@@ -21771,7 +21900,7 @@ var Broadcaster = class {
21771
21900
  };
21772
21901
  var IGNORE = /(^|[\\/])(node_modules|dist|\.git)([\\/]|$)/;
21773
21902
  function watchSource(projectDir, onChange, debounceMs = 200) {
21774
- const dir = existsSync21(join32(projectDir, "src")) ? join32(projectDir, "src") : projectDir;
21903
+ const dir = existsSync22(join33(projectDir, "src")) ? join33(projectDir, "src") : projectDir;
21775
21904
  let timer;
21776
21905
  const watcher = watch(dir, { recursive: true }, (_event, file) => {
21777
21906
  const name = typeof file === "string" ? file : "";
@@ -22075,27 +22204,27 @@ async function emulatorDown(projectDir) {
22075
22204
 
22076
22205
  // src/terragucci-view.ts
22077
22206
  import { execFileSync as execFileSync3 } from "node:child_process";
22078
- import { dirname as dirname13, join as join41, relative as relative9, sep as sep8 } from "node:path";
22207
+ import { dirname as dirname13, join as join42, relative as relative9, sep as sep8 } from "node:path";
22079
22208
  init_terraform_member();
22080
22209
 
22081
22210
  // src/terragucci-reports.ts
22082
- import { readFileSync as readFileSync25, statSync as statSync11 } from "node:fs";
22211
+ import { readFileSync as readFileSync26, statSync as statSync11 } from "node:fs";
22083
22212
  import { createRequire as createRequire4 } from "node:module";
22084
- import { dirname as dirname10, join as join35, resolve as resolve21 } from "node:path";
22213
+ import { dirname as dirname10, join as join36, resolve as resolve21 } from "node:path";
22085
22214
  import { fileURLToPath as fileURLToPath5 } from "node:url";
22086
22215
  import { Ajv2020 } from "ajv/dist/2020.js";
22087
22216
 
22088
22217
  // src/terragucci-lifecycle.ts
22089
22218
  import { execFile as execFile4 } from "node:child_process";
22090
22219
  import { createHash as createHash8 } from "node:crypto";
22091
- import { existsSync as existsSync22, mkdirSync as mkdirSync6, readdirSync as readdirSync12 } from "node:fs";
22220
+ import { existsSync as existsSync23, mkdirSync as mkdirSync6, readdirSync as readdirSync13 } from "node:fs";
22092
22221
  import { tmpdir as tmpdir3 } from "node:os";
22093
- import { basename as basename3, isAbsolute as isAbsolute4, join as join34, resolve as resolve20 } from "node:path";
22222
+ import { basename as basename3, isAbsolute as isAbsolute4, join as join35, resolve as resolve20 } from "node:path";
22094
22223
 
22095
22224
  // node_modules/@intentius/chant/src/gate-decision.ts
22096
22225
  import { spawnSync as spawnSync2 } from "node:child_process";
22097
- import { readFileSync as readFileSync24 } from "node:fs";
22098
- import { join as join33, posix as posix4 } from "node:path";
22226
+ import { readFileSync as readFileSync25 } from "node:fs";
22227
+ import { join as join34, posix as posix4 } from "node:path";
22099
22228
 
22100
22229
  // node_modules/@intentius/chant/src/lifecycle/gate-applied.ts
22101
22230
  function appliedGatePath(op) {
@@ -22204,7 +22333,7 @@ function pinnedClassesAt(repo, base, pins, packages) {
22204
22333
  }
22205
22334
  let installed2;
22206
22335
  try {
22207
- installed2 = JSON.parse(readFileSync24(join33(dir, "package.json"), "utf-8")).version;
22336
+ installed2 = JSON.parse(readFileSync25(join34(dir, "package.json"), "utf-8")).version;
22208
22337
  } catch {
22209
22338
  installed2 = void 0;
22210
22339
  }
@@ -22811,7 +22940,7 @@ var realGit = (args, o = {}) => new Promise((res) => {
22811
22940
  });
22812
22941
  var redact = (s) => s.replace(/(\b[a-z][a-z0-9+.-]*:\/\/)[^/@\s]+@/gi, "$1");
22813
22942
  function cacheDir(origin, root = tmpdir3()) {
22814
- return join34(root, `${CACHE_PREFIX}${createHash8("sha256").update(origin).digest("hex").slice(0, 16)}`);
22943
+ return join35(root, `${CACHE_PREFIX}${createHash8("sha256").update(origin).digest("hex").slice(0, 16)}`);
22815
22944
  }
22816
22945
  var inflight = /* @__PURE__ */ new Map();
22817
22946
  function serially(key, fn) {
@@ -22830,8 +22959,8 @@ function fetchable(url, checkout) {
22830
22959
  async function fetchIntoCache(git3, origin, cache6) {
22831
22960
  assertScratch(basename3(cache6));
22832
22961
  return serially(cache6, async () => {
22833
- if (!existsSync22(join34(cache6, "HEAD"))) {
22834
- if (existsSync22(cache6) && readdirSync12(cache6).length > 0) return { ok: false, error: `${cache6} exists and is not behold's lifecycle cache; behold leaves it alone` };
22962
+ if (!existsSync23(join35(cache6, "HEAD"))) {
22963
+ if (existsSync23(cache6) && readdirSync13(cache6).length > 0) return { ok: false, error: `${cache6} exists and is not behold's lifecycle cache; behold leaves it alone` };
22835
22964
  mkdirSync6(cache6, { recursive: true });
22836
22965
  const init = await git3(["init", "--bare", "-q", cache6]);
22837
22966
  if (init.code !== 0) return { ok: false, error: `could not make the cache ${cache6}: ${init.stderr.trim()}` };
@@ -23032,7 +23161,7 @@ function structural(name, doc) {
23032
23161
  var compiledSchemas = /* @__PURE__ */ new Map();
23033
23162
  function schemaStamp(dist) {
23034
23163
  try {
23035
- const files = [join35(dist, "..", "package.json"), ...Object.values(SCHEMA_FILES).map((f) => join35(dist, f))];
23164
+ const files = [join36(dist, "..", "package.json"), ...Object.values(SCHEMA_FILES).map((f) => join36(dist, f))];
23036
23165
  return [dist, ...files.map((f) => {
23037
23166
  const st = statSync11(f);
23038
23167
  return `${st.mtimeMs}:${st.size}`;
@@ -23042,10 +23171,10 @@ function schemaStamp(dist) {
23042
23171
  }
23043
23172
  }
23044
23173
  function compileSchemas(dist) {
23045
- const version = JSON.parse(readFileSync25(join35(dist, "..", "package.json"), "utf8")).version ?? "";
23174
+ const version = JSON.parse(readFileSync26(join36(dist, "..", "package.json"), "utf8")).version ?? "";
23046
23175
  const ajv = new Ajv2020({ strict: false, allErrors: false });
23047
23176
  const compiled4 = Object.fromEntries(
23048
- Object.keys(SCHEMA_FILES).map((n) => [n, ajv.compile(JSON.parse(readFileSync25(join35(dist, SCHEMA_FILES[n]), "utf8")))])
23177
+ Object.keys(SCHEMA_FILES).map((n) => [n, ajv.compile(JSON.parse(readFileSync26(join36(dist, SCHEMA_FILES[n]), "utf8")))])
23049
23178
  );
23050
23179
  return {
23051
23180
  validation: { by: "schema", terragucci: version },
@@ -23062,7 +23191,7 @@ function terragucciValidator(dirs = []) {
23062
23191
  for (const from of [...dirs, dirname10(fileURLToPath5(import.meta.url))]) {
23063
23192
  let entry;
23064
23193
  try {
23065
- entry = createRequire4(join35(resolve21(from), "noop.js")).resolve("@intentius/terragucci/report.schema.json");
23194
+ entry = createRequire4(join36(resolve21(from), "noop.js")).resolve("@intentius/terragucci/report.schema.json");
23066
23195
  } catch {
23067
23196
  continue;
23068
23197
  }
@@ -23418,11 +23547,11 @@ function joinTerragucci(read, nodes, roots) {
23418
23547
  // src/terragucci-source.ts
23419
23548
  import { spawn as spawn7 } from "node:child_process";
23420
23549
  import { readFile } from "node:fs/promises";
23421
- import { join as join36, resolve as resolve22 } from "node:path";
23550
+ import { join as join37, resolve as resolve22 } from "node:path";
23422
23551
 
23423
23552
  // src/s3-object.ts
23424
23553
  import { createHash as createHash9, createHmac } from "node:crypto";
23425
- import { readFileSync as readFileSync26 } from "node:fs";
23554
+ import { readFileSync as readFileSync27 } from "node:fs";
23426
23555
  var S3Error = class extends Error {
23427
23556
  /** The HTTP status S3 answered, when it answered. */
23428
23557
  status;
@@ -23469,7 +23598,7 @@ function s3FromEnv(bucket, env = process.env) {
23469
23598
  async function assumeRole(w, fetchFn) {
23470
23599
  let token;
23471
23600
  try {
23472
- token = readFileSync26(w.tokenFile, "utf8").trim();
23601
+ token = readFileSync27(w.tokenFile, "utf8").trim();
23473
23602
  } catch (e) {
23474
23603
  throw new S3Error(`cannot read the OIDC token in ${w.tokenFile}: ${e.message}`);
23475
23604
  }
@@ -23666,7 +23795,7 @@ function terragucciSource(spec2, opts = {}) {
23666
23795
  location: dir,
23667
23796
  async read(key) {
23668
23797
  try {
23669
- return await readFile(join36(dir, ...trim(key).split("/")), "utf8");
23798
+ return await readFile(join37(dir, ...trim(key).split("/")), "utf8");
23670
23799
  } catch (e) {
23671
23800
  if (e.code === "ENOENT") return void 0;
23672
23801
  throw e;
@@ -23676,9 +23805,9 @@ function terragucciSource(spec2, opts = {}) {
23676
23805
  }
23677
23806
 
23678
23807
  // src/terragucci-timeline.ts
23679
- import { readFileSync as readFileSync27, statSync as statSync12 } from "node:fs";
23808
+ import { readFileSync as readFileSync28, statSync as statSync12 } from "node:fs";
23680
23809
  import { createRequire as createRequire5 } from "node:module";
23681
- import { dirname as dirname11, join as join37, resolve as resolve23 } from "node:path";
23810
+ import { dirname as dirname11, join as join38, resolve as resolve23 } from "node:path";
23682
23811
  import { fileURLToPath as fileURLToPath6 } from "node:url";
23683
23812
  import { Ajv2020 as Ajv20202 } from "ajv/dist/2020.js";
23684
23813
  var AUDIT_SCHEMA = "terragucci.audit/v1";
@@ -23719,12 +23848,12 @@ function auditValidator(dirs = []) {
23719
23848
  for (const from of [...dirs, dirname11(fileURLToPath6(import.meta.url))]) {
23720
23849
  let dist;
23721
23850
  try {
23722
- dist = dirname11(createRequire5(join37(resolve23(from), "noop.js")).resolve("@intentius/terragucci/report.schema.json"));
23851
+ dist = dirname11(createRequire5(join38(resolve23(from), "noop.js")).resolve("@intentius/terragucci/report.schema.json"));
23723
23852
  } catch {
23724
23853
  continue;
23725
23854
  }
23726
- const pkg = join37(dist, "..", "package.json");
23727
- const file = join37(dist, AUDIT_SCHEMA_FILE);
23855
+ const pkg = join38(dist, "..", "package.json");
23856
+ const file = join38(dist, AUDIT_SCHEMA_FILE);
23728
23857
  let stamp;
23729
23858
  try {
23730
23859
  stamp = [dist, ...[pkg, file].map((f) => {
@@ -23738,8 +23867,8 @@ function auditValidator(dirs = []) {
23738
23867
  if (hit) return hit;
23739
23868
  let v;
23740
23869
  try {
23741
- const version = JSON.parse(readFileSync27(pkg, "utf8")).version ?? "";
23742
- v = compileAuditSchema(JSON.parse(readFileSync27(file, "utf8")), version);
23870
+ const version = JSON.parse(readFileSync28(pkg, "utf8")).version ?? "";
23871
+ v = compileAuditSchema(JSON.parse(readFileSync28(file, "utf8")), version);
23743
23872
  } catch {
23744
23873
  continue;
23745
23874
  }
@@ -23935,7 +24064,7 @@ function terragucciTimelineRoute(app, source2, opts = {}) {
23935
24064
  // src/terragucci-poll.ts
23936
24065
  import { createHash as createHash10 } from "node:crypto";
23937
24066
  import { stat } from "node:fs/promises";
23938
- import { join as join38, resolve as resolve24 } from "node:path";
24067
+ import { join as join39, resolve as resolve24 } from "node:path";
23939
24068
  import { streamSSE } from "hono/streaming";
23940
24069
  var TERRAGUCCI_POLL_SECS = 30;
23941
24070
  var INDEX_KEY = "index.json";
@@ -23986,7 +24115,7 @@ function indexProbe(spec2, opts = {}) {
23986
24115
  return verdict2(prev, etag);
23987
24116
  };
23988
24117
  }
23989
- const file = join38(resolve24(opts.cwd ?? process.cwd(), spec2), name);
24118
+ const file = join39(resolve24(opts.cwd ?? process.cwd(), spec2), name);
23990
24119
  return async (prev) => {
23991
24120
  try {
23992
24121
  const s = await stat(file);
@@ -24141,9 +24270,9 @@ function terragucciLaneRoutes(app, o, base, forget) {
24141
24270
  }
24142
24271
 
24143
24272
  // src/terragucci-progress.ts
24144
- import { readFileSync as readFileSync28, statSync as statSync13 } from "node:fs";
24273
+ import { readFileSync as readFileSync29, statSync as statSync13 } from "node:fs";
24145
24274
  import { createRequire as createRequire6 } from "node:module";
24146
- import { dirname as dirname12, join as join39, resolve as resolve25 } from "node:path";
24275
+ import { dirname as dirname12, join as join40, resolve as resolve25 } from "node:path";
24147
24276
  import { fileURLToPath as fileURLToPath7 } from "node:url";
24148
24277
  import { Ajv2020 as Ajv20203 } from "ajv/dist/2020.js";
24149
24278
  var RUN_SCHEMA = "terragucci.run/v1";
@@ -24188,12 +24317,12 @@ function runValidator(dirs = []) {
24188
24317
  for (const from of [...dirs, dirname12(fileURLToPath7(import.meta.url))]) {
24189
24318
  let dist;
24190
24319
  try {
24191
- dist = dirname12(createRequire6(join39(resolve25(from), "noop.js")).resolve("@intentius/terragucci/report.schema.json"));
24320
+ dist = dirname12(createRequire6(join40(resolve25(from), "noop.js")).resolve("@intentius/terragucci/report.schema.json"));
24192
24321
  } catch {
24193
24322
  continue;
24194
24323
  }
24195
- const pkg = join39(dist, "..", "package.json");
24196
- const file = join39(dist, RUN_SCHEMA_FILE);
24324
+ const pkg = join40(dist, "..", "package.json");
24325
+ const file = join40(dist, RUN_SCHEMA_FILE);
24197
24326
  let stamp;
24198
24327
  try {
24199
24328
  stamp = [dist, ...[pkg, file].map((f) => {
@@ -24207,8 +24336,8 @@ function runValidator(dirs = []) {
24207
24336
  if (hit) return hit;
24208
24337
  let v;
24209
24338
  try {
24210
- const version = JSON.parse(readFileSync28(pkg, "utf8")).version ?? "";
24211
- v = compileRunSchema(JSON.parse(readFileSync28(file, "utf8")), version);
24339
+ const version = JSON.parse(readFileSync29(pkg, "utf8")).version ?? "";
24340
+ v = compileRunSchema(JSON.parse(readFileSync29(file, "utf8")), version);
24212
24341
  } catch {
24213
24342
  continue;
24214
24343
  }
@@ -24501,8 +24630,8 @@ function terragucciProgressRoute(app, progress) {
24501
24630
  }
24502
24631
 
24503
24632
  // src/terragucci-demo.ts
24504
- import { readFileSync as readFileSync29 } from "node:fs";
24505
- import { join as join40 } from "node:path";
24633
+ import { readFileSync as readFileSync30 } from "node:fs";
24634
+ import { join as join41 } from "node:path";
24506
24635
  var DEMO_KEY = "demo.json";
24507
24636
  var DEMO_READ_TTL_MS = 2e3;
24508
24637
  var DEMO_STEPS = ["pull-request", "planned", "merged", "applying", "waiting", "approved", "failed", "resumed", "applied", "reset", "stalled"];
@@ -24591,10 +24720,10 @@ function kioskRoute(app, webRoot2, enabled) {
24591
24720
  if (!enabled) {
24592
24721
  return c.html(disabledPage, 404);
24593
24722
  }
24594
- return new Response(readFileSync29(join40(webRoot2, "kiosk.html"), "utf8"), { headers: { "content-type": "text/html; charset=utf-8", "cache-control": "no-cache" } });
24723
+ return new Response(readFileSync30(join41(webRoot2, "kiosk.html"), "utf8"), { headers: { "content-type": "text/html; charset=utf-8", "cache-control": "no-cache" } });
24595
24724
  });
24596
24725
  }
24597
- var VENDOR_TOOLS = ["terraform", "terragrunt", "cdk-terrain", "choudoufu"];
24726
+ var VENDOR_TOOLS = ["terraform", "terragrunt", "cdk-terrain", "choudoufu", "chant"];
24598
24727
  var isVendorTool = (v) => VENDOR_TOOLS.includes(v);
24599
24728
  var cycleKey = (tool) => `cycles/${tool}/latest.json`;
24600
24729
  var CYCLE_READ_TTL_MS = 1e4;
@@ -24671,7 +24800,7 @@ function vendorRoutes(app, webRoot2, enabled) {
24671
24800
  for (const tool of VENDOR_TOOLS) {
24672
24801
  app.get(`/${tool}`, (c) => {
24673
24802
  if (!enabled) return c.html(disabledPage, 404);
24674
- const html = vendorPage(readFileSync29(join40(webRoot2, "kiosk.html"), "utf8"), tool);
24803
+ const html = vendorPage(readFileSync30(join41(webRoot2, "kiosk.html"), "utf8"), tool);
24675
24804
  return new Response(html, { headers: { "content-type": "text/html; charset=utf-8", "cache-control": "no-cache" } });
24676
24805
  });
24677
24806
  }
@@ -24837,7 +24966,7 @@ function checkoutRoots(dirs, base = repoBase(dirs)) {
24837
24966
  for (const m of estateMembers(dirs)) {
24838
24967
  if (m.kind !== "terraform") continue;
24839
24968
  for (const r of checkoutRootDirs(m.dir)) {
24840
- const path = relative9(base, join41(m.dir, r.dir)).split(sep8).join("/") || ".";
24969
+ const path = relative9(base, join42(m.dir, r.dir)).split(sep8).join("/") || ".";
24841
24970
  out.push({ member: m.name, name: r.name, path });
24842
24971
  }
24843
24972
  }
@@ -24948,8 +25077,8 @@ function terragucciRoutes(app, opts, dirs) {
24948
25077
 
24949
25078
  // src/view-repos.ts
24950
25079
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
24951
- import { existsSync as existsSync23, readdirSync as readdirSync13, readFileSync as readFileSync30 } from "node:fs";
24952
- import { join as join42, resolve as resolve26 } from "node:path";
25080
+ import { existsSync as existsSync24, readdirSync as readdirSync14, readFileSync as readFileSync31 } from "node:fs";
25081
+ import { join as join43, resolve as resolve26 } from "node:path";
24953
25082
  var NAME2 = /^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$/;
24954
25083
  function repoName(value) {
24955
25084
  const v = value.trim().replace(/\.git$/, "");
@@ -24959,11 +25088,11 @@ function repoName(value) {
24959
25088
  function listCheckouts(parent) {
24960
25089
  let names;
24961
25090
  try {
24962
- names = readdirSync13(parent, { withFileTypes: true }).filter((e) => e.isDirectory() && NAME2.test(e.name)).map((e) => e.name).sort();
25091
+ names = readdirSync14(parent, { withFileTypes: true }).filter((e) => e.isDirectory() && NAME2.test(e.name)).map((e) => e.name).sort();
24963
25092
  } catch {
24964
25093
  return [];
24965
25094
  }
24966
- return names.map((name) => ({ name, dir: resolve26(parent, name) })).filter((c) => existsSync23(join42(c.dir, ".git")));
25095
+ return names.map((name) => ({ name, dir: resolve26(parent, name) })).filter((c) => existsSync24(join43(c.dir, ".git")));
24967
25096
  }
24968
25097
  var scope = new AsyncLocalStorage2();
24969
25098
  function scopeServedDirs(cfg) {
@@ -25005,7 +25134,7 @@ var SHA = /^[0-9a-f]{40}([0-9a-f]{24})?$/;
25005
25134
  function checkoutCommit(dir) {
25006
25135
  const read = (f) => {
25007
25136
  try {
25008
- return readFileSync30(join42(dir, ".git", f), "utf8");
25137
+ return readFileSync31(join43(dir, ".git", f), "utf8");
25009
25138
  } catch {
25010
25139
  return void 0;
25011
25140
  }
@@ -25486,8 +25615,8 @@ function lifecycleHistoryRoute(app, base, opts = {}) {
25486
25615
  }
25487
25616
 
25488
25617
  // src/lifecycle-releases.ts
25489
- import { existsSync as existsSync24, readFileSync as readFileSync31 } from "node:fs";
25490
- import { join as join43 } from "node:path";
25618
+ import { existsSync as existsSync25, readFileSync as readFileSync32 } from "node:fs";
25619
+ import { join as join44 } from "node:path";
25491
25620
 
25492
25621
  // node_modules/@intentius/chant/src/lifecycle/legacy-digest.ts
25493
25622
  import { resolve as resolve27 } from "node:path";
@@ -25600,10 +25729,10 @@ function memberNote(l) {
25600
25729
  // src/lifecycle-releases.ts
25601
25730
  var WAVES_SPEC_FILE = "yodel-waves.json";
25602
25731
  function waveOrder(checkout) {
25603
- const p = join43(checkout, WAVES_SPEC_FILE);
25604
- if (!existsSync24(p)) return void 0;
25732
+ const p = join44(checkout, WAVES_SPEC_FILE);
25733
+ if (!existsSync25(p)) return void 0;
25605
25734
  try {
25606
- const doc = JSON.parse(readFileSync31(p, "utf8"));
25735
+ const doc = JSON.parse(readFileSync32(p, "utf8"));
25607
25736
  const names = (doc.waves ?? []).map((w) => w?.name).filter((n) => typeof n === "string" && n.length > 0);
25608
25737
  return names.length ? [...new Set(names)] : void 0;
25609
25738
  } catch {
@@ -25611,7 +25740,7 @@ function waveOrder(checkout) {
25611
25740
  }
25612
25741
  }
25613
25742
  function hasReleaseLedgerHint(checkout) {
25614
- return existsSync24(join43(checkout, "yodel.config.ts")) || existsSync24(join43(checkout, WAVES_SPEC_FILE));
25743
+ return existsSync25(join44(checkout, "yodel.config.ts")) || existsSync25(join44(checkout, WAVES_SPEC_FILE));
25615
25744
  }
25616
25745
  function orderEnvironments(envs, waves) {
25617
25746
  const seen = new Set(envs);
@@ -25653,7 +25782,7 @@ function releaseCells(ledgers, order, sources) {
25653
25782
  }
25654
25783
  async function copyCheckoutRef(git3, checkout, cache6) {
25655
25784
  assertScratch(cache6.split(/[\\/]/).pop());
25656
- if (!existsSync24(join43(cache6, "HEAD"))) {
25785
+ if (!existsSync25(join44(cache6, "HEAD"))) {
25657
25786
  const init = await git3(["init", "--bare", "-q", cache6]);
25658
25787
  if (init.code !== 0) return false;
25659
25788
  }
@@ -25756,8 +25885,8 @@ function releasesRoutes(app, base, opts = {}) {
25756
25885
  }
25757
25886
 
25758
25887
  // src/sql-yodeler-lane.ts
25759
- import { existsSync as existsSync25, readdirSync as readdirSync14, readFileSync as readFileSync32 } from "node:fs";
25760
- import { join as join44 } from "node:path";
25888
+ import { existsSync as existsSync26, readdirSync as readdirSync15, readFileSync as readFileSync33 } from "node:fs";
25889
+ import { join as join45 } from "node:path";
25761
25890
  var YODEL_APPLY_OP = "yodel-apply";
25762
25891
  var YODEL_HEAD_PLANS_DIR = headPlansPath(YODEL_APPLY_OP, "").dir;
25763
25892
  function parseYodelWaves(text2, path = WAVES_SPEC_FILE) {
@@ -25789,19 +25918,19 @@ function parseYodelWaves(text2, path = WAVES_SPEC_FILE) {
25789
25918
  return { path, waves };
25790
25919
  }
25791
25920
  function readYodelWaves(checkout) {
25792
- const p = join44(checkout, WAVES_SPEC_FILE);
25793
- if (!existsSync25(p)) return void 0;
25921
+ const p = join45(checkout, WAVES_SPEC_FILE);
25922
+ if (!existsSync26(p)) return void 0;
25794
25923
  try {
25795
- return parseYodelWaves(readFileSync32(p, "utf8"));
25924
+ return parseYodelWaves(readFileSync33(p, "utf8"));
25796
25925
  } catch (e) {
25797
25926
  return { path: WAVES_SPEC_FILE, waves: [], error: e instanceof Error ? e.message : String(e) };
25798
25927
  }
25799
25928
  }
25800
25929
  function migrateOpEnvironments(checkout) {
25801
- const dir = join44(checkout, "ops");
25802
- if (!existsSync25(dir)) return [];
25930
+ const dir = join45(checkout, "ops");
25931
+ if (!existsSync26(dir)) return [];
25803
25932
  try {
25804
- return readdirSync14(dir).map((f) => /^migrate-(.+)\.op\.ts$/.exec(f)?.[1]).filter((e) => !!e).sort();
25933
+ return readdirSync15(dir).map((f) => /^migrate-(.+)\.op\.ts$/.exec(f)?.[1]).filter((e) => !!e).sort();
25805
25934
  } catch {
25806
25935
  return [];
25807
25936
  }
@@ -25921,20 +26050,20 @@ function sqlYodelerLaneRoute(app, checkout, opts = {}) {
25921
26050
 
25922
26051
  // src/terragucci-estate.ts
25923
26052
  init_yaml();
25924
- import { existsSync as existsSync26, readFileSync as readFileSync33, statSync as statSync14 } from "node:fs";
26053
+ import { existsSync as existsSync27, readFileSync as readFileSync34, statSync as statSync14 } from "node:fs";
25925
26054
  import { createRequire as createRequire7 } from "node:module";
25926
- import { dirname as dirname14, extname, join as join45, resolve as resolve28 } from "node:path";
26055
+ import { dirname as dirname14, extname as extname2, join as join46, resolve as resolve28 } from "node:path";
25927
26056
  import { fileURLToPath as fileURLToPath8 } from "node:url";
25928
26057
  import { Ajv2020 as Ajv20204 } from "ajv/dist/2020.js";
25929
26058
  var RUN_SCHEMA2 = "terragucci.run/v1";
25930
26059
  function configProjects(file) {
25931
26060
  let text2;
25932
26061
  try {
25933
- text2 = readFileSync33(file, "utf8");
26062
+ text2 = readFileSync34(file, "utf8");
25934
26063
  } catch {
25935
26064
  return void 0;
25936
26065
  }
25937
- if (extname(file) === ".ts") return /(^|[\s,{])projects\s*:\s*\{/.test(text2) ? [] : void 0;
26066
+ if (extname2(file) === ".ts") return /(^|[\s,{])projects\s*:\s*\{/.test(text2) ? [] : void 0;
25938
26067
  let doc;
25939
26068
  try {
25940
26069
  doc = parseYAMLDocument(text2);
@@ -25981,16 +26110,16 @@ function runViewValidator(dirs = []) {
25981
26110
  for (const from of [...dirs, dirname14(fileURLToPath8(import.meta.url))]) {
25982
26111
  let entry;
25983
26112
  try {
25984
- entry = createRequire7(join45(resolve28(from), "noop.js")).resolve("@intentius/terragucci/report.schema.json");
26113
+ entry = createRequire7(join46(resolve28(from), "noop.js")).resolve("@intentius/terragucci/report.schema.json");
25985
26114
  } catch {
25986
26115
  continue;
25987
26116
  }
25988
26117
  const dist = dirname14(entry);
25989
- const schema = join45(dist, "run.schema.json");
26118
+ const schema = join46(dist, "run.schema.json");
25990
26119
  let stamp;
25991
26120
  try {
25992
26121
  const st = statSync14(schema);
25993
- const pkg = statSync14(join45(dist, "..", "package.json"));
26122
+ const pkg = statSync14(join46(dist, "..", "package.json"));
25994
26123
  stamp = `${schema}\0${st.mtimeMs}:${st.size}\0${pkg.mtimeMs}`;
25995
26124
  } catch {
25996
26125
  continue;
@@ -25999,8 +26128,8 @@ function runViewValidator(dirs = []) {
25999
26128
  if (hit) return hit;
26000
26129
  let v;
26001
26130
  try {
26002
- const version = JSON.parse(readFileSync33(join45(dist, "..", "package.json"), "utf8")).version ?? "";
26003
- const validate = new Ajv20204({ strict: false, allErrors: false }).compile(JSON.parse(readFileSync33(schema, "utf8")));
26131
+ const version = JSON.parse(readFileSync34(join46(dist, "..", "package.json"), "utf8")).version ?? "";
26132
+ const validate = new Ajv20204({ strict: false, allErrors: false }).compile(JSON.parse(readFileSync34(schema, "utf8")));
26004
26133
  v = {
26005
26134
  validation: { by: "schema", terragucci: version },
26006
26135
  check(doc) {
@@ -26055,8 +26184,8 @@ function controlEdges(views) {
26055
26184
  function siblingCheckout(project, base, projectOf = checkoutProject) {
26056
26185
  const name = project.split("/").filter(Boolean).pop();
26057
26186
  if (!name) return void 0;
26058
- const dir = join45(dirname14(resolve28(base)), name);
26059
- if (dir === resolve28(base) || !existsSync26(join45(dir, ".git"))) return void 0;
26187
+ const dir = join46(dirname14(resolve28(base)), name);
26188
+ if (dir === resolve28(base) || !existsSync27(join46(dir, ".git"))) return void 0;
26060
26189
  return projectOf(dir) === project ? dir : void 0;
26061
26190
  }
26062
26191
  var shellWord = (s) => /^[A-Za-z0-9_./:@%+=,-]+$/.test(s) ? s : `'${s.replace(/'/g, `'\\''`)}'`;
@@ -26263,9 +26392,9 @@ function controlRepoInfo(dirs) {
26263
26392
  }
26264
26393
 
26265
26394
  // src/yodel-report.ts
26266
- import { readdirSync as readdirSync15, readFileSync as readFileSync34, statSync as statSync15 } from "node:fs";
26395
+ import { readdirSync as readdirSync16, readFileSync as readFileSync35, statSync as statSync15 } from "node:fs";
26267
26396
  import { createRequire as createRequire8 } from "node:module";
26268
- import { basename as basename4, dirname as dirname15, join as join46, resolve as resolve29 } from "node:path";
26397
+ import { basename as basename4, dirname as dirname15, join as join47, resolve as resolve29 } from "node:path";
26269
26398
  import { fileURLToPath as fileURLToPath9 } from "node:url";
26270
26399
  import { Ajv2020 as Ajv20205 } from "ajv/dist/2020.js";
26271
26400
 
@@ -26694,13 +26823,13 @@ var installed = /* @__PURE__ */ new Map();
26694
26823
  function packageRoot(from) {
26695
26824
  let entry;
26696
26825
  try {
26697
- entry = createRequire8(join46(resolve29(from), "noop.js")).resolve("@intentius/sql-yodeler");
26826
+ entry = createRequire8(join47(resolve29(from), "noop.js")).resolve("@intentius/sql-yodeler");
26698
26827
  } catch {
26699
26828
  return void 0;
26700
26829
  }
26701
26830
  for (let d = dirname15(entry); d !== dirname15(d); d = dirname15(d)) {
26702
26831
  try {
26703
- const pkg = JSON.parse(readFileSync34(join46(d, "package.json"), "utf8"));
26832
+ const pkg = JSON.parse(readFileSync35(join47(d, "package.json"), "utf8"));
26704
26833
  if (pkg.name === "@intentius/sql-yodeler") return d;
26705
26834
  } catch {
26706
26835
  }
@@ -26712,11 +26841,11 @@ function yodelValidator(dirs = []) {
26712
26841
  const root = packageRoot(from);
26713
26842
  if (!root) continue;
26714
26843
  try {
26715
- const version = JSON.parse(readFileSync34(join46(root, "package.json"), "utf8")).version ?? "";
26844
+ const version = JSON.parse(readFileSync35(join47(root, "package.json"), "utf8")).version ?? "";
26716
26845
  const key = `${root}\0${version}`;
26717
26846
  let v = installed.get(key);
26718
26847
  if (!v) {
26719
- const load2 = (n) => JSON.parse(readFileSync34(join46(root, "schemas", `${n}.schema.json`), "utf8"));
26848
+ const load2 = (n) => JSON.parse(readFileSync35(join47(root, "schemas", `${n}.schema.json`), "utf8"));
26720
26849
  v = compile({ common: load2("common"), report: load2("report"), drift: load2("drift") }, { by: "schema", from: "package", sqlYodeler: version });
26721
26850
  installed.set(key, v);
26722
26851
  }
@@ -26738,7 +26867,7 @@ function filesOf(source2) {
26738
26867
  return refuse14(`--yodel-report ${source2}: no such file or directory`, "Point --yodel-report at the file `yodel report --json` wrote, or the directory holding it.");
26739
26868
  }
26740
26869
  const dir = st.isDirectory() ? source2 : dirname15(source2);
26741
- const files = readdirSync15(dir).filter((f) => f.endsWith(".json")).sort().map((f) => join46(dir, f));
26870
+ const files = readdirSync16(dir).filter((f) => f.endsWith(".json")).sort().map((f) => join47(dir, f));
26742
26871
  return st.isDirectory() ? { dir, files } : { dir, files, named: resolve29(source2) };
26743
26872
  }
26744
26873
  function readYodelReport(source2, validator2) {
@@ -26750,7 +26879,7 @@ function readYodelReport(source2, validator2) {
26750
26879
  for (const file of files) {
26751
26880
  let doc;
26752
26881
  try {
26753
- doc = JSON.parse(readFileSync34(file, "utf8"));
26882
+ doc = JSON.parse(readFileSync35(file, "utf8"));
26754
26883
  } catch (e) {
26755
26884
  if (file === named) refuse14(`${basename4(file)} is not JSON: ${e instanceof Error ? e.message : String(e)}`, remedy);
26756
26885
  ignored.push(basename4(file));
@@ -26837,15 +26966,15 @@ function yodelReportRoute(app, source2, dirs) {
26837
26966
 
26838
26967
  // src/demo-pins.ts
26839
26968
  init_terraform_member();
26840
- import { existsSync as existsSync27, lstatSync as lstatSync2, mkdirSync as mkdirSync7, readFileSync as readFileSync35, readlinkSync as readlinkSync2, symlinkSync as symlinkSync2, writeFileSync as writeFileSync6 } from "node:fs";
26841
- import { dirname as dirname16, join as join47, resolve as resolve30 } from "node:path";
26969
+ import { existsSync as existsSync28, lstatSync as lstatSync2, mkdirSync as mkdirSync7, readFileSync as readFileSync36, readlinkSync as readlinkSync2, symlinkSync as symlinkSync2, writeFileSync as writeFileSync6 } from "node:fs";
26970
+ import { dirname as dirname16, join as join48, resolve as resolve30 } from "node:path";
26842
26971
  var isRecord21 = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
26843
26972
  function linkDemoPins(work, probes = {}) {
26844
- const file = join47(work, "chant.workspace.json");
26845
- if (!existsSync27(file)) return { ok: true, linked: [] };
26973
+ const file = join48(work, "chant.workspace.json");
26974
+ if (!existsSync28(file)) return { ok: true, linked: [] };
26846
26975
  let decl;
26847
26976
  try {
26848
- decl = JSON.parse(readFileSync35(file, "utf8"));
26977
+ decl = JSON.parse(readFileSync36(file, "utf8"));
26849
26978
  } catch {
26850
26979
  return { ok: true, linked: [] };
26851
26980
  }
@@ -26868,7 +26997,7 @@ function linkDemoPins(work, probes = {}) {
26868
26997
  remedy: `Install ${pkg} beside behold, then load the demo again.`
26869
26998
  };
26870
26999
  }
26871
- const link = join47(work, "node_modules", ...pkg.split("/"));
27000
+ const link = join48(work, "node_modules", ...pkg.split("/"));
26872
27001
  if (!present(link)) {
26873
27002
  mkdirSync7(dirname16(link), { recursive: true });
26874
27003
  symlinkSync2(found.dir, link, "junction");
@@ -26903,13 +27032,13 @@ function linksTo(link, target) {
26903
27032
  }
26904
27033
 
26905
27034
  // src/demos.ts
26906
- import { readFileSync as readFileSync36, existsSync as existsSync28, cpSync, mkdirSync as mkdirSync8 } from "node:fs";
26907
- import { dirname as dirname17, isAbsolute as isAbsolute5, join as join48, relative as relative10, resolve as resolve31, sep as sep9 } from "node:path";
27035
+ import { readFileSync as readFileSync37, existsSync as existsSync29, cpSync, mkdirSync as mkdirSync8 } from "node:fs";
27036
+ import { dirname as dirname17, isAbsolute as isAbsolute5, join as join49, relative as relative10, resolve as resolve31, sep as sep9 } from "node:path";
26908
27037
  import { spawn as spawn8, spawnSync as spawnSync3 } from "node:child_process";
26909
27038
  function readCatalog(file, catalog) {
26910
27039
  let raw;
26911
27040
  try {
26912
- raw = JSON.parse(readFileSync36(file, "utf8"));
27041
+ raw = JSON.parse(readFileSync37(file, "utf8"));
26913
27042
  } catch {
26914
27043
  return [];
26915
27044
  }
@@ -26949,10 +27078,10 @@ function validEntry(e) {
26949
27078
  return true;
26950
27079
  }
26951
27080
  function loadDemoRegistry(pkgRoot3) {
26952
- const merged = readCatalog(join48(pkgRoot3, "demos.json"), "demos");
27081
+ const merged = readCatalog(join49(pkgRoot3, "demos.json"), "demos");
26953
27082
  const seen = new Set(merged.map((e) => e.name));
26954
27083
  const named = process.env.BEHOLD_WORKBENCH;
26955
- for (const e of [...readCatalog(join48(pkgRoot3, "workbench.json"), "workbench"), ...named ? readCatalog(resolve31(named), "workbench") : []]) {
27084
+ for (const e of [...readCatalog(join49(pkgRoot3, "workbench.json"), "workbench"), ...named ? readCatalog(resolve31(named), "workbench") : []]) {
26956
27085
  if (seen.has(e.name)) {
26957
27086
  process.stderr.write(`behold: workbench entry "${e.name}" collides with a demo already in the catalog \u2014 dropped
26958
27087
  `);
@@ -26971,11 +27100,11 @@ function missingRequirements(entry) {
26971
27100
  const bins = entry.source === "git" && !entry.requires.includes("git") ? [...entry.requires, "git"] : entry.requires;
26972
27101
  const finder = process.platform === "win32" ? "where" : "which";
26973
27102
  const missing = bins.filter((bin) => {
26974
- if (bin === "choudoufu" && process.env.CHOUDOUFU_BIN && existsSync28(process.env.CHOUDOUFU_BIN)) return false;
27103
+ if (bin === "choudoufu" && process.env.CHOUDOUFU_BIN && existsSync29(process.env.CHOUDOUFU_BIN)) return false;
26975
27104
  return spawnSync3(finder, [bin], { stdio: "ignore" }).status !== 0;
26976
27105
  });
26977
27106
  const local = demoLocalPath(entry);
26978
- if (local && !existsSync28(local)) missing.push(`${entry.path} (not checked out)`);
27107
+ if (local && !existsSync29(local)) missing.push(`${entry.path} (not checked out)`);
26979
27108
  return missing;
26980
27109
  }
26981
27110
  function fetchesFromNetwork(entry) {
@@ -26985,7 +27114,7 @@ function demoTargetDir(entry, cwd = process.cwd()) {
26985
27114
  const inPlace = entry.inPlace ? demoLocalPath(entry) : void 0;
26986
27115
  if (inPlace) return inPlace;
26987
27116
  const legacy = resolve31(cwd, "behold-demo");
26988
- if (entry.name === "writes" && existsSync28(legacy)) return legacy;
27117
+ if (entry.name === "writes" && existsSync29(legacy)) return legacy;
26989
27118
  return resolve31(cwd, "behold-demos", entry.name);
26990
27119
  }
26991
27120
  async function loadDemo(entry, opts) {
@@ -26995,12 +27124,12 @@ async function loadDemo(entry, opts) {
26995
27124
  const inPlace = entry.source === "local" && entry.inPlace;
26996
27125
  const work = inPlace ? local : target;
26997
27126
  if (inPlace) {
26998
- if (!existsSync28(work)) return { ok: false, error: `${entry.path} is not checked out (looked in ${work})` };
27127
+ if (!existsSync29(work)) return { ok: false, error: `${entry.path} is not checked out (looked in ${work})` };
26999
27128
  say(`serving ${work} where it is \u2014 nothing copied`);
27000
- } else if (!existsSync28(target)) {
27129
+ } else if (!existsSync29(target)) {
27001
27130
  if (entry.source === "bundled" || entry.source === "local" && local) {
27002
- const from = entry.source === "bundled" ? join48(pkgRoot3, entry.dir) : local;
27003
- if (!existsSync28(from)) return { ok: false, error: entry.source === "bundled" ? `this install has no bundled ${entry.dir}` : `${entry.path} is not checked out (looked in ${from})` };
27131
+ const from = entry.source === "bundled" ? join49(pkgRoot3, entry.dir) : local;
27132
+ if (!existsSync29(from)) return { ok: false, error: entry.source === "bundled" ? `this install has no bundled ${entry.dir}` : `${entry.path} is not checked out (looked in ${from})` };
27004
27133
  say(`copying to ${target} (it's yours \u2014 edit it)`);
27005
27134
  try {
27006
27135
  cpSync(from, target, {
@@ -27031,7 +27160,7 @@ async function loadDemo(entry, opts) {
27031
27160
  if (!pins.ok) return { ok: false, error: `${pins.error} ${pins.remedy}` };
27032
27161
  for (const p of pins.linked) say(`linked ${p.pkg} ${p.version} into the copy${p.was ? ` (the declaration pinned ${p.was}; now ${p.version})` : ""}`);
27033
27162
  }
27034
- if (!inPlace && existsSync28(join48(work, "package.json")) && !existsSync28(join48(work, "node_modules"))) {
27163
+ if (!inPlace && existsSync29(join49(work, "package.json")) && !existsSync29(join49(work, "node_modules"))) {
27035
27164
  say("npm install\u2026");
27036
27165
  if (await runStep("npm", ["install"], { cwd: work, shell: process.platform === "win32" }) !== 0) {
27037
27166
  return { ok: false, error: `npm install failed in ${work}` };
@@ -27048,7 +27177,7 @@ async function loadDemo(entry, opts) {
27048
27177
  return { ok: false, error: `setup failed (${entry.setup})` };
27049
27178
  }
27050
27179
  }
27051
- return { ok: true, serveDirs: entry.serve.dirs?.length ? entry.serve.dirs.map((d) => join48(work, d)) : [work] };
27180
+ return { ok: true, serveDirs: entry.serve.dirs?.length ? entry.serve.dirs.map((d) => join49(work, d)) : [work] };
27052
27181
  }
27053
27182
  function runStep(cmd, args, opts = {}) {
27054
27183
  return new Promise((res) => {
@@ -27059,8 +27188,8 @@ function runStep(cmd, args, opts = {}) {
27059
27188
  }
27060
27189
 
27061
27190
  // src/server.ts
27062
- var pkgRoot = join49(dirname18(fileURLToPath10(import.meta.url)), "..");
27063
- var webRoot = join49(pkgRoot, "web");
27191
+ var pkgRoot = join50(dirname18(fileURLToPath10(import.meta.url)), "..");
27192
+ var webRoot = join50(pkgRoot, "web");
27064
27193
  var execFileP = async (cmd, args) => (await promisify3(execFile5)(cmd, args, { encoding: "utf8", timeout: 1e4 })).stdout;
27065
27194
  function optsFromQuery(url, tierEnvVar, projectDir) {
27066
27195
  const q = url.searchParams;
@@ -27111,7 +27240,7 @@ function tierFailure(tier, message2) {
27111
27240
  function beholdVersion() {
27112
27241
  try {
27113
27242
  const here = dirname18(fileURLToPath10(import.meta.url));
27114
- return JSON.parse(readFileSync37(join49(here, "..", "package.json"), "utf8")).version ?? "unknown";
27243
+ return JSON.parse(readFileSync38(join50(here, "..", "package.json"), "utf8")).version ?? "unknown";
27115
27244
  } catch {
27116
27245
  return "unknown";
27117
27246
  }
@@ -27158,7 +27287,7 @@ async function captureFrame(projectDir, env, frames, broadcaster) {
27158
27287
  }
27159
27288
  }
27160
27289
  function carveRoutes(app, reportPath, demo) {
27161
- const load2 = () => readCarveReport(reportPath, (p) => readFileSync37(p, "utf8"));
27290
+ const load2 = () => readCarveReport(reportPath, (p) => readFileSync38(p, "utf8"));
27162
27291
  const carveDirs = [dirname18(reportPath), ...demo ? [demo.out] : []];
27163
27292
  const carveStates = () => readCarveStates(carveDirs, nodeCarveIo, 0);
27164
27293
  const emittedNodes = async (states) => {
@@ -27550,8 +27679,8 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
27550
27679
  if (!sub) return c.json({ error: `unknown substrate "${name}"` }, 404);
27551
27680
  if (!sub.bringUp) return c.json({ error: `no bring-up available for "${name}"` }, 400);
27552
27681
  const { label, cmd, args } = sub.bringUp;
27553
- const PIPELINE_FORGES = { "gitlab-ci": "gitlab", forgejo: "forgejo" };
27554
- const forge = PIPELINE_FORGES[name];
27682
+ const PIPELINE_FORGES2 = { "gitlab-ci": "gitlab", forgejo: "forgejo" };
27683
+ const forge = PIPELINE_FORGES2[name];
27555
27684
  if (forge) {
27556
27685
  const parsed = await ciPipeline(cfg.projectDir, { env: cfg.env }, forge).catch(() => void 0);
27557
27686
  if (parsed && parsed.jobs.length > 0) {
@@ -27567,9 +27696,9 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
27567
27696
  return c.json({ started: true, name, ran: label });
27568
27697
  });
27569
27698
  app.post("/api/local/reset", (c) => {
27570
- const down = join49(cfg.projectDir, "scripts/local/local-down.sh");
27571
- const up = join49(cfg.projectDir, "scripts/local/local-up.sh");
27572
- if (!existsSync29(down) || !existsSync29(up)) {
27699
+ const down = join50(cfg.projectDir, "scripts/local/local-down.sh");
27700
+ const up = join50(cfg.projectDir, "scripts/local/local-up.sh");
27701
+ if (!existsSync30(down) || !existsSync30(up)) {
27573
27702
  return c.json({ error: "no local-down.sh / local-up.sh in scripts/local \u2014 reset is only for local emulator projects" }, 400);
27574
27703
  }
27575
27704
  if (!runner.bringUp("reset local emulator", "bash", ["-c", "bash scripts/local/local-down.sh && bash scripts/local/local-up.sh"], cfg.projectDir)) {
@@ -27590,7 +27719,7 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
27590
27719
  const dirs = [];
27591
27720
  const declared = [];
27592
27721
  for (const f of discoverOpIrs(estateDirs)) {
27593
- const parsed = readOpIr(f.path, (p) => readFileSync37(p, "utf8"));
27722
+ const parsed = readOpIr(f.path, (p) => readFileSync38(p, "utf8"));
27594
27723
  if (!parsed.ok) continue;
27595
27724
  const mine = declaredConvergeOps([parsed.ir]);
27596
27725
  if (!mine.length) continue;
@@ -27820,7 +27949,9 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
27820
27949
  const decl = servedTerragucciComponents();
27821
27950
  if (!decl) return {};
27822
27951
  const waves = decl.pipeline.jobs.filter((j) => typeof j.wave === "number").map((j) => ({ job: j.name, wave: j.wave, roots: [...j.applies] }));
27823
- return { terragucciRoots: { roots: Object.keys(decl.roots).sort(), waves } };
27952
+ const tools = repoTools(cfg.projectDir, tgConfig());
27953
+ const rootTools2 = declaredRootTools(cfg.projectDir, decl.roots);
27954
+ return { terragucciRoots: { roots: Object.keys(decl.roots).sort(), waves, ...tools.length ? { tools } : {}, ...Object.keys(rootTools2).length ? { rootTools: rootTools2 } : {} } };
27824
27955
  })(),
27825
27956
  // #517: a SQL Yodeler repo is migrated by its pipeline; same contract.
27826
27957
  ...(() => {
@@ -27896,8 +28027,8 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
27896
28027
  if (cfg.previewMode) return c.json({ error: "switching projects is locked in preview mode" }, 403);
27897
28028
  const body = await c.req.json().catch(() => ({}));
27898
28029
  const dir = typeof body.dir === "string" && body.dir.trim() ? resolve32(body.dir.trim()) : "";
27899
- if (!dir || !existsSync29(dir)) return c.json({ error: `no such directory: ${dir || "(no dir given)"}` }, 400);
27900
- if (!existsSync29(join49(dir, "chant.config.ts"))) {
28030
+ if (!dir || !existsSync30(dir)) return c.json({ error: `no such directory: ${dir || "(no dir given)"}` }, 400);
28031
+ if (!existsSync30(join50(dir, "chant.config.ts"))) {
27901
28032
  return c.json({ error: `${dir} doesn't look like a chant project \u2014 no chant.config.ts` }, 400);
27902
28033
  }
27903
28034
  switchServedProject([dir]);
@@ -27948,7 +28079,7 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
27948
28079
  fetches: fetchesFromNetwork(e),
27949
28080
  ...e.repo ? { repo: e.repo } : {},
27950
28081
  target,
27951
- loaded: existsSync29(target),
28082
+ loaded: existsSync30(target),
27952
28083
  satisfiable: missing.length === 0,
27953
28084
  // #254: the carve walkthrough runs fine here — it just isn't a project
27954
28085
  // to switch INTO. Carve mode claims `/api/graph` and `/api/project` at
@@ -28164,6 +28295,9 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
28164
28295
  const { project } = terraformMemberProject(cfg.projectDir);
28165
28296
  const ir = await componentGraphIr(project, tierTargetOpts(opts));
28166
28297
  const titles = waveTitles(ir, decl);
28298
+ const forge = pipelineForge(decl, cfg.projectDir, tgConfig());
28299
+ const tools = repoTools(cfg.projectDir, tgConfig());
28300
+ const rootToolsByName = declaredRootTools(cfg.projectDir, decl.roots);
28167
28301
  const { svg } = renderGraph(ir, { waveTitles: titles });
28168
28302
  const waves = Object.keys(ir.groups.byWave ?? {}).length;
28169
28303
  const noun = hasTerragruntUnits(cfg.projectDir) ? "unit" : "root";
@@ -28181,7 +28315,11 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
28181
28315
  // The CI facet's source on a terragucci repo: the declared jobs, not a
28182
28316
  // chant-generated pipeline (`/api/ci`, which a public view refuses).
28183
28317
  terragucciComponents: {
28184
- ...decl.pipeline.forge ? { forge: decl.pipeline.forge } : {},
28318
+ // behold#571: the forge, and what said so, for each wave box's mark (web/forge-mark.js).
28319
+ ...forge ? { forge: forge.forge, forgeFrom: forge.from } : decl.pipeline.forge ? { forge: decl.pipeline.forge } : {},
28320
+ ...tools.length ? { tools } : {},
28321
+ // behold#571: the tools a root carries inside it (a SQL Yodeler project), by root name.
28322
+ ...Object.keys(rootToolsByName).length ? { rootTools: rootToolsByName } : {},
28185
28323
  ...decl.pipeline.path ? { pipeline: decl.pipeline.path } : {},
28186
28324
  jobs: Object.values(componentJobs(decl)),
28187
28325
  // component -> the root it applies: the live marks' join onto the
@@ -28245,7 +28383,7 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
28245
28383
  }
28246
28384
  const parsedOps = [];
28247
28385
  for (const f of files) {
28248
- const parsed = readOpIr(f.path, (p) => readFileSync37(p, "utf8"));
28386
+ const parsed = readOpIr(f.path, (p) => readFileSync38(p, "utf8"));
28249
28387
  if (!parsed.ok) return c.json(parsed.refusal, 422);
28250
28388
  parsedOps.push(parsed.ir);
28251
28389
  }
@@ -28258,8 +28396,8 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
28258
28396
  }
28259
28397
  const runState = runner.runState;
28260
28398
  const ranOp = runState.op ? parsedOps.find((o) => o.name === runState.op) : void 0;
28261
- const join54 = ranOp ? joinRun(ranOp, runState.records, runState.gate) : null;
28262
- const opsIr = join54 ? paintPlayhead(declaredIr, join54, runState.gate) : declaredIr;
28399
+ const join55 = ranOp ? joinRun(ranOp, runState.records, runState.gate) : null;
28400
+ const opsIr = join55 ? paintPlayhead(declaredIr, join55, runState.gate) : declaredIr;
28263
28401
  const { svg: svg2 } = renderGraph(opsIr, { boxes: "byStack" });
28264
28402
  const operator = runner.noteDeclaredConvergeOps(declaredConvergeOps(parsedOps));
28265
28403
  return c.json({
@@ -28272,7 +28410,7 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
28272
28410
  target: null,
28273
28411
  mode: "ops",
28274
28412
  ops: parsedOps.length,
28275
- note: `${opsNote(parsedOps, opsIr)} ${playheadNote(runState, join54)} ${operatorNote(operator)}`,
28413
+ note: `${opsNote(parsedOps, opsIr)} ${playheadNote(runState, join55)} ${operatorNote(operator)}`,
28276
28414
  // The operator strip's own model: the ConvergeOps this project
28277
28415
  // declares, plus whatever the last status read said. `declared`
28278
28416
  // without a `strip` is the honest starting state — a loop exists and
@@ -28385,7 +28523,7 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
28385
28523
  srcCompositeEdgesAttached = 0;
28386
28524
  }
28387
28525
  }
28388
- if (!multi && !components && !logical && !opts.lens && !ownKindVia && ir.nodes.length === 0 && !existsSync29(join49(cfg.projectDir, "chant.config.ts"))) {
28526
+ if (!multi && !components && !logical && !opts.lens && !ownKindVia && ir.nodes.length === 0 && !existsSync30(join50(cfg.projectDir, "chant.config.ts"))) {
28389
28527
  return c.json(noProjectError(cfg.projectDir), 404);
28390
28528
  }
28391
28529
  const radial = new URL(c.req.url).searchParams.get("radial") === "1";
@@ -29024,7 +29162,7 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
29024
29162
  if (!c.req.path.startsWith("/api/") && c.res.ok && !c.res.headers.has("cache-control")) c.res.headers.set("cache-control", "no-cache");
29025
29163
  });
29026
29164
  app.use("/*", serveStatic({ root: rel }));
29027
- app.get("/", serveStatic({ path: join49(rel, "index.html") }));
29165
+ app.get("/", serveStatic({ path: join50(rel, "index.html") }));
29028
29166
  if (cfg.terragucci) vendorFallback(app);
29029
29167
  return app;
29030
29168
  }
@@ -29054,7 +29192,7 @@ async function bootLocalEmulators(dir, who) {
29054
29192
  async function startServer(cfg) {
29055
29193
  if (cfg.local) cfg.emulators = await bootLocalEmulators(cfg.projectDir, "behold serve --local");
29056
29194
  for (const dir of cfg.projectDirs ?? [cfg.projectDir]) {
29057
- if (existsSync29(join49(dir, "chant.config.ts"))) addRecent(dir);
29195
+ if (existsSync30(join50(dir, "chant.config.ts"))) addRecent(dir);
29058
29196
  }
29059
29197
  const broadcaster = new Broadcaster();
29060
29198
  const frames = new FrameBuffer();
@@ -29229,8 +29367,8 @@ init_chant();
29229
29367
 
29230
29368
  // src/workspace-convert.ts
29231
29369
  init_chant();
29232
- import { existsSync as existsSync30, mkdirSync as mkdirSync9, readFileSync as readFileSync38, renameSync as renameSync2, writeFileSync as writeFileSync7 } from "node:fs";
29233
- import { basename as basename6, dirname as dirname19, join as join50, relative as relative12, resolve as resolve33, sep as sep11 } from "node:path";
29370
+ import { existsSync as existsSync31, mkdirSync as mkdirSync9, readFileSync as readFileSync39, renameSync as renameSync2, writeFileSync as writeFileSync7 } from "node:fs";
29371
+ import { basename as basename6, dirname as dirname19, join as join51, relative as relative12, resolve as resolve33, sep as sep11 } from "node:path";
29234
29372
  import { shortStackNames as shortStackNames2 } from "@intentius/pinhole";
29235
29373
  init_project();
29236
29374
  init_terraform_member();
@@ -29248,10 +29386,10 @@ function unique(name, taken) {
29248
29386
  var posix5 = (p) => p.split(sep11).join("/");
29249
29387
  function installedVersion(pkg, dir) {
29250
29388
  for (let at2 = resolve33(dir); ; at2 = dirname19(at2)) {
29251
- const manifest = join50(at2, "node_modules", ...pkg.split("/"), "package.json");
29252
- if (existsSync30(manifest)) {
29389
+ const manifest = join51(at2, "node_modules", ...pkg.split("/"), "package.json");
29390
+ if (existsSync31(manifest)) {
29253
29391
  try {
29254
- const v = JSON.parse(readFileSync38(manifest, "utf8")).version;
29392
+ const v = JSON.parse(readFileSync39(manifest, "utf8")).version;
29255
29393
  return typeof v === "string" ? v : void 0;
29256
29394
  } catch {
29257
29395
  return void 0;
@@ -29262,7 +29400,7 @@ function installedVersion(pkg, dir) {
29262
29400
  }
29263
29401
  function planConversion(rootArg) {
29264
29402
  const root = resolve33(rootArg);
29265
- const existing = DECLARATION_FILES.find((f) => existsSync30(join50(root, f)));
29403
+ const existing = DECLARATION_FILES.find((f) => existsSync31(join51(root, f)));
29266
29404
  if (existing) return { ok: false, error: `${root} already has ${existing}; there is nothing to convert.` };
29267
29405
  const shape = detectProjectShape(root);
29268
29406
  if (shape.kind !== "estate" || !shape.members?.length || shape.membersFrom === "itself") {
@@ -29283,10 +29421,10 @@ function planConversion(rootArg) {
29283
29421
  const scan = discoverTerraformRoots(abs[i]);
29284
29422
  for (const r of scan.roots) {
29285
29423
  const name2 = unique(declarationName(r.name), taken);
29286
- members.push({ name: name2, dir: r.dir === "." ? dir : posix5(join50(dir, r.dir)), kind: "terraform" });
29424
+ members.push({ name: name2, dir: r.dir === "." ? dir : posix5(join51(dir, r.dir)), kind: "terraform" });
29287
29425
  moves.push({ from: `${short}/${r.name}/`, to: `${name2}/${name2}/` });
29288
29426
  }
29289
- for (const s of scan.skipped) notes.push(`${posix5(join50(dir, s.dir))} is not declared: ${s.why}.`);
29427
+ for (const s of scan.skipped) notes.push(`${posix5(join51(dir, s.dir))} is not declared: ${s.why}.`);
29290
29428
  if (scan.roots.length > 1) notes.push(`${dir} held ${scan.roots.length} Terraform roots; each is its own member now, since a chant terraform member is one root.`);
29291
29429
  return;
29292
29430
  }
@@ -29314,7 +29452,7 @@ function planConversion(rootArg) {
29314
29452
  };
29315
29453
  const firstLayout = layoutPath(abs[0]);
29316
29454
  moves.sort((a, b) => b.from.length - a.from.length);
29317
- return { ok: true, plan: { root, from: shape.membersFrom === "behold-config" ? "behold-config" : "workspaces", declaration, moves, ...existsSync30(firstLayout) ? { layoutFrom: firstLayout } : {}, notes } };
29455
+ return { ok: true, plan: { root, from: shape.membersFrom === "behold-config" ? "behold-config" : "workspaces", declaration, moves, ...existsSync31(firstLayout) ? { layoutFrom: firstLayout } : {}, notes } };
29318
29456
  }
29319
29457
  function moveLayoutIds(file, moves) {
29320
29458
  const lenses = {};
@@ -29329,18 +29467,18 @@ function moveLayoutIds(file, moves) {
29329
29467
  return { version: 1, lenses };
29330
29468
  }
29331
29469
  function applyConversion(plan) {
29332
- const declarationFile = join50(plan.root, DECLARATION_FILES[0]);
29333
- if (existsSync30(declarationFile)) throw new Error(`${declarationFile} appeared while converting; nothing was written`);
29470
+ const declarationFile = join51(plan.root, DECLARATION_FILES[0]);
29471
+ if (existsSync31(declarationFile)) throw new Error(`${declarationFile} appeared while converting; nothing was written`);
29334
29472
  writeFileSync7(declarationFile, `${JSON.stringify(plan.declaration, null, 2)}
29335
29473
  `);
29336
29474
  let layout;
29337
29475
  const target = layoutPath(plan.root);
29338
29476
  if (!plan.layoutFrom) layout = { skipped: "no saved layout to move" };
29339
29477
  else if (resolve33(plan.layoutFrom) === resolve33(target)) layout = { skipped: "the saved layout is already in the root" };
29340
- else if (existsSync30(target)) layout = { skipped: `${target} already exists; the layout in ${plan.layoutFrom} was left alone` };
29478
+ else if (existsSync31(target)) layout = { skipped: `${target} already exists; the layout in ${plan.layoutFrom} was left alone` };
29341
29479
  else {
29342
29480
  const moved = moveLayoutIds(readLayoutFile(dirname19(dirname19(plan.layoutFrom))), plan.moves);
29343
- mkdirSync9(join50(plan.root, LAYOUT_DIR), { recursive: true });
29481
+ mkdirSync9(join51(plan.root, LAYOUT_DIR), { recursive: true });
29344
29482
  const tmp = `${target}.tmp`;
29345
29483
  writeFileSync7(tmp, `${JSON.stringify(moved, null, 2)}
29346
29484
  `);
@@ -29351,9 +29489,9 @@ function applyConversion(plan) {
29351
29489
  }
29352
29490
 
29353
29491
  // src/export.ts
29354
- import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync8, copyFileSync, cpSync as cpSync2, readFileSync as readFileSync39, readdirSync as readdirSync16, existsSync as existsSync31, realpathSync as realpathSync2 } from "node:fs";
29492
+ import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync8, copyFileSync, cpSync as cpSync2, readFileSync as readFileSync40, readdirSync as readdirSync17, existsSync as existsSync32, realpathSync as realpathSync2 } from "node:fs";
29355
29493
  import { homedir as homedir3 } from "node:os";
29356
- import { join as join51, dirname as dirname20, basename as basename7, relative as relative13, resolve as resolve34, sep as sep12 } from "node:path";
29494
+ import { join as join52, dirname as dirname20, basename as basename7, relative as relative13, resolve as resolve34, sep as sep12 } from "node:path";
29357
29495
  import { createHash as createHash11 } from "node:crypto";
29358
29496
  import { fileURLToPath as fileURLToPath11 } from "node:url";
29359
29497
  var LENS_PARAMS = ["collapse", "components", "detail", "env", "logical", "ops", "radial", "stacks", "tier"];
@@ -29410,24 +29548,24 @@ function captureKeys(axes) {
29410
29548
  return [...keys];
29411
29549
  }
29412
29550
  function webDir() {
29413
- return join51(dirname20(fileURLToPath11(import.meta.url)), "..", "web");
29551
+ return join52(dirname20(fileURLToPath11(import.meta.url)), "..", "web");
29414
29552
  }
29415
29553
  function pkgRoot2() {
29416
- return join51(dirname20(fileURLToPath11(import.meta.url)), "..");
29554
+ return join52(dirname20(fileURLToPath11(import.meta.url)), "..");
29417
29555
  }
29418
29556
  var NOTICE_FILES = ["LICENSE", "THIRD_PARTY.md"];
29419
29557
  function copyNotices(outDir, root = pkgRoot2()) {
29420
29558
  const copied = [];
29421
29559
  for (const f of NOTICE_FILES) {
29422
- if (!existsSync31(join51(root, f))) continue;
29423
- copyFileSync(join51(root, f), join51(outDir, f));
29560
+ if (!existsSync32(join52(root, f))) continue;
29561
+ copyFileSync(join52(root, f), join52(outDir, f));
29424
29562
  copied.push(f);
29425
29563
  }
29426
- const lic = join51(root, "licenses");
29427
- if (existsSync31(lic)) {
29428
- mkdirSync10(join51(outDir, "licenses"), { recursive: true });
29429
- for (const f of readdirSync16(lic)) {
29430
- copyFileSync(join51(lic, f), join51(outDir, "licenses", f));
29564
+ const lic = join52(root, "licenses");
29565
+ if (existsSync32(lic)) {
29566
+ mkdirSync10(join52(outDir, "licenses"), { recursive: true });
29567
+ for (const f of readdirSync17(lic)) {
29568
+ copyFileSync(join52(lic, f), join52(outDir, "licenses", f));
29431
29569
  copied.push(`licenses/${f}`);
29432
29570
  }
29433
29571
  }
@@ -29452,7 +29590,7 @@ async function runExport(cfg, outDir, opts = {}) {
29452
29590
  ...proj.sqlYodeler ? { sqlYodeler: true } : {}
29453
29591
  };
29454
29592
  const scrub = exportScrubber(cfg);
29455
- const snapDir = join51(outDir, "snapshots");
29593
+ const snapDir = join52(outDir, "snapshots");
29456
29594
  mkdirSync10(snapDir, { recursive: true });
29457
29595
  const keyToFile = {};
29458
29596
  let ok = 0;
@@ -29461,7 +29599,7 @@ async function runExport(cfg, outDir, opts = {}) {
29461
29599
  const res = await app.request(`${key}${key.includes("?") ? "&" : "?"}layout=1`);
29462
29600
  const body = scrub(shapeSnapshot(key, await res.text(), opts));
29463
29601
  const file = slug3(key, body);
29464
- writeFileSync8(join51(snapDir, file), body);
29602
+ writeFileSync8(join52(snapDir, file), body);
29465
29603
  keyToFile[key] = `snapshots/${file}`;
29466
29604
  if (res.ok) ok++;
29467
29605
  else failed++;
@@ -29483,29 +29621,29 @@ async function runExport(cfg, outDir, opts = {}) {
29483
29621
  axes,
29484
29622
  keyToFile
29485
29623
  };
29486
- writeFileSync8(join51(outDir, "manifest.json"), JSON.stringify(manifest, null, 2));
29487
- const html = readFileSync39(join51(webDir(), "index.html"), "utf8").replace(
29624
+ writeFileSync8(join52(outDir, "manifest.json"), JSON.stringify(manifest, null, 2));
29625
+ const html = readFileSync40(join52(webDir(), "index.html"), "utf8").replace(
29488
29626
  /<\/head>/i,
29489
29627
  ` <script>window.__BEHOLD_STATIC__ = true;</script>
29490
29628
  </head>`
29491
29629
  );
29492
- writeFileSync8(join51(outDir, "index.html"), html);
29493
- for (const f of readdirSync16(webDir())) {
29630
+ writeFileSync8(join52(outDir, "index.html"), html);
29631
+ for (const f of readdirSync17(webDir())) {
29494
29632
  if (f === "index.html" || f.endsWith(".test.js")) continue;
29495
- cpSync2(join51(webDir(), f), join51(outDir, f), { recursive: true });
29633
+ cpSync2(join52(webDir(), f), join52(outDir, f), { recursive: true });
29496
29634
  }
29497
- writeFileSync8(join51(outDir, "README.md"), BUNDLE_README);
29635
+ writeFileSync8(join52(outDir, "README.md"), BUNDLE_README);
29498
29636
  copyNotices(outDir);
29499
29637
  const name = workerName(cfg.projectDir, opts.name);
29500
29638
  writeFileSync8(
29501
- join51(outDir, "wrangler.jsonc"),
29639
+ join52(outDir, "wrangler.jsonc"),
29502
29640
  JSON.stringify(
29503
29641
  { $schema: "node_modules/wrangler/config-schema.json", name, compatibility_date: "2025-06-01", assets: { directory: "." } },
29504
29642
  null,
29505
29643
  2
29506
29644
  ) + "\n"
29507
29645
  );
29508
- writeFileSync8(join51(outDir, "manifest.json"), JSON.stringify({ ...manifest, files: bundleFiles(outDir).filter((f) => f !== "manifest.json") }, null, 2));
29646
+ writeFileSync8(join52(outDir, "manifest.json"), JSON.stringify({ ...manifest, files: bundleFiles(outDir).filter((f) => f !== "manifest.json") }, null, 2));
29509
29647
  process.stdout.write(
29510
29648
  `behold export \u2192 ${outDir}
29511
29649
  ${ok} snapshots${failed ? ` (${failed} endpoint error(s) captured as-is)` : ""}
@@ -29602,7 +29740,7 @@ function manifestFiles(text2) {
29602
29740
  return Object.values(map).filter((f) => typeof f === "string" && /^snapshots\/[A-Za-z0-9=_.-]+$/.test(f) && !f.includes(".."));
29603
29741
  }
29604
29742
  function bundleFiles(outDir) {
29605
- return readdirSync16(outDir, { recursive: true, withFileTypes: true }).filter((d) => d.isFile()).map((d) => relative13(outDir, join51(d.parentPath, d.name)).split(sep12).join("/")).sort();
29743
+ return readdirSync17(outDir, { recursive: true, withFileTypes: true }).filter((d) => d.isFile()).map((d) => relative13(outDir, join52(d.parentPath, d.name)).split(sep12).join("/")).sort();
29606
29744
  }
29607
29745
  async function publishBundle(outDir, target, client) {
29608
29746
  const files = bundleFiles(outDir);
@@ -29618,7 +29756,7 @@ async function publishBundle(outDir, target, client) {
29618
29756
  }
29619
29757
  const last = ["manifest.json", "index.html"];
29620
29758
  const order = [...files.filter((f) => !last.includes(f)), ...last.filter((f) => files.includes(f))];
29621
- for (const f of order) await client.put(at2(f), readFileSync39(join51(outDir, f)), contentType(f), CONTENT_ADDRESSED.test(f) ? IMMUTABLE : NO_CACHE);
29759
+ for (const f of order) await client.put(at2(f), readFileSync40(join52(outDir, f)), contentType(f), CONTENT_ADDRESSED.test(f) ? IMMUTABLE : NO_CACHE);
29622
29760
  const wrote = new Set(files);
29623
29761
  const removed = [];
29624
29762
  for (const f of previous) {
@@ -29670,8 +29808,8 @@ It's just files \u2014 GitHub Pages, S3, nginx, or Cloudflare Pages
29670
29808
 
29671
29809
  // src/publish-snapshots.ts
29672
29810
  import { execFileSync as execFileSync4 } from "node:child_process";
29673
- import { readFileSync as readFileSync40 } from "node:fs";
29674
- import { join as join52 } from "node:path";
29811
+ import { readFileSync as readFileSync41 } from "node:fs";
29812
+ import { join as join53 } from "node:path";
29675
29813
  var DEFAULT_KEEP = 30;
29676
29814
  var SNAPSHOT_REPORTS_BASE = "../../../";
29677
29815
  var COMMIT = /^[0-9a-f]{7,64}$/;
@@ -29759,7 +29897,7 @@ async function publishSnapshot(outDir, target, commit, client, opts = {}) {
29759
29897
  const keep = opts.keep ?? DEFAULT_KEEP;
29760
29898
  if (!Number.isInteger(keep) || keep < 1) throw new Error(`--keep takes a whole number of at least 1, not ${keep}`);
29761
29899
  const at2 = (f) => `${target.prefix}/${f}`;
29762
- const local = JSON.parse(readFileSync40(join52(outDir, "manifest.json"), "utf8"));
29900
+ const local = JSON.parse(readFileSync41(join53(outDir, "manifest.json"), "utf8"));
29763
29901
  const generated = local.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString();
29764
29902
  const entry = { commit: sha, at: commit.at ?? generated, project: opts.project ?? local.projectDir ?? "", generated };
29765
29903
  const bundle = await publishBundle(outDir, { bucket: target.bucket, prefix: at2(sha) }, client);
@@ -30260,7 +30398,7 @@ function warnIfNotChantProject(dir) {
30260
30398
  if (shape.kind === "estate") {
30261
30399
  process.stderr.write(
30262
30400
  `behold: warning \u2014 ${dir} is an estate root, not a chant project itself.
30263
- Serve its members composed: behold serve ${shape.members.map((m) => join53(dir, m.dir)).join(" ")}
30401
+ Serve its members composed: behold serve ${shape.members.map((m) => join54(dir, m.dir)).join(" ")}
30264
30402
  `
30265
30403
  );
30266
30404
  return;
@@ -30296,7 +30434,7 @@ async function runCarve(rest) {
30296
30434
  process.exit(2);
30297
30435
  }
30298
30436
  const reportPath = resolve35(fileArg);
30299
- const parsed = readCarveReport(reportPath, (p) => readFileSync41(p, "utf8"));
30437
+ const parsed = readCarveReport(reportPath, (p) => readFileSync42(p, "utf8"));
30300
30438
  if (!parsed.ok) {
30301
30439
  process.stderr.write(`behold carve: ${parsed.refusal.error}
30302
30440
  ${parsed.refusal.remedy}
@@ -30325,7 +30463,7 @@ async function runDoctor(rest) {
30325
30463
  }
30326
30464
  }
30327
30465
  const dir = dirArg ?? ".";
30328
- if (!existsSync32(resolve35(dir))) {
30466
+ if (!existsSync33(resolve35(dir))) {
30329
30467
  process.stderr.write(`behold doctor: no such directory: ${resolve35(dir)}
30330
30468
  `);
30331
30469
  process.exit(2);
@@ -30362,7 +30500,7 @@ ${check.stdout || check.stderr}
30362
30500
  if (check.code !== 0) process.exitCode = 1;
30363
30501
  }
30364
30502
  async function runDemo(rest) {
30365
- const pkgRoot3 = join53(dirname21(fileURLToPath12(import.meta.url)), "..");
30503
+ const pkgRoot3 = join54(dirname21(fileURLToPath12(import.meta.url)), "..");
30366
30504
  const registry2 = loadDemoRegistry(pkgRoot3);
30367
30505
  let port = 4600;
30368
30506
  let live2 = false;
@@ -30497,7 +30635,7 @@ async function serveCarveDemo(target, carve, port, live2 = false) {
30497
30635
  };
30498
30636
  process.stdout.write("behold demo carve --live \u2192 the tfstate is real now; the advisor reads what terraform wrote.\n");
30499
30637
  }
30500
- if (existsSync32(join53(project, "package.json")) && !existsSync32(join53(project, "node_modules"))) {
30638
+ if (existsSync33(join54(project, "package.json")) && !existsSync33(join54(project, "node_modules"))) {
30501
30639
  process.stdout.write(`behold demo carve \u2192 npm install in ${carve.project}/ (the chant this walkthrough shells)\u2026
30502
30640
  `);
30503
30641
  const code = await spawnStep("npm", ["install"], project);
@@ -30508,7 +30646,7 @@ async function serveCarveDemo(target, carve, port, live2 = false) {
30508
30646
  }
30509
30647
  }
30510
30648
  let degraded;
30511
- if (!existsSync32(join53(target, "node_modules", ...HCL_PARSER_PKG.split("/")))) {
30649
+ if (!existsSync33(join54(target, "node_modules", ...HCL_PARSER_PKG.split("/")))) {
30512
30650
  process.stdout.write(`behold demo carve \u2192 npm install ${HCL_PARSER_PKG} (chant's HCL parser, ~2MB, once)\u2026
30513
30651
  `);
30514
30652
  const code = await spawnStep("npm", ["install", "--no-save", "--no-package-lock", HCL_PARSER_PKG], target);
@@ -30525,7 +30663,7 @@ async function serveCarveDemo(target, carve, port, live2 = false) {
30525
30663
  );
30526
30664
  if (code !== 0) degraded = `chant carve advise exited ${code}`;
30527
30665
  }
30528
- const serving = !degraded && existsSync32(report) ? report : committed;
30666
+ const serving = !degraded && existsSync33(report) ? report : committed;
30529
30667
  if (degraded) {
30530
30668
  process.stderr.write(
30531
30669
  `behold demo carve: ${degraded}
@@ -30533,7 +30671,7 @@ async function serveCarveDemo(target, carve, port, live2 = false) {
30533
30671
  `
30534
30672
  );
30535
30673
  }
30536
- if (!existsSync32(serving)) {
30674
+ if (!existsSync33(serving)) {
30537
30675
  process.stderr.write(`behold demo carve: no carve report at ${serving}
30538
30676
  `);
30539
30677
  process.exit(2);
@@ -30579,7 +30717,7 @@ async function runPreview(rest) {
30579
30717
  process.exit(2);
30580
30718
  }
30581
30719
  const projectDir = resolve35(dirArg ?? process.cwd());
30582
- if (!existsSync32(projectDir)) {
30720
+ if (!existsSync33(projectDir)) {
30583
30721
  process.stderr.write(`behold preview: project not found at ${projectDir}
30584
30722
  `);
30585
30723
  process.exit(2);
@@ -30670,7 +30808,7 @@ async function runExportCmd(rest) {
30670
30808
  injectEmulatorEnv(env);
30671
30809
  env ??= "local";
30672
30810
  }
30673
- if (!existsSync32(projectDir)) {
30811
+ if (!existsSync33(projectDir)) {
30674
30812
  process.stderr.write(`behold export: project not found at ${projectDir}
30675
30813
  `);
30676
30814
  process.exit(2);