@intentius/behold 0.29.2 → 0.29.4
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 +840 -292
- package/package.json +1 -1
- package/web/app.js +306 -21
- package/web/kiosk-runs.js +61 -6
- package/web/kiosk-runs.test.js +22 -1
- package/web/kiosk.html +21 -3
- package/web/kiosk.js +168 -19
- package/web/kiosk.test.js +160 -3
- package/web/terragucci-change.js +49 -0
- package/web/terragucci-change.test.js +36 -1
- package/web/terragucci-components-live.js +166 -0
- package/web/terragucci-components-live.test.js +145 -0
- package/web/view-url.js +5 -4
- package/web/view-url.test.js +4 -0
package/dist/cli.js
CHANGED
|
@@ -2209,11 +2209,133 @@ var init_scratch = __esm({
|
|
|
2209
2209
|
}
|
|
2210
2210
|
});
|
|
2211
2211
|
|
|
2212
|
+
// src/terragucci-components.ts
|
|
2213
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
2214
|
+
import { join as join3 } from "node:path";
|
|
2215
|
+
function isTerragucciComponents(v) {
|
|
2216
|
+
if (typeof v !== "object" || v === null) return false;
|
|
2217
|
+
const d = v;
|
|
2218
|
+
if (d.schema !== TERRAGUCCI_COMPONENTS_SCHEMA) return false;
|
|
2219
|
+
const roots = d.roots;
|
|
2220
|
+
if (typeof roots !== "object" || roots === null || Array.isArray(roots)) return false;
|
|
2221
|
+
for (const r of Object.values(roots)) {
|
|
2222
|
+
if (typeof r !== "object" || r === null || typeof r.dir !== "string") return false;
|
|
2223
|
+
}
|
|
2224
|
+
if (!Array.isArray(d.components)) return false;
|
|
2225
|
+
for (const c of d.components) {
|
|
2226
|
+
const comp = c;
|
|
2227
|
+
if (typeof comp?.name !== "string" || !isStrings(comp.dependsOn) || !Array.isArray(comp.deploy)) return false;
|
|
2228
|
+
for (const p of comp.deploy) {
|
|
2229
|
+
const phase2 = p;
|
|
2230
|
+
if (typeof phase2?.phase !== "string" || !Array.isArray(phase2.steps)) return false;
|
|
2231
|
+
if (!phase2.steps.every((s) => typeof s?.kind === "string")) return false;
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
const pipeline = d.pipeline;
|
|
2235
|
+
if (typeof pipeline !== "object" || pipeline === null || !Array.isArray(pipeline.jobs)) return false;
|
|
2236
|
+
for (const j of pipeline.jobs) {
|
|
2237
|
+
const job = j;
|
|
2238
|
+
if (typeof job?.name !== "string" || !isStrings(job.needs) || !isStrings(job.applies)) return false;
|
|
2239
|
+
if (job.wave !== void 0 && typeof job.wave !== "number") return false;
|
|
2240
|
+
}
|
|
2241
|
+
return true;
|
|
2242
|
+
}
|
|
2243
|
+
function readTerragucciComponents(dir) {
|
|
2244
|
+
let text;
|
|
2245
|
+
try {
|
|
2246
|
+
text = readFileSync3(join3(dir, TERRAGUCCI_COMPONENTS_FILE), "utf8");
|
|
2247
|
+
} catch {
|
|
2248
|
+
return void 0;
|
|
2249
|
+
}
|
|
2250
|
+
try {
|
|
2251
|
+
const parsed = JSON.parse(text);
|
|
2252
|
+
return isTerragucciComponents(parsed) ? parsed : void 0;
|
|
2253
|
+
} catch {
|
|
2254
|
+
return void 0;
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
function declaredRootScan(decl) {
|
|
2258
|
+
const norm2 = (d) => d.replace(/^\.\/+/, "").replace(/\/+$/, "") || ".";
|
|
2259
|
+
return { roots: Object.entries(decl.roots).map(([name, r]) => ({ name, dir: norm2(r.dir) })), skipped: [] };
|
|
2260
|
+
}
|
|
2261
|
+
function terragucciComponentModule(decl) {
|
|
2262
|
+
const lines2 = [
|
|
2263
|
+
"// Generated by behold (#571) from terragucci.components.json, so chant can",
|
|
2264
|
+
"// draw this repo's roots as components. Written OUTSIDE the repo and",
|
|
2265
|
+
"// rewritten on each read; the repo is untouched.",
|
|
2266
|
+
""
|
|
2267
|
+
];
|
|
2268
|
+
decl.components.forEach((c, i) => {
|
|
2269
|
+
const component = {
|
|
2270
|
+
name: c.name,
|
|
2271
|
+
dependsOn: c.dependsOn,
|
|
2272
|
+
deploy: c.deploy.map((p) => ({
|
|
2273
|
+
phase: p.phase,
|
|
2274
|
+
steps: p.steps.map((s) => s.kind === "terraform-apply" && s.noRollback === void 0 ? { ...s, noRollback: SCAFFOLD_NO_ROLLBACK } : s)
|
|
2275
|
+
}))
|
|
2276
|
+
};
|
|
2277
|
+
lines2.push(`export const component${i} = ${JSON.stringify(component)};`);
|
|
2278
|
+
});
|
|
2279
|
+
lines2.push("");
|
|
2280
|
+
return lines2.join("\n");
|
|
2281
|
+
}
|
|
2282
|
+
function componentRoots(c) {
|
|
2283
|
+
return c.deploy.flatMap((p) => p.steps.filter((s) => s.kind === "terraform-apply" && typeof s.root === "string").map((s) => s.root));
|
|
2284
|
+
}
|
|
2285
|
+
function componentJobs(decl) {
|
|
2286
|
+
const out = {};
|
|
2287
|
+
for (const c of decl.components) {
|
|
2288
|
+
const keys = /* @__PURE__ */ new Set([c.name, ...componentRoots(c)]);
|
|
2289
|
+
const jobs = decl.pipeline.jobs.filter((j) => j.applies.some((a) => keys.has(a)));
|
|
2290
|
+
if (!jobs.length) continue;
|
|
2291
|
+
const primary = jobs.find((j) => j.wave !== void 0) ?? jobs[0];
|
|
2292
|
+
const others = jobs.filter((j) => j !== primary).map((j) => j.name);
|
|
2293
|
+
out[c.name] = {
|
|
2294
|
+
component: c.name,
|
|
2295
|
+
jobName: primary.name,
|
|
2296
|
+
needs: primary.needs,
|
|
2297
|
+
...primary.wave !== void 0 ? { wave: primary.wave } : {},
|
|
2298
|
+
...others.length ? { alsoIn: others } : {}
|
|
2299
|
+
};
|
|
2300
|
+
}
|
|
2301
|
+
return out;
|
|
2302
|
+
}
|
|
2303
|
+
function waveTitles(ir, decl) {
|
|
2304
|
+
const byWave = ir.groups?.byWave ?? {};
|
|
2305
|
+
const jobs = componentJobs(decl);
|
|
2306
|
+
const order = decl.pipeline.jobs.map((j) => j.name);
|
|
2307
|
+
const out = {};
|
|
2308
|
+
for (const [key, members] of Object.entries(byWave)) {
|
|
2309
|
+
const names = new Set(members.map((m) => jobs[m]?.jobName).filter((n) => !!n));
|
|
2310
|
+
if (names.size) out[key] = order.filter((n) => names.has(n)).join(" + ");
|
|
2311
|
+
}
|
|
2312
|
+
return out;
|
|
2313
|
+
}
|
|
2314
|
+
function componentRootMap(decl) {
|
|
2315
|
+
const out = {};
|
|
2316
|
+
for (const c of decl.components) {
|
|
2317
|
+
const root = componentRoots(c)[0];
|
|
2318
|
+
if (root) out[c.name] = root;
|
|
2319
|
+
}
|
|
2320
|
+
return out;
|
|
2321
|
+
}
|
|
2322
|
+
var TERRAGUCCI_COMPONENTS_FILE, TERRAGUCCI_COMPONENTS_SCHEMA, TERRAGUCCI_COMPONENT_MODULE, isStrings, SCAFFOLD_NO_ROLLBACK;
|
|
2323
|
+
var init_terragucci_components = __esm({
|
|
2324
|
+
"src/terragucci-components.ts"() {
|
|
2325
|
+
"use strict";
|
|
2326
|
+
TERRAGUCCI_COMPONENTS_FILE = "terragucci.components.json";
|
|
2327
|
+
TERRAGUCCI_COMPONENTS_SCHEMA = "terragucci.components/v1";
|
|
2328
|
+
TERRAGUCCI_COMPONENT_MODULE = "terragucci.component.ts";
|
|
2329
|
+
isStrings = (v) => Array.isArray(v) && v.every((s) => typeof s === "string");
|
|
2330
|
+
SCAFFOLD_NO_ROLLBACK = "applied by terragucci's pipeline; behold only draws this";
|
|
2331
|
+
}
|
|
2332
|
+
});
|
|
2333
|
+
|
|
2212
2334
|
// src/terraform-member.ts
|
|
2213
2335
|
import { createHash } from "node:crypto";
|
|
2214
2336
|
import { createRequire } from "node:module";
|
|
2215
|
-
import { existsSync as existsSync3, lstatSync, mkdirSync as mkdirSync2, readFileSync as
|
|
2216
|
-
import { basename, dirname as dirname2, join as
|
|
2337
|
+
import { existsSync as existsSync3, lstatSync, mkdirSync as mkdirSync2, readFileSync as readFileSync4, readdirSync as readdirSync2, readlinkSync, realpathSync, symlinkSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
2338
|
+
import { basename, dirname as dirname2, join as join4, relative, resolve, sep } from "node:path";
|
|
2217
2339
|
import { tmpdir } from "node:os";
|
|
2218
2340
|
import { fileURLToPath } from "node:url";
|
|
2219
2341
|
function notARoot(rel, sources) {
|
|
@@ -2232,7 +2354,7 @@ function tfSources(dir) {
|
|
|
2232
2354
|
const out = [];
|
|
2233
2355
|
for (const name of names) {
|
|
2234
2356
|
try {
|
|
2235
|
-
out.push(
|
|
2357
|
+
out.push(readFileSync4(join4(dir, name), "utf8"));
|
|
2236
2358
|
} catch {
|
|
2237
2359
|
}
|
|
2238
2360
|
}
|
|
@@ -2254,7 +2376,7 @@ function discoverTerraformRoots(estate) {
|
|
|
2254
2376
|
}
|
|
2255
2377
|
for (const e of entries) {
|
|
2256
2378
|
if (!e.isDirectory() || SKIP_DIRS.has(e.name) || e.name.startsWith(".")) continue;
|
|
2257
|
-
walk(
|
|
2379
|
+
walk(join4(dir, e.name), depth + 1);
|
|
2258
2380
|
}
|
|
2259
2381
|
};
|
|
2260
2382
|
walk(root, 0);
|
|
@@ -2283,9 +2405,9 @@ function terraformRootsNoteShort(scan) {
|
|
|
2283
2405
|
const roots = `${scan.roots.length} root${scan.roots.length === 1 ? "" : "s"}`;
|
|
2284
2406
|
return scan.skipped.length ? `${roots} \xB7 ${scan.skipped.length} skipped` : roots;
|
|
2285
2407
|
}
|
|
2286
|
-
function declaredPeerRange(pkg, manifestDir =
|
|
2408
|
+
function declaredPeerRange(pkg, manifestDir = join4(beholdDir(), "..")) {
|
|
2287
2409
|
try {
|
|
2288
|
-
const manifest = JSON.parse(
|
|
2410
|
+
const manifest = JSON.parse(readFileSync4(join4(manifestDir, "package.json"), "utf8"));
|
|
2289
2411
|
return manifest.peerDependencies?.[pkg];
|
|
2290
2412
|
} catch {
|
|
2291
2413
|
return void 0;
|
|
@@ -2295,7 +2417,7 @@ function resolvedVersion(pkg, from = beholdDir()) {
|
|
|
2295
2417
|
return resolvedPackage(pkg, from)?.version;
|
|
2296
2418
|
}
|
|
2297
2419
|
function resolvedPackage(pkg, from = beholdDir()) {
|
|
2298
|
-
const req = createRequire(
|
|
2420
|
+
const req = createRequire(join4(resolve(from), "noop.js"));
|
|
2299
2421
|
let entry;
|
|
2300
2422
|
try {
|
|
2301
2423
|
entry = req.resolve(pkg);
|
|
@@ -2305,7 +2427,7 @@ function resolvedPackage(pkg, from = beholdDir()) {
|
|
|
2305
2427
|
let dir = dirname2(entry);
|
|
2306
2428
|
for (; ; ) {
|
|
2307
2429
|
try {
|
|
2308
|
-
const manifest = JSON.parse(
|
|
2430
|
+
const manifest = JSON.parse(readFileSync4(join4(dir, "package.json"), "utf8"));
|
|
2309
2431
|
if (manifest.name === pkg) return { dir, version: manifest.version ?? "" };
|
|
2310
2432
|
} catch {
|
|
2311
2433
|
}
|
|
@@ -2332,7 +2454,7 @@ function terraformReaderState(from = beholdDir()) {
|
|
|
2332
2454
|
};
|
|
2333
2455
|
}
|
|
2334
2456
|
function beholdNodeModules(from = beholdDir()) {
|
|
2335
|
-
const req = createRequire(
|
|
2457
|
+
const req = createRequire(join4(resolve(from), "noop.js"));
|
|
2336
2458
|
let entry;
|
|
2337
2459
|
try {
|
|
2338
2460
|
entry = req.resolve("@intentius/chant");
|
|
@@ -2355,7 +2477,7 @@ function terraformScratchDir(estate, tmp = tmpdir(), flavour = "tf") {
|
|
|
2355
2477
|
root = realpathSync(root);
|
|
2356
2478
|
} catch {
|
|
2357
2479
|
}
|
|
2358
|
-
const dir =
|
|
2480
|
+
const dir = join4(root, name);
|
|
2359
2481
|
if (dir === target || dir.startsWith(target + sep)) {
|
|
2360
2482
|
throw new Error(`scratch discipline: the generated reader config for ${target} would land inside the estate (${dir})`);
|
|
2361
2483
|
}
|
|
@@ -2392,26 +2514,37 @@ function relink(path, target) {
|
|
|
2392
2514
|
}
|
|
2393
2515
|
symlinkSync(target, path);
|
|
2394
2516
|
}
|
|
2395
|
-
function writeTerraformScratchProject(estate, scan, tmp = tmpdir(), flavour = "tf") {
|
|
2517
|
+
function writeTerraformScratchProject(estate, scan, tmp = tmpdir(), flavour = "tf", components) {
|
|
2396
2518
|
const target = resolve(estate);
|
|
2397
2519
|
const dir = terraformScratchDir(target, tmp, flavour);
|
|
2398
2520
|
mkdirSync2(dir, { recursive: true });
|
|
2399
|
-
relink(
|
|
2521
|
+
relink(join4(dir, ESTATE_LINK), target);
|
|
2400
2522
|
const modules = beholdNodeModules();
|
|
2401
|
-
if (modules) relink(
|
|
2523
|
+
if (modules) relink(join4(dir, "node_modules"), modules);
|
|
2402
2524
|
const write = (path, text) => {
|
|
2403
|
-
if (!existsSync3(path) ||
|
|
2525
|
+
if (!existsSync3(path) || readFileSync4(path, "utf8") !== text) writeFileSync2(path, text);
|
|
2404
2526
|
};
|
|
2405
|
-
write(
|
|
2406
|
-
write(
|
|
2527
|
+
write(join4(dir, "package.json"), SCRATCH_PACKAGE_JSON);
|
|
2528
|
+
write(join4(dir, "chant.config.ts"), terraformScratchConfig(scan, ESTATE_LINK, flavour));
|
|
2529
|
+
const module = join4(dir, TERRAGUCCI_COMPONENT_MODULE);
|
|
2530
|
+
if (components) write(module, terragucciComponentModule(components));
|
|
2531
|
+
else if (existsSync3(module)) write(module, "// terragucci.components.json is gone; no components.\nexport {};\n");
|
|
2407
2532
|
return dir;
|
|
2408
2533
|
}
|
|
2534
|
+
function terraformMemberScan(dir) {
|
|
2535
|
+
const components = readTerragucciComponents(dir);
|
|
2536
|
+
return components ? { scan: declaredRootScan(components), components } : { scan: discoverTerraformRoots(dir) };
|
|
2537
|
+
}
|
|
2538
|
+
function terraformMemberProject(dir) {
|
|
2539
|
+
const { scan, components } = terraformMemberScan(dir);
|
|
2540
|
+
return { project: writeTerraformScratchProject(dir, scan, void 0, "tf", components), ...components ? { components } : {} };
|
|
2541
|
+
}
|
|
2409
2542
|
function terraformReadDetail(detail) {
|
|
2410
2543
|
return Math.max(detail ?? 2, 2);
|
|
2411
2544
|
}
|
|
2412
2545
|
async function readTerraformMember(dir, opts, state = terraformReaderState()) {
|
|
2413
2546
|
if (state.refusal) throw new TerraformReadError(state.refusal, dir);
|
|
2414
|
-
const scan =
|
|
2547
|
+
const { scan, components } = terraformMemberScan(dir);
|
|
2415
2548
|
if (!scan.roots.length) {
|
|
2416
2549
|
throw new TerraformReadError(
|
|
2417
2550
|
{
|
|
@@ -2422,7 +2555,7 @@ async function readTerraformMember(dir, opts, state = terraformReaderState()) {
|
|
|
2422
2555
|
dir
|
|
2423
2556
|
);
|
|
2424
2557
|
}
|
|
2425
|
-
const project = writeTerraformScratchProject(dir, scan);
|
|
2558
|
+
const project = writeTerraformScratchProject(dir, scan, void 0, "tf", components);
|
|
2426
2559
|
const { live: _live, overlay: _overlay, env: _env, ...source2 } = opts;
|
|
2427
2560
|
const detail = terraformReadDetail(source2.detail);
|
|
2428
2561
|
const { graphIr: graphIr2 } = await Promise.resolve().then(() => (init_chant(), chant_exports));
|
|
@@ -2434,6 +2567,7 @@ var init_terraform_member = __esm({
|
|
|
2434
2567
|
"use strict";
|
|
2435
2568
|
init_terraform_lens();
|
|
2436
2569
|
init_scratch();
|
|
2570
|
+
init_terragucci_components();
|
|
2437
2571
|
TERRAFORM_LEXICON_PKG = "@intentius/chant-lexicon-terraform";
|
|
2438
2572
|
HCL_PARSER_PKG = "@cdktn/hcl2json";
|
|
2439
2573
|
ROOT_SCAN_DEPTH = 3;
|
|
@@ -2975,8 +3109,8 @@ var init_member_kind = __esm({
|
|
|
2975
3109
|
});
|
|
2976
3110
|
|
|
2977
3111
|
// src/project.ts
|
|
2978
|
-
import { readFileSync as
|
|
2979
|
-
import { join as
|
|
3112
|
+
import { readFileSync as readFileSync5, existsSync as existsSync4 } from "node:fs";
|
|
3113
|
+
import { join as join5 } from "node:path";
|
|
2980
3114
|
import { pathToFileURL } from "node:url";
|
|
2981
3115
|
function readBehaviour(raw) {
|
|
2982
3116
|
const b = raw.behaviour;
|
|
@@ -2997,7 +3131,7 @@ function readMember(v) {
|
|
|
2997
3131
|
}
|
|
2998
3132
|
function chantConfigPath(projectDir) {
|
|
2999
3133
|
for (const name of CONFIG_NAMES) {
|
|
3000
|
-
const p =
|
|
3134
|
+
const p = join5(projectDir, name);
|
|
3001
3135
|
if (existsSync4(p)) return p;
|
|
3002
3136
|
}
|
|
3003
3137
|
return void 0;
|
|
@@ -3091,7 +3225,7 @@ async function detectProject(projectDir) {
|
|
|
3091
3225
|
if (info.environments.length || info.lexicons.length || info.sourceDir || info.stacks?.length) return info;
|
|
3092
3226
|
} catch {
|
|
3093
3227
|
}
|
|
3094
|
-
const content =
|
|
3228
|
+
const content = readFileSync5(path, "utf8");
|
|
3095
3229
|
const sourceDir = parseStringLiteral(content, "sourceDir");
|
|
3096
3230
|
const environments = parseEnvironmentNames(content);
|
|
3097
3231
|
return {
|
|
@@ -3131,10 +3265,10 @@ function readExecutor(cfg) {
|
|
|
3131
3265
|
return Object.keys(out).length ? out : void 0;
|
|
3132
3266
|
}
|
|
3133
3267
|
function loadBeholdConfig(projectDir) {
|
|
3134
|
-
const path =
|
|
3268
|
+
const path = join5(projectDir, BEHOLD_CONFIG_NAME);
|
|
3135
3269
|
if (!existsSync4(path)) return {};
|
|
3136
3270
|
try {
|
|
3137
|
-
const raw = JSON.parse(
|
|
3271
|
+
const raw = JSON.parse(readFileSync5(path, "utf8"));
|
|
3138
3272
|
const tiers = readTiers(raw);
|
|
3139
3273
|
const members = Array.isArray(raw.members) ? raw.members.map(readMember).filter((m) => !!m) : [];
|
|
3140
3274
|
const executor = readExecutor(raw);
|
|
@@ -3151,7 +3285,7 @@ function loadBeholdConfig(projectDir) {
|
|
|
3151
3285
|
}
|
|
3152
3286
|
function readWorkspaces(projectDir) {
|
|
3153
3287
|
try {
|
|
3154
|
-
const raw = JSON.parse(
|
|
3288
|
+
const raw = JSON.parse(readFileSync5(join5(projectDir, "package.json"), "utf8"));
|
|
3155
3289
|
const ws = Array.isArray(raw.workspaces) ? raw.workspaces : raw.workspaces?.packages;
|
|
3156
3290
|
return Array.isArray(ws) ? ws.filter((w) => typeof w === "string") : [];
|
|
3157
3291
|
} catch {
|
|
@@ -3176,12 +3310,12 @@ function detectProjectShape(projectDir) {
|
|
|
3176
3310
|
invalid.push({ dir: m.dir, invalid: `member kind "${m.kind}" has no reader in this behold` });
|
|
3177
3311
|
continue;
|
|
3178
3312
|
}
|
|
3179
|
-
if (spec2.probe(
|
|
3313
|
+
if (spec2.probe(join5(projectDir, m.dir))) members.push(m);
|
|
3180
3314
|
else invalid.push({ dir: m.dir, invalid: `declared as ${m.kind}, but ${m.dir} has no ${spec2.expects}` });
|
|
3181
3315
|
}
|
|
3182
3316
|
} else {
|
|
3183
3317
|
for (const dir of readWorkspaces(projectDir)) {
|
|
3184
|
-
const kind = memberKindOf(
|
|
3318
|
+
const kind = memberKindOf(join5(projectDir, dir));
|
|
3185
3319
|
if (kind) members.push({ dir, kind });
|
|
3186
3320
|
}
|
|
3187
3321
|
}
|
|
@@ -3213,7 +3347,7 @@ var init_project = __esm({
|
|
|
3213
3347
|
// src/member-source.ts
|
|
3214
3348
|
import { createHash as createHash2 } from "node:crypto";
|
|
3215
3349
|
import { readdirSync as readdirSync3, statSync } from "node:fs";
|
|
3216
|
-
import { join as
|
|
3350
|
+
import { join as join6, relative as relative2, resolve as resolve2 } from "node:path";
|
|
3217
3351
|
function setStampExclusions(next) {
|
|
3218
3352
|
exclusions = new Map([...next].map(([k, v]) => [resolve2(k), new Set(v.map((d) => resolve2(d)))]));
|
|
3219
3353
|
}
|
|
@@ -3226,7 +3360,7 @@ function memberSourceStamp(dir) {
|
|
|
3226
3360
|
const entries = readdirSync3(at2, { withFileTypes: true }).sort((a, b) => a.name < b.name ? -1 : 1);
|
|
3227
3361
|
for (const e of entries) {
|
|
3228
3362
|
if (SKIP.has(e.name)) continue;
|
|
3229
|
-
const path =
|
|
3363
|
+
const path = join6(at2, e.name);
|
|
3230
3364
|
if (e.isDirectory()) {
|
|
3231
3365
|
if (!skipDirs?.has(path)) walk(path);
|
|
3232
3366
|
continue;
|
|
@@ -4779,15 +4913,15 @@ var init_yaml = __esm({
|
|
|
4779
4913
|
});
|
|
4780
4914
|
|
|
4781
4915
|
// src/carve-manifest.ts
|
|
4782
|
-
import { readdirSync as readdirSync4, readFileSync as
|
|
4783
|
-
import { dirname as dirname3, isAbsolute, join as
|
|
4916
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync6, statSync as statSync2 } from "node:fs";
|
|
4917
|
+
import { dirname as dirname3, isAbsolute, join as join7, relative as relative3, resolve as resolve3, sep as sep2 } from "node:path";
|
|
4784
4918
|
function parseCarveManifest(value) {
|
|
4785
4919
|
if (!isRecord4(value)) return null;
|
|
4786
4920
|
if (value.version !== 1 && value.version !== 2) return null;
|
|
4787
4921
|
if (typeof value.target !== "string" || !value.target) return null;
|
|
4788
4922
|
return value;
|
|
4789
4923
|
}
|
|
4790
|
-
function readCarveManifest(path, readFile2 = (p) =>
|
|
4924
|
+
function readCarveManifest(path, readFile2 = (p) => readFileSync6(p, "utf8")) {
|
|
4791
4925
|
let text;
|
|
4792
4926
|
try {
|
|
4793
4927
|
text = readFile2(path);
|
|
@@ -4865,7 +4999,7 @@ function listCarveManifests(dir, io = nodeCarveIo, depth = MANIFEST_SCAN_DEPTH)
|
|
|
4865
4999
|
return;
|
|
4866
5000
|
}
|
|
4867
5001
|
for (const name of entries) {
|
|
4868
|
-
const full =
|
|
5002
|
+
const full = join7(d, name);
|
|
4869
5003
|
if (name.endsWith(CARVE_MANIFEST_SUFFIX)) {
|
|
4870
5004
|
out.push(full);
|
|
4871
5005
|
continue;
|
|
@@ -5096,7 +5230,7 @@ var init_carve_manifest = __esm({
|
|
|
5096
5230
|
return false;
|
|
5097
5231
|
}
|
|
5098
5232
|
},
|
|
5099
|
-
readFile: (p) =>
|
|
5233
|
+
readFile: (p) => readFileSync6(p, "utf8")
|
|
5100
5234
|
};
|
|
5101
5235
|
MANIFEST_SCAN_DEPTH = 2;
|
|
5102
5236
|
SKIP_DIRS2 = /* @__PURE__ */ new Set(["node_modules", "dist", "cdk.out", ".terraform", ".git"]);
|
|
@@ -5207,10 +5341,10 @@ __export(chant_exports, {
|
|
|
5207
5341
|
stripAnsi: () => stripAnsi
|
|
5208
5342
|
});
|
|
5209
5343
|
import { spawn as spawn2 } from "node:child_process";
|
|
5210
|
-
import { existsSync as existsSync5, readFileSync as
|
|
5344
|
+
import { existsSync as existsSync5, readFileSync as readFileSync7 } from "node:fs";
|
|
5211
5345
|
import { createRequire as createRequire2 } from "node:module";
|
|
5212
5346
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
5213
|
-
import { dirname as dirname4, join as
|
|
5347
|
+
import { dirname as dirname4, join as join8, resolve as resolve5 } from "node:path";
|
|
5214
5348
|
import { createHash as createHash3 } from "node:crypto";
|
|
5215
5349
|
function envOverridesFor(opts) {
|
|
5216
5350
|
const overrides = { ...opts.spawnEnv ?? {} };
|
|
@@ -5250,7 +5384,7 @@ function packageManifestFrom(req, name) {
|
|
|
5250
5384
|
let dir = dirname4(entry);
|
|
5251
5385
|
for (; ; ) {
|
|
5252
5386
|
try {
|
|
5253
|
-
const pkg = createRequire2(import.meta.url)(
|
|
5387
|
+
const pkg = createRequire2(import.meta.url)(join8(dir, "package.json"));
|
|
5254
5388
|
if (pkg.name === name) return { root: dir, manifest: pkg };
|
|
5255
5389
|
} catch {
|
|
5256
5390
|
}
|
|
@@ -5264,10 +5398,10 @@ function chantPackageFrom(req) {
|
|
|
5264
5398
|
const found = packageManifestFrom(req, "@intentius/chant");
|
|
5265
5399
|
if (!found) return void 0;
|
|
5266
5400
|
const { root, manifest } = found;
|
|
5267
|
-
return { root, bin:
|
|
5401
|
+
return { root, bin: join8(root, manifest.bin?.chant ?? "bin/chant"), ...manifest.version ? { version: manifest.version } : {} };
|
|
5268
5402
|
}
|
|
5269
5403
|
function resolveLexicons(projectDir, lexicons) {
|
|
5270
|
-
const req = createRequire2(
|
|
5404
|
+
const req = createRequire2(join8(resolve5(projectDir), "noop.js"));
|
|
5271
5405
|
return lexicons.map((lexicon) => {
|
|
5272
5406
|
const pkg = `@intentius/chant-lexicon-${lexicon}`;
|
|
5273
5407
|
const found = packageManifestFrom(req, pkg);
|
|
@@ -5280,7 +5414,7 @@ function chantBinFrom(req) {
|
|
|
5280
5414
|
function resolveChant(projectDir) {
|
|
5281
5415
|
const own = chantPackageFrom(createRequire2(import.meta.url));
|
|
5282
5416
|
if (projectDir) {
|
|
5283
|
-
const fromProject = chantPackageFrom(createRequire2(
|
|
5417
|
+
const fromProject = chantPackageFrom(createRequire2(join8(resolve5(projectDir), "noop.js")));
|
|
5284
5418
|
if (fromProject) return { source: fromProject.root === own?.root ? "behold" : "project", ...fromProject };
|
|
5285
5419
|
}
|
|
5286
5420
|
if (own) return { source: "behold", ...own };
|
|
@@ -5289,7 +5423,7 @@ function resolveChant(projectDir) {
|
|
|
5289
5423
|
function chantFloor() {
|
|
5290
5424
|
try {
|
|
5291
5425
|
const here = dirname4(fileURLToPath2(import.meta.url));
|
|
5292
|
-
const pkg = JSON.parse(
|
|
5426
|
+
const pkg = JSON.parse(readFileSync7(join8(here, "..", "package.json"), "utf8"));
|
|
5293
5427
|
return pkg.dependencies?.["@intentius/chant"]?.replace(/^[^0-9]*/, "") || void 0;
|
|
5294
5428
|
} catch {
|
|
5295
5429
|
return void 0;
|
|
@@ -5449,7 +5583,7 @@ function runCommandStream(cmd, args, cwd, onLine) {
|
|
|
5449
5583
|
return { pid: proc.pid ?? -1, kill: () => proc.kill(), done };
|
|
5450
5584
|
}
|
|
5451
5585
|
function legacyGraphPath(projectDir) {
|
|
5452
|
-
const src =
|
|
5586
|
+
const src = join8(projectDir, "src");
|
|
5453
5587
|
return existsSync5(src) ? src : projectDir;
|
|
5454
5588
|
}
|
|
5455
5589
|
async function graphPath(projectDir, opts = {}) {
|
|
@@ -5475,7 +5609,7 @@ async function graphIr(projectDir, opts = {}) {
|
|
|
5475
5609
|
return dropForeignDeclarations(ir, projectDir);
|
|
5476
5610
|
}
|
|
5477
5611
|
async function clusterRootGraphIr(projectDir, opts = {}) {
|
|
5478
|
-
if (!existsSync5(
|
|
5612
|
+
if (!existsSync5(join8(projectDir, "cluster"))) return void 0;
|
|
5479
5613
|
const { live: _live, overlay: _overlay, env: _env, ...sourceOnly } = opts;
|
|
5480
5614
|
try {
|
|
5481
5615
|
return await runChantJson(graphArgs("cluster", "ir", sourceOnly, false), projectDir, envOverridesFor(sourceOnly));
|
|
@@ -8904,8 +9038,8 @@ __export(tree_exports, {
|
|
|
8904
9038
|
workingTree: () => workingTree
|
|
8905
9039
|
});
|
|
8906
9040
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
8907
|
-
import { readdirSync as readdirSync10, readFileSync as
|
|
8908
|
-
import { join as
|
|
9041
|
+
import { readdirSync as readdirSync10, readFileSync as readFileSync20, statSync as statSync8 } from "node:fs";
|
|
9042
|
+
import { join as join27 } from "node:path";
|
|
8909
9043
|
function joinPath(...parts) {
|
|
8910
9044
|
return parts.filter((p) => p !== "" && p !== ".").join("/");
|
|
8911
9045
|
}
|
|
@@ -8914,7 +9048,7 @@ function workingTree(root) {
|
|
|
8914
9048
|
label: "",
|
|
8915
9049
|
stat(path) {
|
|
8916
9050
|
try {
|
|
8917
|
-
const s = statSync8(
|
|
9051
|
+
const s = statSync8(join27(root, path));
|
|
8918
9052
|
return s.isDirectory() ? "dir" : s.isFile() ? "file" : void 0;
|
|
8919
9053
|
} catch {
|
|
8920
9054
|
return void 0;
|
|
@@ -8923,7 +9057,7 @@ function workingTree(root) {
|
|
|
8923
9057
|
list(path) {
|
|
8924
9058
|
let dirents;
|
|
8925
9059
|
try {
|
|
8926
|
-
dirents = readdirSync10(
|
|
9060
|
+
dirents = readdirSync10(join27(root, path), { withFileTypes: true });
|
|
8927
9061
|
} catch {
|
|
8928
9062
|
return void 0;
|
|
8929
9063
|
}
|
|
@@ -8932,7 +9066,7 @@ function workingTree(root) {
|
|
|
8932
9066
|
let type = d.isDirectory() ? "dir" : d.isFile() ? "file" : void 0;
|
|
8933
9067
|
if (!type && d.isSymbolicLink()) {
|
|
8934
9068
|
try {
|
|
8935
|
-
const s = statSync8(
|
|
9069
|
+
const s = statSync8(join27(root, path, d.name));
|
|
8936
9070
|
type = s.isDirectory() ? "dir" : s.isFile() ? "file" : void 0;
|
|
8937
9071
|
} catch {
|
|
8938
9072
|
}
|
|
@@ -8942,10 +9076,10 @@ function workingTree(root) {
|
|
|
8942
9076
|
return out;
|
|
8943
9077
|
},
|
|
8944
9078
|
read(path) {
|
|
8945
|
-
return
|
|
9079
|
+
return readFileSync20(join27(root, path), "utf-8");
|
|
8946
9080
|
},
|
|
8947
9081
|
bytes(path) {
|
|
8948
|
-
return
|
|
9082
|
+
return readFileSync20(join27(root, path));
|
|
8949
9083
|
}
|
|
8950
9084
|
};
|
|
8951
9085
|
}
|
|
@@ -9547,12 +9681,12 @@ var init_identity_gate_rule = __esm({
|
|
|
9547
9681
|
});
|
|
9548
9682
|
|
|
9549
9683
|
// node_modules/@intentius/chant/src/workspace/class-data.ts
|
|
9550
|
-
import { existsSync as existsSync17, readFileSync as
|
|
9551
|
-
import { dirname as dirname7, join as
|
|
9684
|
+
import { existsSync as existsSync17, readFileSync as readFileSync21, statSync as statSync9 } from "node:fs";
|
|
9685
|
+
import { dirname as dirname7, join as join28, posix, resolve as resolve14 } from "node:path";
|
|
9552
9686
|
function diskFiles(dir) {
|
|
9553
9687
|
return (path) => {
|
|
9554
9688
|
try {
|
|
9555
|
-
return
|
|
9689
|
+
return readFileSync21(join28(dir, ...path.split("/")), "utf-8");
|
|
9556
9690
|
} catch {
|
|
9557
9691
|
return void 0;
|
|
9558
9692
|
}
|
|
@@ -9560,9 +9694,9 @@ function diskFiles(dir) {
|
|
|
9560
9694
|
}
|
|
9561
9695
|
function findInstalledPackage(name, fromDir) {
|
|
9562
9696
|
for (let dir = resolve14(fromDir); ; dir = dirname7(dir)) {
|
|
9563
|
-
const candidate =
|
|
9697
|
+
const candidate = join28(dir, "node_modules", ...name.split("/"));
|
|
9564
9698
|
try {
|
|
9565
|
-
if (statSync9(candidate).isDirectory() && existsSync17(
|
|
9699
|
+
if (statSync9(candidate).isDirectory() && existsSync17(join28(candidate, "package.json"))) return candidate;
|
|
9566
9700
|
} catch {
|
|
9567
9701
|
}
|
|
9568
9702
|
if (dirname7(dir) === dir) return void 0;
|
|
@@ -10012,10 +10146,10 @@ var init_jsonc = __esm({
|
|
|
10012
10146
|
});
|
|
10013
10147
|
|
|
10014
10148
|
// node_modules/@intentius/chant/src/package-version.ts
|
|
10015
|
-
import { readFileSync as
|
|
10149
|
+
import { readFileSync as readFileSync22 } from "node:fs";
|
|
10016
10150
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
10017
10151
|
function readChantPackageVersion() {
|
|
10018
|
-
return JSON.parse(
|
|
10152
|
+
return JSON.parse(readFileSync22(fileURLToPath4(new URL("../package.json", import.meta.url)), "utf-8")).version;
|
|
10019
10153
|
}
|
|
10020
10154
|
var init_package_version = __esm({
|
|
10021
10155
|
"node_modules/@intentius/chant/src/package-version.ts"() {
|
|
@@ -10814,8 +10948,8 @@ var init_declaration = __esm({
|
|
|
10814
10948
|
});
|
|
10815
10949
|
|
|
10816
10950
|
// src/cli.ts
|
|
10817
|
-
import { resolve as resolve33, dirname as dirname21, join as
|
|
10818
|
-
import { realpathSync as realpathSync3, existsSync as existsSync30, readFileSync as
|
|
10951
|
+
import { resolve as resolve33, dirname as dirname21, join as join51 } from "node:path";
|
|
10952
|
+
import { realpathSync as realpathSync3, existsSync as existsSync30, readFileSync as readFileSync39, rmSync as rmSync4 } from "node:fs";
|
|
10819
10953
|
import { fileURLToPath as fileURLToPath12 } from "node:url";
|
|
10820
10954
|
import { spawn as spawn9, spawnSync as spawnSync4 } from "node:child_process";
|
|
10821
10955
|
|
|
@@ -10873,8 +11007,8 @@ import { serve } from "@hono/node-server";
|
|
|
10873
11007
|
import { fileURLToPath as fileURLToPath10 } from "node:url";
|
|
10874
11008
|
import { execFile as execFile5 } from "node:child_process";
|
|
10875
11009
|
import { promisify as promisify3 } from "node:util";
|
|
10876
|
-
import { existsSync as existsSync27, readFileSync as
|
|
10877
|
-
import { basename as basename5, dirname as dirname18, join as
|
|
11010
|
+
import { existsSync as existsSync27, readFileSync as readFileSync35 } from "node:fs";
|
|
11011
|
+
import { basename as basename5, dirname as dirname18, join as join47, relative as relative10, resolve as resolve30, sep as sep9 } from "node:path";
|
|
10878
11012
|
|
|
10879
11013
|
// src/recents.ts
|
|
10880
11014
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
@@ -10962,8 +11096,8 @@ function mergeClusterRoot(ir, clusterIr, running) {
|
|
|
10962
11096
|
}
|
|
10963
11097
|
|
|
10964
11098
|
// src/helm-releases.ts
|
|
10965
|
-
import { existsSync as existsSync6, readdirSync as readdirSync5, readFileSync as
|
|
10966
|
-
import { join as
|
|
11099
|
+
import { existsSync as existsSync6, readdirSync as readdirSync5, readFileSync as readFileSync8, statSync as statSync3 } from "node:fs";
|
|
11100
|
+
import { join as join9 } from "node:path";
|
|
10967
11101
|
var RELEASE_KEY = /^release\/([^/]+)\/(.+)$/;
|
|
10968
11102
|
function declaredChartNames(ir) {
|
|
10969
11103
|
const names = /* @__PURE__ */ new Set();
|
|
@@ -10983,12 +11117,12 @@ function matchesDeclaredChart(chart, declared) {
|
|
|
10983
11117
|
}
|
|
10984
11118
|
function discoverReleaseUnits(projectDir) {
|
|
10985
11119
|
const owners = /* @__PURE__ */ new Map();
|
|
10986
|
-
const roots = [
|
|
11120
|
+
const roots = [join9(projectDir, "src"), join9(projectDir, "ops")];
|
|
10987
11121
|
const files = [];
|
|
10988
11122
|
const walk = (dir, depth) => {
|
|
10989
11123
|
if (depth > 4 || !existsSync6(dir)) return;
|
|
10990
11124
|
for (const f of readdirSync5(dir)) {
|
|
10991
|
-
const p =
|
|
11125
|
+
const p = join9(dir, f);
|
|
10992
11126
|
let s;
|
|
10993
11127
|
try {
|
|
10994
11128
|
s = statSync3(p);
|
|
@@ -11003,7 +11137,7 @@ function discoverReleaseUnits(projectDir) {
|
|
|
11003
11137
|
for (const file of files) {
|
|
11004
11138
|
let content;
|
|
11005
11139
|
try {
|
|
11006
|
-
content =
|
|
11140
|
+
content = readFileSync8(file, "utf8");
|
|
11007
11141
|
} catch {
|
|
11008
11142
|
continue;
|
|
11009
11143
|
}
|
|
@@ -11058,8 +11192,8 @@ function synthesizeHelmReleases(ir, observed, owners) {
|
|
|
11058
11192
|
init_yaml();
|
|
11059
11193
|
init_chant();
|
|
11060
11194
|
import { execFileSync, spawn as spawn3 } from "node:child_process";
|
|
11061
|
-
import { readdirSync as readdirSync6, readFileSync as
|
|
11062
|
-
import { join as
|
|
11195
|
+
import { readdirSync as readdirSync6, readFileSync as readFileSync9 } from "node:fs";
|
|
11196
|
+
import { join as join10 } from "node:path";
|
|
11063
11197
|
|
|
11064
11198
|
// src/ci-run.ts
|
|
11065
11199
|
function pipelineProgress(pipeline) {
|
|
@@ -11155,7 +11289,7 @@ function workflowsDir(projectDir) {
|
|
|
11155
11289
|
root = execFileSync("git", ["-C", projectDir, "rev-parse", "--show-toplevel"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim() || projectDir;
|
|
11156
11290
|
} catch {
|
|
11157
11291
|
}
|
|
11158
|
-
return
|
|
11292
|
+
return join10(root, ".github", "workflows");
|
|
11159
11293
|
}
|
|
11160
11294
|
function committedWorkflows(projectDir) {
|
|
11161
11295
|
const dir = workflowsDir(projectDir);
|
|
@@ -11168,7 +11302,7 @@ function committedWorkflows(projectDir) {
|
|
|
11168
11302
|
const out = [];
|
|
11169
11303
|
for (const f of files) {
|
|
11170
11304
|
try {
|
|
11171
|
-
out.push(parseWorkflow(f,
|
|
11305
|
+
out.push(parseWorkflow(f, readFileSync9(join10(dir, f), "utf8")));
|
|
11172
11306
|
} catch {
|
|
11173
11307
|
}
|
|
11174
11308
|
}
|
|
@@ -11358,22 +11492,22 @@ function joinCiProgress(ir, state) {
|
|
|
11358
11492
|
}
|
|
11359
11493
|
|
|
11360
11494
|
// src/ci-run-store.ts
|
|
11361
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as
|
|
11495
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync10, writeFileSync as writeFileSync3, rmSync } from "node:fs";
|
|
11362
11496
|
import { homedir as homedir2 } from "node:os";
|
|
11363
|
-
import { join as
|
|
11497
|
+
import { join as join11, resolve as resolve6 } from "node:path";
|
|
11364
11498
|
function slug(projectDir) {
|
|
11365
11499
|
return resolve6(projectDir).replace(/[^A-Za-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(-80);
|
|
11366
11500
|
}
|
|
11367
11501
|
function defaultRoot() {
|
|
11368
|
-
return process.env.BEHOLD_CI_RUN_DIR ??
|
|
11502
|
+
return process.env.BEHOLD_CI_RUN_DIR ?? join11(homedir2(), ".behold", "ci-runs");
|
|
11369
11503
|
}
|
|
11370
11504
|
function dispatchedRunPath(projectDir, root = defaultRoot()) {
|
|
11371
|
-
return
|
|
11505
|
+
return join11(root, `${slug(projectDir)}.json`);
|
|
11372
11506
|
}
|
|
11373
11507
|
function saveDispatchedRun(run3, root = defaultRoot()) {
|
|
11374
11508
|
try {
|
|
11375
11509
|
const path = dispatchedRunPath(run3.projectDir, root);
|
|
11376
|
-
mkdirSync3(
|
|
11510
|
+
mkdirSync3(join11(path, ".."), { recursive: true });
|
|
11377
11511
|
writeFileSync3(path, JSON.stringify({ version: 1, ...run3 }, null, 2) + "\n");
|
|
11378
11512
|
} catch {
|
|
11379
11513
|
}
|
|
@@ -11382,7 +11516,7 @@ function readDispatchedRun(projectDir, root) {
|
|
|
11382
11516
|
try {
|
|
11383
11517
|
const path = dispatchedRunPath(projectDir, root);
|
|
11384
11518
|
if (!existsSync7(path)) return void 0;
|
|
11385
|
-
const parsed = JSON.parse(
|
|
11519
|
+
const parsed = JSON.parse(readFileSync10(path, "utf8"));
|
|
11386
11520
|
if (parsed?.version !== 1 || typeof parsed.runId !== "number") return void 0;
|
|
11387
11521
|
if (resolve6(parsed.projectDir) !== resolve6(projectDir)) return void 0;
|
|
11388
11522
|
return parsed;
|
|
@@ -12500,7 +12634,7 @@ init_carve_manifest();
|
|
|
12500
12634
|
init_carve_manifest();
|
|
12501
12635
|
init_chant();
|
|
12502
12636
|
import { readdirSync as readdirSync7, statSync as statSync4 } from "node:fs";
|
|
12503
|
-
import { join as
|
|
12637
|
+
import { join as join12 } from "node:path";
|
|
12504
12638
|
|
|
12505
12639
|
// src/member-ir.ts
|
|
12506
12640
|
init_member_source();
|
|
@@ -12582,7 +12716,7 @@ function hasAnyCarveManifest(dir, io = fsIo) {
|
|
|
12582
12716
|
for (const name of entries) {
|
|
12583
12717
|
if (name.endsWith(CARVE_MANIFEST_SUFFIX)) return true;
|
|
12584
12718
|
if (name.startsWith(".") || SKIP2.has(name)) continue;
|
|
12585
|
-
const full =
|
|
12719
|
+
const full = join12(d, name);
|
|
12586
12720
|
if (io.isDirectory(full) && walk(full)) return true;
|
|
12587
12721
|
}
|
|
12588
12722
|
return false;
|
|
@@ -12624,7 +12758,7 @@ async function carveStatesUnder(dirs) {
|
|
|
12624
12758
|
init_read_scheduler();
|
|
12625
12759
|
init_chant();
|
|
12626
12760
|
import { statSync as statSync5 } from "node:fs";
|
|
12627
|
-
import { join as
|
|
12761
|
+
import { join as join14, resolve as resolve10, sep as sep4 } from "node:path";
|
|
12628
12762
|
import { composeStacks, shortStackNames } from "@intentius/pinhole";
|
|
12629
12763
|
|
|
12630
12764
|
// src/overlay-ir.ts
|
|
@@ -12783,7 +12917,7 @@ init_chant();
|
|
|
12783
12917
|
init_floor();
|
|
12784
12918
|
init_member_source();
|
|
12785
12919
|
import { existsSync as existsSync8 } from "node:fs";
|
|
12786
|
-
import { join as
|
|
12920
|
+
import { join as join13, resolve as resolve9 } from "node:path";
|
|
12787
12921
|
|
|
12788
12922
|
// src/workspace-reader.ts
|
|
12789
12923
|
init_chant();
|
|
@@ -12855,7 +12989,7 @@ function rootReader(root, env) {
|
|
|
12855
12989
|
// src/workspace.ts
|
|
12856
12990
|
var DECLARATION_FILES = ["chant.workspace.json", "chant.workspace.jsonc"];
|
|
12857
12991
|
function findDeclaration(dir) {
|
|
12858
|
-
const found = DECLARATION_FILES.filter((f) => existsSync8(
|
|
12992
|
+
const found = DECLARATION_FILES.filter((f) => existsSync8(join13(dir, f)));
|
|
12859
12993
|
if (found.length > 1) return { ambiguous: true };
|
|
12860
12994
|
return found.length === 1 ? { file: found[0] } : void 0;
|
|
12861
12995
|
}
|
|
@@ -13250,7 +13384,7 @@ function pathAlignment(declared, dir, isDir = realIsDir) {
|
|
|
13250
13384
|
const have = root.split(sep4).filter(Boolean);
|
|
13251
13385
|
for (let k = Math.min(want.length, have.length); k >= 1; k--) {
|
|
13252
13386
|
if (!have.slice(-k).every((s, i) => s === want[i])) continue;
|
|
13253
|
-
if (!isDir(
|
|
13387
|
+
if (!isDir(join14(root, ...want.slice(k)))) continue;
|
|
13254
13388
|
return k;
|
|
13255
13389
|
}
|
|
13256
13390
|
return 0;
|
|
@@ -13280,10 +13414,10 @@ function joinNamespaceBindings(members, isDir = realIsDir) {
|
|
|
13280
13414
|
if (!winner || tied) continue;
|
|
13281
13415
|
const prev = best.get(winner.dir);
|
|
13282
13416
|
if (prev === "ambiguous") continue;
|
|
13283
|
-
const
|
|
13284
|
-
if (!prev) best.set(winner.dir, { score: winner.score, join:
|
|
13417
|
+
const join52 = { dir: winner.dir, namespace: b.namespace, path: b.path, declaredBy: b.declaredBy };
|
|
13418
|
+
if (!prev) best.set(winner.dir, { score: winner.score, join: join52 });
|
|
13285
13419
|
else if (prev.join.namespace !== b.namespace) best.set(winner.dir, "ambiguous");
|
|
13286
|
-
else if (winner.score > prev.score) best.set(winner.dir, { score: winner.score, join:
|
|
13420
|
+
else if (winner.score > prev.score) best.set(winner.dir, { score: winner.score, join: join52 });
|
|
13287
13421
|
}
|
|
13288
13422
|
return [...best.values()].filter((v) => v !== "ambiguous").map((v) => v.join);
|
|
13289
13423
|
}
|
|
@@ -14013,7 +14147,7 @@ function projectHelmLogical(ir) {
|
|
|
14013
14147
|
|
|
14014
14148
|
// src/logical-kustomize.ts
|
|
14015
14149
|
import { existsSync as existsSync9 } from "node:fs";
|
|
14016
|
-
import { join as
|
|
14150
|
+
import { join as join15 } from "node:path";
|
|
14017
14151
|
function overlayBoxTitle(name) {
|
|
14018
14152
|
return `overlay ${name}`;
|
|
14019
14153
|
}
|
|
@@ -14033,7 +14167,7 @@ function kustomizationRoot(bases, dir, exists) {
|
|
|
14033
14167
|
let current = dir;
|
|
14034
14168
|
for (let i = 0; i < 4 && current; i++) {
|
|
14035
14169
|
for (const base of bases) {
|
|
14036
|
-
if (exists(
|
|
14170
|
+
if (exists(join15(base, current, "kustomization.yaml")) || exists(join15(base, current, "kustomization.yml"))) {
|
|
14037
14171
|
return current;
|
|
14038
14172
|
}
|
|
14039
14173
|
}
|
|
@@ -14738,6 +14872,32 @@ function resourcesByComponent(ir, known) {
|
|
|
14738
14872
|
}
|
|
14739
14873
|
return byComponent;
|
|
14740
14874
|
}
|
|
14875
|
+
var TERRAFORM_ESTATE_BLOCKS = /* @__PURE__ */ new Set(["resource", "data", "module"]);
|
|
14876
|
+
function terraformBlockOf(n) {
|
|
14877
|
+
const block = n.attrs?.block;
|
|
14878
|
+
if (typeof block === "string") return block;
|
|
14879
|
+
return n.kind.startsWith("Terraform::") ? n.kind.slice("Terraform::".length).toLowerCase() : void 0;
|
|
14880
|
+
}
|
|
14881
|
+
function resourcesByRoot(ir, rootOf2) {
|
|
14882
|
+
const byComponent = {};
|
|
14883
|
+
const componentsOf = /* @__PURE__ */ new Map();
|
|
14884
|
+
for (const [component, root] of Object.entries(rootOf2)) {
|
|
14885
|
+
byComponent[component] = [];
|
|
14886
|
+
componentsOf.set(root, [...componentsOf.get(root) ?? [], component]);
|
|
14887
|
+
}
|
|
14888
|
+
for (const n of ir.nodes) {
|
|
14889
|
+
const root = n.attrs?.root;
|
|
14890
|
+
const block = terraformBlockOf(n);
|
|
14891
|
+
if (typeof root !== "string" || block !== void 0 && !TERRAFORM_ESTATE_BLOCKS.has(block)) continue;
|
|
14892
|
+
for (const component of componentsOf.get(root) ?? []) {
|
|
14893
|
+
byComponent[component].push({ id: n.id, kind: n.kind, lexicon: n.lexicon, physicalId: n.physicalId, ownership: n.ownership });
|
|
14894
|
+
}
|
|
14895
|
+
}
|
|
14896
|
+
return byComponent;
|
|
14897
|
+
}
|
|
14898
|
+
|
|
14899
|
+
// src/server.ts
|
|
14900
|
+
init_terragucci_components();
|
|
14741
14901
|
|
|
14742
14902
|
// src/reconcile.ts
|
|
14743
14903
|
var DISRUPTION_SEVERITY = {
|
|
@@ -14817,17 +14977,17 @@ function summarizePlan(plan, byComponent, nonResource) {
|
|
|
14817
14977
|
import {
|
|
14818
14978
|
layoutIr,
|
|
14819
14979
|
layoutArchitecture,
|
|
14820
|
-
renderSvg,
|
|
14980
|
+
renderSvg as pinholeRenderSvg,
|
|
14821
14981
|
renderMorphHtml,
|
|
14822
14982
|
cardSizes,
|
|
14823
14983
|
registerPack
|
|
14824
14984
|
} from "@intentius/pinhole";
|
|
14825
14985
|
|
|
14826
14986
|
// src/icon-packs.ts
|
|
14827
|
-
import { readFileSync as
|
|
14828
|
-
import { dirname as dirname5, join as
|
|
14987
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
14988
|
+
import { dirname as dirname5, join as join16 } from "node:path";
|
|
14829
14989
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
14830
|
-
var ICON_ROOT =
|
|
14990
|
+
var ICON_ROOT = join16(dirname5(fileURLToPath3(import.meta.url)), "..", "web", "icons");
|
|
14831
14991
|
var cache4 = /* @__PURE__ */ new Map();
|
|
14832
14992
|
function unprefix(body) {
|
|
14833
14993
|
return body.replace(/\s(?:inkscape|sodipodi):[\w-]+\s*=\s*(["'])[\s\S]*?\1/g, "").replace(/\sxlink:href\s*=/g, " href=");
|
|
@@ -14849,7 +15009,7 @@ function plate(glyph) {
|
|
|
14849
15009
|
function loadIcon(rel) {
|
|
14850
15010
|
const hit = cache4.get(rel);
|
|
14851
15011
|
if (hit) return hit;
|
|
14852
|
-
const raw =
|
|
15012
|
+
const raw = readFileSync11(join16(ICON_ROOT, `${rel}.svg`), "utf8");
|
|
14853
15013
|
const open = raw.indexOf("<svg");
|
|
14854
15014
|
const openEnd = raw.indexOf(">", open);
|
|
14855
15015
|
const close = raw.lastIndexOf("</svg");
|
|
@@ -15754,7 +15914,332 @@ function stackOrderNoteShort(graph) {
|
|
|
15754
15914
|
return bits.join(" \xB7 ");
|
|
15755
15915
|
}
|
|
15756
15916
|
|
|
15917
|
+
// src/edge-route.ts
|
|
15918
|
+
var NUM = "(-?[\\d.]+(?:e[-+]?\\d+)?)";
|
|
15919
|
+
var CARD_PAD = 12;
|
|
15920
|
+
var LABEL_PAD = 3;
|
|
15921
|
+
var GUTTER = 24;
|
|
15922
|
+
var STUB = 16;
|
|
15923
|
+
var RADIUS = 8;
|
|
15924
|
+
var PORT_GAP = 16;
|
|
15925
|
+
var r1 = (n) => Math.round(n * 10) / 10;
|
|
15926
|
+
function svgGeometry(svg) {
|
|
15927
|
+
const cards = /* @__PURE__ */ new Map();
|
|
15928
|
+
const card = new RegExp(`<g data-node-id="([^"]*)"[^>]*><rect x="${NUM}" y="${NUM}" width="${NUM}" height="${NUM}"`, "g");
|
|
15929
|
+
for (const m of svg.matchAll(card)) {
|
|
15930
|
+
if (!cards.has(m[1])) cards.set(m[1], { x: +m[2], y: +m[3], w: +m[4], h: +m[5] });
|
|
15931
|
+
}
|
|
15932
|
+
const rich = new RegExp(`<foreignObject x="${NUM}" y="${NUM}" width="${NUM}" height="${NUM}" data-node-id="([^"]*)"`, "g");
|
|
15933
|
+
for (const m of svg.matchAll(rich)) {
|
|
15934
|
+
if (!cards.has(m[5])) cards.set(m[5], { x: +m[1], y: +m[2], w: +m[3], h: +m[4] });
|
|
15935
|
+
}
|
|
15936
|
+
const labels = [];
|
|
15937
|
+
const box = new RegExp(`<rect(?: data-group-id="[^"]*")? x="${NUM}" y="${NUM}" width="${NUM}" height="${NUM}" rx="16"[^>]*/>((?:<text [^>]*>[^<]*</text>)?)`, "g");
|
|
15938
|
+
for (const m of svg.matchAll(box)) {
|
|
15939
|
+
const [x, y, w] = [+m[1], +m[2], +m[3]];
|
|
15940
|
+
const title = /<text x="(-?[\d.]+)" y="(-?[\d.]+)"[^>]*>([^<]*)<\/text>/.exec(m[5] ?? "");
|
|
15941
|
+
if (title) {
|
|
15942
|
+
const chars = title[3].replace(/&[a-z]+;|&#\d+;/g, "x").length;
|
|
15943
|
+
labels.push({ x: +title[1] - 4, y: +title[2] - 14, w: chars * 7.8 + 8, h: 20 });
|
|
15944
|
+
}
|
|
15945
|
+
labels.push({ x: x + w - 44, y: y + 6, w: 38, h: 26 });
|
|
15946
|
+
}
|
|
15947
|
+
const badge = /<text x="(-?[\d.]+)" y="(-?[\d.]+)" text-anchor="end"[^>]*font-size="11" font-weight="600">([^<]*)<\/text>/g;
|
|
15948
|
+
for (const m of svg.matchAll(badge)) {
|
|
15949
|
+
const chars = m[3].replace(/&[a-z]+;|&#\d+;/g, "x").length;
|
|
15950
|
+
labels.push({ x: +m[1] - chars * 7 - 4, y: +m[2] - 13, w: chars * 7 + 8, h: 18 });
|
|
15951
|
+
}
|
|
15952
|
+
return { cards, labels };
|
|
15953
|
+
}
|
|
15954
|
+
var inflate = (r, p) => ({ x: r.x - p, y: r.y - p, w: r.w + 2 * p, h: r.h + 2 * p });
|
|
15955
|
+
var overlaps = (a, b) => a.x < b.x + b.w && b.x < a.x + a.w && a.y < b.y + b.h && b.y < a.y + a.h;
|
|
15956
|
+
function segmentHits(p, q, r) {
|
|
15957
|
+
let t0 = 0;
|
|
15958
|
+
let t1 = 1;
|
|
15959
|
+
const dx = q.x - p.x;
|
|
15960
|
+
const dy = q.y - p.y;
|
|
15961
|
+
const clip2 = (den, num3) => {
|
|
15962
|
+
if (den === 0) return num3 >= 0;
|
|
15963
|
+
const t2 = num3 / den;
|
|
15964
|
+
if (den < 0) {
|
|
15965
|
+
if (t2 > t1) return false;
|
|
15966
|
+
if (t2 > t0) t0 = t2;
|
|
15967
|
+
} else {
|
|
15968
|
+
if (t2 < t0) return false;
|
|
15969
|
+
if (t2 < t1) t1 = t2;
|
|
15970
|
+
}
|
|
15971
|
+
return true;
|
|
15972
|
+
};
|
|
15973
|
+
const e = 1e-6;
|
|
15974
|
+
if (!clip2(-dx, p.x - (r.x + e))) return false;
|
|
15975
|
+
if (!clip2(dx, r.x + r.w - e - p.x)) return false;
|
|
15976
|
+
if (!clip2(-dy, p.y - (r.y + e))) return false;
|
|
15977
|
+
if (!clip2(dy, r.y + r.h - e - p.y)) return false;
|
|
15978
|
+
return t1 > t0;
|
|
15979
|
+
}
|
|
15980
|
+
var cubicAt = (p0, p1, p2, p3, t2) => {
|
|
15981
|
+
const u = 1 - t2;
|
|
15982
|
+
const k = (a, b, c, d) => u * u * u * a + 3 * u * u * t2 * b + 3 * u * t2 * t2 * c + t2 * t2 * t2 * d;
|
|
15983
|
+
return { x: k(p0.x, p1.x, p2.x, p3.x), y: k(p0.y, p1.y, p2.y, p3.y) };
|
|
15984
|
+
};
|
|
15985
|
+
function frameOf(dir) {
|
|
15986
|
+
switch (dir) {
|
|
15987
|
+
case "down":
|
|
15988
|
+
return { to: (p) => p, from: (p) => p, rect: (r) => r };
|
|
15989
|
+
case "up":
|
|
15990
|
+
return { to: (p) => ({ x: p.x, y: -p.y }), from: (p) => ({ x: p.x, y: -p.y }), rect: (r) => ({ x: r.x, y: -(r.y + r.h), w: r.w, h: r.h }) };
|
|
15991
|
+
case "right":
|
|
15992
|
+
return { to: (p) => ({ x: p.y, y: p.x }), from: (p) => ({ x: p.y, y: p.x }), rect: (r) => ({ x: r.y, y: r.x, w: r.h, h: r.w }) };
|
|
15993
|
+
case "left":
|
|
15994
|
+
return { to: (p) => ({ x: p.y, y: -p.x }), from: (p) => ({ x: -p.y, y: p.x }), rect: (r) => ({ x: r.y, y: -(r.x + r.w), w: r.h, h: r.w }) };
|
|
15995
|
+
}
|
|
15996
|
+
}
|
|
15997
|
+
var EXIT = {
|
|
15998
|
+
down: ["bottom", "top"],
|
|
15999
|
+
up: ["top", "bottom"],
|
|
16000
|
+
right: ["right", "left"],
|
|
16001
|
+
left: ["left", "right"]
|
|
16002
|
+
};
|
|
16003
|
+
function directionOf2(a, b) {
|
|
16004
|
+
const below = b.y - (a.y + a.h);
|
|
16005
|
+
const above = a.y - (b.y + b.h);
|
|
16006
|
+
const right = b.x - (a.x + a.w);
|
|
16007
|
+
const left = a.x - (b.x + b.w);
|
|
16008
|
+
const v = Math.max(below, above);
|
|
16009
|
+
const h = Math.max(right, left);
|
|
16010
|
+
if (v < 0 && h < 0) return null;
|
|
16011
|
+
if (v >= h) return below >= above ? "down" : "up";
|
|
16012
|
+
return right >= left ? "right" : "left";
|
|
16013
|
+
}
|
|
16014
|
+
var portOn = (r, side, off) => {
|
|
16015
|
+
switch (side) {
|
|
16016
|
+
case "bottom":
|
|
16017
|
+
return { x: r.x + r.w / 2 + off, y: r.y + r.h };
|
|
16018
|
+
case "top":
|
|
16019
|
+
return { x: r.x + r.w / 2 + off, y: r.y };
|
|
16020
|
+
case "left":
|
|
16021
|
+
return { x: r.x, y: r.y + r.h / 2 + off };
|
|
16022
|
+
case "right":
|
|
16023
|
+
return { x: r.x + r.w, y: r.y + r.h / 2 + off };
|
|
16024
|
+
}
|
|
16025
|
+
};
|
|
16026
|
+
function roundedPath(pts) {
|
|
16027
|
+
const clean = pts.filter((p, i) => i === 0 || Math.hypot(p.x - pts[i - 1].x, p.y - pts[i - 1].y) > 0.01);
|
|
16028
|
+
let d = `M ${r1(clean[0].x)} ${r1(clean[0].y)}`;
|
|
16029
|
+
for (let i = 1; i < clean.length - 1; i++) {
|
|
16030
|
+
const [p, c, n] = [clean[i - 1], clean[i], clean[i + 1]];
|
|
16031
|
+
const l1 = Math.hypot(c.x - p.x, c.y - p.y);
|
|
16032
|
+
const l2 = Math.hypot(n.x - c.x, n.y - c.y);
|
|
16033
|
+
const r = Math.min(RADIUS, l1 / 2, l2 / 2);
|
|
16034
|
+
const a = { x: c.x - (c.x - p.x) / l1 * r, y: c.y - (c.y - p.y) / l1 * r };
|
|
16035
|
+
const b = { x: c.x + (n.x - c.x) / l2 * r, y: c.y + (n.y - c.y) / l2 * r };
|
|
16036
|
+
d += ` L ${r1(a.x)} ${r1(a.y)} Q ${r1(c.x)} ${r1(c.y)} ${r1(b.x)} ${r1(b.y)}`;
|
|
16037
|
+
}
|
|
16038
|
+
const last = clean[clean.length - 1];
|
|
16039
|
+
return `${d} L ${r1(last.x)} ${r1(last.y)}`;
|
|
16040
|
+
}
|
|
16041
|
+
function polylineCrossings(pts, blocks) {
|
|
16042
|
+
let n = 0;
|
|
16043
|
+
for (const r of blocks) {
|
|
16044
|
+
for (let i = 1; i < pts.length; i++) {
|
|
16045
|
+
if (segmentHits(pts[i - 1], pts[i], r)) {
|
|
16046
|
+
n++;
|
|
16047
|
+
break;
|
|
16048
|
+
}
|
|
16049
|
+
}
|
|
16050
|
+
}
|
|
16051
|
+
return n;
|
|
16052
|
+
}
|
|
16053
|
+
function routeEdge(input) {
|
|
16054
|
+
const dir = directionOf2(input.from, input.to);
|
|
16055
|
+
if (!dir) return null;
|
|
16056
|
+
const f = frameOf(dir);
|
|
16057
|
+
const [outSide, inSide] = EXIT[dir];
|
|
16058
|
+
const a = f.to(portOn(input.from, outSide, input.fromOffset ?? 0));
|
|
16059
|
+
const b = f.to(portOn(input.to, inSide, input.toOffset ?? 0));
|
|
16060
|
+
const A = f.rect(input.from);
|
|
16061
|
+
const B = f.rect(input.to);
|
|
16062
|
+
const blocks = [
|
|
16063
|
+
...input.obstacles.map((r) => inflate(f.rect(r), CARD_PAD)),
|
|
16064
|
+
...(input.labels ?? []).map((r) => inflate(f.rect(r), LABEL_PAD)),
|
|
16065
|
+
inflate(A, -0.5),
|
|
16066
|
+
inflate(B, -0.5)
|
|
16067
|
+
];
|
|
16068
|
+
const back = (pts2) => pts2.map((p) => f.from(p));
|
|
16069
|
+
const mid = (a.y + b.y) / 2;
|
|
16070
|
+
const c1 = { x: a.x, y: mid };
|
|
16071
|
+
const c2 = { x: b.x, y: mid };
|
|
16072
|
+
const n = Math.max(8, Math.ceil(Math.hypot(b.x - a.x, b.y - a.y) / 4));
|
|
16073
|
+
const curve = [];
|
|
16074
|
+
for (let s = 0; s <= n; s++) curve.push(cubicAt(a, c1, c2, b, s / n));
|
|
16075
|
+
const curveHits = polylineCrossings(curve, blocks);
|
|
16076
|
+
if (curveHits === 0) {
|
|
16077
|
+
const [p0, p1, p2, p3] = back([a, c1, c2, b]);
|
|
16078
|
+
return {
|
|
16079
|
+
d: `M ${r1(p0.x)} ${r1(p0.y)} C ${r1(p1.x)} ${r1(p1.y)}, ${r1(p2.x)} ${r1(p2.y)}, ${r1(p3.x)} ${r1(p3.y)}`,
|
|
16080
|
+
points: back(curve),
|
|
16081
|
+
curved: true,
|
|
16082
|
+
crossings: 0
|
|
16083
|
+
};
|
|
16084
|
+
}
|
|
16085
|
+
const stub = Math.max(4, Math.min(STUB, (b.y - a.y) / 3));
|
|
16086
|
+
const y1 = a.y + stub;
|
|
16087
|
+
const y2 = b.y - stub;
|
|
16088
|
+
const candidates = [];
|
|
16089
|
+
for (const ym of [mid, y1, y2]) candidates.push([a, { x: a.x, y: ym }, { x: b.x, y: ym }, b]);
|
|
16090
|
+
const gutters = /* @__PURE__ */ new Set();
|
|
16091
|
+
const lane = input.fromOffset ?? 0;
|
|
16092
|
+
for (const r of [...blocks.slice(0, -2), inflate(A, CARD_PAD), inflate(B, CARD_PAD)]) {
|
|
16093
|
+
if (r.y + r.h < Math.min(a.y, b.y) - 200 || r.y > Math.max(a.y, b.y) + 200) continue;
|
|
16094
|
+
for (const g of [r.x - GUTTER + CARD_PAD, r.x + r.w + GUTTER - CARD_PAD]) {
|
|
16095
|
+
gutters.add(g + lane);
|
|
16096
|
+
gutters.add(g);
|
|
16097
|
+
}
|
|
16098
|
+
}
|
|
16099
|
+
for (const g of gutters) candidates.push([a, { x: a.x, y: y1 }, { x: g, y: y1 }, { x: g, y: y2 }, { x: b.x, y: y2 }, b]);
|
|
16100
|
+
const length = (pts2) => pts2.slice(1).reduce((s, p, i) => s + Math.abs(p.x - pts2[i].x) + Math.abs(p.y - pts2[i].y), 0);
|
|
16101
|
+
candidates.sort((p, q) => length(p) - length(q));
|
|
16102
|
+
let best = null;
|
|
16103
|
+
for (const pts2 of candidates) {
|
|
16104
|
+
const hits3 = polylineCrossings(pts2, blocks);
|
|
16105
|
+
if (hits3 === 0) {
|
|
16106
|
+
best = { pts: pts2, hits: hits3 };
|
|
16107
|
+
break;
|
|
16108
|
+
}
|
|
16109
|
+
if (!best || hits3 < best.hits) best = { pts: pts2, hits: hits3 };
|
|
16110
|
+
}
|
|
16111
|
+
if (!best || best.hits >= curveHits) {
|
|
16112
|
+
const [p0, p1, p2, p3] = back([a, c1, c2, b]);
|
|
16113
|
+
return {
|
|
16114
|
+
d: `M ${r1(p0.x)} ${r1(p0.y)} C ${r1(p1.x)} ${r1(p1.y)}, ${r1(p2.x)} ${r1(p2.y)}, ${r1(p3.x)} ${r1(p3.y)}`,
|
|
16115
|
+
points: back(curve),
|
|
16116
|
+
curved: true,
|
|
16117
|
+
crossings: curveHits
|
|
16118
|
+
};
|
|
16119
|
+
}
|
|
16120
|
+
const pts = back(best.pts);
|
|
16121
|
+
return { d: roundedPath(pts), points: pts, curved: false, crossings: best.hits };
|
|
16122
|
+
}
|
|
16123
|
+
function chipSpot(points, w, h, blocks) {
|
|
16124
|
+
if (points.length < 2) return null;
|
|
16125
|
+
const cum = [0];
|
|
16126
|
+
for (let i = 1; i < points.length; i++) cum.push(cum[i - 1] + Math.hypot(points[i].x - points[i - 1].x, points[i].y - points[i - 1].y));
|
|
16127
|
+
const total = cum[cum.length - 1];
|
|
16128
|
+
const at2 = (s) => {
|
|
16129
|
+
let i = 1;
|
|
16130
|
+
while (i < cum.length - 1 && cum[i] < s) i++;
|
|
16131
|
+
const seg = cum[i] - cum[i - 1] || 1;
|
|
16132
|
+
const t2 = (s - cum[i - 1]) / seg;
|
|
16133
|
+
return { x: points[i - 1].x + (points[i].x - points[i - 1].x) * t2, y: points[i - 1].y + (points[i].y - points[i - 1].y) * t2 };
|
|
16134
|
+
};
|
|
16135
|
+
const beside = [{ x: 0, y: 0 }, { x: w / 2 + 4, y: 0 }, { x: -(w / 2 + 4), y: 0 }, { x: 0, y: h / 2 + 4 }, { x: 0, y: -(h / 2 + 4) }];
|
|
16136
|
+
for (const nudge of beside) {
|
|
16137
|
+
for (const frac2 of [0.5, 0.4, 0.6, 0.3, 0.7, 0.2, 0.8, 0.12, 0.88]) {
|
|
16138
|
+
const on = at2(total * frac2);
|
|
16139
|
+
const c = { x: on.x + nudge.x, y: on.y + nudge.y };
|
|
16140
|
+
const chip = { x: c.x - w / 2, y: c.y - h / 2, w, h };
|
|
16141
|
+
if (!blocks.some((r) => overlaps(chip, r))) return c;
|
|
16142
|
+
}
|
|
16143
|
+
}
|
|
16144
|
+
return null;
|
|
16145
|
+
}
|
|
16146
|
+
var PORT_REACH = 40;
|
|
16147
|
+
function clearOfLabels(card, side, offsets, labels) {
|
|
16148
|
+
const along = side === "top" || side === "bottom";
|
|
16149
|
+
const len = along ? card.w : card.h;
|
|
16150
|
+
const margin = 14;
|
|
16151
|
+
const lo = -len / 2 + margin - Math.min(...offsets);
|
|
16152
|
+
const hi = len / 2 - margin - Math.max(...offsets);
|
|
16153
|
+
const probe2 = (shift) => offsets.every((off) => {
|
|
16154
|
+
const p = portOn(card, side, off + shift);
|
|
16155
|
+
const reach = along ? { x: p.x - 2, y: side === "top" ? p.y - PORT_REACH : p.y, w: 4, h: PORT_REACH } : { x: side === "left" ? p.x - PORT_REACH : p.x, y: p.y - 2, w: PORT_REACH, h: 4 };
|
|
16156
|
+
return !labels.some((l) => overlaps(reach, inflate(l, LABEL_PAD)));
|
|
16157
|
+
});
|
|
16158
|
+
if (probe2(0)) return 0;
|
|
16159
|
+
for (let step = 4; step <= len; step += 4) {
|
|
16160
|
+
if (step <= hi && probe2(step)) return step;
|
|
16161
|
+
if (-step >= lo && probe2(-step)) return -step;
|
|
16162
|
+
}
|
|
16163
|
+
return 0;
|
|
16164
|
+
}
|
|
16165
|
+
var EDGE = new RegExp(
|
|
16166
|
+
// The line group pinhole's `Canvas.edge` writes, then (optionally) the chip
|
|
16167
|
+
// group `Canvas.edgeLabel` writes straight after it.
|
|
16168
|
+
`<g data-edge-from="([^"]*)" data-edge-to="([^"]*)"([^>]*)><path class="pin-edge-line([^"]*)" d="([^"]*)"([^>]*)/><path d="([^"]*)"([^>]*)/></g>(?:<g data-edge-from="([^"]*)" data-edge-to="([^"]*)"([^>]*)><rect x="${NUM}" y="${NUM}" width="${NUM}" height="${NUM}"([^>]*)/><text x="${NUM}" y="${NUM}")?`,
|
|
16169
|
+
"g"
|
|
16170
|
+
);
|
|
16171
|
+
function routeEdges(svg) {
|
|
16172
|
+
if (!svg.includes("pin-edge-line")) return svg;
|
|
16173
|
+
const geo = svgGeometry(svg);
|
|
16174
|
+
const found = [...svg.matchAll(EDGE)];
|
|
16175
|
+
if (!found.length) return svg;
|
|
16176
|
+
const dirs = found.map((m) => {
|
|
16177
|
+
const a = geo.cards.get(m[1]);
|
|
16178
|
+
const b = geo.cards.get(m[2]);
|
|
16179
|
+
return a && b && m[1] !== m[2] ? directionOf2(a, b) : null;
|
|
16180
|
+
});
|
|
16181
|
+
const sides = /* @__PURE__ */ new Map();
|
|
16182
|
+
const ends = found.map((m, i) => {
|
|
16183
|
+
const dir = dirs[i];
|
|
16184
|
+
if (!dir) return null;
|
|
16185
|
+
const [outSide, inSide] = EXIT[dir];
|
|
16186
|
+
const a = geo.cards.get(m[1]);
|
|
16187
|
+
const b = geo.cards.get(m[2]);
|
|
16188
|
+
const horiz = dir === "down" || dir === "up";
|
|
16189
|
+
const centre = (r) => horiz ? r.x + r.w / 2 : r.y + r.h / 2;
|
|
16190
|
+
const pair = [
|
|
16191
|
+
{ edge: i, card: m[1], side: outSide, toward: centre(b), offset: 0 },
|
|
16192
|
+
{ edge: i, card: m[2], side: inSide, toward: centre(a), offset: 0 }
|
|
16193
|
+
];
|
|
16194
|
+
for (const e of pair) {
|
|
16195
|
+
const key = `${e.card}\0${e.side}`;
|
|
16196
|
+
const list3 = sides.get(key) ?? [];
|
|
16197
|
+
list3.push(e);
|
|
16198
|
+
sides.set(key, list3);
|
|
16199
|
+
}
|
|
16200
|
+
return pair;
|
|
16201
|
+
});
|
|
16202
|
+
for (const list3 of sides.values()) {
|
|
16203
|
+
const card = geo.cards.get(list3[0].card);
|
|
16204
|
+
const side = list3[0].side;
|
|
16205
|
+
const len = side === "top" || side === "bottom" ? card.w : card.h;
|
|
16206
|
+
if (list3.length > 1) {
|
|
16207
|
+
const gap = Math.min(PORT_GAP, len * 0.7 / (list3.length - 1));
|
|
16208
|
+
list3.sort((p, q) => p.toward - q.toward || p.edge - q.edge);
|
|
16209
|
+
list3.forEach((e, k2) => e.offset = (k2 - (list3.length - 1) / 2) * gap);
|
|
16210
|
+
}
|
|
16211
|
+
const shift = clearOfLabels(card, side, list3.map((e) => e.offset), geo.labels);
|
|
16212
|
+
if (shift) list3.forEach((e) => e.offset += shift);
|
|
16213
|
+
}
|
|
16214
|
+
const cardRects = [...geo.cards.entries()];
|
|
16215
|
+
const chips = [];
|
|
16216
|
+
let k = -1;
|
|
16217
|
+
return svg.replace(EDGE, (whole, ...g) => {
|
|
16218
|
+
k++;
|
|
16219
|
+
const pair = ends[k];
|
|
16220
|
+
if (!pair) return whole;
|
|
16221
|
+
const [from, to] = [g[0], g[1]];
|
|
16222
|
+
const obstacles = cardRects.filter(([id]) => id !== from && id !== to).map(([, r]) => r);
|
|
16223
|
+
const route = routeEdge({ from: geo.cards.get(from), to: geo.cards.get(to), fromOffset: pair[0].offset, toOffset: pair[1].offset, obstacles, labels: geo.labels });
|
|
16224
|
+
if (!route) return whole;
|
|
16225
|
+
let out = `<g data-edge-from="${from}" data-edge-to="${to}"${g[2]}><path class="pin-edge-line${g[3]}" d="${route.d}"${g[5]}/><path d="${route.d}"${g[7]}/></g>`;
|
|
16226
|
+
if (g[8] === void 0) return out;
|
|
16227
|
+
const [rx, ry, rw, rh, tx, ty] = [g[11], g[12], g[13], g[14], g[16], g[17]].map(Number);
|
|
16228
|
+
const blocks = [...[...geo.cards.values()].map((r) => inflate(r, 2)), ...geo.labels, ...chips];
|
|
16229
|
+
const spot = chipSpot(route.points, rw, rh, blocks);
|
|
16230
|
+
const c = spot ?? { x: rx + rw / 2, y: ry + rh / 2 };
|
|
16231
|
+
const dx = c.x - (rx + rw / 2);
|
|
16232
|
+
const dy = c.y - (ry + rh / 2);
|
|
16233
|
+
chips.push({ x: rx + dx - 2, y: ry + dy - 2, w: rw + 4, h: rh + 4 });
|
|
16234
|
+
out += `<g data-edge-from="${g[8]}" data-edge-to="${g[9]}"${g[10]}><rect x="${r1(rx + dx)}" y="${r1(ry + dy)}" width="${g[13]}" height="${g[14]}"${g[15]}/><text x="${r1(tx + dx)}" y="${r1(ty + dy)}"`;
|
|
16235
|
+
return out;
|
|
16236
|
+
});
|
|
16237
|
+
}
|
|
16238
|
+
|
|
15757
16239
|
// src/render.ts
|
|
16240
|
+
function renderSvg(...args) {
|
|
16241
|
+
return routeEdges(pinholeRenderSvg(...args));
|
|
16242
|
+
}
|
|
15758
16243
|
registerPack({ lexicon: "k8s", iconFor: k8sIconFor });
|
|
15759
16244
|
registerPack({ lexicon: "helm", iconFor: helmIconFor });
|
|
15760
16245
|
registerPack({ lexicon: SQL_LEXICON, iconFor: sqlIconFor, fields: sqlCardFields });
|
|
@@ -15856,6 +16341,12 @@ function renderGraph(irIn, opts = {}) {
|
|
|
15856
16341
|
box.title = title === box.id && box.parent !== void 0 && title.startsWith(`${box.parent}/`) ? title.slice(box.parent.length + 1) : title;
|
|
15857
16342
|
}
|
|
15858
16343
|
}
|
|
16344
|
+
if (boxKey === "byWave" && opts.waveTitles) {
|
|
16345
|
+
for (const box of layout.groups ?? []) {
|
|
16346
|
+
const title = box.id === void 0 ? void 0 : opts.waveTitles[box.id];
|
|
16347
|
+
if (title !== void 0) box.title = title;
|
|
16348
|
+
}
|
|
16349
|
+
}
|
|
15859
16350
|
const svg = renderSvg(ir, layout, {
|
|
15860
16351
|
fit: true,
|
|
15861
16352
|
hideTitle: true,
|
|
@@ -16604,7 +17095,7 @@ function radializeLayout(layout, groupOf, size = /* @__PURE__ */ new Map()) {
|
|
|
16604
17095
|
n.y += (k * 7 % 5 - 2) * 0.4;
|
|
16605
17096
|
});
|
|
16606
17097
|
for (let iter = 0; iter < 2500; iter++) {
|
|
16607
|
-
let
|
|
17098
|
+
let overlaps2 = 0;
|
|
16608
17099
|
for (let a = 0; a < nodes.length; a++) {
|
|
16609
17100
|
for (let b = a + 1; b < nodes.length; b++) {
|
|
16610
17101
|
const dx = nodes[b].x - nodes[a].x;
|
|
@@ -16614,7 +17105,7 @@ function radializeLayout(layout, groupOf, size = /* @__PURE__ */ new Map()) {
|
|
|
16614
17105
|
const ox = sepW - Math.abs(dx);
|
|
16615
17106
|
const oy = sepH - Math.abs(dy);
|
|
16616
17107
|
if (ox <= 0 || oy <= 0) continue;
|
|
16617
|
-
|
|
17108
|
+
overlaps2++;
|
|
16618
17109
|
const d = Math.hypot(dx, dy) || 0.01;
|
|
16619
17110
|
const push = Math.min(ox, oy) * 0.75 + 2;
|
|
16620
17111
|
const ux = dx / d;
|
|
@@ -16625,7 +17116,7 @@ function radializeLayout(layout, groupOf, size = /* @__PURE__ */ new Map()) {
|
|
|
16625
17116
|
nodes[b].y += uy * push;
|
|
16626
17117
|
}
|
|
16627
17118
|
}
|
|
16628
|
-
if (
|
|
17119
|
+
if (overlaps2 === 0) break;
|
|
16629
17120
|
}
|
|
16630
17121
|
const minX = Math.min(...nodes.map((n) => n.x - wOf(n) / 2));
|
|
16631
17122
|
const minY = Math.min(...nodes.map((n) => n.y - hOf(n) / 2));
|
|
@@ -16653,12 +17144,12 @@ init_carve_manifest();
|
|
|
16653
17144
|
|
|
16654
17145
|
// src/carve-actions.ts
|
|
16655
17146
|
init_chant();
|
|
16656
|
-
import { existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as
|
|
16657
|
-
import { isAbsolute as isAbsolute3, join as
|
|
17147
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync14, readdirSync as readdirSync8, statSync as statSync6 } from "node:fs";
|
|
17148
|
+
import { isAbsolute as isAbsolute3, join as join19, relative as relative4, resolve as resolve11, sep as sep5 } from "node:path";
|
|
16658
17149
|
|
|
16659
17150
|
// src/layout.ts
|
|
16660
|
-
import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as
|
|
16661
|
-
import { join as
|
|
17151
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync12, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync4, accessSync, constants } from "node:fs";
|
|
17152
|
+
import { join as join17 } from "node:path";
|
|
16662
17153
|
var LAYOUT_DIR = ".behold";
|
|
16663
17154
|
var LAYOUT_FILE = "layout.json";
|
|
16664
17155
|
var MAX_BODY_BYTES = 64 * 1024;
|
|
@@ -16667,7 +17158,7 @@ var MAX_IDS_PER_LENS = 2e3;
|
|
|
16667
17158
|
var MAX_LENSES = 64;
|
|
16668
17159
|
var MAX_ID_LENGTH = 512;
|
|
16669
17160
|
var MAX_LENS_LENGTH = 128;
|
|
16670
|
-
var
|
|
17161
|
+
var NUM2 = ["dx", "dy", "dw", "dh"];
|
|
16671
17162
|
function slug2(s) {
|
|
16672
17163
|
return String(s ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "unknown";
|
|
16673
17164
|
}
|
|
@@ -16684,7 +17175,7 @@ function normalizeDeltas(raw) {
|
|
|
16684
17175
|
for (const [id, d] of Object.entries(raw)) {
|
|
16685
17176
|
if (!id || id.length > MAX_ID_LENGTH || id === "__proto__" || !d || typeof d !== "object") continue;
|
|
16686
17177
|
const clean = {};
|
|
16687
|
-
for (const k of
|
|
17178
|
+
for (const k of NUM2) {
|
|
16688
17179
|
const v = Number(d[k]);
|
|
16689
17180
|
if (Number.isFinite(v) && v !== 0) clean[k] = v;
|
|
16690
17181
|
}
|
|
@@ -16699,7 +17190,7 @@ function lensFromQuery(params) {
|
|
|
16699
17190
|
return [slug2(zoom), params.get("radial") === "1" ? "radial" : null, stack ? slug2(`stack-${stack}`) : null].filter(Boolean).join("+");
|
|
16700
17191
|
}
|
|
16701
17192
|
function layoutPath(projectDir) {
|
|
16702
|
-
return
|
|
17193
|
+
return join17(projectDir, LAYOUT_DIR, LAYOUT_FILE);
|
|
16703
17194
|
}
|
|
16704
17195
|
function unwritableReason(projectDir) {
|
|
16705
17196
|
if (!projectDir || !existsSync10(projectDir)) return `no such project directory: ${projectDir || "(none)"}`;
|
|
@@ -16715,7 +17206,7 @@ function readLayoutFile(projectDir) {
|
|
|
16715
17206
|
const file = layoutPath(projectDir);
|
|
16716
17207
|
try {
|
|
16717
17208
|
if (!existsSync10(file)) return empty;
|
|
16718
|
-
const raw =
|
|
17209
|
+
const raw = readFileSync12(file, "utf8");
|
|
16719
17210
|
if (raw.length > MAX_FILE_BYTES) return empty;
|
|
16720
17211
|
const parsed = JSON.parse(raw);
|
|
16721
17212
|
if (!parsed || typeof parsed !== "object" || !parsed.lenses || typeof parsed.lenses !== "object") return empty;
|
|
@@ -16755,7 +17246,7 @@ function writeLens(projectDir, lens, deltas) {
|
|
|
16755
17246
|
}
|
|
16756
17247
|
const body = JSON.stringify({ version: 1, lenses }, null, 2) + "\n";
|
|
16757
17248
|
if (body.length > MAX_FILE_BYTES) throw new LayoutTooLarge(`a layout sidecar is capped at ${MAX_FILE_BYTES} bytes`);
|
|
16758
|
-
mkdirSync4(
|
|
17249
|
+
mkdirSync4(join17(projectDir, LAYOUT_DIR), { recursive: true });
|
|
16759
17250
|
const tmp = `${file}.tmp`;
|
|
16760
17251
|
writeFileSync4(tmp, body, "utf8");
|
|
16761
17252
|
renameSync(tmp, file);
|
|
@@ -16841,8 +17332,8 @@ function reanchorEdges(svg, moved) {
|
|
|
16841
17332
|
// src/carve-live.ts
|
|
16842
17333
|
init_scratch();
|
|
16843
17334
|
import { spawn as spawn4 } from "node:child_process";
|
|
16844
|
-
import { readFileSync as
|
|
16845
|
-
import { join as
|
|
17335
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync5, existsSync as existsSync11 } from "node:fs";
|
|
17336
|
+
import { join as join18 } from "node:path";
|
|
16846
17337
|
var LIVE_CONTAINER = "behold-carve-floci";
|
|
16847
17338
|
var LIVE_PORT = 4602;
|
|
16848
17339
|
var LIVE_IMAGE = "floci/floci:1.5.34";
|
|
@@ -16902,9 +17393,9 @@ async function teardownScratchFloci() {
|
|
|
16902
17393
|
await capture("docker", ["rm", "-f", LIVE_CONTAINER], process.cwd()).catch(() => void 0);
|
|
16903
17394
|
}
|
|
16904
17395
|
async function applyIntoFloci(fromDir, step) {
|
|
16905
|
-
const template =
|
|
17396
|
+
const template = join18(fromDir, "floci-override.tf.disabled");
|
|
16906
17397
|
if (!existsSync11(template)) return `no floci-override.tf.disabled in ${fromDir} \u2014 this estate wasn't authored for the live tier`;
|
|
16907
|
-
writeFileSync5(
|
|
17398
|
+
writeFileSync5(join18(fromDir, "floci_override.tf"), armOverride(readFileSync13(template, "utf8"), LIVE_PORT));
|
|
16908
17399
|
const init = await step("terraform", ["init", "-input=false", "-no-color"], fromDir);
|
|
16909
17400
|
if (init !== 0) return `terraform init exited ${init} (provider downloads need network)`;
|
|
16910
17401
|
const apply = await step(
|
|
@@ -16954,7 +17445,7 @@ async function runCarveObserve(demo, select) {
|
|
|
16954
17445
|
"run `behold demo carve --live` (needs docker + terraform)"
|
|
16955
17446
|
);
|
|
16956
17447
|
}
|
|
16957
|
-
if (!existsSync12(
|
|
17448
|
+
if (!existsSync12(join19(demo.out, "src"))) {
|
|
16958
17449
|
return refuse6("carve-action", "nothing has been emitted yet", "run Emit first \u2014 observe reads the carveout emit writes");
|
|
16959
17450
|
}
|
|
16960
17451
|
const args = ["lifecycle", "diff", "prod", "--live", "--json"];
|
|
@@ -17052,7 +17543,7 @@ function readArtifacts(demo, dir, filter) {
|
|
|
17052
17543
|
for (const name of entries) {
|
|
17053
17544
|
if (out.length >= MAX_ARTIFACTS) return;
|
|
17054
17545
|
if (name === "node_modules" || name.startsWith(".")) continue;
|
|
17055
|
-
const full =
|
|
17546
|
+
const full = join19(d, name);
|
|
17056
17547
|
let st;
|
|
17057
17548
|
try {
|
|
17058
17549
|
st = statSync6(full);
|
|
@@ -17067,7 +17558,7 @@ function readArtifacts(demo, dir, filter) {
|
|
|
17067
17558
|
if (!filter(rel)) continue;
|
|
17068
17559
|
let text = "";
|
|
17069
17560
|
try {
|
|
17070
|
-
text =
|
|
17561
|
+
text = readFileSync14(full, "utf8");
|
|
17071
17562
|
} catch {
|
|
17072
17563
|
continue;
|
|
17073
17564
|
}
|
|
@@ -17099,7 +17590,7 @@ async function runCarveEmit(demo, select) {
|
|
|
17099
17590
|
const block = carveWriteBlock(demo);
|
|
17100
17591
|
if (block) return refuse6("read-only", block, "Start the walkthrough with `behold demo carve`.");
|
|
17101
17592
|
mkdirSync5(demo.out, { recursive: true });
|
|
17102
|
-
const reportFile =
|
|
17593
|
+
const reportFile = join19(demo.out, `${carveSlug(select)}-boundary.json`);
|
|
17103
17594
|
const args = [
|
|
17104
17595
|
"carve",
|
|
17105
17596
|
"emit",
|
|
@@ -17128,10 +17619,10 @@ async function runCarveEmit(demo, select) {
|
|
|
17128
17619
|
}
|
|
17129
17620
|
let boundary = null;
|
|
17130
17621
|
try {
|
|
17131
|
-
boundary = JSON.parse(
|
|
17622
|
+
boundary = JSON.parse(readFileSync14(reportFile, "utf8"));
|
|
17132
17623
|
} catch {
|
|
17133
17624
|
}
|
|
17134
|
-
const lintPath = relative4(demo.project,
|
|
17625
|
+
const lintPath = relative4(demo.project, join19(demo.out, "src")).split(sep5).join("/");
|
|
17135
17626
|
const lintArgs = ["lint", lintPath];
|
|
17136
17627
|
const lint = await runChantRaw(lintArgs, demo.project).catch((err) => ({
|
|
17137
17628
|
code: 127,
|
|
@@ -17194,8 +17685,8 @@ async function runCarveBridge(demo, select) {
|
|
|
17194
17685
|
}
|
|
17195
17686
|
|
|
17196
17687
|
// src/ops.ts
|
|
17197
|
-
import { readdirSync as readdirSync9, readFileSync as
|
|
17198
|
-
import { join as
|
|
17688
|
+
import { readdirSync as readdirSync9, readFileSync as readFileSync15, existsSync as existsSync13 } from "node:fs";
|
|
17689
|
+
import { join as join20 } from "node:path";
|
|
17199
17690
|
var APPLY_TARGET_LEXICON = {
|
|
17200
17691
|
cloudformation: "aws",
|
|
17201
17692
|
kubectl: "k8s",
|
|
@@ -17217,11 +17708,11 @@ function discoverOps(projectDir) {
|
|
|
17217
17708
|
const seen = /* @__PURE__ */ new Set();
|
|
17218
17709
|
const out = [];
|
|
17219
17710
|
for (const sub of ["ops", "src", "."]) {
|
|
17220
|
-
const dir =
|
|
17711
|
+
const dir = join20(projectDir, sub);
|
|
17221
17712
|
if (!existsSync13(dir)) continue;
|
|
17222
17713
|
for (const f of readdirSync9(dir)) {
|
|
17223
17714
|
if (!f.endsWith(".op.ts")) continue;
|
|
17224
|
-
const content =
|
|
17715
|
+
const content = readFileSync15(join20(dir, f), "utf8");
|
|
17225
17716
|
const name = content.match(/name:\s*["'`]([^"'`]+)["'`]/)?.[1];
|
|
17226
17717
|
if (!name || seen.has(name)) continue;
|
|
17227
17718
|
seen.add(name);
|
|
@@ -17244,13 +17735,13 @@ function discoverOps(projectDir) {
|
|
|
17244
17735
|
return out.sort((a, b) => a.name.localeCompare(b.name));
|
|
17245
17736
|
}
|
|
17246
17737
|
function opIrPath(projectDir, name) {
|
|
17247
|
-
return
|
|
17738
|
+
return join20(projectDir, "dist", "ops", name, "op.json");
|
|
17248
17739
|
}
|
|
17249
17740
|
function discoverOpIrs(projectDirs) {
|
|
17250
17741
|
const seen = /* @__PURE__ */ new Set();
|
|
17251
17742
|
const out = [];
|
|
17252
17743
|
for (const dir of projectDirs) {
|
|
17253
|
-
const root =
|
|
17744
|
+
const root = join20(dir, "dist", "ops");
|
|
17254
17745
|
if (!existsSync13(root)) continue;
|
|
17255
17746
|
for (const name of readdirSync9(root)) {
|
|
17256
17747
|
if (seen.has(name)) continue;
|
|
@@ -17490,11 +17981,11 @@ var RAN = { ok: "ok", fail: "failed", skipped: "skipped" };
|
|
|
17490
17981
|
function tookLabel(ms) {
|
|
17491
17982
|
return ms < 1e3 ? `${ms}ms` : `${(ms / 1e3).toFixed(1)}s`;
|
|
17492
17983
|
}
|
|
17493
|
-
function paintPlayhead(ir,
|
|
17494
|
-
if (!
|
|
17984
|
+
function paintPlayhead(ir, join52, gate) {
|
|
17985
|
+
if (!join52.byNode.size && !join52.at) return ir;
|
|
17495
17986
|
const nodes = ir.nodes.map((node) => {
|
|
17496
|
-
const run3 =
|
|
17497
|
-
const here =
|
|
17987
|
+
const run3 = join52.byNode.get(node.id);
|
|
17988
|
+
const here = join52.at === node.id;
|
|
17498
17989
|
if (!run3 && !here) return node;
|
|
17499
17990
|
const isGate = node.attrs?._step === "gate";
|
|
17500
17991
|
const attrs = { ...node.attrs };
|
|
@@ -17509,7 +18000,7 @@ function paintPlayhead(ir, join51, gate) {
|
|
|
17509
18000
|
if (here) {
|
|
17510
18001
|
attrs._playhead = true;
|
|
17511
18002
|
attrs._status = isGate && gate ? "warn" : "accent";
|
|
17512
|
-
attrs.run = isGate && gate ? `waiting for approval since ${gate.since}` :
|
|
18003
|
+
attrs.run = isGate && gate ? `waiting for approval since ${gate.since}` : join52.atReason ?? "here";
|
|
17513
18004
|
if (isGate && gate?.description) attrs.gateDescription = gate.description;
|
|
17514
18005
|
}
|
|
17515
18006
|
return { ...node, attrs };
|
|
@@ -17531,11 +18022,11 @@ function pendingGateCard(op, gate, ir) {
|
|
|
17531
18022
|
}
|
|
17532
18023
|
};
|
|
17533
18024
|
}
|
|
17534
|
-
function playheadNote(state,
|
|
18025
|
+
function playheadNote(state, join52) {
|
|
17535
18026
|
if (!state.op) {
|
|
17536
18027
|
return "No run state: nothing has been run from this behold session, so every step paints as declared.";
|
|
17537
18028
|
}
|
|
17538
|
-
const settled =
|
|
18029
|
+
const settled = join52 ? join52.byNode.size : state.records.length;
|
|
17539
18030
|
const bits = [];
|
|
17540
18031
|
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`;
|
|
17541
18032
|
if (state.status === "running") {
|
|
@@ -17551,9 +18042,9 @@ function playheadNote(state, join51) {
|
|
|
17551
18042
|
} else if (state.gateNote) {
|
|
17552
18043
|
bits.push(`gate state unavailable \u2014 ${state.gateNote}`);
|
|
17553
18044
|
}
|
|
17554
|
-
if (
|
|
18045
|
+
if (join52?.unplaced.length) {
|
|
17555
18046
|
bits.push(
|
|
17556
|
-
`${
|
|
18047
|
+
`${join52.unplaced.length} record${join52.unplaced.length === 1 ? "" : "s"} matched no declared step and ${join52.unplaced.length === 1 ? "is" : "are"} not painted`
|
|
17557
18048
|
);
|
|
17558
18049
|
}
|
|
17559
18050
|
if (!bits.length) return `${head}.`;
|
|
@@ -18224,8 +18715,8 @@ var OpRunner = class {
|
|
|
18224
18715
|
};
|
|
18225
18716
|
|
|
18226
18717
|
// src/public-mode.ts
|
|
18227
|
-
import { readFileSync as
|
|
18228
|
-
import { join as
|
|
18718
|
+
import { readFileSync as readFileSync16 } from "node:fs";
|
|
18719
|
+
import { join as join21 } from "node:path";
|
|
18229
18720
|
var ReadOnlyRunner = class {
|
|
18230
18721
|
running = null;
|
|
18231
18722
|
applyProgress = initialApplyProgress;
|
|
@@ -18288,7 +18779,7 @@ function publicReadRefusal(path, query) {
|
|
|
18288
18779
|
}
|
|
18289
18780
|
var PUBLIC_FLAG = "<script>window.__BEHOLD_PUBLIC__ = true;</script>";
|
|
18290
18781
|
function publicPage(webRoot2) {
|
|
18291
|
-
const html =
|
|
18782
|
+
const html = readFileSync16(join21(webRoot2, "index.html"), "utf8");
|
|
18292
18783
|
return html.replace("</head>", ` ${PUBLIC_FLAG}
|
|
18293
18784
|
</head>`);
|
|
18294
18785
|
}
|
|
@@ -18305,8 +18796,8 @@ function publicRoutes(app, webRoot2) {
|
|
|
18305
18796
|
|
|
18306
18797
|
// src/substrates.ts
|
|
18307
18798
|
import { spawn as spawn5 } from "node:child_process";
|
|
18308
|
-
import { existsSync as existsSync14, readFileSync as
|
|
18309
|
-
import { join as
|
|
18799
|
+
import { existsSync as existsSync14, readFileSync as readFileSync17 } from "node:fs";
|
|
18800
|
+
import { join as join22 } from "node:path";
|
|
18310
18801
|
import { platform } from "node:os";
|
|
18311
18802
|
var DOCKER_DOWN_DETAIL = "docker is down";
|
|
18312
18803
|
function probe(cmd, args) {
|
|
@@ -18335,11 +18826,11 @@ async function dockerRunning(run3, nameFilter) {
|
|
|
18335
18826
|
return out.split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
18336
18827
|
}
|
|
18337
18828
|
function scriptBringUp(projectDir, relPath, label) {
|
|
18338
|
-
return existsSync14(
|
|
18829
|
+
return existsSync14(join22(projectDir, relPath)) ? { label, cmd: "bash", args: [relPath] } : void 0;
|
|
18339
18830
|
}
|
|
18340
18831
|
function projectLexicons(projectDir) {
|
|
18341
18832
|
try {
|
|
18342
|
-
const src =
|
|
18833
|
+
const src = readFileSync17(join22(projectDir, "chant.config.ts"), "utf-8");
|
|
18343
18834
|
const m = src.match(/lexicons\s*:\s*\[([^\]]*)\]/);
|
|
18344
18835
|
if (!m) return [];
|
|
18345
18836
|
return [...m[1].matchAll(/["']([^"']+)["']/g)].map((x) => x[1]);
|
|
@@ -18391,7 +18882,7 @@ async function detectSubstrates(projectDir, preview = false, boundContext, probe
|
|
|
18391
18882
|
["forgejo", "Forgejo", ".forgejo", "test/forgejo-runtime-e2e.sh"]
|
|
18392
18883
|
];
|
|
18393
18884
|
for (const [name, label, marker, script] of forges) {
|
|
18394
|
-
if (!existsSync14(
|
|
18885
|
+
if (!existsSync14(join22(projectDir, marker))) continue;
|
|
18395
18886
|
const c = docker ? await dockerRunning(run3, name) : [];
|
|
18396
18887
|
const d = dep(c.length > 0, "container up", "on-demand (pipeline run)");
|
|
18397
18888
|
subs.push({
|
|
@@ -18425,7 +18916,7 @@ async function detectSubstrates(projectDir, preview = false, boundContext, probe
|
|
|
18425
18916
|
detail: endpoint ? `targeting ${endpoint}` : "real Fly (FLY_FLAPS_BASE_URL unset)"
|
|
18426
18917
|
});
|
|
18427
18918
|
}
|
|
18428
|
-
if (existsSync14(
|
|
18919
|
+
if (existsSync14(join22(projectDir, ".github", "workflows"))) {
|
|
18429
18920
|
const gh = await run3("gh", ["auth", "status"]);
|
|
18430
18921
|
const ready = gh.code === 0;
|
|
18431
18922
|
subs.push({
|
|
@@ -18438,7 +18929,7 @@ async function detectSubstrates(projectDir, preview = false, boundContext, probe
|
|
|
18438
18929
|
if (lexicons.includes("temporal")) {
|
|
18439
18930
|
let hasProfiles = false;
|
|
18440
18931
|
try {
|
|
18441
|
-
hasProfiles = /temporal\s*:\s*\{[\s\S]{0,400}?profiles\s*:/.test(
|
|
18932
|
+
hasProfiles = /temporal\s*:\s*\{[\s\S]{0,400}?profiles\s*:/.test(readFileSync17(join22(projectDir, "chant.config.ts"), "utf-8"));
|
|
18442
18933
|
} catch {
|
|
18443
18934
|
}
|
|
18444
18935
|
subs.push({
|
|
@@ -18581,8 +19072,8 @@ function statusVocabulary(kinds) {
|
|
|
18581
19072
|
}
|
|
18582
19073
|
|
|
18583
19074
|
// src/behaviour.ts
|
|
18584
|
-
import { readFileSync as
|
|
18585
|
-
import { join as
|
|
19075
|
+
import { readFileSync as readFileSync18 } from "node:fs";
|
|
19076
|
+
import { join as join23 } from "node:path";
|
|
18586
19077
|
var rec5 = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
|
|
18587
19078
|
var str6 = (v) => typeof v === "string" && v.trim().length > 0 ? v : void 0;
|
|
18588
19079
|
var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
@@ -18689,7 +19180,7 @@ var FIRST_TOTAL_SHOWN = "two members stated an estate total; the first is shown"
|
|
|
18689
19180
|
var behaviourFileName = (env) => `behaviour.${env}.json`;
|
|
18690
19181
|
var realRead = (path) => {
|
|
18691
19182
|
try {
|
|
18692
|
-
return
|
|
19183
|
+
return readFileSync18(path, "utf8");
|
|
18693
19184
|
} catch {
|
|
18694
19185
|
return void 0;
|
|
18695
19186
|
}
|
|
@@ -18747,7 +19238,7 @@ function attachBehaviour(ir, members, env, readFile2 = realRead) {
|
|
|
18747
19238
|
}
|
|
18748
19239
|
const file = behaviourFileName(env);
|
|
18749
19240
|
looked.push(`${label}/${file}`);
|
|
18750
|
-
const raw = readFile2(
|
|
19241
|
+
const raw = readFile2(join23(m.dir, file));
|
|
18751
19242
|
if (raw === void 0) {
|
|
18752
19243
|
sources.set(label, "none");
|
|
18753
19244
|
continue;
|
|
@@ -19183,7 +19674,7 @@ init_choudoufu_live();
|
|
|
19183
19674
|
init_choudoufu_member();
|
|
19184
19675
|
import { mkdtempSync, rmSync as rmSync3 } from "node:fs";
|
|
19185
19676
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
19186
|
-
import { join as
|
|
19677
|
+
import { join as join24 } from "node:path";
|
|
19187
19678
|
var isRecord10 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
19188
19679
|
var refuse7 = (error, remedy) => ({ ok: false, refusal: { error, code: "choudoufu-live-check", remedy } });
|
|
19189
19680
|
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.";
|
|
@@ -19257,8 +19748,8 @@ var planArgv = (out) => ({
|
|
|
19257
19748
|
show: ["show", "-json", out]
|
|
19258
19749
|
});
|
|
19259
19750
|
async function readChoudoufuPlan(dir, run3 = captureChoudoufu) {
|
|
19260
|
-
const scratch = mkdtempSync(
|
|
19261
|
-
const file =
|
|
19751
|
+
const scratch = mkdtempSync(join24(tmpdir2(), "behold-choudoufu-plan-"));
|
|
19752
|
+
const file = join24(scratch, "plan.tfplan");
|
|
19262
19753
|
const argv = planArgv(file);
|
|
19263
19754
|
try {
|
|
19264
19755
|
const planRun = await run3(argv.plan, dir);
|
|
@@ -19290,8 +19781,8 @@ init_choudoufu_refs();
|
|
|
19290
19781
|
// src/choudoufu-moves.ts
|
|
19291
19782
|
init_choudoufu_member();
|
|
19292
19783
|
init_choudoufu_live();
|
|
19293
|
-
import { existsSync as existsSync15, readFileSync as
|
|
19294
|
-
import { join as
|
|
19784
|
+
import { existsSync as existsSync15, readFileSync as readFileSync19 } from "node:fs";
|
|
19785
|
+
import { join as join25, relative as relative5 } from "node:path";
|
|
19295
19786
|
var isRecord11 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
19296
19787
|
var refuse8 = (error, remedy) => ({ ok: false, refusal: { error, code: "choudoufu-live-check", remedy } });
|
|
19297
19788
|
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.";
|
|
@@ -19311,7 +19802,7 @@ function parseCarvePlan(value) {
|
|
|
19311
19802
|
}
|
|
19312
19803
|
};
|
|
19313
19804
|
}
|
|
19314
|
-
function readCarvePlan(path, readFile2 = (p) =>
|
|
19805
|
+
function readCarvePlan(path, readFile2 = (p) => readFileSync19(p, "utf8")) {
|
|
19315
19806
|
let text;
|
|
19316
19807
|
try {
|
|
19317
19808
|
text = readFile2(path);
|
|
@@ -19327,7 +19818,7 @@ function readCarvePlan(path, readFile2 = (p) => readFileSync18(p, "utf8")) {
|
|
|
19327
19818
|
function discoverCarvePlans(memberDirs, base) {
|
|
19328
19819
|
const out = [];
|
|
19329
19820
|
for (const dir of memberDirs) {
|
|
19330
|
-
const p =
|
|
19821
|
+
const p = join25(dir, "carve.json");
|
|
19331
19822
|
if (existsSync15(p)) out.push(relative5(base, p));
|
|
19332
19823
|
}
|
|
19333
19824
|
return out;
|
|
@@ -19558,24 +20049,24 @@ function getRuntime() {
|
|
|
19558
20049
|
|
|
19559
20050
|
// node_modules/@intentius/chant/src/lifecycle/member-ledger.ts
|
|
19560
20051
|
import { existsSync as existsSync18 } from "node:fs";
|
|
19561
|
-
import { dirname as dirname8, join as
|
|
20052
|
+
import { dirname as dirname8, join as join29, relative as relative6, resolve as resolve15, sep as sep6 } from "node:path";
|
|
19562
20053
|
|
|
19563
20054
|
// node_modules/@intentius/chant/src/project-root.ts
|
|
19564
20055
|
import { existsSync as existsSync16 } from "fs";
|
|
19565
|
-
import { dirname as dirname6, join as
|
|
20056
|
+
import { dirname as dirname6, join as join26, resolve as resolve13 } from "path";
|
|
19566
20057
|
var WORKSPACE_DECLARATION_FILES = ["chant.workspace.json", "chant.workspace.jsonc"];
|
|
19567
20058
|
function findWorkspaceRoot(startDir) {
|
|
19568
20059
|
const start = resolve13(startDir);
|
|
19569
20060
|
let top;
|
|
19570
20061
|
for (let dir = start; ; dir = dirname6(dir)) {
|
|
19571
|
-
if (existsSync16(
|
|
20062
|
+
if (existsSync16(join26(dir, ".git"))) {
|
|
19572
20063
|
top = dir;
|
|
19573
20064
|
break;
|
|
19574
20065
|
}
|
|
19575
20066
|
if (dirname6(dir) === dir) break;
|
|
19576
20067
|
}
|
|
19577
20068
|
for (let dir = start; ; dir = dirname6(dir)) {
|
|
19578
|
-
const [json2, jsonc] = WORKSPACE_DECLARATION_FILES.map((name) =>
|
|
20069
|
+
const [json2, jsonc] = WORKSPACE_DECLARATION_FILES.map((name) => join26(dir, name));
|
|
19579
20070
|
const hasJson = existsSync16(json2);
|
|
19580
20071
|
const hasJsonc = existsSync16(jsonc);
|
|
19581
20072
|
if (hasJson && hasJsonc) return { dir, file: json2, conflicting: jsonc };
|
|
@@ -19637,7 +20128,7 @@ async function ledgerIn(root, dir) {
|
|
|
19637
20128
|
}
|
|
19638
20129
|
let outer = FLAT;
|
|
19639
20130
|
const parent = dirname8(root);
|
|
19640
|
-
if (parent !== root && !existsSync18(
|
|
20131
|
+
if (parent !== root && !existsSync18(join29(root, ".git"))) {
|
|
19641
20132
|
const outerFound = findWorkspaceRoot(parent);
|
|
19642
20133
|
if (outerFound) outer = await ledgerIn(outerFound.dir, root);
|
|
19643
20134
|
}
|
|
@@ -20192,7 +20683,7 @@ function decideOverride(input) {
|
|
|
20192
20683
|
|
|
20193
20684
|
// src/terragucci-repo.ts
|
|
20194
20685
|
import { existsSync as existsSync19 } from "node:fs";
|
|
20195
|
-
import { dirname as dirname9, join as
|
|
20686
|
+
import { dirname as dirname9, join as join30, resolve as resolve16 } from "node:path";
|
|
20196
20687
|
var TERRAGUCCI_CONFIG_NAMES = ["terragucci.yml", "terragucci.yaml", "terragucci.json", "terragucci.ts"];
|
|
20197
20688
|
function terragucciConfig(dir) {
|
|
20198
20689
|
return walkUp(dir, TERRAGUCCI_CONFIG_NAMES);
|
|
@@ -20201,10 +20692,10 @@ function walkUp(dir, names) {
|
|
|
20201
20692
|
let at2 = resolve16(dir);
|
|
20202
20693
|
for (; ; ) {
|
|
20203
20694
|
for (const name of names) {
|
|
20204
|
-
const file =
|
|
20695
|
+
const file = join30(at2, name);
|
|
20205
20696
|
if (existsSync19(file)) return file;
|
|
20206
20697
|
}
|
|
20207
|
-
if (existsSync19(
|
|
20698
|
+
if (existsSync19(join30(at2, ".git"))) return void 0;
|
|
20208
20699
|
const up = dirname9(at2);
|
|
20209
20700
|
if (up === at2) return void 0;
|
|
20210
20701
|
at2 = up;
|
|
@@ -20638,6 +21129,7 @@ function allowedHostsFrom(flag = [], env = process.env.BEHOLD_ALLOWED_HOSTS) {
|
|
|
20638
21129
|
// src/server.ts
|
|
20639
21130
|
init_member_kind();
|
|
20640
21131
|
init_terraform_member();
|
|
21132
|
+
init_terraform_lens();
|
|
20641
21133
|
|
|
20642
21134
|
// src/doctor.ts
|
|
20643
21135
|
init_chant();
|
|
@@ -21007,7 +21499,7 @@ init_foreign();
|
|
|
21007
21499
|
|
|
21008
21500
|
// src/events.ts
|
|
21009
21501
|
import { watch, existsSync as existsSync20 } from "node:fs";
|
|
21010
|
-
import { join as
|
|
21502
|
+
import { join as join31 } from "node:path";
|
|
21011
21503
|
var Broadcaster = class {
|
|
21012
21504
|
listeners = /* @__PURE__ */ new Set();
|
|
21013
21505
|
subscribe(fn) {
|
|
@@ -21025,7 +21517,7 @@ var Broadcaster = class {
|
|
|
21025
21517
|
};
|
|
21026
21518
|
var IGNORE = /(^|[\\/])(node_modules|dist|\.git)([\\/]|$)/;
|
|
21027
21519
|
function watchSource(projectDir, onChange, debounceMs = 200) {
|
|
21028
|
-
const dir = existsSync20(
|
|
21520
|
+
const dir = existsSync20(join31(projectDir, "src")) ? join31(projectDir, "src") : projectDir;
|
|
21029
21521
|
let timer;
|
|
21030
21522
|
const watcher = watch(dir, { recursive: true }, (_event, file) => {
|
|
21031
21523
|
const name = typeof file === "string" ? file : "";
|
|
@@ -21328,13 +21820,13 @@ async function emulatorDown(projectDir) {
|
|
|
21328
21820
|
|
|
21329
21821
|
// src/terragucci-view.ts
|
|
21330
21822
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
21331
|
-
import { dirname as dirname13, join as
|
|
21823
|
+
import { dirname as dirname13, join as join40, relative as relative8, sep as sep7 } from "node:path";
|
|
21332
21824
|
init_terraform_member();
|
|
21333
21825
|
|
|
21334
21826
|
// src/terragucci-reports.ts
|
|
21335
|
-
import { readFileSync as
|
|
21827
|
+
import { readFileSync as readFileSync24, statSync as statSync10 } from "node:fs";
|
|
21336
21828
|
import { createRequire as createRequire4 } from "node:module";
|
|
21337
|
-
import { dirname as dirname10, join as
|
|
21829
|
+
import { dirname as dirname10, join as join34, resolve as resolve20 } from "node:path";
|
|
21338
21830
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
21339
21831
|
import { Ajv2020 } from "ajv/dist/2020.js";
|
|
21340
21832
|
|
|
@@ -21343,12 +21835,12 @@ import { execFile as execFile4 } from "node:child_process";
|
|
|
21343
21835
|
import { createHash as createHash8 } from "node:crypto";
|
|
21344
21836
|
import { existsSync as existsSync21, mkdirSync as mkdirSync6, readdirSync as readdirSync11 } from "node:fs";
|
|
21345
21837
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
21346
|
-
import { basename as basename3, isAbsolute as isAbsolute4, join as
|
|
21838
|
+
import { basename as basename3, isAbsolute as isAbsolute4, join as join33, resolve as resolve19 } from "node:path";
|
|
21347
21839
|
|
|
21348
21840
|
// node_modules/@intentius/chant/src/gate-decision.ts
|
|
21349
21841
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
21350
|
-
import { readFileSync as
|
|
21351
|
-
import { join as
|
|
21842
|
+
import { readFileSync as readFileSync23 } from "node:fs";
|
|
21843
|
+
import { join as join32, posix as posix3 } from "node:path";
|
|
21352
21844
|
|
|
21353
21845
|
// node_modules/@intentius/chant/src/lifecycle/gate-applied.ts
|
|
21354
21846
|
function appliedGatePath(op) {
|
|
@@ -21457,7 +21949,7 @@ function pinnedClassesAt(repo, base, pins, packages) {
|
|
|
21457
21949
|
}
|
|
21458
21950
|
let installed2;
|
|
21459
21951
|
try {
|
|
21460
|
-
installed2 = JSON.parse(
|
|
21952
|
+
installed2 = JSON.parse(readFileSync23(join32(dir, "package.json"), "utf-8")).version;
|
|
21461
21953
|
} catch {
|
|
21462
21954
|
installed2 = void 0;
|
|
21463
21955
|
}
|
|
@@ -22052,7 +22544,7 @@ var realGit = (args, o = {}) => new Promise((res) => {
|
|
|
22052
22544
|
});
|
|
22053
22545
|
var redact = (s) => s.replace(/(\b[a-z][a-z0-9+.-]*:\/\/)[^/@\s]+@/gi, "$1");
|
|
22054
22546
|
function cacheDir(origin, root = tmpdir3()) {
|
|
22055
|
-
return
|
|
22547
|
+
return join33(root, `${CACHE_PREFIX}${createHash8("sha256").update(origin).digest("hex").slice(0, 16)}`);
|
|
22056
22548
|
}
|
|
22057
22549
|
var inflight = /* @__PURE__ */ new Map();
|
|
22058
22550
|
function serially(key, fn) {
|
|
@@ -22071,7 +22563,7 @@ function fetchable(url, checkout) {
|
|
|
22071
22563
|
async function fetchIntoCache(git3, origin, cache6) {
|
|
22072
22564
|
assertScratch(basename3(cache6));
|
|
22073
22565
|
return serially(cache6, async () => {
|
|
22074
|
-
if (!existsSync21(
|
|
22566
|
+
if (!existsSync21(join33(cache6, "HEAD"))) {
|
|
22075
22567
|
if (existsSync21(cache6) && readdirSync11(cache6).length > 0) return { ok: false, error: `${cache6} exists and is not behold's lifecycle cache; behold leaves it alone` };
|
|
22076
22568
|
mkdirSync6(cache6, { recursive: true });
|
|
22077
22569
|
const init = await git3(["init", "--bare", "-q", cache6]);
|
|
@@ -22259,7 +22751,7 @@ function structural(name, doc) {
|
|
|
22259
22751
|
var compiledSchemas = /* @__PURE__ */ new Map();
|
|
22260
22752
|
function schemaStamp(dist) {
|
|
22261
22753
|
try {
|
|
22262
|
-
const files = [
|
|
22754
|
+
const files = [join34(dist, "..", "package.json"), ...Object.values(SCHEMA_FILES).map((f) => join34(dist, f))];
|
|
22263
22755
|
return [dist, ...files.map((f) => {
|
|
22264
22756
|
const st = statSync10(f);
|
|
22265
22757
|
return `${st.mtimeMs}:${st.size}`;
|
|
@@ -22269,10 +22761,10 @@ function schemaStamp(dist) {
|
|
|
22269
22761
|
}
|
|
22270
22762
|
}
|
|
22271
22763
|
function compileSchemas(dist) {
|
|
22272
|
-
const version = JSON.parse(
|
|
22764
|
+
const version = JSON.parse(readFileSync24(join34(dist, "..", "package.json"), "utf8")).version ?? "";
|
|
22273
22765
|
const ajv = new Ajv2020({ strict: false, allErrors: false });
|
|
22274
22766
|
const compiled4 = Object.fromEntries(
|
|
22275
|
-
Object.keys(SCHEMA_FILES).map((n) => [n, ajv.compile(JSON.parse(
|
|
22767
|
+
Object.keys(SCHEMA_FILES).map((n) => [n, ajv.compile(JSON.parse(readFileSync24(join34(dist, SCHEMA_FILES[n]), "utf8")))])
|
|
22276
22768
|
);
|
|
22277
22769
|
return {
|
|
22278
22770
|
validation: { by: "schema", terragucci: version },
|
|
@@ -22289,7 +22781,7 @@ function terragucciValidator(dirs = []) {
|
|
|
22289
22781
|
for (const from of [...dirs, dirname10(fileURLToPath5(import.meta.url))]) {
|
|
22290
22782
|
let entry;
|
|
22291
22783
|
try {
|
|
22292
|
-
entry = createRequire4(
|
|
22784
|
+
entry = createRequire4(join34(resolve20(from), "noop.js")).resolve("@intentius/terragucci/report.schema.json");
|
|
22293
22785
|
} catch {
|
|
22294
22786
|
continue;
|
|
22295
22787
|
}
|
|
@@ -22630,11 +23122,11 @@ function joinTerragucci(read, nodes, roots) {
|
|
|
22630
23122
|
// src/terragucci-source.ts
|
|
22631
23123
|
import { spawn as spawn7 } from "node:child_process";
|
|
22632
23124
|
import { readFile } from "node:fs/promises";
|
|
22633
|
-
import { join as
|
|
23125
|
+
import { join as join35, resolve as resolve21 } from "node:path";
|
|
22634
23126
|
|
|
22635
23127
|
// src/s3-object.ts
|
|
22636
23128
|
import { createHash as createHash9, createHmac } from "node:crypto";
|
|
22637
|
-
import { readFileSync as
|
|
23129
|
+
import { readFileSync as readFileSync25 } from "node:fs";
|
|
22638
23130
|
var S3Error = class extends Error {
|
|
22639
23131
|
/** The HTTP status S3 answered, when it answered. */
|
|
22640
23132
|
status;
|
|
@@ -22681,7 +23173,7 @@ function s3FromEnv(bucket, env = process.env) {
|
|
|
22681
23173
|
async function assumeRole(w, fetchFn) {
|
|
22682
23174
|
let token;
|
|
22683
23175
|
try {
|
|
22684
|
-
token =
|
|
23176
|
+
token = readFileSync25(w.tokenFile, "utf8").trim();
|
|
22685
23177
|
} catch (e) {
|
|
22686
23178
|
throw new S3Error(`cannot read the OIDC token in ${w.tokenFile}: ${e.message}`);
|
|
22687
23179
|
}
|
|
@@ -22878,7 +23370,7 @@ function terragucciSource(spec2, opts = {}) {
|
|
|
22878
23370
|
location: dir,
|
|
22879
23371
|
async read(key) {
|
|
22880
23372
|
try {
|
|
22881
|
-
return await readFile(
|
|
23373
|
+
return await readFile(join35(dir, ...trim(key).split("/")), "utf8");
|
|
22882
23374
|
} catch (e) {
|
|
22883
23375
|
if (e.code === "ENOENT") return void 0;
|
|
22884
23376
|
throw e;
|
|
@@ -22888,9 +23380,9 @@ function terragucciSource(spec2, opts = {}) {
|
|
|
22888
23380
|
}
|
|
22889
23381
|
|
|
22890
23382
|
// src/terragucci-timeline.ts
|
|
22891
|
-
import { readFileSync as
|
|
23383
|
+
import { readFileSync as readFileSync26, statSync as statSync11 } from "node:fs";
|
|
22892
23384
|
import { createRequire as createRequire5 } from "node:module";
|
|
22893
|
-
import { dirname as dirname11, join as
|
|
23385
|
+
import { dirname as dirname11, join as join36, resolve as resolve22 } from "node:path";
|
|
22894
23386
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
22895
23387
|
import { Ajv2020 as Ajv20202 } from "ajv/dist/2020.js";
|
|
22896
23388
|
var AUDIT_SCHEMA = "terragucci.audit/v1";
|
|
@@ -22931,12 +23423,12 @@ function auditValidator(dirs = []) {
|
|
|
22931
23423
|
for (const from of [...dirs, dirname11(fileURLToPath6(import.meta.url))]) {
|
|
22932
23424
|
let dist;
|
|
22933
23425
|
try {
|
|
22934
|
-
dist = dirname11(createRequire5(
|
|
23426
|
+
dist = dirname11(createRequire5(join36(resolve22(from), "noop.js")).resolve("@intentius/terragucci/report.schema.json"));
|
|
22935
23427
|
} catch {
|
|
22936
23428
|
continue;
|
|
22937
23429
|
}
|
|
22938
|
-
const pkg =
|
|
22939
|
-
const file =
|
|
23430
|
+
const pkg = join36(dist, "..", "package.json");
|
|
23431
|
+
const file = join36(dist, AUDIT_SCHEMA_FILE);
|
|
22940
23432
|
let stamp;
|
|
22941
23433
|
try {
|
|
22942
23434
|
stamp = [dist, ...[pkg, file].map((f) => {
|
|
@@ -22950,8 +23442,8 @@ function auditValidator(dirs = []) {
|
|
|
22950
23442
|
if (hit) return hit;
|
|
22951
23443
|
let v;
|
|
22952
23444
|
try {
|
|
22953
|
-
const version = JSON.parse(
|
|
22954
|
-
v = compileAuditSchema(JSON.parse(
|
|
23445
|
+
const version = JSON.parse(readFileSync26(pkg, "utf8")).version ?? "";
|
|
23446
|
+
v = compileAuditSchema(JSON.parse(readFileSync26(file, "utf8")), version);
|
|
22955
23447
|
} catch {
|
|
22956
23448
|
continue;
|
|
22957
23449
|
}
|
|
@@ -23147,7 +23639,7 @@ function terragucciTimelineRoute(app, source2, opts = {}) {
|
|
|
23147
23639
|
// src/terragucci-poll.ts
|
|
23148
23640
|
import { createHash as createHash10 } from "node:crypto";
|
|
23149
23641
|
import { stat } from "node:fs/promises";
|
|
23150
|
-
import { join as
|
|
23642
|
+
import { join as join37, resolve as resolve23 } from "node:path";
|
|
23151
23643
|
import { streamSSE } from "hono/streaming";
|
|
23152
23644
|
var TERRAGUCCI_POLL_SECS = 30;
|
|
23153
23645
|
var INDEX_KEY = "index.json";
|
|
@@ -23198,7 +23690,7 @@ function indexProbe(spec2, opts = {}) {
|
|
|
23198
23690
|
return verdict2(prev, etag);
|
|
23199
23691
|
};
|
|
23200
23692
|
}
|
|
23201
|
-
const file =
|
|
23693
|
+
const file = join37(resolve23(opts.cwd ?? process.cwd(), spec2), name);
|
|
23202
23694
|
return async (prev) => {
|
|
23203
23695
|
try {
|
|
23204
23696
|
const s = await stat(file);
|
|
@@ -23353,9 +23845,9 @@ function terragucciLaneRoutes(app, o, base, forget) {
|
|
|
23353
23845
|
}
|
|
23354
23846
|
|
|
23355
23847
|
// src/terragucci-progress.ts
|
|
23356
|
-
import { readFileSync as
|
|
23848
|
+
import { readFileSync as readFileSync27, statSync as statSync12 } from "node:fs";
|
|
23357
23849
|
import { createRequire as createRequire6 } from "node:module";
|
|
23358
|
-
import { dirname as dirname12, join as
|
|
23850
|
+
import { dirname as dirname12, join as join38, resolve as resolve24 } from "node:path";
|
|
23359
23851
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
23360
23852
|
import { Ajv2020 as Ajv20203 } from "ajv/dist/2020.js";
|
|
23361
23853
|
var RUN_SCHEMA = "terragucci.run/v1";
|
|
@@ -23400,12 +23892,12 @@ function runValidator(dirs = []) {
|
|
|
23400
23892
|
for (const from of [...dirs, dirname12(fileURLToPath7(import.meta.url))]) {
|
|
23401
23893
|
let dist;
|
|
23402
23894
|
try {
|
|
23403
|
-
dist = dirname12(createRequire6(
|
|
23895
|
+
dist = dirname12(createRequire6(join38(resolve24(from), "noop.js")).resolve("@intentius/terragucci/report.schema.json"));
|
|
23404
23896
|
} catch {
|
|
23405
23897
|
continue;
|
|
23406
23898
|
}
|
|
23407
|
-
const pkg =
|
|
23408
|
-
const file =
|
|
23899
|
+
const pkg = join38(dist, "..", "package.json");
|
|
23900
|
+
const file = join38(dist, RUN_SCHEMA_FILE);
|
|
23409
23901
|
let stamp;
|
|
23410
23902
|
try {
|
|
23411
23903
|
stamp = [dist, ...[pkg, file].map((f) => {
|
|
@@ -23419,8 +23911,8 @@ function runValidator(dirs = []) {
|
|
|
23419
23911
|
if (hit) return hit;
|
|
23420
23912
|
let v;
|
|
23421
23913
|
try {
|
|
23422
|
-
const version = JSON.parse(
|
|
23423
|
-
v = compileRunSchema(JSON.parse(
|
|
23914
|
+
const version = JSON.parse(readFileSync27(pkg, "utf8")).version ?? "";
|
|
23915
|
+
v = compileRunSchema(JSON.parse(readFileSync27(file, "utf8")), version);
|
|
23424
23916
|
} catch {
|
|
23425
23917
|
continue;
|
|
23426
23918
|
}
|
|
@@ -23713,11 +24205,12 @@ function terragucciProgressRoute(app, progress) {
|
|
|
23713
24205
|
}
|
|
23714
24206
|
|
|
23715
24207
|
// src/terragucci-demo.ts
|
|
23716
|
-
import { readFileSync as
|
|
23717
|
-
import { join as
|
|
24208
|
+
import { readFileSync as readFileSync28 } from "node:fs";
|
|
24209
|
+
import { join as join39 } from "node:path";
|
|
23718
24210
|
var DEMO_KEY = "demo.json";
|
|
23719
24211
|
var DEMO_READ_TTL_MS = 2e3;
|
|
23720
24212
|
var DEMO_STEPS = ["pull-request", "planned", "merged", "applying", "waiting", "approved", "failed", "resumed", "applied", "reset", "stalled"];
|
|
24213
|
+
var DEMO_ABOUT_FIELDS = ["changes", "watch", "shows"];
|
|
23721
24214
|
var UTC = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/;
|
|
23722
24215
|
var isRecord17 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
23723
24216
|
var str13 = (v) => typeof v === "string";
|
|
@@ -23737,6 +24230,10 @@ function demoProblem(doc) {
|
|
|
23737
24230
|
}
|
|
23738
24231
|
if (doc.pull !== null && !int(doc.pull)) return "pull is neither an integer nor null";
|
|
23739
24232
|
if (doc.commit !== null && !str13(doc.commit)) return "commit is neither a string nor null";
|
|
24233
|
+
if (doc.about !== void 0 && doc.about !== null) {
|
|
24234
|
+
if (!isRecord17(doc.about)) return "about is neither an object nor null";
|
|
24235
|
+
for (const f of DEMO_ABOUT_FIELDS) if (!str13(doc.about[f]) || !doc.about[f].trim()) return `about.${f} is not a non-empty string`;
|
|
24236
|
+
}
|
|
23740
24237
|
return void 0;
|
|
23741
24238
|
}
|
|
23742
24239
|
async function readDemo(source2, now = /* @__PURE__ */ new Date()) {
|
|
@@ -23771,7 +24268,8 @@ async function readDemo(source2, now = /* @__PURE__ */ new Date()) {
|
|
|
23771
24268
|
started_at: d.started_at,
|
|
23772
24269
|
next: d.next ? { action: d.next.action, at: d.next.at } : null,
|
|
23773
24270
|
pull: d.pull,
|
|
23774
|
-
commit: d.commit
|
|
24271
|
+
commit: d.commit,
|
|
24272
|
+
about: d.about ? { changes: d.about.changes, watch: d.about.watch, shows: d.about.shows } : null
|
|
23775
24273
|
}
|
|
23776
24274
|
};
|
|
23777
24275
|
}
|
|
@@ -23792,7 +24290,7 @@ function kioskRoute(app, webRoot2, enabled) {
|
|
|
23792
24290
|
404
|
|
23793
24291
|
);
|
|
23794
24292
|
}
|
|
23795
|
-
return new Response(
|
|
24293
|
+
return new Response(readFileSync28(join39(webRoot2, "kiosk.html"), "utf8"), { headers: { "content-type": "text/html; charset=utf-8", "cache-control": "no-cache" } });
|
|
23796
24294
|
});
|
|
23797
24295
|
}
|
|
23798
24296
|
|
|
@@ -23951,7 +24449,7 @@ function checkoutRoots(dirs, base = repoBase(dirs)) {
|
|
|
23951
24449
|
for (const m of estateMembers(dirs)) {
|
|
23952
24450
|
if (m.kind !== "terraform") continue;
|
|
23953
24451
|
for (const r of discoverTerraformRoots(m.dir).roots) {
|
|
23954
|
-
const path = relative8(base,
|
|
24452
|
+
const path = relative8(base, join40(m.dir, r.dir)).split(sep7).join("/") || ".";
|
|
23955
24453
|
out.push({ member: m.name, name: r.name, path });
|
|
23956
24454
|
}
|
|
23957
24455
|
}
|
|
@@ -24511,8 +25009,8 @@ function lifecycleHistoryRoute(app, base, opts = {}) {
|
|
|
24511
25009
|
}
|
|
24512
25010
|
|
|
24513
25011
|
// src/lifecycle-releases.ts
|
|
24514
|
-
import { existsSync as existsSync22, readFileSync as
|
|
24515
|
-
import { join as
|
|
25012
|
+
import { existsSync as existsSync22, readFileSync as readFileSync29 } from "node:fs";
|
|
25013
|
+
import { join as join41 } from "node:path";
|
|
24516
25014
|
|
|
24517
25015
|
// node_modules/@intentius/chant/src/lifecycle/legacy-digest.ts
|
|
24518
25016
|
import { resolve as resolve25 } from "node:path";
|
|
@@ -24625,10 +25123,10 @@ function memberNote(l) {
|
|
|
24625
25123
|
// src/lifecycle-releases.ts
|
|
24626
25124
|
var WAVES_SPEC_FILE = "yodel-waves.json";
|
|
24627
25125
|
function waveOrder(checkout) {
|
|
24628
|
-
const p =
|
|
25126
|
+
const p = join41(checkout, WAVES_SPEC_FILE);
|
|
24629
25127
|
if (!existsSync22(p)) return void 0;
|
|
24630
25128
|
try {
|
|
24631
|
-
const doc = JSON.parse(
|
|
25129
|
+
const doc = JSON.parse(readFileSync29(p, "utf8"));
|
|
24632
25130
|
const names = (doc.waves ?? []).map((w) => w?.name).filter((n) => typeof n === "string" && n.length > 0);
|
|
24633
25131
|
return names.length ? [...new Set(names)] : void 0;
|
|
24634
25132
|
} catch {
|
|
@@ -24636,7 +25134,7 @@ function waveOrder(checkout) {
|
|
|
24636
25134
|
}
|
|
24637
25135
|
}
|
|
24638
25136
|
function hasReleaseLedgerHint(checkout) {
|
|
24639
|
-
return existsSync22(
|
|
25137
|
+
return existsSync22(join41(checkout, "yodel.config.ts")) || existsSync22(join41(checkout, WAVES_SPEC_FILE));
|
|
24640
25138
|
}
|
|
24641
25139
|
function orderEnvironments(envs, waves) {
|
|
24642
25140
|
const seen = new Set(envs);
|
|
@@ -24678,7 +25176,7 @@ function releaseCells(ledgers, order, sources) {
|
|
|
24678
25176
|
}
|
|
24679
25177
|
async function copyCheckoutRef(git3, checkout, cache6) {
|
|
24680
25178
|
assertScratch(cache6.split(/[\\/]/).pop());
|
|
24681
|
-
if (!existsSync22(
|
|
25179
|
+
if (!existsSync22(join41(cache6, "HEAD"))) {
|
|
24682
25180
|
const init = await git3(["init", "--bare", "-q", cache6]);
|
|
24683
25181
|
if (init.code !== 0) return false;
|
|
24684
25182
|
}
|
|
@@ -24781,8 +25279,8 @@ function releasesRoutes(app, base, opts = {}) {
|
|
|
24781
25279
|
}
|
|
24782
25280
|
|
|
24783
25281
|
// src/sql-yodeler-lane.ts
|
|
24784
|
-
import { existsSync as existsSync23, readdirSync as readdirSync12, readFileSync as
|
|
24785
|
-
import { join as
|
|
25282
|
+
import { existsSync as existsSync23, readdirSync as readdirSync12, readFileSync as readFileSync30 } from "node:fs";
|
|
25283
|
+
import { join as join42 } from "node:path";
|
|
24786
25284
|
var YODEL_APPLY_OP = "yodel-apply";
|
|
24787
25285
|
var YODEL_HEAD_PLANS_DIR = headPlansPath(YODEL_APPLY_OP, "").dir;
|
|
24788
25286
|
function parseYodelWaves(text, path = WAVES_SPEC_FILE) {
|
|
@@ -24814,16 +25312,16 @@ function parseYodelWaves(text, path = WAVES_SPEC_FILE) {
|
|
|
24814
25312
|
return { path, waves };
|
|
24815
25313
|
}
|
|
24816
25314
|
function readYodelWaves(checkout) {
|
|
24817
|
-
const p =
|
|
25315
|
+
const p = join42(checkout, WAVES_SPEC_FILE);
|
|
24818
25316
|
if (!existsSync23(p)) return void 0;
|
|
24819
25317
|
try {
|
|
24820
|
-
return parseYodelWaves(
|
|
25318
|
+
return parseYodelWaves(readFileSync30(p, "utf8"));
|
|
24821
25319
|
} catch (e) {
|
|
24822
25320
|
return { path: WAVES_SPEC_FILE, waves: [], error: e instanceof Error ? e.message : String(e) };
|
|
24823
25321
|
}
|
|
24824
25322
|
}
|
|
24825
25323
|
function migrateOpEnvironments(checkout) {
|
|
24826
|
-
const dir =
|
|
25324
|
+
const dir = join42(checkout, "ops");
|
|
24827
25325
|
if (!existsSync23(dir)) return [];
|
|
24828
25326
|
try {
|
|
24829
25327
|
return readdirSync12(dir).map((f) => /^migrate-(.+)\.op\.ts$/.exec(f)?.[1]).filter((e) => !!e).sort();
|
|
@@ -24946,16 +25444,16 @@ function sqlYodelerLaneRoute(app, checkout, opts = {}) {
|
|
|
24946
25444
|
|
|
24947
25445
|
// src/terragucci-estate.ts
|
|
24948
25446
|
init_yaml();
|
|
24949
|
-
import { existsSync as existsSync24, readFileSync as
|
|
25447
|
+
import { existsSync as existsSync24, readFileSync as readFileSync31, statSync as statSync13 } from "node:fs";
|
|
24950
25448
|
import { createRequire as createRequire7 } from "node:module";
|
|
24951
|
-
import { dirname as dirname14, extname, join as
|
|
25449
|
+
import { dirname as dirname14, extname, join as join43, resolve as resolve26 } from "node:path";
|
|
24952
25450
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
24953
25451
|
import { Ajv2020 as Ajv20204 } from "ajv/dist/2020.js";
|
|
24954
25452
|
var RUN_SCHEMA2 = "terragucci.run/v1";
|
|
24955
25453
|
function configProjects(file) {
|
|
24956
25454
|
let text;
|
|
24957
25455
|
try {
|
|
24958
|
-
text =
|
|
25456
|
+
text = readFileSync31(file, "utf8");
|
|
24959
25457
|
} catch {
|
|
24960
25458
|
return void 0;
|
|
24961
25459
|
}
|
|
@@ -25006,16 +25504,16 @@ function runViewValidator(dirs = []) {
|
|
|
25006
25504
|
for (const from of [...dirs, dirname14(fileURLToPath8(import.meta.url))]) {
|
|
25007
25505
|
let entry;
|
|
25008
25506
|
try {
|
|
25009
|
-
entry = createRequire7(
|
|
25507
|
+
entry = createRequire7(join43(resolve26(from), "noop.js")).resolve("@intentius/terragucci/report.schema.json");
|
|
25010
25508
|
} catch {
|
|
25011
25509
|
continue;
|
|
25012
25510
|
}
|
|
25013
25511
|
const dist = dirname14(entry);
|
|
25014
|
-
const schema =
|
|
25512
|
+
const schema = join43(dist, "run.schema.json");
|
|
25015
25513
|
let stamp;
|
|
25016
25514
|
try {
|
|
25017
25515
|
const st = statSync13(schema);
|
|
25018
|
-
const pkg = statSync13(
|
|
25516
|
+
const pkg = statSync13(join43(dist, "..", "package.json"));
|
|
25019
25517
|
stamp = `${schema}\0${st.mtimeMs}:${st.size}\0${pkg.mtimeMs}`;
|
|
25020
25518
|
} catch {
|
|
25021
25519
|
continue;
|
|
@@ -25024,8 +25522,8 @@ function runViewValidator(dirs = []) {
|
|
|
25024
25522
|
if (hit) return hit;
|
|
25025
25523
|
let v;
|
|
25026
25524
|
try {
|
|
25027
|
-
const version = JSON.parse(
|
|
25028
|
-
const validate = new Ajv20204({ strict: false, allErrors: false }).compile(JSON.parse(
|
|
25525
|
+
const version = JSON.parse(readFileSync31(join43(dist, "..", "package.json"), "utf8")).version ?? "";
|
|
25526
|
+
const validate = new Ajv20204({ strict: false, allErrors: false }).compile(JSON.parse(readFileSync31(schema, "utf8")));
|
|
25029
25527
|
v = {
|
|
25030
25528
|
validation: { by: "schema", terragucci: version },
|
|
25031
25529
|
check(doc) {
|
|
@@ -25080,8 +25578,8 @@ function controlEdges(views) {
|
|
|
25080
25578
|
function siblingCheckout(project, base, projectOf = checkoutProject) {
|
|
25081
25579
|
const name = project.split("/").filter(Boolean).pop();
|
|
25082
25580
|
if (!name) return void 0;
|
|
25083
|
-
const dir =
|
|
25084
|
-
if (dir === resolve26(base) || !existsSync24(
|
|
25581
|
+
const dir = join43(dirname14(resolve26(base)), name);
|
|
25582
|
+
if (dir === resolve26(base) || !existsSync24(join43(dir, ".git"))) return void 0;
|
|
25085
25583
|
return projectOf(dir) === project ? dir : void 0;
|
|
25086
25584
|
}
|
|
25087
25585
|
var shellWord = (s) => /^[A-Za-z0-9_./:@%+=,-]+$/.test(s) ? s : `'${s.replace(/'/g, `'\\''`)}'`;
|
|
@@ -25288,9 +25786,9 @@ function controlRepoInfo(dirs) {
|
|
|
25288
25786
|
}
|
|
25289
25787
|
|
|
25290
25788
|
// src/yodel-report.ts
|
|
25291
|
-
import { readdirSync as readdirSync13, readFileSync as
|
|
25789
|
+
import { readdirSync as readdirSync13, readFileSync as readFileSync32, statSync as statSync14 } from "node:fs";
|
|
25292
25790
|
import { createRequire as createRequire8 } from "node:module";
|
|
25293
|
-
import { basename as basename4, dirname as dirname15, join as
|
|
25791
|
+
import { basename as basename4, dirname as dirname15, join as join44, resolve as resolve27 } from "node:path";
|
|
25294
25792
|
import { fileURLToPath as fileURLToPath9 } from "node:url";
|
|
25295
25793
|
import { Ajv2020 as Ajv20205 } from "ajv/dist/2020.js";
|
|
25296
25794
|
|
|
@@ -25719,13 +26217,13 @@ var installed = /* @__PURE__ */ new Map();
|
|
|
25719
26217
|
function packageRoot(from) {
|
|
25720
26218
|
let entry;
|
|
25721
26219
|
try {
|
|
25722
|
-
entry = createRequire8(
|
|
26220
|
+
entry = createRequire8(join44(resolve27(from), "noop.js")).resolve("@intentius/sql-yodeler");
|
|
25723
26221
|
} catch {
|
|
25724
26222
|
return void 0;
|
|
25725
26223
|
}
|
|
25726
26224
|
for (let d = dirname15(entry); d !== dirname15(d); d = dirname15(d)) {
|
|
25727
26225
|
try {
|
|
25728
|
-
const pkg = JSON.parse(
|
|
26226
|
+
const pkg = JSON.parse(readFileSync32(join44(d, "package.json"), "utf8"));
|
|
25729
26227
|
if (pkg.name === "@intentius/sql-yodeler") return d;
|
|
25730
26228
|
} catch {
|
|
25731
26229
|
}
|
|
@@ -25737,11 +26235,11 @@ function yodelValidator(dirs = []) {
|
|
|
25737
26235
|
const root = packageRoot(from);
|
|
25738
26236
|
if (!root) continue;
|
|
25739
26237
|
try {
|
|
25740
|
-
const version = JSON.parse(
|
|
26238
|
+
const version = JSON.parse(readFileSync32(join44(root, "package.json"), "utf8")).version ?? "";
|
|
25741
26239
|
const key = `${root}\0${version}`;
|
|
25742
26240
|
let v = installed.get(key);
|
|
25743
26241
|
if (!v) {
|
|
25744
|
-
const load2 = (n) => JSON.parse(
|
|
26242
|
+
const load2 = (n) => JSON.parse(readFileSync32(join44(root, "schemas", `${n}.schema.json`), "utf8"));
|
|
25745
26243
|
v = compile({ common: load2("common"), report: load2("report"), drift: load2("drift") }, { by: "schema", from: "package", sqlYodeler: version });
|
|
25746
26244
|
installed.set(key, v);
|
|
25747
26245
|
}
|
|
@@ -25763,7 +26261,7 @@ function filesOf(source2) {
|
|
|
25763
26261
|
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.");
|
|
25764
26262
|
}
|
|
25765
26263
|
const dir = st.isDirectory() ? source2 : dirname15(source2);
|
|
25766
|
-
const files = readdirSync13(dir).filter((f) => f.endsWith(".json")).sort().map((f) =>
|
|
26264
|
+
const files = readdirSync13(dir).filter((f) => f.endsWith(".json")).sort().map((f) => join44(dir, f));
|
|
25767
26265
|
return st.isDirectory() ? { dir, files } : { dir, files, named: resolve27(source2) };
|
|
25768
26266
|
}
|
|
25769
26267
|
function readYodelReport(source2, validator2) {
|
|
@@ -25775,7 +26273,7 @@ function readYodelReport(source2, validator2) {
|
|
|
25775
26273
|
for (const file of files) {
|
|
25776
26274
|
let doc;
|
|
25777
26275
|
try {
|
|
25778
|
-
doc = JSON.parse(
|
|
26276
|
+
doc = JSON.parse(readFileSync32(file, "utf8"));
|
|
25779
26277
|
} catch (e) {
|
|
25780
26278
|
if (file === named) refuse14(`${basename4(file)} is not JSON: ${e instanceof Error ? e.message : String(e)}`, remedy);
|
|
25781
26279
|
ignored.push(basename4(file));
|
|
@@ -25862,15 +26360,15 @@ function yodelReportRoute(app, source2, dirs) {
|
|
|
25862
26360
|
|
|
25863
26361
|
// src/demo-pins.ts
|
|
25864
26362
|
init_terraform_member();
|
|
25865
|
-
import { existsSync as existsSync25, lstatSync as lstatSync2, mkdirSync as mkdirSync7, readFileSync as
|
|
25866
|
-
import { dirname as dirname16, join as
|
|
26363
|
+
import { existsSync as existsSync25, lstatSync as lstatSync2, mkdirSync as mkdirSync7, readFileSync as readFileSync33, readlinkSync as readlinkSync2, symlinkSync as symlinkSync2, writeFileSync as writeFileSync6 } from "node:fs";
|
|
26364
|
+
import { dirname as dirname16, join as join45, resolve as resolve28 } from "node:path";
|
|
25867
26365
|
var isRecord21 = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
25868
26366
|
function linkDemoPins(work, probes = {}) {
|
|
25869
|
-
const file =
|
|
26367
|
+
const file = join45(work, "chant.workspace.json");
|
|
25870
26368
|
if (!existsSync25(file)) return { ok: true, linked: [] };
|
|
25871
26369
|
let decl;
|
|
25872
26370
|
try {
|
|
25873
|
-
decl = JSON.parse(
|
|
26371
|
+
decl = JSON.parse(readFileSync33(file, "utf8"));
|
|
25874
26372
|
} catch {
|
|
25875
26373
|
return { ok: true, linked: [] };
|
|
25876
26374
|
}
|
|
@@ -25893,7 +26391,7 @@ function linkDemoPins(work, probes = {}) {
|
|
|
25893
26391
|
remedy: `Install ${pkg} beside behold, then load the demo again.`
|
|
25894
26392
|
};
|
|
25895
26393
|
}
|
|
25896
|
-
const link =
|
|
26394
|
+
const link = join45(work, "node_modules", ...pkg.split("/"));
|
|
25897
26395
|
if (!present(link)) {
|
|
25898
26396
|
mkdirSync7(dirname16(link), { recursive: true });
|
|
25899
26397
|
symlinkSync2(found.dir, link, "junction");
|
|
@@ -25928,13 +26426,13 @@ function linksTo(link, target) {
|
|
|
25928
26426
|
}
|
|
25929
26427
|
|
|
25930
26428
|
// src/demos.ts
|
|
25931
|
-
import { readFileSync as
|
|
25932
|
-
import { dirname as dirname17, isAbsolute as isAbsolute5, join as
|
|
26429
|
+
import { readFileSync as readFileSync34, existsSync as existsSync26, cpSync, mkdirSync as mkdirSync8 } from "node:fs";
|
|
26430
|
+
import { dirname as dirname17, isAbsolute as isAbsolute5, join as join46, relative as relative9, resolve as resolve29, sep as sep8 } from "node:path";
|
|
25933
26431
|
import { spawn as spawn8, spawnSync as spawnSync3 } from "node:child_process";
|
|
25934
26432
|
function readCatalog(file, catalog) {
|
|
25935
26433
|
let raw;
|
|
25936
26434
|
try {
|
|
25937
|
-
raw = JSON.parse(
|
|
26435
|
+
raw = JSON.parse(readFileSync34(file, "utf8"));
|
|
25938
26436
|
} catch {
|
|
25939
26437
|
return [];
|
|
25940
26438
|
}
|
|
@@ -25974,10 +26472,10 @@ function validEntry(e) {
|
|
|
25974
26472
|
return true;
|
|
25975
26473
|
}
|
|
25976
26474
|
function loadDemoRegistry(pkgRoot3) {
|
|
25977
|
-
const merged = readCatalog(
|
|
26475
|
+
const merged = readCatalog(join46(pkgRoot3, "demos.json"), "demos");
|
|
25978
26476
|
const seen = new Set(merged.map((e) => e.name));
|
|
25979
26477
|
const named = process.env.BEHOLD_WORKBENCH;
|
|
25980
|
-
for (const e of [...readCatalog(
|
|
26478
|
+
for (const e of [...readCatalog(join46(pkgRoot3, "workbench.json"), "workbench"), ...named ? readCatalog(resolve29(named), "workbench") : []]) {
|
|
25981
26479
|
if (seen.has(e.name)) {
|
|
25982
26480
|
process.stderr.write(`behold: workbench entry "${e.name}" collides with a demo already in the catalog \u2014 dropped
|
|
25983
26481
|
`);
|
|
@@ -26024,7 +26522,7 @@ async function loadDemo(entry, opts) {
|
|
|
26024
26522
|
say(`serving ${work} where it is \u2014 nothing copied`);
|
|
26025
26523
|
} else if (!existsSync26(target)) {
|
|
26026
26524
|
if (entry.source === "bundled" || entry.source === "local" && local) {
|
|
26027
|
-
const from = entry.source === "bundled" ?
|
|
26525
|
+
const from = entry.source === "bundled" ? join46(pkgRoot3, entry.dir) : local;
|
|
26028
26526
|
if (!existsSync26(from)) return { ok: false, error: entry.source === "bundled" ? `this install has no bundled ${entry.dir}` : `${entry.path} is not checked out (looked in ${from})` };
|
|
26029
26527
|
say(`copying to ${target} (it's yours \u2014 edit it)`);
|
|
26030
26528
|
try {
|
|
@@ -26056,7 +26554,7 @@ async function loadDemo(entry, opts) {
|
|
|
26056
26554
|
if (!pins.ok) return { ok: false, error: `${pins.error} ${pins.remedy}` };
|
|
26057
26555
|
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})` : ""}`);
|
|
26058
26556
|
}
|
|
26059
|
-
if (!inPlace && existsSync26(
|
|
26557
|
+
if (!inPlace && existsSync26(join46(work, "package.json")) && !existsSync26(join46(work, "node_modules"))) {
|
|
26060
26558
|
say("npm install\u2026");
|
|
26061
26559
|
if (await runStep("npm", ["install"], { cwd: work, shell: process.platform === "win32" }) !== 0) {
|
|
26062
26560
|
return { ok: false, error: `npm install failed in ${work}` };
|
|
@@ -26073,7 +26571,7 @@ async function loadDemo(entry, opts) {
|
|
|
26073
26571
|
return { ok: false, error: `setup failed (${entry.setup})` };
|
|
26074
26572
|
}
|
|
26075
26573
|
}
|
|
26076
|
-
return { ok: true, serveDirs: entry.serve.dirs?.length ? entry.serve.dirs.map((d) =>
|
|
26574
|
+
return { ok: true, serveDirs: entry.serve.dirs?.length ? entry.serve.dirs.map((d) => join46(work, d)) : [work] };
|
|
26077
26575
|
}
|
|
26078
26576
|
function runStep(cmd, args, opts = {}) {
|
|
26079
26577
|
return new Promise((res) => {
|
|
@@ -26084,8 +26582,8 @@ function runStep(cmd, args, opts = {}) {
|
|
|
26084
26582
|
}
|
|
26085
26583
|
|
|
26086
26584
|
// src/server.ts
|
|
26087
|
-
var pkgRoot =
|
|
26088
|
-
var webRoot =
|
|
26585
|
+
var pkgRoot = join47(dirname18(fileURLToPath10(import.meta.url)), "..");
|
|
26586
|
+
var webRoot = join47(pkgRoot, "web");
|
|
26089
26587
|
var execFileP = async (cmd, args) => (await promisify3(execFile5)(cmd, args, { encoding: "utf8", timeout: 1e4 })).stdout;
|
|
26090
26588
|
function optsFromQuery(url, tierEnvVar, projectDir) {
|
|
26091
26589
|
const q = url.searchParams;
|
|
@@ -26136,7 +26634,7 @@ function tierFailure(tier, message2) {
|
|
|
26136
26634
|
function beholdVersion() {
|
|
26137
26635
|
try {
|
|
26138
26636
|
const here = dirname18(fileURLToPath10(import.meta.url));
|
|
26139
|
-
return JSON.parse(
|
|
26637
|
+
return JSON.parse(readFileSync35(join47(here, "..", "package.json"), "utf8")).version ?? "unknown";
|
|
26140
26638
|
} catch {
|
|
26141
26639
|
return "unknown";
|
|
26142
26640
|
}
|
|
@@ -26183,7 +26681,7 @@ async function captureFrame(projectDir, env, frames, broadcaster) {
|
|
|
26183
26681
|
}
|
|
26184
26682
|
}
|
|
26185
26683
|
function carveRoutes(app, reportPath, demo) {
|
|
26186
|
-
const load2 = () => readCarveReport(reportPath, (p) =>
|
|
26684
|
+
const load2 = () => readCarveReport(reportPath, (p) => readFileSync35(p, "utf8"));
|
|
26187
26685
|
const carveDirs = [dirname18(reportPath), ...demo ? [demo.out] : []];
|
|
26188
26686
|
const carveStates = () => readCarveStates(carveDirs, nodeCarveIo, 0);
|
|
26189
26687
|
const emittedNodes = async (states) => {
|
|
@@ -26589,8 +27087,8 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
|
|
|
26589
27087
|
return c.json({ started: true, name, ran: label });
|
|
26590
27088
|
});
|
|
26591
27089
|
app.post("/api/local/reset", (c) => {
|
|
26592
|
-
const down =
|
|
26593
|
-
const up =
|
|
27090
|
+
const down = join47(cfg.projectDir, "scripts/local/local-down.sh");
|
|
27091
|
+
const up = join47(cfg.projectDir, "scripts/local/local-up.sh");
|
|
26594
27092
|
if (!existsSync27(down) || !existsSync27(up)) {
|
|
26595
27093
|
return c.json({ error: "no local-down.sh / local-up.sh in scripts/local \u2014 reset is only for local emulator projects" }, 400);
|
|
26596
27094
|
}
|
|
@@ -26612,7 +27110,7 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
|
|
|
26612
27110
|
const dirs = [];
|
|
26613
27111
|
const declared = [];
|
|
26614
27112
|
for (const f of discoverOpIrs(estateDirs)) {
|
|
26615
|
-
const parsed = readOpIr(f.path, (p) =>
|
|
27113
|
+
const parsed = readOpIr(f.path, (p) => readFileSync35(p, "utf8"));
|
|
26616
27114
|
if (!parsed.ok) continue;
|
|
26617
27115
|
const mine = declaredConvergeOps([parsed.ir]);
|
|
26618
27116
|
if (!mine.length) continue;
|
|
@@ -26831,6 +27329,9 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
|
|
|
26831
27329
|
// #489: a terragucci repo is applied by its pipeline; the SPA offers no
|
|
26832
27330
|
// write at all, and the write routes refuse with the same words.
|
|
26833
27331
|
...tgConfig() ? { terragucci: { config: tgConfig(), ...terragucciRefusal(tgConfig(), "deploying from behold") } } : {},
|
|
27332
|
+
// #571: the repo declares its roots as components, so the page opens on
|
|
27333
|
+
// the components zoom (web/app.js `bootZoom`).
|
|
27334
|
+
...servedTerragucciComponents() ? { terragucciComponents: true } : {},
|
|
26834
27335
|
// #517: a SQL Yodeler repo is migrated by its pipeline; same contract.
|
|
26835
27336
|
...(() => {
|
|
26836
27337
|
const r = guardedRepo();
|
|
@@ -26906,7 +27407,7 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
|
|
|
26906
27407
|
const body = await c.req.json().catch(() => ({}));
|
|
26907
27408
|
const dir = typeof body.dir === "string" && body.dir.trim() ? resolve30(body.dir.trim()) : "";
|
|
26908
27409
|
if (!dir || !existsSync27(dir)) return c.json({ error: `no such directory: ${dir || "(no dir given)"}` }, 400);
|
|
26909
|
-
if (!existsSync27(
|
|
27410
|
+
if (!existsSync27(join47(dir, "chant.config.ts"))) {
|
|
26910
27411
|
return c.json({ error: `${dir} doesn't look like a chant project \u2014 no chant.config.ts` }, 400);
|
|
26911
27412
|
}
|
|
26912
27413
|
switchServedProject([dir]);
|
|
@@ -27158,6 +27659,49 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
|
|
|
27158
27659
|
]
|
|
27159
27660
|
})
|
|
27160
27661
|
);
|
|
27662
|
+
const servedTerragucciComponents = () => (cfg.projectDirs?.length ?? 1) === 1 && memberKindOf(cfg.projectDir) === "terraform" ? readTerragucciComponents(cfg.projectDir) : void 0;
|
|
27663
|
+
const terragucciResources = async (decl, opts) => {
|
|
27664
|
+
try {
|
|
27665
|
+
const entities = normalizeTerraformNodes(structuredClone(await memberIr(cfg.projectDir, { ...tierTargetOpts(opts), detail: 2 }, terraformVia)));
|
|
27666
|
+
return resourcesByRoot(entities, componentRootMap(decl));
|
|
27667
|
+
} catch {
|
|
27668
|
+
return {};
|
|
27669
|
+
}
|
|
27670
|
+
};
|
|
27671
|
+
const terragucciComponentsGraph = async (decl, opts) => {
|
|
27672
|
+
const state = terraformReaderState();
|
|
27673
|
+
if (state.refusal) throw new TerraformReadError(state.refusal, cfg.projectDir);
|
|
27674
|
+
const { project } = terraformMemberProject(cfg.projectDir);
|
|
27675
|
+
const ir = await componentGraphIr(project, tierTargetOpts(opts));
|
|
27676
|
+
const titles = waveTitles(ir, decl);
|
|
27677
|
+
const { svg } = renderGraph(ir, { waveTitles: titles });
|
|
27678
|
+
const waves = Object.keys(ir.groups.byWave ?? {}).length;
|
|
27679
|
+
const note = `${ir.nodes.length} root${ir.nodes.length === 1 ? "" : "s"} in ${waves} wave${waves === 1 ? "" : "s"}, from ${TERRAGUCCI_COMPONENTS_FILE}`;
|
|
27680
|
+
return {
|
|
27681
|
+
ir,
|
|
27682
|
+
svg,
|
|
27683
|
+
meta: {
|
|
27684
|
+
projectDir: cfg.projectDir,
|
|
27685
|
+
env: null,
|
|
27686
|
+
tier: opts.tier ?? null,
|
|
27687
|
+
target: opts.target ?? null,
|
|
27688
|
+
components: true,
|
|
27689
|
+
note,
|
|
27690
|
+
// The CI facet's source on a terragucci repo: the declared jobs, not a
|
|
27691
|
+
// chant-generated pipeline (`/api/ci`, which a public view refuses).
|
|
27692
|
+
terragucciComponents: {
|
|
27693
|
+
...decl.pipeline.forge ? { forge: decl.pipeline.forge } : {},
|
|
27694
|
+
...decl.pipeline.path ? { pipeline: decl.pipeline.path } : {},
|
|
27695
|
+
jobs: Object.values(componentJobs(decl)),
|
|
27696
|
+
// component -> the root it applies: the live marks' join onto the
|
|
27697
|
+
// reports' and run view's roots (web/terragucci-components-live.js).
|
|
27698
|
+
roots: componentRootMap(decl),
|
|
27699
|
+
waveTitles: titles,
|
|
27700
|
+
resources: await terragucciResources(decl, opts)
|
|
27701
|
+
}
|
|
27702
|
+
}
|
|
27703
|
+
};
|
|
27704
|
+
};
|
|
27161
27705
|
app.get("/api/graph", async (c) => {
|
|
27162
27706
|
const url = new URL(c.req.url);
|
|
27163
27707
|
const opts = optsFromQuery(url, tierEnvVar, cfg.projectDir);
|
|
@@ -27210,7 +27754,7 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
|
|
|
27210
27754
|
}
|
|
27211
27755
|
const parsedOps = [];
|
|
27212
27756
|
for (const f of files) {
|
|
27213
|
-
const parsed = readOpIr(f.path, (p) =>
|
|
27757
|
+
const parsed = readOpIr(f.path, (p) => readFileSync35(p, "utf8"));
|
|
27214
27758
|
if (!parsed.ok) return c.json(parsed.refusal, 422);
|
|
27215
27759
|
parsedOps.push(parsed.ir);
|
|
27216
27760
|
}
|
|
@@ -27223,8 +27767,8 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
|
|
|
27223
27767
|
}
|
|
27224
27768
|
const runState = runner.runState;
|
|
27225
27769
|
const ranOp = runState.op ? parsedOps.find((o) => o.name === runState.op) : void 0;
|
|
27226
|
-
const
|
|
27227
|
-
const opsIr =
|
|
27770
|
+
const join52 = ranOp ? joinRun(ranOp, runState.records, runState.gate) : null;
|
|
27771
|
+
const opsIr = join52 ? paintPlayhead(declaredIr, join52, runState.gate) : declaredIr;
|
|
27228
27772
|
const { svg: svg2 } = renderGraph(opsIr, { boxes: "byStack" });
|
|
27229
27773
|
const operator = runner.noteDeclaredConvergeOps(declaredConvergeOps(parsedOps));
|
|
27230
27774
|
return c.json({
|
|
@@ -27237,7 +27781,7 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
|
|
|
27237
27781
|
target: null,
|
|
27238
27782
|
mode: "ops",
|
|
27239
27783
|
ops: parsedOps.length,
|
|
27240
|
-
note: `${opsNote(parsedOps, opsIr)} ${playheadNote(runState,
|
|
27784
|
+
note: `${opsNote(parsedOps, opsIr)} ${playheadNote(runState, join52)} ${operatorNote(operator)}`,
|
|
27241
27785
|
// The operator strip's own model: the ConvergeOps this project
|
|
27242
27786
|
// declares, plus whatever the last status read said. `declared`
|
|
27243
27787
|
// without a `strip` is the honest starting state — a loop exists and
|
|
@@ -27265,6 +27809,8 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
|
|
|
27265
27809
|
// workspace, so behold's own lexicon only speaks for a loose one.
|
|
27266
27810
|
graph.edges.length === 0 && (multi ? cfg.projectDirs : [cfg.projectDir]).some((d) => memberKindOf(d) === "choudoufu" && !workspaceMemberOf(d)) ? choudoufuLexiconNote() : void 0
|
|
27267
27811
|
);
|
|
27812
|
+
const tgDecl = components ? servedTerragucciComponents() : void 0;
|
|
27813
|
+
if (tgDecl) return c.json(await terragucciComponentsGraph(tgDecl, opts));
|
|
27268
27814
|
let ir;
|
|
27269
27815
|
let mode;
|
|
27270
27816
|
let metaEnv = cfg.env ?? null;
|
|
@@ -27348,7 +27894,7 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
|
|
|
27348
27894
|
srcCompositeEdgesAttached = 0;
|
|
27349
27895
|
}
|
|
27350
27896
|
}
|
|
27351
|
-
if (!multi && !components && !logical && !opts.lens && !ownKindVia && ir.nodes.length === 0 && !existsSync27(
|
|
27897
|
+
if (!multi && !components && !logical && !opts.lens && !ownKindVia && ir.nodes.length === 0 && !existsSync27(join47(cfg.projectDir, "chant.config.ts"))) {
|
|
27352
27898
|
return c.json(noProjectError(cfg.projectDir), 404);
|
|
27353
27899
|
}
|
|
27354
27900
|
const radial = new URL(c.req.url).searchParams.get("radial") === "1";
|
|
@@ -27490,6 +28036,8 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
|
|
|
27490
28036
|
app.get("/api/resources", async (c) => {
|
|
27491
28037
|
const opts = optsFromQuery(new URL(c.req.url), tierEnvVar, cfg.projectDir);
|
|
27492
28038
|
const env = opts.env ?? cfg.env;
|
|
28039
|
+
const tgDecl = servedTerragucciComponents();
|
|
28040
|
+
if (tgDecl) return c.json({ byComponent: await terragucciResources(tgDecl, opts) });
|
|
27493
28041
|
const kind = memberKindOf(cfg.projectDir);
|
|
27494
28042
|
if (kind && kind !== "chant") return c.json({ byComponent: {} });
|
|
27495
28043
|
try {
|
|
@@ -27985,7 +28533,7 @@ function createApp(cfg, broadcaster = new Broadcaster(), frames = new FrameBuffe
|
|
|
27985
28533
|
if (!c.req.path.startsWith("/api/") && c.res.ok && !c.res.headers.has("cache-control")) c.res.headers.set("cache-control", "no-cache");
|
|
27986
28534
|
});
|
|
27987
28535
|
app.use("/*", serveStatic({ root: rel }));
|
|
27988
|
-
app.get("/", serveStatic({ path:
|
|
28536
|
+
app.get("/", serveStatic({ path: join47(rel, "index.html") }));
|
|
27989
28537
|
return app;
|
|
27990
28538
|
}
|
|
27991
28539
|
async function bootLocalEmulators(dir, who) {
|
|
@@ -28014,7 +28562,7 @@ async function bootLocalEmulators(dir, who) {
|
|
|
28014
28562
|
async function startServer(cfg) {
|
|
28015
28563
|
if (cfg.local) cfg.emulators = await bootLocalEmulators(cfg.projectDir, "behold serve --local");
|
|
28016
28564
|
for (const dir of cfg.projectDirs ?? [cfg.projectDir]) {
|
|
28017
|
-
if (existsSync27(
|
|
28565
|
+
if (existsSync27(join47(dir, "chant.config.ts"))) addRecent(dir);
|
|
28018
28566
|
}
|
|
28019
28567
|
const broadcaster = new Broadcaster();
|
|
28020
28568
|
const frames = new FrameBuffer();
|
|
@@ -28188,8 +28736,8 @@ init_chant();
|
|
|
28188
28736
|
|
|
28189
28737
|
// src/workspace-convert.ts
|
|
28190
28738
|
init_chant();
|
|
28191
|
-
import { existsSync as existsSync28, mkdirSync as mkdirSync9, readFileSync as
|
|
28192
|
-
import { basename as basename6, dirname as dirname19, join as
|
|
28739
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync9, readFileSync as readFileSync36, renameSync as renameSync2, writeFileSync as writeFileSync7 } from "node:fs";
|
|
28740
|
+
import { basename as basename6, dirname as dirname19, join as join48, relative as relative11, resolve as resolve31, sep as sep10 } from "node:path";
|
|
28193
28741
|
import { shortStackNames as shortStackNames2 } from "@intentius/pinhole";
|
|
28194
28742
|
init_project();
|
|
28195
28743
|
init_terraform_member();
|
|
@@ -28207,10 +28755,10 @@ function unique(name, taken) {
|
|
|
28207
28755
|
var posix4 = (p) => p.split(sep10).join("/");
|
|
28208
28756
|
function installedVersion(pkg, dir) {
|
|
28209
28757
|
for (let at2 = resolve31(dir); ; at2 = dirname19(at2)) {
|
|
28210
|
-
const manifest =
|
|
28758
|
+
const manifest = join48(at2, "node_modules", ...pkg.split("/"), "package.json");
|
|
28211
28759
|
if (existsSync28(manifest)) {
|
|
28212
28760
|
try {
|
|
28213
|
-
const v = JSON.parse(
|
|
28761
|
+
const v = JSON.parse(readFileSync36(manifest, "utf8")).version;
|
|
28214
28762
|
return typeof v === "string" ? v : void 0;
|
|
28215
28763
|
} catch {
|
|
28216
28764
|
return void 0;
|
|
@@ -28221,7 +28769,7 @@ function installedVersion(pkg, dir) {
|
|
|
28221
28769
|
}
|
|
28222
28770
|
function planConversion(rootArg) {
|
|
28223
28771
|
const root = resolve31(rootArg);
|
|
28224
|
-
const existing = DECLARATION_FILES.find((f) => existsSync28(
|
|
28772
|
+
const existing = DECLARATION_FILES.find((f) => existsSync28(join48(root, f)));
|
|
28225
28773
|
if (existing) return { ok: false, error: `${root} already has ${existing}; there is nothing to convert.` };
|
|
28226
28774
|
const shape = detectProjectShape(root);
|
|
28227
28775
|
if (shape.kind !== "estate" || !shape.members?.length || shape.membersFrom === "itself") {
|
|
@@ -28242,10 +28790,10 @@ function planConversion(rootArg) {
|
|
|
28242
28790
|
const scan = discoverTerraformRoots(abs[i]);
|
|
28243
28791
|
for (const r of scan.roots) {
|
|
28244
28792
|
const name2 = unique(declarationName(r.name), taken);
|
|
28245
|
-
members.push({ name: name2, dir: r.dir === "." ? dir : posix4(
|
|
28793
|
+
members.push({ name: name2, dir: r.dir === "." ? dir : posix4(join48(dir, r.dir)), kind: "terraform" });
|
|
28246
28794
|
moves.push({ from: `${short}/${r.name}/`, to: `${name2}/${name2}/` });
|
|
28247
28795
|
}
|
|
28248
|
-
for (const s of scan.skipped) notes.push(`${posix4(
|
|
28796
|
+
for (const s of scan.skipped) notes.push(`${posix4(join48(dir, s.dir))} is not declared: ${s.why}.`);
|
|
28249
28797
|
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.`);
|
|
28250
28798
|
return;
|
|
28251
28799
|
}
|
|
@@ -28288,7 +28836,7 @@ function moveLayoutIds(file, moves) {
|
|
|
28288
28836
|
return { version: 1, lenses };
|
|
28289
28837
|
}
|
|
28290
28838
|
function applyConversion(plan) {
|
|
28291
|
-
const declarationFile =
|
|
28839
|
+
const declarationFile = join48(plan.root, DECLARATION_FILES[0]);
|
|
28292
28840
|
if (existsSync28(declarationFile)) throw new Error(`${declarationFile} appeared while converting; nothing was written`);
|
|
28293
28841
|
writeFileSync7(declarationFile, `${JSON.stringify(plan.declaration, null, 2)}
|
|
28294
28842
|
`);
|
|
@@ -28299,7 +28847,7 @@ function applyConversion(plan) {
|
|
|
28299
28847
|
else if (existsSync28(target)) layout = { skipped: `${target} already exists; the layout in ${plan.layoutFrom} was left alone` };
|
|
28300
28848
|
else {
|
|
28301
28849
|
const moved = moveLayoutIds(readLayoutFile(dirname19(dirname19(plan.layoutFrom))), plan.moves);
|
|
28302
|
-
mkdirSync9(
|
|
28850
|
+
mkdirSync9(join48(plan.root, LAYOUT_DIR), { recursive: true });
|
|
28303
28851
|
const tmp = `${target}.tmp`;
|
|
28304
28852
|
writeFileSync7(tmp, `${JSON.stringify(moved, null, 2)}
|
|
28305
28853
|
`);
|
|
@@ -28310,9 +28858,9 @@ function applyConversion(plan) {
|
|
|
28310
28858
|
}
|
|
28311
28859
|
|
|
28312
28860
|
// src/export.ts
|
|
28313
|
-
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync8, copyFileSync, cpSync as cpSync2, readFileSync as
|
|
28861
|
+
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync8, copyFileSync, cpSync as cpSync2, readFileSync as readFileSync37, readdirSync as readdirSync14, existsSync as existsSync29, realpathSync as realpathSync2 } from "node:fs";
|
|
28314
28862
|
import { homedir as homedir3 } from "node:os";
|
|
28315
|
-
import { join as
|
|
28863
|
+
import { join as join49, dirname as dirname20, basename as basename7, relative as relative12, resolve as resolve32, sep as sep11 } from "node:path";
|
|
28316
28864
|
import { createHash as createHash11 } from "node:crypto";
|
|
28317
28865
|
import { fileURLToPath as fileURLToPath11 } from "node:url";
|
|
28318
28866
|
var LENS_PARAMS = ["collapse", "components", "detail", "env", "logical", "ops", "radial", "stacks", "tier"];
|
|
@@ -28369,24 +28917,24 @@ function captureKeys(axes) {
|
|
|
28369
28917
|
return [...keys];
|
|
28370
28918
|
}
|
|
28371
28919
|
function webDir() {
|
|
28372
|
-
return
|
|
28920
|
+
return join49(dirname20(fileURLToPath11(import.meta.url)), "..", "web");
|
|
28373
28921
|
}
|
|
28374
28922
|
function pkgRoot2() {
|
|
28375
|
-
return
|
|
28923
|
+
return join49(dirname20(fileURLToPath11(import.meta.url)), "..");
|
|
28376
28924
|
}
|
|
28377
28925
|
var NOTICE_FILES = ["LICENSE", "THIRD_PARTY.md"];
|
|
28378
28926
|
function copyNotices(outDir, root = pkgRoot2()) {
|
|
28379
28927
|
const copied = [];
|
|
28380
28928
|
for (const f of NOTICE_FILES) {
|
|
28381
|
-
if (!existsSync29(
|
|
28382
|
-
copyFileSync(
|
|
28929
|
+
if (!existsSync29(join49(root, f))) continue;
|
|
28930
|
+
copyFileSync(join49(root, f), join49(outDir, f));
|
|
28383
28931
|
copied.push(f);
|
|
28384
28932
|
}
|
|
28385
|
-
const lic =
|
|
28933
|
+
const lic = join49(root, "licenses");
|
|
28386
28934
|
if (existsSync29(lic)) {
|
|
28387
|
-
mkdirSync10(
|
|
28935
|
+
mkdirSync10(join49(outDir, "licenses"), { recursive: true });
|
|
28388
28936
|
for (const f of readdirSync14(lic)) {
|
|
28389
|
-
copyFileSync(
|
|
28937
|
+
copyFileSync(join49(lic, f), join49(outDir, "licenses", f));
|
|
28390
28938
|
copied.push(`licenses/${f}`);
|
|
28391
28939
|
}
|
|
28392
28940
|
}
|
|
@@ -28411,7 +28959,7 @@ async function runExport(cfg, outDir, opts = {}) {
|
|
|
28411
28959
|
...proj.sqlYodeler ? { sqlYodeler: true } : {}
|
|
28412
28960
|
};
|
|
28413
28961
|
const scrub = exportScrubber(cfg);
|
|
28414
|
-
const snapDir =
|
|
28962
|
+
const snapDir = join49(outDir, "snapshots");
|
|
28415
28963
|
mkdirSync10(snapDir, { recursive: true });
|
|
28416
28964
|
const keyToFile = {};
|
|
28417
28965
|
let ok = 0;
|
|
@@ -28420,7 +28968,7 @@ async function runExport(cfg, outDir, opts = {}) {
|
|
|
28420
28968
|
const res = await app.request(`${key}${key.includes("?") ? "&" : "?"}layout=1`);
|
|
28421
28969
|
const body = scrub(shapeSnapshot(key, await res.text(), opts));
|
|
28422
28970
|
const file = slug3(key, body);
|
|
28423
|
-
writeFileSync8(
|
|
28971
|
+
writeFileSync8(join49(snapDir, file), body);
|
|
28424
28972
|
keyToFile[key] = `snapshots/${file}`;
|
|
28425
28973
|
if (res.ok) ok++;
|
|
28426
28974
|
else failed++;
|
|
@@ -28442,29 +28990,29 @@ async function runExport(cfg, outDir, opts = {}) {
|
|
|
28442
28990
|
axes,
|
|
28443
28991
|
keyToFile
|
|
28444
28992
|
};
|
|
28445
|
-
writeFileSync8(
|
|
28446
|
-
const html =
|
|
28993
|
+
writeFileSync8(join49(outDir, "manifest.json"), JSON.stringify(manifest, null, 2));
|
|
28994
|
+
const html = readFileSync37(join49(webDir(), "index.html"), "utf8").replace(
|
|
28447
28995
|
/<\/head>/i,
|
|
28448
28996
|
` <script>window.__BEHOLD_STATIC__ = true;</script>
|
|
28449
28997
|
</head>`
|
|
28450
28998
|
);
|
|
28451
|
-
writeFileSync8(
|
|
28999
|
+
writeFileSync8(join49(outDir, "index.html"), html);
|
|
28452
29000
|
for (const f of readdirSync14(webDir())) {
|
|
28453
29001
|
if (f === "index.html" || f.endsWith(".test.js")) continue;
|
|
28454
|
-
cpSync2(
|
|
29002
|
+
cpSync2(join49(webDir(), f), join49(outDir, f), { recursive: true });
|
|
28455
29003
|
}
|
|
28456
|
-
writeFileSync8(
|
|
29004
|
+
writeFileSync8(join49(outDir, "README.md"), BUNDLE_README);
|
|
28457
29005
|
copyNotices(outDir);
|
|
28458
29006
|
const name = workerName(cfg.projectDir, opts.name);
|
|
28459
29007
|
writeFileSync8(
|
|
28460
|
-
|
|
29008
|
+
join49(outDir, "wrangler.jsonc"),
|
|
28461
29009
|
JSON.stringify(
|
|
28462
29010
|
{ $schema: "node_modules/wrangler/config-schema.json", name, compatibility_date: "2025-06-01", assets: { directory: "." } },
|
|
28463
29011
|
null,
|
|
28464
29012
|
2
|
|
28465
29013
|
) + "\n"
|
|
28466
29014
|
);
|
|
28467
|
-
writeFileSync8(
|
|
29015
|
+
writeFileSync8(join49(outDir, "manifest.json"), JSON.stringify({ ...manifest, files: bundleFiles(outDir).filter((f) => f !== "manifest.json") }, null, 2));
|
|
28468
29016
|
process.stdout.write(
|
|
28469
29017
|
`behold export \u2192 ${outDir}
|
|
28470
29018
|
${ok} snapshots${failed ? ` (${failed} endpoint error(s) captured as-is)` : ""}
|
|
@@ -28561,7 +29109,7 @@ function manifestFiles(text) {
|
|
|
28561
29109
|
return Object.values(map).filter((f) => typeof f === "string" && /^snapshots\/[A-Za-z0-9=_.-]+$/.test(f) && !f.includes(".."));
|
|
28562
29110
|
}
|
|
28563
29111
|
function bundleFiles(outDir) {
|
|
28564
|
-
return readdirSync14(outDir, { recursive: true, withFileTypes: true }).filter((d) => d.isFile()).map((d) => relative12(outDir,
|
|
29112
|
+
return readdirSync14(outDir, { recursive: true, withFileTypes: true }).filter((d) => d.isFile()).map((d) => relative12(outDir, join49(d.parentPath, d.name)).split(sep11).join("/")).sort();
|
|
28565
29113
|
}
|
|
28566
29114
|
async function publishBundle(outDir, target, client) {
|
|
28567
29115
|
const files = bundleFiles(outDir);
|
|
@@ -28577,7 +29125,7 @@ async function publishBundle(outDir, target, client) {
|
|
|
28577
29125
|
}
|
|
28578
29126
|
const last = ["manifest.json", "index.html"];
|
|
28579
29127
|
const order = [...files.filter((f) => !last.includes(f)), ...last.filter((f) => files.includes(f))];
|
|
28580
|
-
for (const f of order) await client.put(at2(f),
|
|
29128
|
+
for (const f of order) await client.put(at2(f), readFileSync37(join49(outDir, f)), contentType(f), CONTENT_ADDRESSED.test(f) ? IMMUTABLE : NO_CACHE);
|
|
28581
29129
|
const wrote = new Set(files);
|
|
28582
29130
|
const removed = [];
|
|
28583
29131
|
for (const f of previous) {
|
|
@@ -28629,8 +29177,8 @@ It's just files \u2014 GitHub Pages, S3, nginx, or Cloudflare Pages
|
|
|
28629
29177
|
|
|
28630
29178
|
// src/publish-snapshots.ts
|
|
28631
29179
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
28632
|
-
import { readFileSync as
|
|
28633
|
-
import { join as
|
|
29180
|
+
import { readFileSync as readFileSync38 } from "node:fs";
|
|
29181
|
+
import { join as join50 } from "node:path";
|
|
28634
29182
|
var DEFAULT_KEEP = 30;
|
|
28635
29183
|
var SNAPSHOT_REPORTS_BASE = "../../../";
|
|
28636
29184
|
var COMMIT = /^[0-9a-f]{7,64}$/;
|
|
@@ -28718,7 +29266,7 @@ async function publishSnapshot(outDir, target, commit, client, opts = {}) {
|
|
|
28718
29266
|
const keep = opts.keep ?? DEFAULT_KEEP;
|
|
28719
29267
|
if (!Number.isInteger(keep) || keep < 1) throw new Error(`--keep takes a whole number of at least 1, not ${keep}`);
|
|
28720
29268
|
const at2 = (f) => `${target.prefix}/${f}`;
|
|
28721
|
-
const local = JSON.parse(
|
|
29269
|
+
const local = JSON.parse(readFileSync38(join50(outDir, "manifest.json"), "utf8"));
|
|
28722
29270
|
const generated = local.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
28723
29271
|
const entry = { commit: sha, at: commit.at ?? generated, project: opts.project ?? local.projectDir ?? "", generated };
|
|
28724
29272
|
const bundle = await publishBundle(outDir, { bucket: target.bucket, prefix: at2(sha) }, client);
|
|
@@ -29181,7 +29729,7 @@ function warnIfNotChantProject(dir) {
|
|
|
29181
29729
|
if (shape.kind === "estate") {
|
|
29182
29730
|
process.stderr.write(
|
|
29183
29731
|
`behold: warning \u2014 ${dir} is an estate root, not a chant project itself.
|
|
29184
|
-
Serve its members composed: behold serve ${shape.members.map((m) =>
|
|
29732
|
+
Serve its members composed: behold serve ${shape.members.map((m) => join51(dir, m.dir)).join(" ")}
|
|
29185
29733
|
`
|
|
29186
29734
|
);
|
|
29187
29735
|
return;
|
|
@@ -29217,7 +29765,7 @@ async function runCarve(rest) {
|
|
|
29217
29765
|
process.exit(2);
|
|
29218
29766
|
}
|
|
29219
29767
|
const reportPath = resolve33(fileArg);
|
|
29220
|
-
const parsed = readCarveReport(reportPath, (p) =>
|
|
29768
|
+
const parsed = readCarveReport(reportPath, (p) => readFileSync39(p, "utf8"));
|
|
29221
29769
|
if (!parsed.ok) {
|
|
29222
29770
|
process.stderr.write(`behold carve: ${parsed.refusal.error}
|
|
29223
29771
|
${parsed.refusal.remedy}
|
|
@@ -29283,7 +29831,7 @@ ${check.stdout || check.stderr}
|
|
|
29283
29831
|
if (check.code !== 0) process.exitCode = 1;
|
|
29284
29832
|
}
|
|
29285
29833
|
async function runDemo(rest) {
|
|
29286
|
-
const pkgRoot3 =
|
|
29834
|
+
const pkgRoot3 = join51(dirname21(fileURLToPath12(import.meta.url)), "..");
|
|
29287
29835
|
const registry2 = loadDemoRegistry(pkgRoot3);
|
|
29288
29836
|
let port = 4600;
|
|
29289
29837
|
let live2 = false;
|
|
@@ -29418,7 +29966,7 @@ async function serveCarveDemo(target, carve, port, live2 = false) {
|
|
|
29418
29966
|
};
|
|
29419
29967
|
process.stdout.write("behold demo carve --live \u2192 the tfstate is real now; the advisor reads what terraform wrote.\n");
|
|
29420
29968
|
}
|
|
29421
|
-
if (existsSync30(
|
|
29969
|
+
if (existsSync30(join51(project, "package.json")) && !existsSync30(join51(project, "node_modules"))) {
|
|
29422
29970
|
process.stdout.write(`behold demo carve \u2192 npm install in ${carve.project}/ (the chant this walkthrough shells)\u2026
|
|
29423
29971
|
`);
|
|
29424
29972
|
const code = await spawnStep("npm", ["install"], project);
|
|
@@ -29429,7 +29977,7 @@ async function serveCarveDemo(target, carve, port, live2 = false) {
|
|
|
29429
29977
|
}
|
|
29430
29978
|
}
|
|
29431
29979
|
let degraded;
|
|
29432
|
-
if (!existsSync30(
|
|
29980
|
+
if (!existsSync30(join51(target, "node_modules", ...HCL_PARSER_PKG.split("/")))) {
|
|
29433
29981
|
process.stdout.write(`behold demo carve \u2192 npm install ${HCL_PARSER_PKG} (chant's HCL parser, ~2MB, once)\u2026
|
|
29434
29982
|
`);
|
|
29435
29983
|
const code = await spawnStep("npm", ["install", "--no-save", "--no-package-lock", HCL_PARSER_PKG], target);
|