@wairon/cli 5.1.1-dev.6 → 5.1.1-dev.7

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/index.js CHANGED
@@ -65,7 +65,7 @@ var init_defaults = __esm({
65
65
  copilot: ".github/prompts",
66
66
  codex: ".codex/agents"
67
67
  };
68
- WAIRON_VERSION = "5.1.1-dev.6";
68
+ WAIRON_VERSION = "5.1.1-dev.7";
69
69
  GITHUB_REPO = "SYW-Apps/Waffle-AIron";
70
70
  ARCHITECT_AGENT_ID = "agent-architect";
71
71
  ARCHITECT_TEMPLATE_ID = "architect";
@@ -3976,9 +3976,9 @@ var init_surfaces = __esm({
3976
3976
  // src/core/rules/namespace.ts
3977
3977
  function isExternalNamespaceRef(ctx, ref) {
3978
3978
  if (ref.startsWith("::") || ref.startsWith("super::")) return true;
3979
- const sep6 = ref.indexOf("::");
3980
- if (sep6 === -1) return false;
3981
- return !ctx.subsystemIds.has(ref.slice(0, sep6));
3979
+ const sep9 = ref.indexOf("::");
3980
+ if (sep9 === -1) return false;
3981
+ return !ctx.subsystemIds.has(ref.slice(0, sep9));
3982
3982
  }
3983
3983
  function resolveSurfaceRef(ctx, ref) {
3984
3984
  const local = ref.split("::").filter((seg) => seg && seg !== "super").pop();
@@ -4315,10 +4315,10 @@ function stepGraph(steps) {
4315
4315
  const s = byNum.get(n);
4316
4316
  if (s.type !== "parallel" || s.endStep === void 0 || !s.branches?.length) continue;
4317
4317
  const entries = s.branches.map((b) => b.step).sort((a, b) => a - b);
4318
- const join49 = fallNext(s.endStep);
4318
+ const join50 = fallNext(s.endStep);
4319
4319
  for (let i = 0; i < entries.length; i++) {
4320
4320
  const armEnd = i + 1 < entries.length ? prevOf(entries[i + 1]) : s.endStep;
4321
- if (armEnd !== void 0 && armEnd >= entries[i]) armEndJoin.set(armEnd, join49);
4321
+ if (armEnd !== void 0 && armEnd >= entries[i]) armEndJoin.set(armEnd, join50);
4322
4322
  }
4323
4323
  }
4324
4324
  const successorsOf = (n) => {
@@ -4392,7 +4392,8 @@ var init_narrative_flow = __esm({
4392
4392
  { code: "REGION_OVERLAP", defaultSeverity: "error", summary: "loop/try regions interleave \u2014 regions must nest or be disjoint to map onto structured code" },
4393
4393
  { code: "JUMP_INTO_REGION", defaultSeverity: "warning", summary: "Jump lands in the middle of a loop/try body from outside \u2014 regions are entered through their header" },
4394
4394
  { code: "FALLTHROUGH_INTO_HANDLER", defaultSeverity: "warning", summary: "try body falls through into its own catch/finally region on the success path" },
4395
- { code: "BACKWARD_JUMP", defaultSeverity: "warning", summary: "Backward jump that is not a continue to an enclosing loop header \u2014 model repetition with a loop step" }
4395
+ { code: "BACKWARD_JUMP", defaultSeverity: "warning", summary: "Backward jump that is not a continue to an enclosing loop header \u2014 model repetition with a loop step" },
4396
+ { code: "DUPLICATE_STEP_LABEL", defaultSeverity: "error", summary: "Two steps in one narrative share a label \u2014 the symbolic anchor later deltas address by" }
4396
4397
  ],
4397
4398
  check(ctx) {
4398
4399
  for (const impl of ctx.implementations) {
@@ -4401,6 +4402,23 @@ var init_narrative_flow = __esm({
4401
4402
  const steps = implMethod.narrative;
4402
4403
  if (!steps.length) continue;
4403
4404
  const where = `Method "${implMethod.name}" in implementation "${impl.id}": `;
4405
+ const labelled = /* @__PURE__ */ new Map();
4406
+ for (const step of steps) {
4407
+ const label = step.label;
4408
+ if (!label) continue;
4409
+ const first = labelled.get(label);
4410
+ if (first !== void 0) {
4411
+ ctx.addIssue(
4412
+ "error",
4413
+ "DUPLICATE_STEP_LABEL",
4414
+ `${where}steps ${first} and ${step.stepNumber} share the label "${label}". A label anchors one step for later deltas to address; two steps holding it makes every symbolic reference ambiguous and blocks all further edits to this implementation. Rename one.`,
4415
+ impl.id,
4416
+ isDraftCtx
4417
+ );
4418
+ } else {
4419
+ labelled.set(label, step.stepNumber);
4420
+ }
4421
+ }
4404
4422
  let sound = true;
4405
4423
  const malformed = (msg) => {
4406
4424
  sound = false;
@@ -7626,11 +7644,11 @@ var init_narrative_antipatterns = __esm({
7626
7644
  const memberEdges = keys.flatMap((k) => (adjacency.get(k) ?? []).filter((e) => inScc.has(e.toKey)));
7627
7645
  if (memberEdges.length === 0) continue;
7628
7646
  const anchor = [...memberEdges].sort((a, b) => a.fromKey.localeCompare(b.fromKey))[0];
7629
- const path64 = [...keys].sort().join(" \u2192 ");
7647
+ const path67 = [...keys].sort().join(" \u2192 ");
7630
7648
  ctx.addIssue(
7631
7649
  "warning",
7632
7650
  "UNCONDITIONAL_CALL_CYCLE",
7633
- `Call cycle with no guard: ${path64} \u2014 every call edge in this cycle is unavoidable on all paths of its narrative (e.g. step ${anchor.stepNumber} of "${anchor.methodName}" in "${anchor.impl.id}" always calls ${anchor.toLabel}). This recurses without a base case, by construction. Guard at least one edge with a branch/return before the call, or lint.allow with the termination argument.`,
7651
+ `Call cycle with no guard: ${path67} \u2014 every call edge in this cycle is unavoidable on all paths of its narrative (e.g. step ${anchor.stepNumber} of "${anchor.methodName}" in "${anchor.impl.id}" always calls ${anchor.toLabel}). This recurses without a base case, by construction. Guard at least one edge with a branch/return before the call, or lint.allow with the termination argument.`,
7634
7652
  anchor.impl.id,
7635
7653
  memberEdges.some((e) => ctx.isImplementationDraft(e.impl))
7636
7654
  );
@@ -14403,6 +14421,137 @@ var init_repository = __esm({
14403
14421
  }
14404
14422
  });
14405
14423
 
14424
+ // src/core/baseline.ts
14425
+ function diffSize(d) {
14426
+ return d.added.length + d.changed.length + d.removed.length;
14427
+ }
14428
+ function baselineDir() {
14429
+ return process.env["WAIRON_BASELINE_DIR"] || path17.join(os5.homedir(), ".wairon", "baselines");
14430
+ }
14431
+ function keyFor(root) {
14432
+ const normalized = path17.resolve(root).replace(/\\/g, "/").toLowerCase();
14433
+ return crypto3.createHash("sha256").update(normalized).digest("hex").slice(0, 16);
14434
+ }
14435
+ function baselinePath(root) {
14436
+ return path17.join(baselineDir(), `${keyFor(root)}.json`);
14437
+ }
14438
+ function readBaseline(root = getProjectRoot()) {
14439
+ const p = baselinePath(root);
14440
+ if (!pathExists(p)) return null;
14441
+ try {
14442
+ return JSON.parse(fs13.readFileSync(p, "utf8"));
14443
+ } catch {
14444
+ return null;
14445
+ }
14446
+ }
14447
+ function writeBaseline(record2) {
14448
+ const p = baselinePath(record2.projectRoot);
14449
+ ensureDir(path17.dirname(p));
14450
+ fs13.writeFileSync(p, `${JSON.stringify(record2, null, 2)}
14451
+ `);
14452
+ return p;
14453
+ }
14454
+ function currentSpecs(root) {
14455
+ const mountDirs = loadSubsystemSpecs().filter((s) => s.projectPath && !s.id.includes("::")).map((s) => `${path17.resolve(root, s.projectPath).split(path17.sep).join("/")}/`);
14456
+ const out = {};
14457
+ for (const [abs, content] of snapshotSpecFiles()) {
14458
+ const normalized = path17.resolve(abs).split(path17.sep).join("/");
14459
+ if (mountDirs.some((dir) => normalized.startsWith(dir))) continue;
14460
+ out[path17.relative(root, abs).split(path17.sep).join("/")] = content;
14461
+ }
14462
+ return out;
14463
+ }
14464
+ function captureBaseline(approvedBy, children = {}, root = getProjectRoot(), scope) {
14465
+ const system = loadSystemSpec();
14466
+ const current2 = currentSpecs(root);
14467
+ let specs = current2;
14468
+ if (scope) {
14469
+ const previous = readBaseline(root)?.specs ?? {};
14470
+ specs = { ...previous };
14471
+ for (const rel2 of Object.keys(previous)) {
14472
+ if (scope.paths.has(rel2) && current2[rel2] === void 0) delete specs[rel2];
14473
+ }
14474
+ for (const rel2 of scope.paths) {
14475
+ if (current2[rel2] !== void 0) specs[rel2] = current2[rel2];
14476
+ }
14477
+ }
14478
+ return {
14479
+ schemaVersion: SCHEMA_VERSION,
14480
+ projectRoot: path17.resolve(root),
14481
+ systemName: system?.name ?? path17.basename(root),
14482
+ approvedAt: (/* @__PURE__ */ new Date()).toISOString(),
14483
+ approvedBy,
14484
+ stateId: computeGateStateId(),
14485
+ specs,
14486
+ children
14487
+ };
14488
+ }
14489
+ function diffAgainstBaseline(root = getProjectRoot()) {
14490
+ const baseline = readBaseline(root);
14491
+ if (!baseline) return null;
14492
+ const current2 = currentSpecs(root);
14493
+ const added = [];
14494
+ const changed = [];
14495
+ const removed = [];
14496
+ const unchangedPaths = [];
14497
+ for (const [rel2, content] of Object.entries(current2)) {
14498
+ const before = baseline.specs[rel2];
14499
+ if (before === void 0) added.push(rel2);
14500
+ else if (before !== content) changed.push(rel2);
14501
+ else unchangedPaths.push(rel2);
14502
+ }
14503
+ for (const rel2 of Object.keys(baseline.specs)) {
14504
+ if (current2[rel2] === void 0) removed.push(rel2);
14505
+ }
14506
+ return {
14507
+ added: added.sort(),
14508
+ changed: changed.sort(),
14509
+ removed: removed.sort(),
14510
+ unchangedPaths: unchangedPaths.sort()
14511
+ };
14512
+ }
14513
+ function settledSpecPaths(root = getProjectRoot()) {
14514
+ const diff = diffAgainstBaseline(root);
14515
+ return diff ? new Set(diff.unchangedPaths) : null;
14516
+ }
14517
+ function pinOf(stateId) {
14518
+ return `${stateId.algorithm}:${stateId.digest}`;
14519
+ }
14520
+ function currentChildPins(mounts, root = getProjectRoot()) {
14521
+ const pins = {};
14522
+ for (const mount of mounts) {
14523
+ if (!mount.projectPath || mount.id.includes("::")) continue;
14524
+ const childRoot = path17.resolve(root, mount.projectPath);
14525
+ const child = readBaseline(childRoot);
14526
+ if (child) pins[mount.id] = pinOf(child.stateId);
14527
+ }
14528
+ return pins;
14529
+ }
14530
+ function movedChildren(mounts, root = getProjectRoot()) {
14531
+ const baseline = readBaseline(root);
14532
+ if (!baseline) return [];
14533
+ const now = currentChildPins(mounts, root);
14534
+ const moved = [];
14535
+ for (const [id, pinned] of Object.entries(baseline.children)) {
14536
+ const current2 = now[id] ?? null;
14537
+ if (current2 !== pinned) moved.push({ id, pinned, now: current2 });
14538
+ }
14539
+ return moved;
14540
+ }
14541
+ var fs13, os5, path17, crypto3, SCHEMA_VERSION;
14542
+ var init_baseline = __esm({
14543
+ "src/core/baseline.ts"() {
14544
+ "use strict";
14545
+ fs13 = __toESM(require("fs"));
14546
+ os5 = __toESM(require("os"));
14547
+ path17 = __toESM(require("path"));
14548
+ crypto3 = __toESM(require("crypto"));
14549
+ init_fs();
14550
+ init_specs2();
14551
+ SCHEMA_VERSION = "1.0.0";
14552
+ }
14553
+ });
14554
+
14406
14555
  // src/core/validation.ts
14407
14556
  var validation_exports = {};
14408
14557
  __export(validation_exports, {
@@ -14533,7 +14682,7 @@ function validateSddTree(rulesOrOptions, projectType = "backend") {
14533
14682
  const types = loadTypeSpecs();
14534
14683
  const surfaceSnapshots = loadSurfaceSnapshots();
14535
14684
  const codeModel = buildCodeModel(implementations, getProjectRoot());
14536
- const statusBearing = treatAllAsComplete ? [...subsystems, ...components, ...interfaces, ...implementations] : [];
14685
+ const statusBearing = treatAllAsComplete ? [...subsystems, ...components, ...interfaces, ...implementations] : settledStatusBearing({ subsystems, components, interfaces, implementations });
14537
14686
  const statusSnapshot = statusBearing.map((s) => s.status);
14538
14687
  for (const s of statusBearing) s.status = "complete";
14539
14688
  try {
@@ -14655,10 +14804,34 @@ function validateSddTree(rulesOrOptions, projectType = "backend") {
14655
14804
  });
14656
14805
  }
14657
14806
  }
14807
+ function settledStatusBearing(loaded) {
14808
+ let settled;
14809
+ try {
14810
+ settled = settledSpecPaths();
14811
+ } catch {
14812
+ return [];
14813
+ }
14814
+ if (!settled || settled.size === 0) return [];
14815
+ const root = getProjectRoot();
14816
+ const index = scanAllSpecs();
14817
+ const rel2 = (abs) => path18.relative(root, abs).split(path18.sep).join("/");
14818
+ const out = [];
14819
+ const take = (specs, paths) => {
14820
+ for (const spec of specs) {
14821
+ const p = paths[spec.id];
14822
+ if (p && settled.has(rel2(p))) out.push(spec);
14823
+ }
14824
+ };
14825
+ take(loaded.subsystems, index.paths.subsystem);
14826
+ take(loaded.components, index.paths.component);
14827
+ take(loaded.interfaces, index.paths.interface);
14828
+ take(loaded.implementations, index.paths.implementation);
14829
+ return out;
14830
+ }
14658
14831
  function validateAsComplete(options) {
14659
14832
  return validateSddTree({ ...options ?? {}, treatAllAsComplete: true });
14660
14833
  }
14661
- var SUBPROJECT_REFERENCE_CODES, SUBPROJECT_CONFORMANCE_CODES;
14834
+ var path18, SUBPROJECT_REFERENCE_CODES, SUBPROJECT_CONFORMANCE_CODES;
14662
14835
  var init_validation = __esm({
14663
14836
  "src/core/validation.ts"() {
14664
14837
  "use strict";
@@ -14672,6 +14845,8 @@ var init_validation = __esm({
14672
14845
  init_source_analysis();
14673
14846
  init_specs2();
14674
14847
  init_fs();
14848
+ path18 = __toESM(require("path"));
14849
+ init_baseline();
14675
14850
  SUBPROJECT_REFERENCE_CODES = /* @__PURE__ */ new Set([
14676
14851
  "UNDEFINED_TYPE_REFERENCE",
14677
14852
  "INVALID_DEPENDENCY_REFERENCE",
@@ -15001,8 +15176,8 @@ function generateSequenceDiagram(componentId, methodName, options) {
15001
15176
  const steps = [...methodImpl.narrative].sort((a, b) => a.stepNumber - b.stepNumber);
15002
15177
  for (const step of steps) {
15003
15178
  for (const par of parallelArms) {
15004
- const sep6 = par.sepByStep.get(step.stepNumber);
15005
- if (sep6 !== void 0) lines.push(` and ${escapeLabel(sep6)}`);
15179
+ const sep9 = par.sepByStep.get(step.stepNumber);
15180
+ if (sep9 !== void 0) lines.push(` and ${escapeLabel(sep9)}`);
15006
15181
  }
15007
15182
  switch (step.type) {
15008
15183
  case "local":
@@ -15282,6 +15457,7 @@ __export(specs_exports, {
15282
15457
  saveTypeSpec: () => saveTypeSpec,
15283
15458
  scanAllSpecs: () => scanAllSpecs,
15284
15459
  snapshotSpecFiles: () => snapshotSpecFiles,
15460
+ specPathsInScope: () => specPathsInScope,
15285
15461
  splitNamespace: () => splitNamespace,
15286
15462
  updateSpec: () => updateSpec,
15287
15463
  workspaceFor: () => workspaceFor
@@ -15355,16 +15531,16 @@ function relativizeId(id, prefix) {
15355
15531
  return `${"super::".repeat(prefixParts.length - common)}${idParts.slice(common).join("::")}`;
15356
15532
  }
15357
15533
  function isWithin(dir, file) {
15358
- const d = path17.resolve(dir);
15359
- const f = path17.resolve(file);
15360
- return f === d || f.startsWith(d + path17.sep);
15534
+ const d = path19.resolve(dir);
15535
+ const f = path19.resolve(file);
15536
+ return f === d || f.startsWith(d + path19.sep);
15361
15537
  }
15362
15538
  function projectPathEscapesRoot(projectRoot2, projectPath, resolvedChildDir) {
15363
- return path17.isAbsolute(projectPath) || !isWithin(projectRoot2, resolvedChildDir);
15539
+ return path19.isAbsolute(projectPath) || !isWithin(projectRoot2, resolvedChildDir);
15364
15540
  }
15365
15541
  function assertContainedProjectPath(projectRoot2, projectPath) {
15366
- const root = path17.resolve(projectRoot2);
15367
- const resolved = path17.resolve(root, projectPath);
15542
+ const root = path19.resolve(projectRoot2);
15543
+ const resolved = path19.resolve(root, projectPath);
15368
15544
  if (projectPathEscapesRoot(root, projectPath, resolved)) {
15369
15545
  throw new Error(
15370
15546
  `projectPath "${projectPath}" must resolve within the project root "${root}", but resolves to "${resolved}"; absolute paths and ../-escaping paths are rejected so a chained subproject is always contained by its parent.`
@@ -15375,11 +15551,11 @@ function assertContainedProjectPath(projectRoot2, projectPath) {
15375
15551
  function findChainingParent(childRoot) {
15376
15552
  let childResolved;
15377
15553
  try {
15378
- childResolved = path17.resolve(childRoot);
15554
+ childResolved = path19.resolve(childRoot);
15379
15555
  } catch {
15380
15556
  return null;
15381
15557
  }
15382
- let dir = path17.dirname(childResolved);
15558
+ let dir = path19.dirname(childResolved);
15383
15559
  for (let hops = 0; hops < 32; hops++) {
15384
15560
  const specsDir = aiPathsAt(dir).specsDir();
15385
15561
  if (pathExists(specsDir)) {
@@ -15394,7 +15570,7 @@ function findChainingParent(childRoot) {
15394
15570
  const projectPath = raw.projectPath;
15395
15571
  if (typeof projectPath === "string" && projectPath.trim() !== "") {
15396
15572
  try {
15397
- if (path17.resolve(dir, projectPath) === childResolved) {
15573
+ if (path19.resolve(dir, projectPath) === childResolved) {
15398
15574
  const id = raw.id;
15399
15575
  return { parentRoot: dir, subsystemId: typeof id === "string" ? id : "?" };
15400
15576
  }
@@ -15404,7 +15580,7 @@ function findChainingParent(childRoot) {
15404
15580
  }
15405
15581
  }
15406
15582
  }
15407
- const up = path17.dirname(dir);
15583
+ const up = path19.dirname(dir);
15408
15584
  if (up === dir) break;
15409
15585
  dir = up;
15410
15586
  }
@@ -15509,18 +15685,18 @@ function findOwner(id, components) {
15509
15685
  }) ?? null;
15510
15686
  }
15511
15687
  function moveComponentFolder(fromDir, toDir) {
15512
- if (path17.normalize(fromDir) === path17.normalize(toDir)) return false;
15513
- if (!fs13.existsSync(fromDir) || fs13.existsSync(toDir)) return false;
15514
- ensureDir(path17.dirname(toDir));
15515
- fs13.renameSync(fromDir, toDir);
15688
+ if (path19.normalize(fromDir) === path19.normalize(toDir)) return false;
15689
+ if (!fs14.existsSync(fromDir) || fs14.existsSync(toDir)) return false;
15690
+ ensureDir(path19.dirname(toDir));
15691
+ fs14.renameSync(fromDir, toDir);
15516
15692
  return true;
15517
15693
  }
15518
15694
  function cleanEmptyDirs(filePath, specsRoot) {
15519
- let dir = path17.dirname(filePath);
15695
+ let dir = path19.dirname(filePath);
15520
15696
  while (dir !== specsRoot && dir.startsWith(specsRoot)) {
15521
- if (fs13.existsSync(dir) && fs13.readdirSync(dir).length === 0) {
15522
- fs13.rmdirSync(dir);
15523
- dir = path17.dirname(dir);
15697
+ if (fs14.existsSync(dir) && fs14.readdirSync(dir).length === 0) {
15698
+ fs14.rmdirSync(dir);
15699
+ dir = path19.dirname(dir);
15524
15700
  } else {
15525
15701
  break;
15526
15702
  }
@@ -15539,13 +15715,13 @@ function parseOrThrow(schema, value, kind, id) {
15539
15715
  function computeSpecTreeSignature(dirs) {
15540
15716
  const parts = [];
15541
15717
  for (const dir of dirs) {
15542
- if (!fs13.existsSync(dir)) {
15718
+ if (!fs14.existsSync(dir)) {
15543
15719
  parts.push(`${dir}:missing`);
15544
15720
  continue;
15545
15721
  }
15546
15722
  for (const f of listFilesRecursive(dir, ".yaml")) {
15547
15723
  try {
15548
- const st = fs13.statSync(f);
15724
+ const st = fs14.statSync(f);
15549
15725
  parts.push(`${f}:${st.mtimeMs}:${st.size}`);
15550
15726
  } catch {
15551
15727
  parts.push(`${f}:gone`);
@@ -15555,7 +15731,7 @@ function computeSpecTreeSignature(dirs) {
15555
15731
  return parts.join("|");
15556
15732
  }
15557
15733
  function workspaceFor(rootDir) {
15558
- const key = path17.resolve(rootDir);
15734
+ const key = path19.resolve(rootDir);
15559
15735
  let ws = workspaces.get(key);
15560
15736
  if (!ws) {
15561
15737
  ws = new SpecWorkspace(key);
@@ -15694,7 +15870,7 @@ function readLockState() {
15694
15870
  return { state: stateIdEquals(record2.stateId, current2) ? "locked" : "stale", record: record2, current: current2 };
15695
15871
  }
15696
15872
  function computeStateIdAt(root) {
15697
- const resolved = path17.resolve(root);
15873
+ const resolved = path19.resolve(root);
15698
15874
  return runWithProjectRoot(resolved, () => {
15699
15875
  workspaceFor(resolved).invalidate();
15700
15876
  const system = loadSystemSpec();
@@ -15724,12 +15900,15 @@ function collectPromotableSpecs(scopeSubsystem) {
15724
15900
  function applySpecStatus(kind, id, status2) {
15725
15901
  current().applySpecStatus(kind, id, status2);
15726
15902
  }
15903
+ function specPathsInScope(scopeSubsystem) {
15904
+ return current().specPathsInScope(scopeSubsystem);
15905
+ }
15727
15906
  function snapshotSpecFiles() {
15728
15907
  return current().snapshotSpecFiles();
15729
15908
  }
15730
15909
  function restoreSpecFiles(snapshot) {
15731
15910
  for (const [file, content] of snapshot) {
15732
- fs13.writeFileSync(file, content);
15911
+ fs14.writeFileSync(file, content);
15733
15912
  }
15734
15913
  }
15735
15914
  function findLegacySpecFiles() {
@@ -15738,12 +15917,12 @@ function findLegacySpecFiles() {
15738
15917
  function updateSpec(kind, id, delta, hooks) {
15739
15918
  return current().updateSpec(kind, id, delta, hooks);
15740
15919
  }
15741
- var fs13, path17, SIGNATURE_TTL_MS, SpecWorkspace, workspaces;
15920
+ var fs14, path19, SIGNATURE_TTL_MS, SpecWorkspace, workspaces;
15742
15921
  var init_specs2 = __esm({
15743
15922
  "src/core/specs.ts"() {
15744
15923
  "use strict";
15745
- fs13 = __toESM(require("fs"));
15746
- path17 = __toESM(require("path"));
15924
+ fs14 = __toESM(require("fs"));
15925
+ path19 = __toESM(require("path"));
15747
15926
  init_loader();
15748
15927
  init_fs();
15749
15928
  init_statehash();
@@ -15764,7 +15943,7 @@ var init_specs2 = __esm({
15764
15943
  this.rootSubsystems = /* @__PURE__ */ new Set();
15765
15944
  this.scanVisitedSpecDirs = [];
15766
15945
  this.loaderIssues = [];
15767
- this.rootDir = path17.resolve(rootDir);
15946
+ this.rootDir = path19.resolve(rootDir);
15768
15947
  this.paths = aiPathsAt(this.rootDir);
15769
15948
  }
15770
15949
  invalidate() {
@@ -15791,7 +15970,7 @@ var init_specs2 = __esm({
15791
15970
  this.rootSubsystems.clear();
15792
15971
  this.cachedRecursive = recursive;
15793
15972
  this.scanVisitedSpecDirs = [];
15794
- const visited = /* @__PURE__ */ new Set([path17.resolve(this.rootDir)]);
15973
+ const visited = /* @__PURE__ */ new Set([path19.resolve(this.rootDir)]);
15795
15974
  const maxDepth = typeof recursive === "number" ? recursive : recursive ? Infinity : 0;
15796
15975
  this.cachedIndex = this.scanSpecsForProject(this.rootDir, "", visited, maxDepth, 0);
15797
15976
  this.cachedSpecDirs = this.scanVisitedSpecDirs;
@@ -15806,10 +15985,10 @@ var init_specs2 = __esm({
15806
15985
  this.scanVisitedSpecDirs.push(specsDir);
15807
15986
  if (!pathExists(specsDir)) return index;
15808
15987
  const files = listFilesRecursive(specsDir, ".yaml");
15809
- const systemYaml = path17.normalize(projectPaths.specsSystem());
15988
+ const systemYaml = path19.normalize(projectPaths.specsSystem());
15810
15989
  const localSubprojects = [];
15811
15990
  for (const file of files) {
15812
- const normFile = path17.normalize(file);
15991
+ const normFile = path19.normalize(file);
15813
15992
  if (normFile === systemYaml) continue;
15814
15993
  let detectedType = "spec";
15815
15994
  try {
@@ -15819,7 +15998,7 @@ var init_specs2 = __esm({
15819
15998
  severity: "error",
15820
15999
  code: "INVALID_YAML",
15821
16000
  message: `Spec file "${file}" is not a valid YAML object or is empty.`,
15822
- specId: path17.basename(file, ".yaml")
16001
+ specId: path19.basename(file, ".yaml")
15823
16002
  });
15824
16003
  continue;
15825
16004
  }
@@ -15851,8 +16030,8 @@ var init_specs2 = __esm({
15851
16030
  detectedType = "implementation";
15852
16031
  const parsed = ImplementationSpecSchema.parse(raw);
15853
16032
  if (parsed.sourcePath) {
15854
- const absSourcePath = path17.resolve(projectDir, parsed.sourcePath);
15855
- parsed.sourcePath = path17.relative(projectDir, absSourcePath).replace(/\\/g, "/");
16033
+ const absSourcePath = path19.resolve(projectDir, parsed.sourcePath);
16034
+ parsed.sourcePath = path19.relative(projectDir, absSourcePath).replace(/\\/g, "/");
15856
16035
  }
15857
16036
  index.implementations.push(parsed);
15858
16037
  index.paths.implementation[parsed.id] = file;
@@ -15874,11 +16053,11 @@ var init_specs2 = __esm({
15874
16053
  severity: "error",
15875
16054
  code: "UNKNOWN_SPEC_TYPE",
15876
16055
  message: `Spec file "${file}" does not match any recognized L1-L4 schema structure.`,
15877
- specId: path17.basename(file, ".yaml")
16056
+ specId: path19.basename(file, ".yaml")
15878
16057
  });
15879
16058
  }
15880
16059
  } catch (e) {
15881
- const filename = path17.basename(file, ".yaml");
16060
+ const filename = path19.basename(file, ".yaml");
15882
16061
  this.loaderIssues.push({
15883
16062
  severity: "error",
15884
16063
  code: "SCHEMA_VALIDATION_ERROR",
@@ -15976,7 +16155,7 @@ var init_specs2 = __esm({
15976
16155
  }
15977
16156
  if (currentDepth < maxDepth) {
15978
16157
  for (const subproj of localSubprojects) {
15979
- const childDir = path17.resolve(projectDir, subproj.projectPath);
16158
+ const childDir = path19.resolve(projectDir, subproj.projectPath);
15980
16159
  if (projectPathEscapesRoot(this.rootDir, subproj.projectPath, childDir)) {
15981
16160
  this.loaderIssues.push({
15982
16161
  severity: "error",
@@ -15995,7 +16174,7 @@ var init_specs2 = __esm({
15995
16174
  });
15996
16175
  continue;
15997
16176
  }
15998
- if (!fs13.existsSync(childDir)) {
16177
+ if (!fs14.existsSync(childDir)) {
15999
16178
  this.loaderIssues.push({
16000
16179
  severity: "error",
16001
16180
  code: "SUBPROJECT_NOT_FOUND",
@@ -16038,7 +16217,7 @@ var init_specs2 = __esm({
16038
16217
  const index = this.scanAll();
16039
16218
  const sub = index.subsystems.find((s) => s.id === currentPrefix);
16040
16219
  if (sub && sub.projectPath) {
16041
- const nextDir = path17.resolve(currentDir, sub.projectPath);
16220
+ const nextDir = path19.resolve(currentDir, sub.projectPath);
16042
16221
  if (projectPathEscapesRoot(this.rootDir, sub.projectPath, nextDir)) {
16043
16222
  this.loaderIssues.push({
16044
16223
  severity: "error",
@@ -16090,9 +16269,9 @@ var init_specs2 = __esm({
16090
16269
  return index.paths.subsystem[matches2[0]];
16091
16270
  }
16092
16271
  if (pathExists(this.paths.specsSubsystemsDir()) && listFiles(this.paths.specsSubsystemsDir(), ".yaml").length > 0) {
16093
- return path17.join(this.paths.specsSubsystemsDir(), `${id}.yaml`);
16272
+ return path19.join(this.paths.specsSubsystemsDir(), `${id}.yaml`);
16094
16273
  }
16095
- return path17.join(this.paths.specsDir(), id, ".index.yaml");
16274
+ return path19.join(this.paths.specsDir(), id, ".index.yaml");
16096
16275
  }
16097
16276
  getComponentPath(id, subsystemId) {
16098
16277
  const index = this.scanAll();
@@ -16112,21 +16291,21 @@ var init_specs2 = __esm({
16112
16291
  if (owner) {
16113
16292
  const ownerPath = index.paths.component[owner.id];
16114
16293
  if (ownerPath && ownerPath.endsWith(".index.yaml")) {
16115
- return path17.join(path17.dirname(ownerPath), id, ".index.yaml");
16294
+ return path19.join(path19.dirname(ownerPath), id, ".index.yaml");
16116
16295
  }
16117
16296
  }
16118
16297
  if (subsystemId) {
16119
16298
  const subPath = this.getSubsystemPath(subsystemId);
16120
- const subDir = path17.dirname(subPath);
16299
+ const subDir = path19.dirname(subPath);
16121
16300
  if (subPath.endsWith(".index.yaml")) {
16122
- return path17.join(subDir, id, ".index.yaml");
16301
+ return path19.join(subDir, id, ".index.yaml");
16123
16302
  }
16124
16303
  }
16125
16304
  if (pathExists(this.paths.specsComponentsDir()) && listFiles(this.paths.specsComponentsDir(), ".yaml").length > 0) {
16126
- return path17.join(this.paths.specsComponentsDir(), `${id}.yaml`);
16305
+ return path19.join(this.paths.specsComponentsDir(), `${id}.yaml`);
16127
16306
  }
16128
16307
  const targetSubsystem = subsystemId || "default";
16129
- return path17.join(this.paths.specsDir(), targetSubsystem, id, ".index.yaml");
16308
+ return path19.join(this.paths.specsDir(), targetSubsystem, id, ".index.yaml");
16130
16309
  }
16131
16310
  getInterfacePath(id, componentId) {
16132
16311
  const index = this.scanAll();
@@ -16152,16 +16331,16 @@ var init_specs2 = __esm({
16152
16331
  }
16153
16332
  if (componentId) {
16154
16333
  const compPath = this.getComponentPath(componentId);
16155
- const compDir = path17.dirname(compPath);
16334
+ const compDir = path19.dirname(compPath);
16156
16335
  if (compPath.endsWith(".index.yaml")) {
16157
- return path17.join(compDir, ".interface.yaml");
16336
+ return path19.join(compDir, ".interface.yaml");
16158
16337
  }
16159
16338
  }
16160
16339
  if (pathExists(this.paths.specsInterfacesDir()) && listFiles(this.paths.specsInterfacesDir(), ".yaml").length > 0) {
16161
- return path17.join(this.paths.specsInterfacesDir(), `${id}.yaml`);
16340
+ return path19.join(this.paths.specsInterfacesDir(), `${id}.yaml`);
16162
16341
  }
16163
16342
  const targetComponent = componentId || "default";
16164
- return path17.join(this.paths.specsDir(), "default", targetComponent, ".interface.yaml");
16343
+ return path19.join(this.paths.specsDir(), "default", targetComponent, ".interface.yaml");
16165
16344
  }
16166
16345
  getImplementationPath(id, contractId) {
16167
16346
  const index = this.scanAll();
@@ -16187,16 +16366,16 @@ var init_specs2 = __esm({
16187
16366
  }
16188
16367
  if (contractId) {
16189
16368
  const intfPath = this.getInterfacePath(contractId);
16190
- const intfDir = path17.dirname(intfPath);
16369
+ const intfDir = path19.dirname(intfPath);
16191
16370
  if (intfPath.endsWith(".interface.yaml")) {
16192
- return path17.join(intfDir, ".implementation.yaml");
16371
+ return path19.join(intfDir, ".implementation.yaml");
16193
16372
  }
16194
16373
  }
16195
16374
  if (pathExists(this.paths.specsImplementationsDir()) && listFiles(this.paths.specsImplementationsDir(), ".yaml").length > 0) {
16196
- return path17.join(this.paths.specsImplementationsDir(), `${id}.yaml`);
16375
+ return path19.join(this.paths.specsImplementationsDir(), `${id}.yaml`);
16197
16376
  }
16198
16377
  const targetContract = contractId ? contractId.replace(/^i/, "") : "default";
16199
- return path17.join(this.paths.specsDir(), "default", targetContract, ".implementation.yaml");
16378
+ return path19.join(this.paths.specsDir(), "default", targetContract, ".implementation.yaml");
16200
16379
  }
16201
16380
  getTypePath(id, subsystemId, group) {
16202
16381
  const index = this.scanAll();
@@ -16227,7 +16406,7 @@ var init_specs2 = __esm({
16227
16406
  const groupPath = index.paths.group[targetGroup] || index.paths.group[plainGroup];
16228
16407
  if (groupPath) {
16229
16408
  const localId2 = id.split("::").pop();
16230
- return path17.join(path17.dirname(groupPath), `${localId2}.yaml`);
16409
+ return path19.join(path19.dirname(groupPath), `${localId2}.yaml`);
16231
16410
  }
16232
16411
  }
16233
16412
  let localId = id;
@@ -16240,12 +16419,12 @@ var init_specs2 = __esm({
16240
16419
  }
16241
16420
  if (subsystemId) {
16242
16421
  const subPath = this.getSubsystemPath(subsystemId);
16243
- const subDir = path17.dirname(subPath);
16422
+ const subDir = path19.dirname(subPath);
16244
16423
  if (subPath.endsWith(".index.yaml")) {
16245
- return path17.join(subDir, "types", `${localId}.yaml`);
16424
+ return path19.join(subDir, "types", `${localId}.yaml`);
16246
16425
  }
16247
16426
  }
16248
- return path17.join(this.paths.specsTypesDir(), `${localId}.yaml`);
16427
+ return path19.join(this.paths.specsTypesDir(), `${localId}.yaml`);
16249
16428
  }
16250
16429
  getGroupPath(id, subsystemId) {
16251
16430
  const index = this.scanAll();
@@ -16279,12 +16458,12 @@ var init_specs2 = __esm({
16279
16458
  }
16280
16459
  if (subsystemId) {
16281
16460
  const subPath = this.getSubsystemPath(subsystemId);
16282
- const subDir = path17.dirname(subPath);
16461
+ const subDir = path19.dirname(subPath);
16283
16462
  if (subPath.endsWith(".index.yaml")) {
16284
- return path17.join(subDir, "types", localId, ".index.yaml");
16463
+ return path19.join(subDir, "types", localId, ".index.yaml");
16285
16464
  }
16286
16465
  }
16287
- return path17.join(this.paths.specsTypesDir(), localId, ".index.yaml");
16466
+ return path19.join(this.paths.specsTypesDir(), localId, ".index.yaml");
16288
16467
  }
16289
16468
  // -------------------------------------------------------------------------
16290
16469
  // Level 0: System
@@ -16307,7 +16486,7 @@ var init_specs2 = __esm({
16307
16486
  }
16308
16487
  saveSystemSpec(spec) {
16309
16488
  const p = this.paths.specsSystem();
16310
- ensureDir(path17.dirname(p));
16489
+ ensureDir(path19.dirname(p));
16311
16490
  writeYamlFile(p, parseOrThrow(SystemSpecSchema, spec, "system", spec.name));
16312
16491
  invalidateSpecCache();
16313
16492
  }
@@ -16425,7 +16604,7 @@ var init_specs2 = __esm({
16425
16604
  }
16426
16605
  saveSubsystemSpec(spec) {
16427
16606
  const p = this.getSubsystemPath(spec.id);
16428
- ensureDir(path17.dirname(p));
16607
+ ensureDir(path19.dirname(p));
16429
16608
  const { prefix } = splitNamespace(spec.id);
16430
16609
  if (!prefix && spec.projectPath && spec.projectPath.trim() !== "") {
16431
16610
  assertContainedProjectPath(this.rootDir, spec.projectPath);
@@ -16456,9 +16635,9 @@ var init_specs2 = __esm({
16456
16635
  }
16457
16636
  deleteSubsystemSpec(id) {
16458
16637
  const p = this.getSubsystemPath(id);
16459
- if (!fs13.existsSync(p)) return false;
16460
- fs13.unlinkSync(p);
16461
- cleanEmptyDirs(p, path17.resolve(this.paths.specsDir()));
16638
+ if (!fs14.existsSync(p)) return false;
16639
+ fs14.unlinkSync(p);
16640
+ cleanEmptyDirs(p, path19.resolve(this.paths.specsDir()));
16462
16641
  invalidateSpecCache();
16463
16642
  return true;
16464
16643
  }
@@ -16491,7 +16670,7 @@ var init_specs2 = __esm({
16491
16670
  saveComponentSpec(spec, opts) {
16492
16671
  const notices = [];
16493
16672
  const p = this.getComponentPath(spec.id, spec.subsystem);
16494
- ensureDir(path17.dirname(p));
16673
+ ensureDir(path19.dirname(p));
16495
16674
  const specToWrite = this.prepareComponentForWrite(spec);
16496
16675
  const existing = this.loadComponentSpec(spec.id);
16497
16676
  if (existing) {
@@ -16508,7 +16687,7 @@ var init_specs2 = __esm({
16508
16687
  const subsystemChanged = existing && existing.subsystem !== spec.subsystem && splitNamespace(existing.subsystem).localId !== splitNamespace(spec.subsystem).localId;
16509
16688
  if (subsystemChanged && !p.endsWith(".index.yaml")) {
16510
16689
  notices.push(
16511
- `component "${spec.id}" already exists at ${path17.relative(this.rootDir, p)} \u2014 the flat layout re-saves in place and never relocates the file. The subsystem field is now "${spec.subsystem}" (was "${existing.subsystem}").`
16690
+ `component "${spec.id}" already exists at ${path19.relative(this.rootDir, p)} \u2014 the flat layout re-saves in place and never relocates the file. The subsystem field is now "${spec.subsystem}" (was "${existing.subsystem}").`
16512
16691
  );
16513
16692
  }
16514
16693
  specToWrite.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -16519,9 +16698,9 @@ var init_specs2 = __esm({
16519
16698
  }
16520
16699
  deleteComponentSpec(id) {
16521
16700
  const p = this.getComponentPath(id);
16522
- if (!fs13.existsSync(p)) return false;
16523
- fs13.unlinkSync(p);
16524
- cleanEmptyDirs(p, path17.resolve(this.paths.specsDir()));
16701
+ if (!fs14.existsSync(p)) return false;
16702
+ fs14.unlinkSync(p);
16703
+ cleanEmptyDirs(p, path19.resolve(this.paths.specsDir()));
16525
16704
  invalidateSpecCache();
16526
16705
  return true;
16527
16706
  }
@@ -16534,12 +16713,12 @@ var init_specs2 = __esm({
16534
16713
  if (owner) {
16535
16714
  const ownerPath = index.paths.component[owner.id];
16536
16715
  if (ownerPath && ownerPath.endsWith(".index.yaml")) {
16537
- const ownerSubDir = path17.dirname(this.getSubsystemPath(owner.subsystem));
16538
- return path17.join(ownerSubDir, owner.id, comp.id);
16716
+ const ownerSubDir = path19.dirname(this.getSubsystemPath(owner.subsystem));
16717
+ return path19.join(ownerSubDir, owner.id, comp.id);
16539
16718
  }
16540
16719
  }
16541
- const subDir = path17.dirname(this.getSubsystemPath(comp.subsystem));
16542
- return path17.join(subDir, comp.id);
16720
+ const subDir = path19.dirname(this.getSubsystemPath(comp.subsystem));
16721
+ return path19.join(subDir, comp.id);
16543
16722
  }
16544
16723
  /**
16545
16724
  * Move component folders so the physical tree mirrors ownership: each owned
@@ -16555,7 +16734,7 @@ var init_specs2 = __esm({
16555
16734
  if (!currentPath) continue;
16556
16735
  const desiredDir = this.desiredComponentDir(comp, index);
16557
16736
  if (!desiredDir) continue;
16558
- if (moveComponentFolder(path17.dirname(currentPath), desiredDir)) moved.push(comp.id);
16737
+ if (moveComponentFolder(path19.dirname(currentPath), desiredDir)) moved.push(comp.id);
16559
16738
  }
16560
16739
  if (moved.length) invalidateSpecCache();
16561
16740
  return moved;
@@ -16611,7 +16790,7 @@ var init_specs2 = __esm({
16611
16790
  if (!occupantId) return;
16612
16791
  if (occupantId === id || splitNamespace(occupantId).localId === splitNamespace(id).localId) return;
16613
16792
  throw new Error(
16614
- `Cannot write ${kind} "${id}": ${parentLabel} is already ${kind === "interface" ? "served by" : "implemented by"} "${occupantId}" at ${path17.relative(this.rootDir, p)}, and both ids resolve to that one file. Re-author "${occupantId}" instead, or delete it first if you meant to replace it.`
16793
+ `Cannot write ${kind} "${id}": ${parentLabel} is already ${kind === "interface" ? "served by" : "implemented by"} "${occupantId}" at ${path19.relative(this.rootDir, p)}, and both ids resolve to that one file. Re-author "${occupantId}" instead, or delete it first if you meant to replace it.`
16615
16794
  );
16616
16795
  }
16617
16796
  /** Returns non-fatal placement notices (see saveTypeSpec) — empty when there is nothing to clarify. */
@@ -16619,12 +16798,12 @@ var init_specs2 = __esm({
16619
16798
  const notices = [];
16620
16799
  const p = this.getInterfacePath(spec.id, spec.component);
16621
16800
  this.assertPathHoldsNoOtherSpec(p, spec.id, "interface", `component "${spec.component}"`);
16622
- ensureDir(path17.dirname(p));
16801
+ ensureDir(path19.dirname(p));
16623
16802
  const specToWrite = this.prepareInterfaceForWrite(spec);
16624
16803
  const existing = this.loadInterfaceSpec(spec.id);
16625
16804
  if (existing && existing.component !== spec.component && splitNamespace(existing.component).localId !== splitNamespace(spec.component).localId) {
16626
16805
  notices.push(
16627
- `interface "${spec.id}" already exists at ${path17.relative(this.rootDir, p)} \u2014 re-saving updates the component binding field in place (now "${spec.component}", was "${existing.component}") and never moves the file.`
16806
+ `interface "${spec.id}" already exists at ${path19.relative(this.rootDir, p)} \u2014 re-saving updates the component binding field in place (now "${spec.component}", was "${existing.component}") and never moves the file.`
16628
16807
  );
16629
16808
  }
16630
16809
  if (existing) {
@@ -16647,9 +16826,9 @@ var init_specs2 = __esm({
16647
16826
  }
16648
16827
  deleteInterfaceSpec(id) {
16649
16828
  const p = this.getInterfacePath(id);
16650
- if (!fs13.existsSync(p)) return false;
16651
- fs13.unlinkSync(p);
16652
- cleanEmptyDirs(p, path17.resolve(this.paths.specsDir()));
16829
+ if (!fs14.existsSync(p)) return false;
16830
+ fs14.unlinkSync(p);
16831
+ cleanEmptyDirs(p, path19.resolve(this.paths.specsDir()));
16653
16832
  invalidateSpecCache();
16654
16833
  return true;
16655
16834
  }
@@ -16683,12 +16862,12 @@ var init_specs2 = __esm({
16683
16862
  const notices = [];
16684
16863
  const p = this.getImplementationPath(spec.id, spec.contract);
16685
16864
  this.assertPathHoldsNoOtherSpec(p, spec.id, "implementation", `contract "${spec.contract}"`);
16686
- ensureDir(path17.dirname(p));
16865
+ ensureDir(path19.dirname(p));
16687
16866
  const specToWrite = this.prepareImplementationForWrite(spec);
16688
16867
  const existing = this.loadImplementationSpec(spec.id);
16689
16868
  if (existing && existing.contract !== spec.contract && splitNamespace(existing.contract).localId !== splitNamespace(spec.contract).localId) {
16690
16869
  notices.push(
16691
- `implementation "${spec.id}" already exists at ${path17.relative(this.rootDir, p)} \u2014 re-saving updates the contract binding field in place (now "${spec.contract}", was "${existing.contract}") and never moves the file.`
16870
+ `implementation "${spec.id}" already exists at ${path19.relative(this.rootDir, p)} \u2014 re-saving updates the contract binding field in place (now "${spec.contract}", was "${existing.contract}") and never moves the file.`
16692
16871
  );
16693
16872
  }
16694
16873
  if (existing) {
@@ -16704,9 +16883,9 @@ var init_specs2 = __esm({
16704
16883
  }
16705
16884
  deleteImplementationSpec(id) {
16706
16885
  const p = this.getImplementationPath(id);
16707
- if (!fs13.existsSync(p)) return false;
16708
- fs13.unlinkSync(p);
16709
- cleanEmptyDirs(p, path17.resolve(this.paths.specsDir()));
16886
+ if (!fs14.existsSync(p)) return false;
16887
+ fs14.unlinkSync(p);
16888
+ cleanEmptyDirs(p, path19.resolve(this.paths.specsDir()));
16710
16889
  invalidateSpecCache();
16711
16890
  return true;
16712
16891
  }
@@ -16731,11 +16910,11 @@ var init_specs2 = __esm({
16731
16910
  const existing = this.loadTypeSpec(spec.id);
16732
16911
  const group = spec.group || (existing ? existing.group : void 0);
16733
16912
  const p = this.getTypePath(spec.id, spec.subsystem, group);
16734
- ensureDir(path17.dirname(p));
16913
+ ensureDir(path19.dirname(p));
16735
16914
  const subsystemChanged = existing && (existing.subsystem ?? "") !== (spec.subsystem ?? "") && splitNamespace(existing.subsystem ?? "").localId !== splitNamespace(spec.subsystem ?? "").localId;
16736
16915
  if (subsystemChanged) {
16737
16916
  notices.push(
16738
- `type "${spec.id}" already exists at ${path17.relative(this.rootDir, p)} \u2014 re-saving updates fields in place and never relocates the file. The subsystem field is now "${spec.subsystem ?? "(none)"}" (was "${existing.subsystem ?? "(none)"}").`
16917
+ `type "${spec.id}" already exists at ${path19.relative(this.rootDir, p)} \u2014 re-saving updates fields in place and never relocates the file. The subsystem field is now "${spec.subsystem ?? "(none)"}" (was "${existing.subsystem ?? "(none)"}").`
16739
16918
  );
16740
16919
  }
16741
16920
  if (spec.subsystem && (!existing || subsystemChanged) && !this.getSubsystemPath(spec.subsystem).endsWith(".index.yaml")) {
@@ -16758,9 +16937,9 @@ var init_specs2 = __esm({
16758
16937
  deleteTypeSpec(id) {
16759
16938
  const spec = this.loadTypeSpec(id);
16760
16939
  const p = this.getTypePath(id, spec?.subsystem, spec?.group);
16761
- if (!fs13.existsSync(p)) return false;
16762
- fs13.unlinkSync(p);
16763
- cleanEmptyDirs(p, path17.resolve(this.paths.specsDir()));
16940
+ if (!fs14.existsSync(p)) return false;
16941
+ fs14.unlinkSync(p);
16942
+ cleanEmptyDirs(p, path19.resolve(this.paths.specsDir()));
16764
16943
  invalidateSpecCache();
16765
16944
  return true;
16766
16945
  }
@@ -16775,7 +16954,7 @@ var init_specs2 = __esm({
16775
16954
  }
16776
16955
  saveGroupSpec(spec) {
16777
16956
  const p = this.getGroupPath(spec.id);
16778
- ensureDir(path17.dirname(p));
16957
+ ensureDir(path19.dirname(p));
16779
16958
  const specToWrite = this.prepareGroupForWrite(spec);
16780
16959
  const existing = this.loadGroupSpec(spec.id);
16781
16960
  if (existing) {
@@ -16787,9 +16966,9 @@ var init_specs2 = __esm({
16787
16966
  }
16788
16967
  deleteGroupSpec(id) {
16789
16968
  const p = this.getGroupPath(id);
16790
- if (!fs13.existsSync(p)) return false;
16791
- fs13.unlinkSync(p);
16792
- cleanEmptyDirs(p, path17.resolve(this.paths.specsDir()));
16969
+ if (!fs14.existsSync(p)) return false;
16970
+ fs14.unlinkSync(p);
16971
+ cleanEmptyDirs(p, path19.resolve(this.paths.specsDir()));
16793
16972
  invalidateSpecCache();
16794
16973
  return true;
16795
16974
  }
@@ -16837,6 +17016,50 @@ var init_specs2 = __esm({
16837
17016
  }
16838
17017
  return out;
16839
17018
  }
17019
+ /**
17020
+ * Every spec FILE inside a subsystem scope (absolute paths), regardless of
17021
+ * status. `collectPromotableSpecs` answers a different question — which specs
17022
+ * are not yet complete — so it cannot stand in for this: a scoped approval
17023
+ * must cover the specs it approves whether or not they were already settled.
17024
+ */
17025
+ specPathsInScope(scopeSubsystem) {
17026
+ const index = this.scanAll();
17027
+ const components = this.loadComponentSpecs();
17028
+ const interfaces = this.loadInterfaceSpecs();
17029
+ const implementations = this.loadImplementationSpecs();
17030
+ const inScope = (specSubsystem) => {
17031
+ if (!scopeSubsystem) return true;
17032
+ if (!specSubsystem) return false;
17033
+ return specSubsystem === scopeSubsystem || specSubsystem.startsWith(`${scopeSubsystem}::`);
17034
+ };
17035
+ const out = /* @__PURE__ */ new Set();
17036
+ const add = (p) => {
17037
+ if (p) out.add(path19.resolve(p));
17038
+ };
17039
+ for (const s of this.loadSubsystemSpecs()) {
17040
+ if (!scopeSubsystem || s.id === scopeSubsystem || s.id.startsWith(`${scopeSubsystem}::`)) {
17041
+ add(index.paths.subsystem[s.id]);
17042
+ }
17043
+ }
17044
+ for (const c of components) {
17045
+ if (inScope(c.subsystem)) add(index.paths.component[c.id]);
17046
+ }
17047
+ for (const i of interfaces) {
17048
+ const comp = components.find((c) => c.id === i.component);
17049
+ if (comp && inScope(comp.subsystem)) add(index.paths.interface[i.id]);
17050
+ }
17051
+ for (const m of implementations) {
17052
+ const intf = interfaces.find((i) => i.id === m.contract);
17053
+ const comp = intf ? components.find((c) => c.id === intf.component) : null;
17054
+ if (comp && inScope(comp.subsystem)) add(index.paths.implementation[m.id]);
17055
+ }
17056
+ if (!scopeSubsystem) {
17057
+ add(this.paths.specsSystem());
17058
+ for (const p of Object.values(index.paths.type)) add(p);
17059
+ for (const p of Object.values(index.paths.group)) add(p);
17060
+ }
17061
+ return [...out];
17062
+ }
16840
17063
  /** Set a single spec's status (bumps updatedAt). Caller invalidates the cache. */
16841
17064
  applySpecStatus(kind, id, status2) {
16842
17065
  switch (kind) {
@@ -16874,16 +17097,16 @@ var init_specs2 = __esm({
16874
17097
  const files = /* @__PURE__ */ new Set();
16875
17098
  const sysPath = this.paths.specsSystem();
16876
17099
  if (pathExists(sysPath)) {
16877
- files.add(path17.resolve(sysPath));
17100
+ files.add(path19.resolve(sysPath));
16878
17101
  }
16879
17102
  for (const group of Object.values(index.paths)) {
16880
17103
  for (const file of Object.values(group)) {
16881
- files.add(path17.resolve(file));
17104
+ files.add(path19.resolve(file));
16882
17105
  }
16883
17106
  }
16884
17107
  for (const file of files) {
16885
- if (fs13.existsSync(file)) {
16886
- snapshot.set(file, fs13.readFileSync(file, "utf8"));
17108
+ if (fs14.existsSync(file)) {
17109
+ snapshot.set(file, fs14.readFileSync(file, "utf8"));
16887
17110
  }
16888
17111
  }
16889
17112
  return snapshot;
@@ -16897,20 +17120,20 @@ var init_specs2 = __esm({
16897
17120
  const files = listFilesRecursive(specsDir, ".yaml");
16898
17121
  const legacy = [];
16899
17122
  for (const f of files) {
16900
- const base = path17.basename(f);
16901
- const dir = path17.dirname(f);
17123
+ const base = path19.basename(f);
17124
+ const dir = path19.dirname(f);
16902
17125
  if (base === "system.yaml") {
16903
- legacy.push({ path: f, expected: path17.join(dir, ".index.yaml") });
17126
+ legacy.push({ path: f, expected: path19.join(dir, ".index.yaml") });
16904
17127
  } else if (base === "subsystem.yaml") {
16905
- legacy.push({ path: f, expected: path17.join(dir, ".index.yaml") });
17128
+ legacy.push({ path: f, expected: path19.join(dir, ".index.yaml") });
16906
17129
  } else if (base === "component.yaml") {
16907
- legacy.push({ path: f, expected: path17.join(dir, ".index.yaml") });
17130
+ legacy.push({ path: f, expected: path19.join(dir, ".index.yaml") });
16908
17131
  } else if (base === "group.yaml") {
16909
- legacy.push({ path: f, expected: path17.join(dir, ".index.yaml") });
17132
+ legacy.push({ path: f, expected: path19.join(dir, ".index.yaml") });
16910
17133
  } else if (base === "interface.yaml") {
16911
- legacy.push({ path: f, expected: path17.join(dir, ".interface.yaml") });
17134
+ legacy.push({ path: f, expected: path19.join(dir, ".interface.yaml") });
16912
17135
  } else if (base === "implementation.yaml") {
16913
- legacy.push({ path: f, expected: path17.join(dir, ".implementation.yaml") });
17136
+ legacy.push({ path: f, expected: path19.join(dir, ".implementation.yaml") });
16914
17137
  }
16915
17138
  }
16916
17139
  return legacy;
@@ -17405,7 +17628,7 @@ function provisionProject(name) {
17405
17628
  function ensureProjectInitialized(fallbackName) {
17406
17629
  const now = (/* @__PURE__ */ new Date()).toISOString();
17407
17630
  const paths = aiPathsAt(getProjectRoot());
17408
- const hasSystem = fs14.existsSync(paths.specsSystem());
17631
+ const hasSystem = fs15.existsSync(paths.specsSystem());
17409
17632
  let name = fallbackName;
17410
17633
  if (hasSystem) {
17411
17634
  const existing = loadSystemSpec();
@@ -17413,7 +17636,7 @@ function ensureProjectInitialized(fallbackName) {
17413
17636
  }
17414
17637
  let wroteConfig = false;
17415
17638
  let wroteSystem = false;
17416
- if (!fs14.existsSync(paths.projectConfig())) {
17639
+ if (!fs15.existsSync(paths.projectConfig())) {
17417
17640
  saveProjectConfig(defaultProjectConfig(name, now));
17418
17641
  wroteConfig = true;
17419
17642
  }
@@ -17442,11 +17665,11 @@ function promoteAllComplete() {
17442
17665
  function walkChainedSubprojects(projectRoot2, onChild) {
17443
17666
  const visited = /* @__PURE__ */ new Set();
17444
17667
  const walk = (dir) => {
17445
- const resolved = path18.resolve(dir);
17668
+ const resolved = path20.resolve(dir);
17446
17669
  if (visited.has(resolved)) return;
17447
17670
  visited.add(resolved);
17448
17671
  const specsDir = aiPathsAt(dir).specsDir();
17449
- if (!fs14.existsSync(specsDir)) return;
17672
+ if (!fs15.existsSync(specsDir)) return;
17450
17673
  for (const file of listFilesRecursive(specsDir, ".yaml")) {
17451
17674
  let raw;
17452
17675
  try {
@@ -17464,7 +17687,7 @@ function walkChainedSubprojects(projectRoot2, onChild) {
17464
17687
  continue;
17465
17688
  }
17466
17689
  const id = raw.id;
17467
- onChild(childDir, typeof id === "string" ? id : path18.basename(childDir));
17690
+ onChild(childDir, typeof id === "string" ? id : path20.basename(childDir));
17468
17691
  walk(childDir);
17469
17692
  }
17470
17693
  };
@@ -17473,7 +17696,7 @@ function walkChainedSubprojects(projectRoot2, onChild) {
17473
17696
  function listDirectChainedSubprojects(projectRoot2) {
17474
17697
  const out = [];
17475
17698
  const specsDir = aiPathsAt(projectRoot2).specsDir();
17476
- if (!fs14.existsSync(specsDir)) return out;
17699
+ if (!fs15.existsSync(specsDir)) return out;
17477
17700
  for (const file of listFilesRecursive(specsDir, ".yaml")) {
17478
17701
  let raw;
17479
17702
  try {
@@ -17491,12 +17714,12 @@ function listDirectChainedSubprojects(projectRoot2) {
17491
17714
  continue;
17492
17715
  }
17493
17716
  const id = raw.id;
17494
- out.push({ dir, subsystemId: typeof id === "string" ? id : path18.basename(dir) });
17717
+ out.push({ dir, subsystemId: typeof id === "string" ? id : path20.basename(dir) });
17495
17718
  }
17496
17719
  return out;
17497
17720
  }
17498
17721
  function childHasSpecsButNoConfig(childDir) {
17499
- return fs14.existsSync(aiPathsAt(childDir).specsDir()) && !fs14.existsSync(aiPathsAt(childDir).projectConfig());
17722
+ return fs15.existsSync(aiPathsAt(childDir).specsDir()) && !fs15.existsSync(aiPathsAt(childDir).projectConfig());
17500
17723
  }
17501
17724
  function findChainingSubprojectsMissingConfig(projectRoot2) {
17502
17725
  const missing = [];
@@ -17545,14 +17768,14 @@ function moveSubsystemProject(subsystemId, newProjectPath) {
17545
17768
  const oldDir = assertContainedProjectPath(root, sub.projectPath);
17546
17769
  const newDir = assertContainedProjectPath(root, nextPath);
17547
17770
  if (oldDir !== newDir) {
17548
- if (!fs14.existsSync(oldDir)) {
17771
+ if (!fs15.existsSync(oldDir)) {
17549
17772
  throw new WaironError(`Subproject directory not found at its current path: ${oldDir}`);
17550
17773
  }
17551
- if (fs14.existsSync(newDir)) {
17774
+ if (fs15.existsSync(newDir)) {
17552
17775
  throw new WaironError(`Target directory already exists: ${newDir}`);
17553
17776
  }
17554
- ensureDir(path18.dirname(newDir));
17555
- fs14.renameSync(oldDir, newDir);
17777
+ ensureDir(path20.dirname(newDir));
17778
+ fs15.renameSync(oldDir, newDir);
17556
17779
  }
17557
17780
  saveSubsystemSpec({ ...sub, projectPath: nextPath, updatedAt: (/* @__PURE__ */ new Date()).toISOString() });
17558
17781
  invalidateSpecCache();
@@ -17561,9 +17784,9 @@ function toPosixPath(p) {
17561
17784
  return p.replace(/\\/g, "/");
17562
17785
  }
17563
17786
  function isWithinDir(dir, file) {
17564
- const d = path18.resolve(dir);
17565
- const f = path18.resolve(file);
17566
- return f === d || f.startsWith(d + path18.sep);
17787
+ const d = path20.resolve(dir);
17788
+ const f = path20.resolve(file);
17789
+ return f === d || f.startsWith(d + path20.sep);
17567
17790
  }
17568
17791
  function externalizeSubsystem(subsystemId, projectPath) {
17569
17792
  if (subsystemId.includes("::")) {
@@ -17575,14 +17798,14 @@ function externalizeSubsystem(subsystemId, projectPath) {
17575
17798
  }
17576
17799
  const parentRoot = getProjectRoot();
17577
17800
  const parentSpecsDir = aiPathsAt(parentRoot).specsDir();
17578
- const fooDir = path18.join(parentSpecsDir, subsystemId);
17579
- if (!fs14.existsSync(fooDir)) {
17801
+ const fooDir = path20.join(parentSpecsDir, subsystemId);
17802
+ if (!fs15.existsSync(fooDir)) {
17580
17803
  throw new WaironError(`subsystem specs directory not found: ${fooDir}`);
17581
17804
  }
17582
17805
  const relPath = toPosixPath(projectPath);
17583
17806
  const childDir = assertContainedProjectPath(parentRoot, relPath);
17584
- const childFooDir = path18.join(childDir, ".wai", "specs", subsystemId);
17585
- if (fs14.existsSync(childFooDir)) {
17807
+ const childFooDir = path20.join(childDir, ".wai", "specs", subsystemId);
17808
+ if (fs15.existsSync(childFooDir)) {
17586
17809
  throw new WaironError(`target already contains a "${subsystemId}" subsystem: ${childFooDir}`);
17587
17810
  }
17588
17811
  const renameMap = buildRenameMap(
@@ -17592,17 +17815,17 @@ function externalizeSubsystem(subsystemId, projectPath) {
17592
17815
  );
17593
17816
  const childSystemName = foo.name || subsystemId;
17594
17817
  runWithProjectRoot(childDir, () => {
17595
- ensureDir(path18.join(childDir, ".wai", "specs"));
17818
+ ensureDir(path20.join(childDir, ".wai", "specs"));
17596
17819
  provisionProject(childSystemName);
17597
17820
  });
17598
- ensureDir(path18.dirname(childFooDir));
17599
- fs14.renameSync(fooDir, childFooDir);
17600
- patchSubsystemIndex(path18.join(childFooDir, ".index.yaml"), (s) => {
17821
+ ensureDir(path20.dirname(childFooDir));
17822
+ fs15.renameSync(fooDir, childFooDir);
17823
+ patchSubsystemIndex(path20.join(childFooDir, ".index.yaml"), (s) => {
17601
17824
  s.parentSystem = childSystemName;
17602
17825
  delete s.projectPath;
17603
17826
  });
17604
17827
  ensureDir(fooDir);
17605
- writeYamlFile(path18.join(fooDir, ".index.yaml"), {
17828
+ writeYamlFile(path20.join(fooDir, ".index.yaml"), {
17606
17829
  id: subsystemId,
17607
17830
  name: foo.name,
17608
17831
  description: foo.description,
@@ -17628,9 +17851,9 @@ function internalizeSubsystem(subsystemId) {
17628
17851
  const parentRoot = getProjectRoot();
17629
17852
  const parentSpecsDir = aiPathsAt(parentRoot).specsDir();
17630
17853
  const childDir = assertContainedProjectPath(parentRoot, foo.projectPath);
17631
- const childWai = path18.join(childDir, ".wai");
17632
- const childFooDir = path18.join(childDir, ".wai", "specs", subsystemId);
17633
- if (!fs14.existsSync(childFooDir)) {
17854
+ const childWai = path20.join(childDir, ".wai");
17855
+ const childFooDir = path20.join(childDir, ".wai", "specs", subsystemId);
17856
+ if (!fs15.existsSync(childFooDir)) {
17634
17857
  throw new WaironError(`external subproject missing subsystem "${subsystemId}": ${childFooDir}`);
17635
17858
  }
17636
17859
  const childOwnSubs = runWithProjectRoot(childDir, () => loadSubsystemSpecs()).filter((s) => !s.id.includes("::"));
@@ -17643,15 +17866,15 @@ function internalizeSubsystem(subsystemId) {
17643
17866
  false
17644
17867
  );
17645
17868
  const parentSystemName = loadSystemSpec()?.name ?? foo.parentSystem;
17646
- const fooDir = path18.join(parentSpecsDir, subsystemId);
17647
- fs14.rmSync(fooDir, { recursive: true, force: true });
17648
- ensureDir(path18.dirname(fooDir));
17649
- fs14.renameSync(childFooDir, fooDir);
17650
- patchSubsystemIndex(path18.join(fooDir, ".index.yaml"), (s) => {
17869
+ const fooDir = path20.join(parentSpecsDir, subsystemId);
17870
+ fs15.rmSync(fooDir, { recursive: true, force: true });
17871
+ ensureDir(path20.dirname(fooDir));
17872
+ fs15.renameSync(childFooDir, fooDir);
17873
+ patchSubsystemIndex(path20.join(fooDir, ".index.yaml"), (s) => {
17651
17874
  s.parentSystem = parentSystemName;
17652
17875
  delete s.projectPath;
17653
17876
  });
17654
- fs14.rmSync(childWai, { recursive: true, force: true });
17877
+ fs15.rmSync(childWai, { recursive: true, force: true });
17655
17878
  rewriteRefsInDir(parentSpecsDir, renameMap, fooDir);
17656
17879
  invalidateSpecCache();
17657
17880
  }
@@ -17748,18 +17971,18 @@ function rewriteRefsInDir(specsDir, renameMap, excludeDir) {
17748
17971
  }
17749
17972
  }
17750
17973
  function patchSubsystemIndex(indexPath, mutate) {
17751
- if (!fs14.existsSync(indexPath)) return;
17974
+ if (!fs15.existsSync(indexPath)) return;
17752
17975
  const raw = readYamlFile(indexPath);
17753
17976
  mutate(raw);
17754
17977
  raw.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
17755
17978
  writeYamlFile(indexPath, raw);
17756
17979
  }
17757
- var fs14, path18;
17980
+ var fs15, path20;
17758
17981
  var init_provision = __esm({
17759
17982
  "src/core/provision.ts"() {
17760
17983
  "use strict";
17761
- fs14 = __toESM(require("fs"));
17762
- path18 = __toESM(require("path"));
17984
+ fs15 = __toESM(require("fs"));
17985
+ path20 = __toESM(require("path"));
17763
17986
  init_specs2();
17764
17987
  init_loader();
17765
17988
  init_fs();
@@ -17800,18 +18023,18 @@ __export(ai_guide_exports, {
17800
18023
  writeRootGuideDelegator: () => writeRootGuideDelegator
17801
18024
  });
17802
18025
  function globalGuideFilePath(targetType) {
17803
- if (targetType === "claude") return path19.join(process.env["CLAUDE_CONFIG_DIR"] || path19.join(os5.homedir(), ".claude"), "CLAUDE.md");
17804
- if (targetType === "gemini") return path19.join(process.env["GEMINI_CONFIG_DIR"] || path19.join(os5.homedir(), ".gemini"), "GEMINI.md");
18026
+ if (targetType === "claude") return path21.join(process.env["CLAUDE_CONFIG_DIR"] || path21.join(os6.homedir(), ".claude"), "CLAUDE.md");
18027
+ if (targetType === "gemini") return path21.join(process.env["GEMINI_CONFIG_DIR"] || path21.join(os6.homedir(), ".gemini"), "GEMINI.md");
17805
18028
  return null;
17806
18029
  }
17807
18030
  function localGuideFilePath(projectRoot2, targetType) {
17808
- if (targetType === "claude") return path19.join(projectRoot2, ".claude", "CLAUDE.md");
17809
- if (targetType === "gemini" || targetType === "agy") return path19.join(projectRoot2, ".gemini", "GEMINI.md");
18031
+ if (targetType === "claude") return path21.join(projectRoot2, ".claude", "CLAUDE.md");
18032
+ if (targetType === "gemini" || targetType === "agy") return path21.join(projectRoot2, ".gemini", "GEMINI.md");
17810
18033
  return null;
17811
18034
  }
17812
18035
  function hasWaironGuide(filePath) {
17813
- if (!fs15.existsSync(filePath)) return false;
17814
- return fs15.readFileSync(filePath, "utf-8").includes(GUIDE_MARKER_START);
18036
+ if (!fs16.existsSync(filePath)) return false;
18037
+ return fs16.readFileSync(filePath, "utf-8").includes(GUIDE_MARKER_START);
17815
18038
  }
17816
18039
  function injectGuide(filePath, scope) {
17817
18040
  const body = scope === "global" ? GLOBAL_GUIDE_BODY : LOCAL_GUIDE_BODY;
@@ -17822,11 +18045,11 @@ ${versionStamp()}
17822
18045
  ${body}
17823
18046
  ${GUIDE_MARKER_END}
17824
18047
  `;
17825
- const existing = fs15.existsSync(filePath) ? fs15.readFileSync(filePath, "utf-8") : "";
18048
+ const existing = fs16.existsSync(filePath) ? fs16.readFileSync(filePath, "utf-8") : "";
17826
18049
  const stripped = stripGuideSection(existing);
17827
18050
  const newContent = stripped.trimEnd() + section;
17828
- fs15.mkdirSync(path19.dirname(filePath), { recursive: true });
17829
- fs15.writeFileSync(filePath, newContent, "utf-8");
18051
+ fs16.mkdirSync(path21.dirname(filePath), { recursive: true });
18052
+ fs16.writeFileSync(filePath, newContent, "utf-8");
17830
18053
  }
17831
18054
  function stripGuideSection(content) {
17832
18055
  const start = content.indexOf(GUIDE_MARKER_START);
@@ -17836,7 +18059,7 @@ function stripGuideSection(content) {
17836
18059
  }
17837
18060
  function writeRootGuideDelegator(projectRoot2, targetType) {
17838
18061
  if (targetType === "claude") {
17839
- const filePath = path19.join(projectRoot2, "CLAUDE.md");
18062
+ const filePath = path21.join(projectRoot2, "CLAUDE.md");
17840
18063
  const content = `@.claude/CLAUDE.md
17841
18064
 
17842
18065
  # Wairon SDD Project
@@ -17849,42 +18072,42 @@ To design or modify the system, invoke the **\`sdd-architect\`** skill
17849
18072
  (in \`.claude/skills/\`). Author and validate specs with the \`sdd_*\` MCP tools;
17850
18073
  the \`wairon\` CLI is the human developer's tool, not yours.
17851
18074
  `;
17852
- fs15.writeFileSync(filePath, content, "utf-8");
18075
+ fs16.writeFileSync(filePath, content, "utf-8");
17853
18076
  } else if (targetType === "gemini" || targetType === "agy") {
17854
- const filePath = path19.join(projectRoot2, "GEMINI.md");
18077
+ const filePath = path21.join(projectRoot2, "GEMINI.md");
17855
18078
  const content = `# Wairon SDD Project
17856
18079
  ${GUIDE_MARKER_START}
17857
18080
  ${versionStamp()}
17858
18081
  ${LOCAL_GUIDE_BODY}
17859
18082
  ${GUIDE_MARKER_END}
17860
18083
  `;
17861
- fs15.writeFileSync(filePath, content, "utf-8");
18084
+ fs16.writeFileSync(filePath, content, "utf-8");
17862
18085
  } else if (targetType === "cursor") {
17863
- const filePath = path19.join(projectRoot2, ".cursorrules");
18086
+ const filePath = path21.join(projectRoot2, ".cursorrules");
17864
18087
  const content = `# Wairon SDD Project
17865
18088
 
17866
18089
  This project uses the Wairon Spec-Driven Development (SDD) framework.
17867
18090
 
17868
18091
  Refer to the rules in [.cursor/rules/](.cursor/rules/) for full instructions.
17869
18092
  `;
17870
- fs15.writeFileSync(filePath, content, "utf-8");
18093
+ fs16.writeFileSync(filePath, content, "utf-8");
17871
18094
  } else if (targetType === "copilot") {
17872
- const filePath = path19.join(projectRoot2, ".github", "copilot-instructions.md");
17873
- fs15.mkdirSync(path19.dirname(filePath), { recursive: true });
18095
+ const filePath = path21.join(projectRoot2, ".github", "copilot-instructions.md");
18096
+ fs16.mkdirSync(path21.dirname(filePath), { recursive: true });
17874
18097
  const content = `# Wairon SDD Project
17875
18098
 
17876
18099
  This project uses the Wairon Spec-Driven Development (SDD) framework.
17877
18100
 
17878
18101
  Refer to the prompts in [.github/prompts/](.github/prompts/) for instructions.
17879
18102
  `;
17880
- fs15.writeFileSync(filePath, content, "utf-8");
18103
+ fs16.writeFileSync(filePath, content, "utf-8");
17881
18104
  } else if (targetType === "codex") {
17882
- const filePath = path19.join(projectRoot2, ".codexrules");
18105
+ const filePath = path21.join(projectRoot2, ".codexrules");
17883
18106
  const content = `# Wairon SDD Project
17884
18107
 
17885
18108
  Refer to [.codex/agents/](.codex/agents/) for full instructions.
17886
18109
  `;
17887
- fs15.writeFileSync(filePath, content, "utf-8");
18110
+ fs16.writeFileSync(filePath, content, "utf-8");
17888
18111
  }
17889
18112
  }
17890
18113
  function reinjectLocalGuides(projectRoot2, targetTypes) {
@@ -17900,13 +18123,13 @@ function reinjectLocalGuides(projectRoot2, targetTypes) {
17900
18123
  }
17901
18124
  return written;
17902
18125
  }
17903
- var fs15, os5, path19, GUIDE_MARKER_START, GUIDE_MARKER_END, GLOBAL_GUIDE_BODY, LOCAL_GUIDE_BODY, GUIDE_TARGETS;
18126
+ var fs16, os6, path21, GUIDE_MARKER_START, GUIDE_MARKER_END, GLOBAL_GUIDE_BODY, LOCAL_GUIDE_BODY, GUIDE_TARGETS;
17904
18127
  var init_ai_guide = __esm({
17905
18128
  "src/utils/ai-guide.ts"() {
17906
18129
  "use strict";
17907
- fs15 = __toESM(require("fs"));
17908
- os5 = __toESM(require("os"));
17909
- path19 = __toESM(require("path"));
18130
+ fs16 = __toESM(require("fs"));
18131
+ os6 = __toESM(require("os"));
18132
+ path21 = __toESM(require("path"));
17910
18133
  init_stamp();
17911
18134
  GUIDE_MARKER_START = "<!-- wairon-guide-start -->";
17912
18135
  GUIDE_MARKER_END = "<!-- wairon-guide-end -->";
@@ -17968,7 +18191,7 @@ __export(domains_exports, {
17968
18191
  resolveDomains: () => resolveDomains
17969
18192
  });
17970
18193
  function rel(p) {
17971
- return path24.relative(process.cwd(), p).replace(/\\/g, "/");
18194
+ return path26.relative(process.cwd(), p).replace(/\\/g, "/");
17972
18195
  }
17973
18196
  function deriveSubsystemDomains() {
17974
18197
  const subsystems = loadSubsystemSpecs();
@@ -18018,11 +18241,11 @@ function removeFreeStandingDomain(id) {
18018
18241
  config.domains.splice(idx, 1);
18019
18242
  saveTopologyConfig(config);
18020
18243
  }
18021
- var path24;
18244
+ var path26;
18022
18245
  var init_domains = __esm({
18023
18246
  "src/core/domains.ts"() {
18024
18247
  "use strict";
18025
- path24 = __toESM(require("path"));
18248
+ path26 = __toESM(require("path"));
18026
18249
  init_loader();
18027
18250
  init_specs2();
18028
18251
  init_errors();
@@ -18178,16 +18401,16 @@ function packNamespace(pack) {
18178
18401
  return pack.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
18179
18402
  }
18180
18403
  function extensionsFor(builtin, packSkills) {
18181
- return packSkills.filter((s) => s.extends === builtin && fs17.existsSync(s.sourcePath));
18404
+ return packSkills.filter((s) => s.extends === builtin && fs18.existsSync(s.sourcePath));
18182
18405
  }
18183
18406
  function composeBuiltinSkill(name, packSkills) {
18184
18407
  const srcPath = skillTemplatePath(name);
18185
- const base = fs17.existsSync(srcPath) ? fs17.readFileSync(srcPath, "utf-8") : "";
18408
+ const base = fs18.existsSync(srcPath) ? fs18.readFileSync(srcPath, "utf-8") : "";
18186
18409
  const sections = extensionsFor(name, packSkills);
18187
18410
  if (sections.length === 0) return base;
18188
18411
  const parts = [base.trimEnd()];
18189
18412
  for (const section of sections) {
18190
- const body = fs17.readFileSync(section.sourcePath, "utf-8").replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "");
18413
+ const body = fs18.readFileSync(section.sourcePath, "utf-8").replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "");
18191
18414
  parts.push(`## Platform: ${section.pack}`, body.trim());
18192
18415
  }
18193
18416
  return `${parts.join("\n\n")}
@@ -18203,16 +18426,16 @@ function readFrontmatter(raw, fallbackName) {
18203
18426
  return { name: field("name") || fallbackName, description: field("description") };
18204
18427
  }
18205
18428
  function builtinSkillsDir() {
18206
- return path25.resolve(__dirname, "..", "templates", "skills");
18429
+ return path27.resolve(__dirname, "..", "templates", "skills");
18207
18430
  }
18208
18431
  function skillTemplatePath(name) {
18209
- return path25.join(builtinSkillsDir(), `${name}.md`);
18432
+ return path27.join(builtinSkillsDir(), `${name}.md`);
18210
18433
  }
18211
18434
  function skillDestPath(type, destDir, name) {
18212
18435
  if (type === "claude" || type === "codex" || type === "gemini" || type === "agy") {
18213
- return path25.join(destDir, name, "SKILL.md");
18436
+ return path27.join(destDir, name, "SKILL.md");
18214
18437
  }
18215
- return path25.join(destDir, `${name}.md`);
18438
+ return path27.join(destDir, `${name}.md`);
18216
18439
  }
18217
18440
  function skillsDirForTarget(type) {
18218
18441
  switch (type) {
@@ -18247,22 +18470,22 @@ function exportSddSkills(targetTypes) {
18247
18470
  ensureDir(destDir);
18248
18471
  destinations.push(destDir);
18249
18472
  for (const name of SKILL_NAMES) {
18250
- if (!fs17.existsSync(skillTemplatePath(name))) continue;
18473
+ if (!fs18.existsSync(skillTemplatePath(name))) continue;
18251
18474
  const content = composeBuiltinSkill(name, packSkills.filter((s) => s.targets.includes(type)));
18252
18475
  const destPath = skillDestPath(type, destDir, name);
18253
- ensureDir(path25.dirname(destPath));
18254
- fs17.writeFileSync(destPath, content, "utf-8");
18476
+ ensureDir(path27.dirname(destPath));
18477
+ fs18.writeFileSync(destPath, content, "utf-8");
18255
18478
  fileCount++;
18256
18479
  }
18257
18480
  for (const skill of packSkills) {
18258
18481
  if (skill.extends !== void 0) continue;
18259
18482
  if (!skill.targets.includes(type)) continue;
18260
- if (!fs17.existsSync(skill.sourcePath)) continue;
18483
+ if (!fs18.existsSync(skill.sourcePath)) continue;
18261
18484
  const id = packSkillId(skill);
18262
- const content = fs17.readFileSync(skill.sourcePath, "utf-8");
18485
+ const content = fs18.readFileSync(skill.sourcePath, "utf-8");
18263
18486
  const destPath = skillDestPath(type, destDir, id);
18264
- ensureDir(path25.dirname(destPath));
18265
- fs17.writeFileSync(destPath, content, "utf-8");
18487
+ ensureDir(path27.dirname(destPath));
18488
+ fs18.writeFileSync(destPath, content, "utf-8");
18266
18489
  fileCount++;
18267
18490
  }
18268
18491
  }
@@ -18275,12 +18498,12 @@ function checkSkillFreshness(type) {
18275
18498
  const packSkills = loadProjectExtensions2().skills.filter((s) => s.targets.includes(type));
18276
18499
  for (const name of SKILL_NAMES) {
18277
18500
  const destPath = skillDestPath(type, dir, name);
18278
- if (!fs17.existsSync(destPath)) {
18501
+ if (!fs18.existsSync(destPath)) {
18279
18502
  result.missing.push(name);
18280
18503
  continue;
18281
18504
  }
18282
18505
  const want = composeBuiltinSkill(name, packSkills);
18283
- const have = fs17.readFileSync(destPath, "utf-8");
18506
+ const have = fs18.readFileSync(destPath, "utf-8");
18284
18507
  if (have === want) result.ok.push(name);
18285
18508
  else result.stale.push(name);
18286
18509
  }
@@ -18292,7 +18515,7 @@ function activeTargetTypes() {
18292
18515
  return config.targets.filter((t) => !("enabled" in t) || t.enabled).map((t) => typeof t === "string" ? t : t.type);
18293
18516
  }
18294
18517
  function readSkillFrontmatter(name) {
18295
- return readFrontmatter(fs17.readFileSync(skillTemplatePath(name), "utf-8"), name);
18518
+ return readFrontmatter(fs18.readFileSync(skillTemplatePath(name), "utf-8"), name);
18296
18519
  }
18297
18520
  function listSkillResources() {
18298
18521
  const builtin = RESOURCE_SKILL_IDS.map((id) => {
@@ -18306,9 +18529,9 @@ function listSkillResources() {
18306
18529
  defaultForHostedMcp: true
18307
18530
  };
18308
18531
  });
18309
- const pack = loadProjectExtensions2().skills.filter((s) => s.extends === void 0 && fs17.existsSync(s.sourcePath)).map((skill) => {
18532
+ const pack = loadProjectExtensions2().skills.filter((s) => s.extends === void 0 && fs18.existsSync(s.sourcePath)).map((skill) => {
18310
18533
  const id = packSkillId(skill);
18311
- const fm = readFrontmatter(fs17.readFileSync(skill.sourcePath, "utf-8"), id);
18534
+ const fm = readFrontmatter(fs18.readFileSync(skill.sourcePath, "utf-8"), id);
18312
18535
  return {
18313
18536
  id,
18314
18537
  name: fm.name,
@@ -18324,8 +18547,8 @@ function readSkillResource(resourceId) {
18324
18547
  const packSkills = loadProjectExtensions2().skills;
18325
18548
  if (SKILL_NAMES.includes(resourceId)) return composeBuiltinSkill(resourceId, packSkills);
18326
18549
  const packSkill = packSkills.find((s) => s.extends === void 0 && packSkillId(s) === resourceId);
18327
- if (packSkill) return fs17.readFileSync(packSkill.sourcePath, "utf-8");
18328
- return fs17.readFileSync(skillTemplatePath(resourceId), "utf-8");
18550
+ if (packSkill) return fs18.readFileSync(packSkill.sourcePath, "utf-8");
18551
+ return fs18.readFileSync(skillTemplatePath(resourceId), "utf-8");
18329
18552
  }
18330
18553
  function listResources() {
18331
18554
  return listSkillResources();
@@ -18338,12 +18561,12 @@ function readResource(resourceId) {
18338
18561
  if (!known) throw new SkillResourceNotFoundError(resourceId);
18339
18562
  return readSkillResource(resourceId);
18340
18563
  }
18341
- var path25, fs17, SKILL_NAMES, SKILL_RESOURCE_SCHEME, RESOURCE_SKILL_IDS, SkillResourceNotFoundError;
18564
+ var path27, fs18, SKILL_NAMES, SKILL_RESOURCE_SCHEME, RESOURCE_SKILL_IDS, SkillResourceNotFoundError;
18342
18565
  var init_skills = __esm({
18343
18566
  "src/core/skills.ts"() {
18344
18567
  "use strict";
18345
- path25 = __toESM(require("path"));
18346
- fs17 = __toESM(require("fs"));
18568
+ path27 = __toESM(require("path"));
18569
+ fs18 = __toESM(require("fs"));
18347
18570
  init_fs();
18348
18571
  init_defaults();
18349
18572
  init_extensions();
@@ -18570,23 +18793,34 @@ async function runStatus(options = {}) {
18570
18793
  const lock = lockLine().trim();
18571
18794
  if (lock) {
18572
18795
  logger.blank();
18573
- if (lock.includes("STALE")) logger.warn(lock);
18796
+ if (lock.includes("changed since approval")) logger.warn(lock);
18574
18797
  else logger.info(lock);
18575
18798
  }
18576
18799
  logger.blank();
18577
18800
  }
18578
18801
  function lockLine() {
18579
18802
  try {
18580
- const { state, record: record2 } = readLockState();
18581
- if (state === "unlocked") return "";
18582
- if (state === "locked") {
18803
+ const baseline = readBaseline();
18804
+ if (!baseline) return "";
18805
+ const moved = movedChildren(loadSubsystemSpecs());
18806
+ const childNote = moved.length ? `
18807
+ ${moved.length} chained child project(s) moved since approval: ${moved.map((m) => m.id).join(", ")}.` : "";
18808
+ const diff = diffAgainstBaseline();
18809
+ if (!diff || diffSize(diff) === 0) {
18583
18810
  return `
18584
- Lock: FROZEN at ${record2.lockedAt} by ${record2.lockedBy} (wairon ${record2.validatorVersion}).
18811
+ Approved: ${baseline.approvedAt} by ${baseline.approvedBy} \u2014 no spec has changed since.${childNote}
18585
18812
  `;
18586
18813
  }
18814
+ const parts = [];
18815
+ if (diff.changed.length) parts.push(`${diff.changed.length} changed`);
18816
+ if (diff.added.length) parts.push(`${diff.added.length} added`);
18817
+ if (diff.removed.length) parts.push(`${diff.removed.length} removed`);
18818
+ const named = [...diff.changed, ...diff.added, ...diff.removed].slice(0, 5);
18819
+ const rest = diffSize(diff) - named.length;
18587
18820
  return `
18588
- Lock: STALE \u2014 the specs or the governing doctrine changed since ${record2.lockedAt}, so this lock no longer holds and promotion will refuse it. Re-run \`wairon lock\` to freeze the current state.
18589
- `;
18821
+ ${diffSize(diff)} spec(s) changed since approval (${parts.join(", ")}) \u2014 approved ${baseline.approvedAt} by ${baseline.approvedBy}:
18822
+ ` + named.map((p) => ` ${p}`).join("\n") + (rest > 0 ? `
18823
+ \u2026 and ${rest} more` : "") + childNote + "\n";
18590
18824
  } catch {
18591
18825
  return "";
18592
18826
  }
@@ -18713,6 +18947,7 @@ var init_status = __esm({
18713
18947
  init_loader();
18714
18948
  init_fs();
18715
18949
  init_specs2();
18950
+ init_baseline();
18716
18951
  }
18717
18952
  });
18718
18953
 
@@ -18761,7 +18996,7 @@ function errText(message) {
18761
18996
  }
18762
18997
  function captureBuildStamp(entryPath) {
18763
18998
  try {
18764
- const s = fs18.statSync(entryPath);
18999
+ const s = fs19.statSync(entryPath);
18765
19000
  return { path: entryPath, mtimeMs: s.mtimeMs, size: s.size };
18766
19001
  } catch {
18767
19002
  return null;
@@ -18770,7 +19005,7 @@ function captureBuildStamp(entryPath) {
18770
19005
  function isBuildStale(stamp) {
18771
19006
  if (!stamp) return false;
18772
19007
  try {
18773
- const s = fs18.statSync(stamp.path);
19008
+ const s = fs19.statSync(stamp.path);
18774
19009
  return s.mtimeMs !== stamp.mtimeMs || s.size !== stamp.size;
18775
19010
  } catch {
18776
19011
  return false;
@@ -19988,10 +20223,6 @@ NOTICE:
19988
20223
  description: "Hosted project lifecycle (execute-primary): LOCK the bound project (validate-as-complete gate + commit-scoped lock record). Executes directly when your resolved permission is yes and returns the completed outcome; when it is approval, a pending approval request is created instead (await it with sdd_host_await_approval).",
19989
20224
  inputSchema: {}
19990
20225
  }, hostedStub);
19991
- reg(server, "sdd_host_promote_project", {
19992
- description: "Hosted project lifecycle (execute-primary): PROMOTE the bound, locked project after a StateId re-check. Executes directly when your resolved permission is yes; when it is approval, a pending approval request is created instead.",
19993
- inputSchema: {}
19994
- }, hostedStub);
19995
20226
  reg(server, "sdd_host_initialize_project", {
19996
20227
  description: "Hosted project lifecycle (execute-primary): initialize a new hosted project into its REQUIRED owner organization unit (with an optional profile selection). Executes directly when your resolved permission is yes; when it is approval, a pending approval request is created instead.",
19997
20228
  inputSchema: {
@@ -20077,7 +20308,7 @@ async function scopeToClientWorkspace(server) {
20077
20308
  } catch {
20078
20309
  dir = null;
20079
20310
  }
20080
- if (dir && (fs18.existsSync(path27.join(dir, ".wai")) || fs18.existsSync(path27.join(dir, ".wairon")))) {
20311
+ if (dir && (fs19.existsSync(path29.join(dir, ".wai")) || fs19.existsSync(path29.join(dir, ".wairon")))) {
20081
20312
  setProjectRoot(dir);
20082
20313
  process.stderr.write(`[wairon mcp] scoped to client workspace root: ${dir}
20083
20314
  `);
@@ -20101,7 +20332,7 @@ async function startMcpServer() {
20101
20332
  } catch {
20102
20333
  }
20103
20334
  }
20104
- var import_mcp, import_stdio, import_zod9, import_types3, fs18, path27, import_url, SERVER_BUILD_STAMP, STALE_SERVER_WARNING, SPEC_WRITE_TOOLS, listChangedEmitters, STORE_MANAGED_FIELDS, ALWAYS_CARRIED_FIELDS, SKILL_RESOURCE_MIME, AGENT_BRIEF_SCHEME;
20335
+ var import_mcp, import_stdio, import_zod9, import_types3, fs19, path29, import_url, SERVER_BUILD_STAMP, STALE_SERVER_WARNING, SPEC_WRITE_TOOLS, listChangedEmitters, STORE_MANAGED_FIELDS, ALWAYS_CARRIED_FIELDS, SKILL_RESOURCE_MIME, AGENT_BRIEF_SCHEME;
20105
20336
  var init_server = __esm({
20106
20337
  "src/mcp/server.ts"() {
20107
20338
  "use strict";
@@ -20109,8 +20340,8 @@ var init_server = __esm({
20109
20340
  import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
20110
20341
  import_zod9 = require("zod");
20111
20342
  import_types3 = require("@modelcontextprotocol/sdk/types.js");
20112
- fs18 = __toESM(require("fs"));
20113
- path27 = __toESM(require("path"));
20343
+ fs19 = __toESM(require("fs"));
20344
+ path29 = __toESM(require("path"));
20114
20345
  import_url = require("url");
20115
20346
  init_fs();
20116
20347
  init_defaults();
@@ -20161,34 +20392,34 @@ __export(mcp_exports, {
20161
20392
  validateConfigDir: () => validateConfigDir
20162
20393
  });
20163
20394
  function geminiGlobalDir(override) {
20164
- return override || process.env["GEMINI_CONFIG_DIR"] || path28.join(os6.homedir(), ".gemini");
20395
+ return override || process.env["GEMINI_CONFIG_DIR"] || path30.join(os7.homedir(), ".gemini");
20165
20396
  }
20166
20397
  function claudeMcpConfigPath(useGlobal, override) {
20167
- if (!useGlobal) return path28.join(process.cwd(), ".mcp.json");
20398
+ if (!useGlobal) return path30.join(process.cwd(), ".mcp.json");
20168
20399
  const dir = override || process.env["CLAUDE_CONFIG_DIR"];
20169
- return dir ? path28.join(dir, ".claude.json") : path28.join(os6.homedir(), ".claude.json");
20400
+ return dir ? path30.join(dir, ".claude.json") : path30.join(os7.homedir(), ".claude.json");
20170
20401
  }
20171
20402
  function validateConfigDir(dir, backend) {
20172
- const resolved = path28.resolve(dir);
20403
+ const resolved = path30.resolve(dir);
20173
20404
  const agent = backend === "claude" ? "Claude" : "Gemini/Antigravity";
20174
- if (!fs19.existsSync(resolved)) {
20175
- const parent = path28.dirname(resolved);
20176
- if (!fs19.existsSync(parent)) {
20405
+ if (!fs20.existsSync(resolved)) {
20406
+ const parent = path30.dirname(resolved);
20407
+ if (!fs20.existsSync(parent)) {
20177
20408
  throw new WaironError(`--config-dir "${dir}" does not exist and its parent is missing \u2014 check the path.`);
20178
20409
  }
20179
20410
  logger.warn(`Config dir "${resolved}" does not exist yet; it will be created.`);
20180
20411
  return;
20181
20412
  }
20182
- if (!fs19.statSync(resolved).isDirectory()) {
20413
+ if (!fs20.statSync(resolved).isDirectory()) {
20183
20414
  throw new WaironError(`--config-dir "${dir}" is not a directory.`);
20184
20415
  }
20185
20416
  const markers = backend === "claude" ? ["settings.json", "settings.local.json", ".credentials.json", "projects", "statsig", "todos", "shell-snapshots", "CLAUDE.md"] : ["settings.json", "GEMINI.md", "oauth_creds.json", "antigravity-cli", "tmp"];
20186
- const entries = fs19.readdirSync(resolved);
20417
+ const entries = fs20.readdirSync(resolved);
20187
20418
  if (entries.length === 0) {
20188
20419
  logger.warn(`Config dir "${resolved}" is empty; proceeding (treating it as a fresh ${agent} config dir).`);
20189
20420
  return;
20190
20421
  }
20191
- if (!markers.some((m) => fs19.existsSync(path28.join(resolved, m)))) {
20422
+ if (!markers.some((m) => fs20.existsSync(path30.join(resolved, m)))) {
20192
20423
  throw new WaironError(
20193
20424
  `"${dir}" does not look like a ${agent} config directory (none of ${markers.slice(0, 4).join(", ")} found). Point --config-dir at the agent's config directory.`
20194
20425
  );
@@ -20196,12 +20427,12 @@ function validateConfigDir(dir, backend) {
20196
20427
  }
20197
20428
  async function runMcpServe() {
20198
20429
  const { setProjectRoot: setProjectRoot2, getProjectRoot: getProjectRoot2, findProjectRoot: findProjectRoot2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
20199
- const cwd = path28.resolve(process.cwd());
20430
+ const cwd = path30.resolve(process.cwd());
20200
20431
  const envDir = process.env["WAIRON_PROJECT_DIR"];
20201
20432
  let resolved;
20202
20433
  let how;
20203
- if (envDir && fs19.existsSync(path28.join(envDir, ".wai"))) {
20204
- resolved = path28.resolve(envDir);
20434
+ if (envDir && fs20.existsSync(path30.join(envDir, ".wai"))) {
20435
+ resolved = path30.resolve(envDir);
20205
20436
  how = "WAIRON_PROJECT_DIR (pinned at install)";
20206
20437
  } else {
20207
20438
  const found = findProjectRoot2(cwd);
@@ -20264,20 +20495,20 @@ async function runMcpInstall(options = {}) {
20264
20495
  let settingsPath;
20265
20496
  if (backend === "gemini") {
20266
20497
  if (useGlobal) {
20267
- configBase = path28.join(geminiGlobalDir(options.configDir), "antigravity-cli");
20268
- settingsPath = path28.join(configBase, "mcp_config.json");
20498
+ configBase = path30.join(geminiGlobalDir(options.configDir), "antigravity-cli");
20499
+ settingsPath = path30.join(configBase, "mcp_config.json");
20269
20500
  } else {
20270
- configBase = path28.join(process.cwd(), ".gemini");
20271
- settingsPath = path28.join(configBase, "settings.json");
20501
+ configBase = path30.join(process.cwd(), ".gemini");
20502
+ settingsPath = path30.join(configBase, "settings.json");
20272
20503
  }
20273
20504
  } else {
20274
20505
  settingsPath = claudeMcpConfigPath(useGlobal, options.configDir);
20275
- configBase = path28.dirname(settingsPath);
20506
+ configBase = path30.dirname(settingsPath);
20276
20507
  }
20277
20508
  let settings = {};
20278
- if (fs19.existsSync(settingsPath)) {
20509
+ if (fs20.existsSync(settingsPath)) {
20279
20510
  try {
20280
- settings = JSON.parse(fs19.readFileSync(settingsPath, "utf8"));
20511
+ settings = JSON.parse(fs20.readFileSync(settingsPath, "utf8"));
20281
20512
  } catch {
20282
20513
  logger.warn(`Could not parse ${settingsPath} \u2014 starting fresh.`);
20283
20514
  }
@@ -20285,7 +20516,7 @@ async function runMcpInstall(options = {}) {
20285
20516
  const mcpServers = settings["mcpServers"] ?? {};
20286
20517
  const agentLabel = backend === "gemini" ? "Antigravity" : "Claude";
20287
20518
  const isPackaged = typeof process.pkg !== "undefined";
20288
- const scriptPath = process.argv[1] ? path28.resolve(process.argv[1]).replace(/\\/g, "/") : null;
20519
+ const scriptPath = process.argv[1] ? path30.resolve(process.argv[1]).replace(/\\/g, "/") : null;
20289
20520
  const useDirectNode = !isPackaged && scriptPath && (scriptPath.endsWith(".js") || scriptPath.endsWith(".ts"));
20290
20521
  const env = useGlobal ? {} : { WAIRON_PROJECT_DIR: process.cwd().replace(/\\/g, "/") };
20291
20522
  const desiredEntry = useDirectNode ? { command: "node", args: [scriptPath, "mcp", "serve"], env } : { command: "wairon", args: ["mcp", "serve"], env };
@@ -20297,8 +20528,8 @@ async function runMcpInstall(options = {}) {
20297
20528
  const wasStale = !!existingEntry;
20298
20529
  mcpServers["wairon"] = desiredEntry;
20299
20530
  settings["mcpServers"] = mcpServers;
20300
- if (!fs19.existsSync(configBase)) fs19.mkdirSync(configBase, { recursive: true });
20301
- fs19.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
20531
+ if (!fs20.existsSync(configBase)) fs20.mkdirSync(configBase, { recursive: true });
20532
+ fs20.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
20302
20533
  logger.success(`wairon MCP server ${wasStale ? "updated (was stale)" : "registered"} for ${agentLabel} in ${import_chalk4.default.cyan(settingsPath)}.`);
20303
20534
  logger.blank();
20304
20535
  logger.info("AI tools using this config will have access to these wairon tools:");
@@ -20323,8 +20554,8 @@ async function runMcpStatus() {
20323
20554
  const projectConfig = loadProjectConfig();
20324
20555
  const claudeProject = claudeMcpConfigPath(false);
20325
20556
  const claudeGlobal = claudeMcpConfigPath(true);
20326
- const geminiProject = path28.join(process.cwd(), ".gemini", "settings.json");
20327
- const geminiGlobal = path28.join(geminiGlobalDir(), "antigravity-cli", "mcp_config.json");
20557
+ const geminiProject = path30.join(process.cwd(), ".gemini", "settings.json");
20558
+ const geminiGlobal = path30.join(geminiGlobalDir(), "antigravity-cli", "mcp_config.json");
20328
20559
  logger.blank();
20329
20560
  logger.info(`${import_chalk4.default.bold("wairon MCP Server")}`);
20330
20561
  logger.blank();
@@ -20335,12 +20566,12 @@ async function runMcpStatus() {
20335
20566
  { label: "Antigravity (global)", filePath: geminiGlobal, fallbackName: "mcp_config.json" }
20336
20567
  ];
20337
20568
  for (const { label, filePath, fallbackName } of checks) {
20338
- if (!fs19.existsSync(filePath)) {
20569
+ if (!fs20.existsSync(filePath)) {
20339
20570
  console.log(` ${label}: ${import_chalk4.default.gray(`${fallbackName} not found`)}`);
20340
20571
  continue;
20341
20572
  }
20342
20573
  try {
20343
- const s = JSON.parse(fs19.readFileSync(filePath, "utf8"));
20574
+ const s = JSON.parse(fs20.readFileSync(filePath, "utf8"));
20344
20575
  const registered = !!s["mcpServers"]?.["wairon"];
20345
20576
  const mark = registered ? import_chalk4.default.green("\u2713 registered") : import_chalk4.default.gray("not registered");
20346
20577
  console.log(` ${label}: ${mark} ${import_chalk4.default.gray(filePath)}`);
@@ -20356,16 +20587,16 @@ async function runMcpStatus() {
20356
20587
  logger.info(`To start manually: ${import_chalk4.default.bold("wairon mcp serve")}`);
20357
20588
  logger.blank();
20358
20589
  const mcpDir = aiDir("mcp");
20359
- if (fs19.existsSync(mcpDir)) {
20590
+ if (fs20.existsSync(mcpDir)) {
20360
20591
  logger.info(`MCP state dir: ${import_chalk4.default.gray(mcpDir)}`);
20361
20592
  }
20362
20593
  }
20363
20594
  function removeLegacyGlobalPlugin() {
20364
- const home = process.env["USERPROFILE"] ?? process.env["HOME"] ?? os6.homedir();
20365
- const pluginDir = path28.join(home, ".gemini", "config", "plugins", "wairon");
20595
+ const home = process.env["USERPROFILE"] ?? process.env["HOME"] ?? os7.homedir();
20596
+ const pluginDir = path30.join(home, ".gemini", "config", "plugins", "wairon");
20366
20597
  try {
20367
- if (fs19.existsSync(pluginDir)) {
20368
- fs19.rmSync(pluginDir, { recursive: true, force: true });
20598
+ if (fs20.existsSync(pluginDir)) {
20599
+ fs20.rmSync(pluginDir, { recursive: true, force: true });
20369
20600
  logger.info(`Removed legacy global Antigravity plugin at ${import_chalk4.default.gray(pluginDir)} (it collides with the wairon MCP server).`);
20370
20601
  return true;
20371
20602
  }
@@ -20374,13 +20605,13 @@ function removeLegacyGlobalPlugin() {
20374
20605
  }
20375
20606
  return false;
20376
20607
  }
20377
- var fs19, os6, path28, import_chalk4;
20608
+ var fs20, os7, path30, import_chalk4;
20378
20609
  var init_mcp = __esm({
20379
20610
  "src/commands/mcp.ts"() {
20380
20611
  "use strict";
20381
- fs19 = __toESM(require("fs"));
20382
- os6 = __toESM(require("os"));
20383
- path28 = __toESM(require("path"));
20612
+ fs20 = __toESM(require("fs"));
20613
+ os7 = __toESM(require("os"));
20614
+ path30 = __toESM(require("path"));
20384
20615
  import_chalk4 = __toESM(require("chalk"));
20385
20616
  init_logger();
20386
20617
  init_loader();
@@ -23215,8 +23446,8 @@ var require_dist = __commonJS({
23215
23446
  function slug(name) {
23216
23447
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
23217
23448
  }
23218
- var fs53 = __toESM2(require("fs"));
23219
- var path64 = __toESM2(require("path"));
23449
+ var fs54 = __toESM2(require("fs"));
23450
+ var path67 = __toESM2(require("path"));
23220
23451
  var import_fflate = require_node();
23221
23452
  var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", ".hg", ".svn"]);
23222
23453
  function listEntries(archive) {
@@ -23254,9 +23485,9 @@ var require_dist = __commonJS({
23254
23485
  }
23255
23486
  function writeTree(destDir, files) {
23256
23487
  for (const file of files) {
23257
- const absolute = path64.join(destDir, file.path);
23258
- fs53.mkdirSync(path64.dirname(absolute), { recursive: true });
23259
- fs53.writeFileSync(absolute, file.contents);
23488
+ const absolute = path67.join(destDir, file.path);
23489
+ fs54.mkdirSync(path67.dirname(absolute), { recursive: true });
23490
+ fs54.writeFileSync(absolute, file.contents);
23260
23491
  }
23261
23492
  }
23262
23493
  function classifyKind(name, symlinks) {
@@ -23265,14 +23496,14 @@ var require_dist = __commonJS({
23265
23496
  return "file";
23266
23497
  }
23267
23498
  function walkPackDir(root, current2, out) {
23268
- for (const entry of fs53.readdirSync(current2, { withFileTypes: true })) {
23499
+ for (const entry of fs54.readdirSync(current2, { withFileTypes: true })) {
23269
23500
  if (entry.isDirectory()) {
23270
23501
  if (SKIP_DIRS.has(entry.name)) continue;
23271
- walkPackDir(root, path64.join(current2, entry.name), out);
23502
+ walkPackDir(root, path67.join(current2, entry.name), out);
23272
23503
  } else if (entry.isFile()) {
23273
- const absolute = path64.join(current2, entry.name);
23274
- const relative22 = path64.relative(root, absolute).split(path64.sep).join("/");
23275
- out.push({ path: relative22, contents: fs53.readFileSync(absolute) });
23504
+ const absolute = path67.join(current2, entry.name);
23505
+ const relative22 = path67.relative(root, absolute).split(path67.sep).join("/");
23506
+ out.push({ path: relative22, contents: fs54.readFileSync(absolute) });
23276
23507
  }
23277
23508
  }
23278
23509
  }
@@ -23441,7 +23672,7 @@ var require_dist = __commonJS({
23441
23672
  });
23442
23673
 
23443
23674
  // src/cli/index.ts
23444
- var path63 = __toESM(require("path"));
23675
+ var path66 = __toESM(require("path"));
23445
23676
  var import_commander = require("commander");
23446
23677
  init_defaults();
23447
23678
  init_logger();
@@ -23668,7 +23899,7 @@ function isSupportedAlias(name) {
23668
23899
  }
23669
23900
 
23670
23901
  // src/commands/init.ts
23671
- var path29 = __toESM(require("path"));
23902
+ var path31 = __toESM(require("path"));
23672
23903
  var import_chalk5 = __toESM(require("chalk"));
23673
23904
  var import_inquirer = __toESM(require("inquirer"));
23674
23905
  init_logger();
@@ -23689,7 +23920,7 @@ var WAIRON_MANAGED_MARKER = "wairon:managed";
23689
23920
  var WAIRON_MANAGED_BANNER = `<!-- ${WAIRON_MANAGED_MARKER} \u2014 generated by \`wairon generate\`; do not edit, changes are overwritten -->`;
23690
23921
 
23691
23922
  // src/exporters/claude.ts
23692
- var path20 = __toESM(require("path"));
23923
+ var path22 = __toESM(require("path"));
23693
23924
  init_fs();
23694
23925
  var ClaudeExporter = class {
23695
23926
  constructor() {
@@ -23698,7 +23929,7 @@ var ClaudeExporter = class {
23698
23929
  outputPath(ctx) {
23699
23930
  const { agent, target, projectRoot: projectRoot2 } = ctx;
23700
23931
  const outputDir = "outputDir" in target ? target.outputDir : ".claude/agents";
23701
- return path20.resolve(projectRoot2, outputDir, `${agent.id.replace(/::/g, "--")}.md`);
23932
+ return path22.resolve(projectRoot2, outputDir, `${agent.id.replace(/::/g, "--")}.md`);
23702
23933
  }
23703
23934
  export(ctx) {
23704
23935
  const { agent, renderedInstructions } = ctx;
@@ -23719,7 +23950,7 @@ var ClaudeExporter = class {
23719
23950
  };
23720
23951
 
23721
23952
  // src/exporters/custom.ts
23722
- var path21 = __toESM(require("path"));
23953
+ var path23 = __toESM(require("path"));
23723
23954
  init_fs();
23724
23955
  var CustomExporter = class {
23725
23956
  constructor() {
@@ -23730,7 +23961,7 @@ var CustomExporter = class {
23730
23961
  if (!("outputDir" in target)) {
23731
23962
  throw new Error("CustomExporter requires target.outputDir");
23732
23963
  }
23733
- return path21.resolve(projectRoot2, target.outputDir, `${agent.id.replace(/::/g, "--")}.md`);
23964
+ return path23.resolve(projectRoot2, target.outputDir, `${agent.id.replace(/::/g, "--")}.md`);
23734
23965
  }
23735
23966
  export(ctx) {
23736
23967
  const { agent, target, renderedInstructions } = ctx;
@@ -23753,7 +23984,7 @@ var CustomExporter = class {
23753
23984
  };
23754
23985
 
23755
23986
  // src/exporters/gemini.ts
23756
- var path22 = __toESM(require("path"));
23987
+ var path24 = __toESM(require("path"));
23757
23988
  init_fs();
23758
23989
  var GeminiExporter = class {
23759
23990
  constructor() {
@@ -23762,7 +23993,7 @@ var GeminiExporter = class {
23762
23993
  outputPath(ctx) {
23763
23994
  const { agent, target, projectRoot: projectRoot2 } = ctx;
23764
23995
  const outputDir = "outputDir" in target ? target.outputDir : ".gemini/agents";
23765
- return path22.resolve(projectRoot2, outputDir, `${agent.id.replace(/::/g, "--")}.yaml`);
23996
+ return path24.resolve(projectRoot2, outputDir, `${agent.id.replace(/::/g, "--")}.yaml`);
23766
23997
  }
23767
23998
  export(ctx) {
23768
23999
  const { agent, renderedInstructions } = ctx;
@@ -23787,11 +24018,11 @@ function yamlString(value) {
23787
24018
  }
23788
24019
 
23789
24020
  // src/exporters/generate.ts
23790
- var path26 = __toESM(require("path"));
24021
+ var path28 = __toESM(require("path"));
23791
24022
 
23792
24023
  // src/core/detection.ts
23793
- var fs16 = __toESM(require("fs"));
23794
- var path23 = __toESM(require("path"));
24024
+ var fs17 = __toESM(require("fs"));
24025
+ var path25 = __toESM(require("path"));
23795
24026
  init_defaults();
23796
24027
  var PACKAGE_MARKERS = [
23797
24028
  "package.json",
@@ -23843,7 +24074,7 @@ function deduplicateIds(candidates, existingIds = /* @__PURE__ */ new Set()) {
23843
24074
  });
23844
24075
  }
23845
24076
  function parseGitmodules(filePath) {
23846
- const content = fs16.readFileSync(filePath, "utf-8");
24077
+ const content = fs17.readFileSync(filePath, "utf-8");
23847
24078
  const entries = [];
23848
24079
  let current2 = {};
23849
24080
  for (const line2 of content.split("\n")) {
@@ -23865,8 +24096,8 @@ function parseGitmodules(filePath) {
23865
24096
  return entries;
23866
24097
  }
23867
24098
  function detectGitSubmodules(projectRoot2) {
23868
- const gitmodulesPath = path23.join(projectRoot2, ".gitmodules");
23869
- if (!fs16.existsSync(gitmodulesPath)) return [];
24099
+ const gitmodulesPath = path25.join(projectRoot2, ".gitmodules");
24100
+ if (!fs17.existsSync(gitmodulesPath)) return [];
23870
24101
  return parseGitmodules(gitmodulesPath).map((entry) => ({
23871
24102
  suggestedId: pathToId(entry.path),
23872
24103
  suggestedName: pathToName(entry.path),
@@ -23884,18 +24115,18 @@ function walkForGit(projectRoot2, currentDir, depth, results) {
23884
24115
  if (depth > MAX_SCAN_DEPTH) return;
23885
24116
  let entries;
23886
24117
  try {
23887
- entries = fs16.readdirSync(currentDir, { withFileTypes: true });
24118
+ entries = fs17.readdirSync(currentDir, { withFileTypes: true });
23888
24119
  } catch {
23889
24120
  return;
23890
24121
  }
23891
24122
  for (const entry of entries) {
23892
24123
  if (!entry.isDirectory()) continue;
23893
24124
  if (SCAN_EXCLUDE_DIRS.has(entry.name)) continue;
23894
- const fullPath = path23.join(currentDir, entry.name);
23895
- const relPath = normalizePath3(path23.relative(projectRoot2, fullPath));
24125
+ const fullPath = path25.join(currentDir, entry.name);
24126
+ const relPath = normalizePath3(path25.relative(projectRoot2, fullPath));
23896
24127
  if (relPath === "" || relPath === ".") continue;
23897
- const gitPath = path23.join(fullPath, ".git");
23898
- if (fs16.existsSync(gitPath)) {
24128
+ const gitPath = path25.join(fullPath, ".git");
24129
+ if (fs17.existsSync(gitPath)) {
23899
24130
  results.push({
23900
24131
  suggestedId: pathToId(relPath),
23901
24132
  suggestedName: pathToName(relPath),
@@ -23917,17 +24148,17 @@ function walkForPackages(projectRoot2, currentDir, depth, results) {
23917
24148
  if (depth > MAX_SCAN_DEPTH) return;
23918
24149
  let entries;
23919
24150
  try {
23920
- entries = fs16.readdirSync(currentDir, { withFileTypes: true });
24151
+ entries = fs17.readdirSync(currentDir, { withFileTypes: true });
23921
24152
  } catch {
23922
24153
  return;
23923
24154
  }
23924
24155
  for (const entry of entries) {
23925
24156
  if (!entry.isDirectory()) continue;
23926
24157
  if (SCAN_EXCLUDE_DIRS.has(entry.name)) continue;
23927
- const fullPath = path23.join(currentDir, entry.name);
23928
- const relPath = normalizePath3(path23.relative(projectRoot2, fullPath));
24158
+ const fullPath = path25.join(currentDir, entry.name);
24159
+ const relPath = normalizePath3(path25.relative(projectRoot2, fullPath));
23929
24160
  if (relPath === "" || relPath === ".") continue;
23930
- const hasMarker = PACKAGE_MARKERS.some((m) => fs16.existsSync(path23.join(fullPath, m)));
24161
+ const hasMarker = PACKAGE_MARKERS.some((m) => fs17.existsSync(path25.join(fullPath, m)));
23931
24162
  if (hasMarker) {
23932
24163
  results.push({
23933
24164
  suggestedId: pathToId(relPath),
@@ -23941,8 +24172,8 @@ function walkForPackages(projectRoot2, currentDir, depth, results) {
23941
24172
  }
23942
24173
  }
23943
24174
  function pathToId(relPath) {
23944
- const basename13 = path23.basename(relPath);
23945
- return basename13.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
24175
+ const basename14 = path25.basename(relPath);
24176
+ return basename14.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
23946
24177
  }
23947
24178
  function pathToName(relPath) {
23948
24179
  const id = pathToId(relPath);
@@ -24169,7 +24400,7 @@ function resolveExpectedOutputPaths(agents, projectConfig, projectRoot2 = getPro
24169
24400
  const targetConfig = resolveTargetConfig(agentTarget, projectConfig);
24170
24401
  if (!targetConfig) continue;
24171
24402
  const ctx = { agent, projectRoot: projectRoot2, target: targetConfig };
24172
- expected.add(path26.resolve(getExporter(targetConfig).outputPath(ctx)));
24403
+ expected.add(path28.resolve(getExporter(targetConfig).outputPath(ctx)));
24173
24404
  }
24174
24405
  }
24175
24406
  return expected;
@@ -24187,7 +24418,7 @@ async function runInit(options = {}) {
24187
24418
  logger.header("wairon init");
24188
24419
  const cwd = process.cwd();
24189
24420
  const ancestorRoot = findSystemRoot(cwd);
24190
- if (ancestorRoot && path29.resolve(ancestorRoot) === path29.resolve(cwd)) {
24421
+ if (ancestorRoot && path31.resolve(ancestorRoot) === path31.resolve(cwd)) {
24191
24422
  logger.info("Project already initialized.");
24192
24423
  logger.info("Design your spec tree with the SDD architect skill, then run `wairon generate`.");
24193
24424
  return;
@@ -24203,8 +24434,8 @@ async function runInit(options = {}) {
24203
24434
  await runInitInteractive();
24204
24435
  }
24205
24436
  async function runInitAsExternalSubsystem(parentRoot, cwd, options) {
24206
- const relPath = path29.relative(parentRoot, cwd) || ".";
24207
- const defaultId = path29.basename(cwd);
24437
+ const relPath = path31.relative(parentRoot, cwd) || ".";
24438
+ const defaultId = path31.basename(cwd);
24208
24439
  logger.info(`Detected a parent wairon project at ${parentRoot}`);
24209
24440
  logger.info(`This directory ("${relPath}") is not yet a wairon project.`);
24210
24441
  if (!options.yes) {
@@ -24264,7 +24495,7 @@ async function runInitAsExternalSubsystem(parentRoot, cwd, options) {
24264
24495
  }
24265
24496
  async function runInitNonInteractive() {
24266
24497
  const cwd = process.cwd();
24267
- const projectName = path29.basename(cwd);
24498
+ const projectName = path31.basename(cwd);
24268
24499
  const now = (/* @__PURE__ */ new Date()).toISOString();
24269
24500
  const targets = [defaultTargetConfig("claude"), defaultTargetConfig("agy")];
24270
24501
  const projectConfig = buildProjectConfig(projectName, targets, now, "backend");
@@ -24286,7 +24517,7 @@ async function runInitNonInteractive() {
24286
24517
  }
24287
24518
  async function runInitInteractive() {
24288
24519
  const cwd = process.cwd();
24289
- const defaultProjectName = path29.basename(cwd);
24520
+ const defaultProjectName = path31.basename(cwd);
24290
24521
  const { projectName } = await import_inquirer.default.prompt([
24291
24522
  {
24292
24523
  type: "input",
@@ -24446,7 +24677,7 @@ async function executeInit(projectName, targets, projectConfig, guidePlan, now)
24446
24677
  projectRoot: projectRoot2,
24447
24678
  target: targetConfig
24448
24679
  });
24449
- logger.success(`Generated: ${path29.relative(cwd, result.outputPath)}`);
24680
+ logger.success(`Generated: ${path31.relative(cwd, result.outputPath)}`);
24450
24681
  }
24451
24682
  }
24452
24683
  writeStarterDocs(projectName);
@@ -24461,7 +24692,7 @@ async function executeInit(projectName, targets, projectConfig, guidePlan, now)
24461
24692
  if (guidePlan.claudeLocal) {
24462
24693
  const p = localGuideFilePath(projectRoot2, "claude");
24463
24694
  injectGuide(p, "local");
24464
- logger.success(`Injected wairon guide into ${path29.relative(cwd, p)}`);
24695
+ logger.success(`Injected wairon guide into ${path31.relative(cwd, p)}`);
24465
24696
  writeRootGuideDelegator(projectRoot2, "claude");
24466
24697
  logger.success(`Created root CLAUDE.md delegator pointing to .claude/CLAUDE.md`);
24467
24698
  }
@@ -24473,7 +24704,7 @@ async function executeInit(projectName, targets, projectConfig, guidePlan, now)
24473
24704
  if (guidePlan.geminiLocal) {
24474
24705
  const p = localGuideFilePath(projectRoot2, "gemini");
24475
24706
  injectGuide(p, "local");
24476
- logger.success(`Injected wairon guide into ${path29.relative(cwd, p)}`);
24707
+ logger.success(`Injected wairon guide into ${path31.relative(cwd, p)}`);
24477
24708
  writeRootGuideDelegator(projectRoot2, "gemini");
24478
24709
  logger.success(`Created root GEMINI.md delegator pointing to .gemini/GEMINI.md`);
24479
24710
  }
@@ -24706,8 +24937,8 @@ A new project initialized with Wairon.
24706
24937
  }
24707
24938
 
24708
24939
  // src/commands/generate.ts
24709
- var fs20 = __toESM(require("fs"));
24710
- var path30 = __toESM(require("path"));
24940
+ var fs21 = __toESM(require("fs"));
24941
+ var path32 = __toESM(require("path"));
24711
24942
  init_logger();
24712
24943
  init_loader();
24713
24944
  init_fs();
@@ -24715,29 +24946,29 @@ init_provision();
24715
24946
  init_specs2();
24716
24947
  var WAIRON_AGENT_FILE = /-(owner|implementer|architect)\.md$/;
24717
24948
  function pruneStaleAgents(expectedPaths, scanDirs) {
24718
- const dirs = new Set(scanDirs ?? [...expectedPaths].map((p) => path30.dirname(p)));
24949
+ const dirs = new Set(scanDirs ?? [...expectedPaths].map((p) => path32.dirname(p)));
24719
24950
  let pruned = 0;
24720
24951
  for (const dir of dirs) {
24721
24952
  let entries;
24722
24953
  try {
24723
- entries = fs20.readdirSync(dir);
24954
+ entries = fs21.readdirSync(dir);
24724
24955
  } catch {
24725
24956
  continue;
24726
24957
  }
24727
24958
  for (const name of entries) {
24728
24959
  if (!name.endsWith(".md")) continue;
24729
- const full = path30.resolve(dir, name);
24960
+ const full = path32.resolve(dir, name);
24730
24961
  if (expectedPaths.has(full)) continue;
24731
24962
  let owned = WAIRON_AGENT_FILE.test(name);
24732
24963
  if (!owned) {
24733
24964
  try {
24734
- owned = fs20.readFileSync(full, "utf8").includes(WAIRON_MANAGED_MARKER);
24965
+ owned = fs21.readFileSync(full, "utf8").includes(WAIRON_MANAGED_MARKER);
24735
24966
  } catch {
24736
24967
  owned = false;
24737
24968
  }
24738
24969
  }
24739
24970
  if (!owned) continue;
24740
- fs20.unlinkSync(full);
24971
+ fs21.unlinkSync(full);
24741
24972
  pruned++;
24742
24973
  logger.verbose(`Pruned stale: ${full}`);
24743
24974
  }
@@ -24751,7 +24982,7 @@ async function runGenerate(options = {}) {
24751
24982
  const children = listDirectChainedSubprojects(getProjectRoot());
24752
24983
  for (const child of children) {
24753
24984
  logger.blank();
24754
- logger.info(`\u21B3 Chained subproject "${child.subsystemId}" \u2014 generating its layer in ${path30.relative(getProjectRoot(), child.dir) || "."}/`);
24985
+ logger.info(`\u21B3 Chained subproject "${child.subsystemId}" \u2014 generating its layer in ${path32.relative(getProjectRoot(), child.dir) || "."}/`);
24755
24986
  await runWithProjectRoot(child.dir, async () => {
24756
24987
  ensureProjectInitialized(child.subsystemId);
24757
24988
  invalidateSpecCache();
@@ -24772,7 +25003,7 @@ async function generateLayer(options = {}) {
24772
25003
  } else if (options.dryRun) {
24773
25004
  logger.info("Dry run \u2014 rules.materializeAgentFiles is off: no agent files are written; leftover managed files would be removed.");
24774
25005
  } else if (options.prune !== false) {
24775
- const candidateDirs = [...resolveExpectedOutputPaths(registry.agents, projectConfig)].map((p) => path30.dirname(p));
25006
+ const candidateDirs = [...resolveExpectedOutputPaths(registry.agents, projectConfig)].map((p) => path32.dirname(p));
24776
25007
  const removed = pruneStaleAgents(/* @__PURE__ */ new Set(), candidateDirs);
24777
25008
  if (removed > 0) {
24778
25009
  logger.info(`Removed ${removed} previously materialized agent file(s) \u2014 agents are served as live briefs (sdd_get_agent_brief); opt back in with rules.materializeAgentFiles: true.`);
@@ -24859,22 +25090,34 @@ function materializeAgentLayer(agents, projectConfig, options) {
24859
25090
  }
24860
25091
 
24861
25092
  // src/commands/lock.ts
24862
- var os7 = __toESM(require("os"));
25093
+ var os8 = __toESM(require("os"));
24863
25094
  var import_inquirer2 = __toESM(require("inquirer"));
24864
25095
  init_logger();
25096
+ init_baseline();
24865
25097
  init_defaults();
25098
+ var path33 = __toESM(require("path"));
25099
+ init_fs();
24866
25100
  async function runLock(options = {}, gate) {
24867
- const promotable = collectPromotableSpecs(options.subsystem);
24868
- if (promotable.length === 0) {
24869
- logger.info("All specs are already complete \u2014 this will re-validate and regenerate the agent topology.");
25101
+ const diff = diffAgainstBaseline();
25102
+ if (!diff) {
25103
+ logger.info("First approval of this tree \u2014 the whole spec tree becomes the approved baseline.");
25104
+ } else if (diffSize(diff) === 0) {
25105
+ logger.info("Nothing has changed since the last approval \u2014 this will re-validate and regenerate the agent topology.");
24870
25106
  } else {
24871
- logger.info(`${promotable.length} spec(s) will be frozen as complete:`);
24872
- for (const p of promotable) {
24873
- logger.info(` \u2022 ${p.kind.padEnd(14)} ${p.id} (${p.status} \u2192 complete)`);
25107
+ logger.info(`${diffSize(diff)} spec(s) changed since the last approval:`);
25108
+ for (const p of diff.changed) logger.info(` ~ ${p}`);
25109
+ for (const p of diff.added) logger.info(` + ${p}`);
25110
+ for (const p of diff.removed) logger.info(` - ${p}`);
25111
+ }
25112
+ const moved = movedChildren(loadSubsystemSpecs());
25113
+ if (moved.length > 0) {
25114
+ logger.info(`${moved.length} chained child project(s) moved since the last approval:`);
25115
+ for (const m of moved) {
25116
+ logger.info(` ${m.id}: ${m.pinned.slice(0, 19)}\u2026 \u2192 ${m.now ? `${m.now.slice(0, 19)}\u2026` : "(no approval)"}`);
24874
25117
  }
24875
25118
  }
24876
25119
  logger.blank();
24877
- logger.warn("This freezes the design as the source of truth and (re)generates the agent topology.");
25120
+ logger.warn("This records the current design as approved and (re)generates the agent topology.");
24878
25121
  if (!options.yes) {
24879
25122
  if (!process.stdin.isTTY) {
24880
25123
  logger.error("Non-interactive shell \u2014 re-run with --yes to confirm the lock.");
@@ -24884,24 +25127,15 @@ async function runLock(options = {}, gate) {
24884
25127
  {
24885
25128
  type: "confirm",
24886
25129
  name: "confirmed",
24887
- message: "Lock these specs and generate the agent topology? This freezes the design.",
25130
+ message: "Approve this design and generate the agent topology?",
24888
25131
  default: false
24889
25132
  }
24890
25133
  ]);
24891
25134
  if (!confirmed) return null;
24892
25135
  }
24893
- if (options.subsystem) {
24894
- for (const p of promotable) applySpecStatus(p.kind, p.id, "complete");
24895
- invalidateSpecCache();
24896
- } else {
24897
- promoteAllComplete();
24898
- }
24899
- if (promotable.length > 0) {
24900
- logger.success(`Locked ${promotable.length} spec(s) as complete.`);
24901
- }
24902
25136
  let lockedBy = "local";
24903
25137
  try {
24904
- lockedBy = `local:${os7.userInfo().username}`;
25138
+ lockedBy = `local:${os8.userInfo().username}`;
24905
25139
  } catch {
24906
25140
  }
24907
25141
  const record2 = {
@@ -24917,6 +25151,13 @@ async function runLock(options = {}, gate) {
24917
25151
  status: "ready"
24918
25152
  };
24919
25153
  writeLockRecord(record2);
25154
+ const root = getProjectRoot();
25155
+ const scope = options.subsystem ? {
25156
+ paths: new Set(
25157
+ specPathsInScope(options.subsystem).map((p) => path33.relative(root, p).split(path33.sep).join("/"))
25158
+ )
25159
+ } : void 0;
25160
+ writeBaseline(captureBaseline(lockedBy, currentChildPins(loadSubsystemSpecs(), root), root, scope));
24920
25161
  return record2;
24921
25162
  }
24922
25163
 
@@ -25173,29 +25414,29 @@ init_mcp();
25173
25414
 
25174
25415
  // src/commands/update.ts
25175
25416
  var https2 = __toESM(require("https"));
25176
- var fs22 = __toESM(require("fs"));
25177
- var path31 = __toESM(require("path"));
25178
- var os8 = __toESM(require("os"));
25179
- var crypto3 = __toESM(require("crypto"));
25417
+ var fs23 = __toESM(require("fs"));
25418
+ var path34 = __toESM(require("path"));
25419
+ var os9 = __toESM(require("os"));
25420
+ var crypto4 = __toESM(require("crypto"));
25180
25421
  var import_child_process2 = require("child_process");
25181
25422
  init_logger();
25182
25423
  init_defaults();
25183
25424
  init_version();
25184
25425
 
25185
25426
  // src/utils/download.ts
25186
- var fs21 = __toESM(require("fs"));
25427
+ var fs22 = __toESM(require("fs"));
25187
25428
  var http = __toESM(require("http"));
25188
25429
  var https = __toESM(require("https"));
25189
25430
  init_defaults();
25190
25431
  function downloadFile(url, dest) {
25191
- return new Promise((resolve26, reject) => {
25192
- const file = fs21.createWriteStream(dest);
25432
+ return new Promise((resolve27, reject) => {
25433
+ const file = fs22.createWriteStream(dest);
25193
25434
  const get4 = url.startsWith("https://") ? https.get : http.get;
25194
25435
  get4(url, { headers: { "User-Agent": `wairon/${WAIRON_VERSION}` }, agent: false }, (res) => {
25195
25436
  if (res.statusCode === 301 || res.statusCode === 302) {
25196
25437
  file.close();
25197
25438
  res.destroy();
25198
- downloadFile(res.headers.location, dest).then(resolve26).catch(reject);
25439
+ downloadFile(res.headers.location, dest).then(resolve27).catch(reject);
25199
25440
  return;
25200
25441
  }
25201
25442
  if (res.statusCode !== 200) {
@@ -25207,16 +25448,16 @@ function downloadFile(url, dest) {
25207
25448
  res.pipe(file);
25208
25449
  file.on("finish", () => {
25209
25450
  res.destroy();
25210
- file.close(() => resolve26());
25451
+ file.close(() => resolve27());
25211
25452
  });
25212
25453
  file.on("error", (err) => {
25213
25454
  res.destroy();
25214
- fs21.unlink(dest, () => {
25455
+ fs22.unlink(dest, () => {
25215
25456
  });
25216
25457
  reject(err);
25217
25458
  });
25218
25459
  }).on("error", (err) => {
25219
- fs21.unlink(dest, () => {
25460
+ fs22.unlink(dest, () => {
25220
25461
  });
25221
25462
  reject(err);
25222
25463
  });
@@ -25282,8 +25523,8 @@ async function runUpdate(options = {}) {
25282
25523
  logger.info(`Download manually from: ${release.html_url}`);
25283
25524
  process.exit(1);
25284
25525
  }
25285
- const tmpDir = os8.tmpdir();
25286
- const tmpFile = path31.join(tmpDir, assetName);
25526
+ const tmpDir = os9.tmpdir();
25527
+ const tmpFile = path34.join(tmpDir, assetName);
25287
25528
  logger.info(`Downloading ${assetName}...`);
25288
25529
  try {
25289
25530
  await downloadFile(asset.browser_download_url, tmpFile);
@@ -25300,16 +25541,16 @@ async function runUpdate(options = {}) {
25300
25541
  const checksumAssetName = assetName + ".sha256";
25301
25542
  const checksumAsset = release.assets.find((a) => a.name === checksumAssetName);
25302
25543
  if (checksumAsset) {
25303
- const tmpChecksum = path31.join(tmpDir, checksumAssetName);
25544
+ const tmpChecksum = path34.join(tmpDir, checksumAssetName);
25304
25545
  logger.info(`Verifying checksum...`);
25305
25546
  try {
25306
25547
  await downloadFile(checksumAsset.browser_download_url, tmpChecksum);
25307
25548
  verifyChecksum(tmpFile, tmpChecksum, assetName);
25308
- fs22.unlinkSync(tmpChecksum);
25549
+ fs23.unlinkSync(tmpChecksum);
25309
25550
  } catch (err) {
25310
25551
  logger.error(`Checksum verification failed: ${err.message}`);
25311
25552
  try {
25312
- fs22.unlinkSync(tmpFile);
25553
+ fs23.unlinkSync(tmpFile);
25313
25554
  } catch {
25314
25555
  }
25315
25556
  process.exit(1);
@@ -25344,7 +25585,7 @@ function releaseChannelLabel(tag) {
25344
25585
  return "stable";
25345
25586
  }
25346
25587
  function fetchReleases(repo) {
25347
- return new Promise((resolve26, reject) => {
25588
+ return new Promise((resolve27, reject) => {
25348
25589
  const url = `https://api.github.com/repos/${repo}/releases?per_page=20`;
25349
25590
  const options = {
25350
25591
  headers: {
@@ -25364,7 +25605,7 @@ function fetchReleases(repo) {
25364
25605
  return;
25365
25606
  }
25366
25607
  try {
25367
- resolve26(JSON.parse(data));
25608
+ resolve27(JSON.parse(data));
25368
25609
  } catch {
25369
25610
  reject(new Error("Failed to parse GitHub API response"));
25370
25611
  }
@@ -25374,10 +25615,10 @@ function fetchReleases(repo) {
25374
25615
  });
25375
25616
  }
25376
25617
  function verifyChecksum(filePath, checksumFile, expectedFilename) {
25377
- const checksumContent = fs22.readFileSync(checksumFile, "utf-8").trim();
25618
+ const checksumContent = fs23.readFileSync(checksumFile, "utf-8").trim();
25378
25619
  const expectedHash = checksumContent.split(/\s+/)[0].toLowerCase();
25379
- const fileBuffer = fs22.readFileSync(filePath);
25380
- const actualHash = crypto3.createHash("sha256").update(fileBuffer).digest("hex").toLowerCase();
25620
+ const fileBuffer = fs23.readFileSync(filePath);
25621
+ const actualHash = crypto4.createHash("sha256").update(fileBuffer).digest("hex").toLowerCase();
25381
25622
  if (actualHash !== expectedHash) {
25382
25623
  throw new Error(
25383
25624
  `SHA-256 mismatch for ${expectedFilename}
@@ -25407,9 +25648,9 @@ function isPkgBinary2() {
25407
25648
  function installBinary(tmpFile, destPath) {
25408
25649
  const platform = process.platform;
25409
25650
  const isZip = tmpFile.endsWith(".zip");
25410
- const extractDir = path31.join(os8.tmpdir(), "wairon-extract");
25411
- if (fs22.existsSync(extractDir)) fs22.rmSync(extractDir, { recursive: true });
25412
- fs22.mkdirSync(extractDir, { recursive: true });
25651
+ const extractDir = path34.join(os9.tmpdir(), "wairon-extract");
25652
+ if (fs23.existsSync(extractDir)) fs23.rmSync(extractDir, { recursive: true });
25653
+ fs23.mkdirSync(extractDir, { recursive: true });
25413
25654
  if (isZip) {
25414
25655
  (0, import_child_process2.execSync)(
25415
25656
  `powershell -NoProfile -NonInteractive -Command "Expand-Archive -Path '${tmpFile}' -DestinationPath '${extractDir}' -Force"`,
@@ -25419,18 +25660,18 @@ function installBinary(tmpFile, destPath) {
25419
25660
  (0, import_child_process2.execSync)(`tar -xzf "${tmpFile}" -C "${extractDir}"`, { stdio: ["ignore", "pipe", "pipe"] });
25420
25661
  }
25421
25662
  const binaryName = platform === "win32" ? "wairon.exe" : "wairon";
25422
- const extractedBinary = path31.join(extractDir, binaryName);
25423
- if (!fs22.existsSync(extractedBinary)) {
25663
+ const extractedBinary = path34.join(extractDir, binaryName);
25664
+ if (!fs23.existsSync(extractedBinary)) {
25424
25665
  throw new Error(`Extracted binary not found at ${extractedBinary}`);
25425
25666
  }
25426
25667
  if (platform === "win32") {
25427
25668
  const oldPath = destPath + ".old";
25428
25669
  try {
25429
25670
  cleanStaleBinary(oldPath);
25430
- fs22.renameSync(destPath, oldPath);
25431
- fs22.copyFileSync(extractedBinary, destPath);
25671
+ fs23.renameSync(destPath, oldPath);
25672
+ fs23.copyFileSync(extractedBinary, destPath);
25432
25673
  try {
25433
- fs22.unlinkSync(oldPath);
25674
+ fs23.unlinkSync(oldPath);
25434
25675
  } catch {
25435
25676
  }
25436
25677
  } catch (err) {
@@ -25444,25 +25685,25 @@ function installBinary(tmpFile, destPath) {
25444
25685
  }
25445
25686
  } else {
25446
25687
  const tmpDest = destPath + ".new";
25447
- fs22.copyFileSync(extractedBinary, tmpDest);
25448
- fs22.chmodSync(tmpDest, 493);
25449
- fs22.renameSync(tmpDest, destPath);
25688
+ fs23.copyFileSync(extractedBinary, tmpDest);
25689
+ fs23.chmodSync(tmpDest, 493);
25690
+ fs23.renameSync(tmpDest, destPath);
25450
25691
  }
25451
25692
  try {
25452
- fs22.unlinkSync(tmpFile);
25693
+ fs23.unlinkSync(tmpFile);
25453
25694
  } catch {
25454
25695
  }
25455
25696
  try {
25456
- fs22.rmSync(extractDir, { recursive: true });
25697
+ fs23.rmSync(extractDir, { recursive: true });
25457
25698
  } catch {
25458
25699
  }
25459
25700
  }
25460
25701
  function cleanStaleBinary(oldPath) {
25461
25702
  const target = oldPath ?? (isPkgBinary2() ? process.execPath + ".old" : null);
25462
25703
  if (!target) return;
25463
- if (fs22.existsSync(target)) {
25704
+ if (fs23.existsSync(target)) {
25464
25705
  try {
25465
- fs22.unlinkSync(target);
25706
+ fs23.unlinkSync(target);
25466
25707
  } catch {
25467
25708
  }
25468
25709
  }
@@ -25539,7 +25780,7 @@ async function filteredCheckbox(config) {
25539
25780
  32,
25540
25781
  Math.max(...items.map((i) => i.label.length))
25541
25782
  );
25542
- return new Promise((resolve26) => {
25783
+ return new Promise((resolve27) => {
25543
25784
  const checked = /* @__PURE__ */ new Set();
25544
25785
  let cursor = 0;
25545
25786
  let filterIdx = 0;
@@ -25606,7 +25847,7 @@ async function filteredCheckbox(config) {
25606
25847
  );
25607
25848
  teardown();
25608
25849
  const result = items.filter((_, idx) => checked.has(idx)).map((i) => i.value);
25609
- resolve26(result);
25850
+ resolve27(result);
25610
25851
  }
25611
25852
  function abort() {
25612
25853
  process.stdout.write("\n");
@@ -25878,9 +26119,9 @@ async function runSkillsInstall() {
25878
26119
  }
25879
26120
 
25880
26121
  // src/commands/doctor.ts
25881
- var fs23 = __toESM(require("fs"));
25882
- var os9 = __toESM(require("os"));
25883
- var path32 = __toESM(require("path"));
26122
+ var fs24 = __toESM(require("fs"));
26123
+ var os10 = __toESM(require("os"));
26124
+ var path35 = __toESM(require("path"));
25884
26125
  var import_chalk12 = __toESM(require("chalk"));
25885
26126
  init_logger();
25886
26127
  init_defaults();
@@ -25911,10 +26152,10 @@ function stampVerdict(content) {
25911
26152
  return { mark: "warn", note: `v${v} \u2014 stale, installed is v${WAIRON_VERSION}` };
25912
26153
  }
25913
26154
  function mcpEntryHealth(settingsPath) {
25914
- if (!fs23.existsSync(settingsPath)) return { mark: "warn", note: "not registered" };
26155
+ if (!fs24.existsSync(settingsPath)) return { mark: "warn", note: "not registered" };
25915
26156
  let entry;
25916
26157
  try {
25917
- const s = JSON.parse(fs23.readFileSync(settingsPath, "utf8"));
26158
+ const s = JSON.parse(fs24.readFileSync(settingsPath, "utf8"));
25918
26159
  entry = s.mcpServers?.["wairon"];
25919
26160
  } catch {
25920
26161
  return { mark: "error", note: "parse error" };
@@ -25922,7 +26163,7 @@ function mcpEntryHealth(settingsPath) {
25922
26163
  if (!entry) return { mark: "warn", note: "not registered" };
25923
26164
  if (entry.command === "node" && Array.isArray(entry.args) && typeof entry.args[0] === "string") {
25924
26165
  const scriptPath = entry.args[0];
25925
- if (!fs23.existsSync(scriptPath)) {
26166
+ if (!fs24.existsSync(scriptPath)) {
25926
26167
  return { mark: "error", note: `registered but the server path is missing \u2014 ${scriptPath}` };
25927
26168
  }
25928
26169
  }
@@ -25974,7 +26215,7 @@ async function runDoctor(options = {}) {
25974
26215
  const { findChainingSubprojectsMissingConfig: findChainingSubprojectsMissingConfig2 } = (init_provision(), __toCommonJS(provision_exports));
25975
26216
  const missing = findChainingSubprojectsMissingConfig2(getProjectRoot());
25976
26217
  if (missing.length > 0) {
25977
- line(tally, "warn", `${missing.length} chained subproject(s) have specs but no project.yaml (un-runnable standalone): ${missing.map((d) => path32.relative(getProjectRoot(), d) || ".").join(", ")}. Run \`wairon doctor --fix\` to initialize them.`);
26218
+ line(tally, "warn", `${missing.length} chained subproject(s) have specs but no project.yaml (un-runnable standalone): ${missing.map((d) => path35.relative(getProjectRoot(), d) || ".").join(", ")}. Run \`wairon doctor --fix\` to initialize them.`);
25978
26219
  }
25979
26220
  } catch {
25980
26221
  }
@@ -26012,7 +26253,7 @@ async function runDoctor(options = {}) {
26012
26253
  const gp = localGuideFilePath(process.cwd(), t);
26013
26254
  if (!gp || seenGuides.has(gp)) continue;
26014
26255
  seenGuides.add(gp);
26015
- const rel2 = path32.relative(process.cwd(), gp).replace(/\\/g, "/");
26256
+ const rel2 = path35.relative(process.cwd(), gp).replace(/\\/g, "/");
26016
26257
  if (!pathExists(gp)) {
26017
26258
  line(tally, "warn", `${rel2} guide \u2014 not injected (run \`wairon generate\`)`);
26018
26259
  continue;
@@ -26094,17 +26335,17 @@ async function runDoctor(options = {}) {
26094
26335
  line(tally, h.mark, `Claude (project .mcp.json): ${h.note}${h.mark === "ok" ? "" : " \u2014 run `wairon mcp install --backend claude`"}`);
26095
26336
  }
26096
26337
  if (wantGemini) {
26097
- const globalCfg = path32.join(os9.homedir(), ".gemini", "antigravity-cli", "mcp_config.json");
26338
+ const globalCfg = path35.join(os10.homedir(), ".gemini", "antigravity-cli", "mcp_config.json");
26098
26339
  const hg = mcpEntryHealth(globalCfg);
26099
26340
  line(tally, hg.mark, `Antigravity (global mcp_config.json): ${hg.note}${hg.mark === "ok" ? "" : " \u2014 run `wairon mcp install --backend gemini --global`"}`);
26100
26341
  const projPath = fromProjectRoot(".gemini", "settings.json");
26101
- if (fs23.existsSync(projPath)) {
26342
+ if (fs24.existsSync(projPath)) {
26102
26343
  const hp = mcpEntryHealth(projPath);
26103
26344
  line(tally, hp.mark === "error" ? "error" : "ok", `Gemini CLI (project): ${hp.note} ${import_chalk12.default.gray("(Antigravity ignores this file)")}`);
26104
26345
  }
26105
26346
  }
26106
- const pluginDir = path32.join(os9.homedir(), ".gemini", "config", "plugins", "wairon");
26107
- if (fs23.existsSync(pluginDir)) {
26347
+ const pluginDir = path35.join(os10.homedir(), ".gemini", "config", "plugins", "wairon");
26348
+ if (fs24.existsSync(pluginDir)) {
26108
26349
  line(tally, "warn", `Legacy Antigravity plugin present (${pluginDir}) \u2014 it collides with the wairon MCP server. Remove it with \`wairon doctor --fix\`.`);
26109
26350
  }
26110
26351
  logger.blank();
@@ -26143,7 +26384,7 @@ async function applyFixes() {
26143
26384
  const legacySpecs = findLegacySpecFiles();
26144
26385
  if (legacySpecs.length > 0) {
26145
26386
  for (const { path: oldPath, expected: newPath } of legacySpecs) {
26146
- fs23.renameSync(oldPath, newPath);
26387
+ fs24.renameSync(oldPath, newPath);
26147
26388
  }
26148
26389
  console.log(` ${icon("ok")} Migrated ${legacySpecs.length} legacy spec file(s) to the new dot-prefixed unified schema.`);
26149
26390
  }
@@ -26197,8 +26438,8 @@ function printSummary(tally) {
26197
26438
  }
26198
26439
 
26199
26440
  // src/commands/diagram.ts
26200
- var fs24 = __toESM(require("fs"));
26201
- var path33 = __toESM(require("path"));
26441
+ var fs25 = __toESM(require("fs"));
26442
+ var path36 = __toESM(require("path"));
26202
26443
  init_logger();
26203
26444
  init_loader();
26204
26445
  init_fs();
@@ -26233,71 +26474,71 @@ function collectIssues() {
26233
26474
  }
26234
26475
  function writeCanvas(dest) {
26235
26476
  const model = buildCanvasModel(collectIssues());
26236
- ensureDir(path33.dirname(path33.resolve(dest)));
26237
- fs24.writeFileSync(dest, renderCanvasHtml(model), "utf-8");
26477
+ ensureDir(path36.dirname(path36.resolve(dest)));
26478
+ fs25.writeFileSync(dest, renderCanvasHtml(model), "utf-8");
26238
26479
  }
26239
26480
  function parseSequenceRef(ref) {
26240
- const sep6 = ref.includes(":") ? ref.lastIndexOf(":") : ref.lastIndexOf(".");
26241
- if (sep6 <= 0 || sep6 === ref.length - 1) {
26481
+ const sep9 = ref.includes(":") ? ref.lastIndexOf(":") : ref.lastIndexOf(".");
26482
+ if (sep9 <= 0 || sep9 === ref.length - 1) {
26242
26483
  throw new WaironError(
26243
26484
  `Invalid --sequence reference "${ref}". Use <componentId>:<methodName> (e.g. billing-portal:authorize).`
26244
26485
  );
26245
26486
  }
26246
- return { component: ref.slice(0, sep6), method: ref.slice(sep6 + 1) };
26487
+ return { component: ref.slice(0, sep9), method: ref.slice(sep9 + 1) };
26247
26488
  }
26248
26489
  async function runDiagram(rawOptions = {}) {
26249
26490
  assertProjectInitialized();
26250
26491
  const options = applyFormat(rawOptions);
26251
26492
  if (options.canvas && !options.all) {
26252
- const dest2 = options.out ?? path33.join(AI_PATHS.docsDir(), "diagrams", "canvas.html");
26493
+ const dest2 = options.out ?? path36.join(AI_PATHS.docsDir(), "diagrams", "canvas.html");
26253
26494
  writeCanvas(dest2);
26254
26495
  logger.success(`Interactive canvas written to ${dest2}`);
26255
26496
  logger.info("Open it in a browser \u2014 fully self-contained (works offline).");
26256
26497
  return;
26257
26498
  }
26258
26499
  if (options.drawio && !options.all) {
26259
- const dest2 = options.out ?? path33.join(AI_PATHS.docsDir(), "diagrams", "architecture.drawio");
26260
- ensureDir(path33.dirname(path33.resolve(dest2)));
26261
- fs24.writeFileSync(dest2, generateDrawioXml(buildCanvasModel()), "utf-8");
26500
+ const dest2 = options.out ?? path36.join(AI_PATHS.docsDir(), "diagrams", "architecture.drawio");
26501
+ ensureDir(path36.dirname(path36.resolve(dest2)));
26502
+ fs25.writeFileSync(dest2, generateDrawioXml(buildCanvasModel()), "utf-8");
26262
26503
  logger.success(`draw.io diagram written to ${dest2}`);
26263
26504
  logger.info("Open with draw.io / diagrams.net (or import into tools that accept the format).");
26264
26505
  return;
26265
26506
  }
26266
26507
  if (options.excalidraw && !options.all) {
26267
- const dest2 = options.out ?? path33.join(AI_PATHS.docsDir(), "diagrams", "architecture.excalidraw");
26268
- ensureDir(path33.dirname(path33.resolve(dest2)));
26269
- fs24.writeFileSync(dest2, generateExcalidrawScene(buildCanvasModel()), "utf-8");
26508
+ const dest2 = options.out ?? path36.join(AI_PATHS.docsDir(), "diagrams", "architecture.excalidraw");
26509
+ ensureDir(path36.dirname(path36.resolve(dest2)));
26510
+ fs25.writeFileSync(dest2, generateExcalidrawScene(buildCanvasModel()), "utf-8");
26270
26511
  logger.success(`Excalidraw scene written to ${dest2}`);
26271
26512
  logger.info("Open with excalidraw.com or the VS Code extension.");
26272
26513
  return;
26273
26514
  }
26274
26515
  const wantsMermaid = options.format?.toLowerCase().startsWith("mermaid") || !!options.subsystem || !!options.sequence;
26275
26516
  if (!options.all && !options.sequence && !wantsMermaid) {
26276
- const dest2 = options.out ?? path33.join(AI_PATHS.docsDir(), "diagrams", "canvas.html");
26517
+ const dest2 = options.out ?? path36.join(AI_PATHS.docsDir(), "diagrams", "canvas.html");
26277
26518
  writeCanvas(dest2);
26278
26519
  logger.success(`Interactive canvas written to ${dest2}`);
26279
26520
  logger.info("Open it in a browser \u2014 fully self-contained (works offline). Other formats: --format mermaid|drawio|excalidraw.");
26280
26521
  return;
26281
26522
  }
26282
26523
  if (options.all) {
26283
- const outDir = options.out ?? path33.join(AI_PATHS.docsDir(), "diagrams");
26524
+ const outDir = options.out ?? path36.join(AI_PATHS.docsDir(), "diagrams");
26284
26525
  const files = generateDiagramSet();
26285
26526
  if (files.length === 0) {
26286
26527
  logger.warn("No diagrams to generate \u2014 the spec tree has no components yet.");
26287
26528
  return;
26288
26529
  }
26289
26530
  for (const file of files) {
26290
- const dest2 = path33.join(outDir, file.relPath);
26291
- ensureDir(path33.dirname(dest2));
26292
- fs24.writeFileSync(dest2, toMarkdown(file), "utf-8");
26531
+ const dest2 = path36.join(outDir, file.relPath);
26532
+ ensureDir(path36.dirname(dest2));
26533
+ fs25.writeFileSync(dest2, toMarkdown(file), "utf-8");
26293
26534
  }
26294
- writeCanvas(path33.join(outDir, "canvas.html"));
26535
+ writeCanvas(path36.join(outDir, "canvas.html"));
26295
26536
  const exportModel = buildCanvasModel();
26296
- fs24.writeFileSync(path33.join(outDir, "architecture.drawio"), generateDrawioXml(exportModel), "utf-8");
26297
- fs24.writeFileSync(path33.join(outDir, "architecture.excalidraw"), generateExcalidrawScene(exportModel), "utf-8");
26537
+ fs25.writeFileSync(path36.join(outDir, "architecture.drawio"), generateDrawioXml(exportModel), "utf-8");
26538
+ fs25.writeFileSync(path36.join(outDir, "architecture.excalidraw"), generateExcalidrawScene(exportModel), "utf-8");
26298
26539
  const graph = loadSpecGraph();
26299
- const indexPath = path33.join(outDir, "README.md");
26300
- fs24.writeFileSync(indexPath, diagramSetIndex(files, graph.systemName), "utf-8");
26540
+ const indexPath = path36.join(outDir, "README.md");
26541
+ fs25.writeFileSync(indexPath, diagramSetIndex(files, graph.systemName), "utf-8");
26301
26542
  logger.success(`Generated ${files.length} diagram(s) + interactive canvas.html + index into ${outDir}`);
26302
26543
  for (const file of files.slice(0, 12)) {
26303
26544
  logger.info(` ${file.relPath}`);
@@ -26308,26 +26549,26 @@ async function runDiagram(rawOptions = {}) {
26308
26549
  let mermaid;
26309
26550
  let title;
26310
26551
  let defaultDest;
26311
- const diagramsDir = path33.join(AI_PATHS.docsDir(), "diagrams");
26552
+ const diagramsDir = path36.join(AI_PATHS.docsDir(), "diagrams");
26312
26553
  if (options.sequence) {
26313
26554
  const { component, method: method2 } = parseSequenceRef(options.sequence);
26314
26555
  mermaid = generateSequenceDiagram(component, method2, { depth: options.depth });
26315
26556
  title = `${component}.${method2} \u2014 narrative sequence`;
26316
- defaultDest = path33.join(diagramsDir, "sequences", `${component.replace(/::/g, "--")}.${method2}.md`);
26557
+ defaultDest = path36.join(diagramsDir, "sequences", `${component.replace(/::/g, "--")}.${method2}.md`);
26317
26558
  } else if (options.subsystem) {
26318
26559
  mermaid = generateComponentDiagram({ subsystem: options.subsystem });
26319
26560
  title = `${options.subsystem} \u2014 components`;
26320
- defaultDest = path33.join(diagramsDir, "subsystems", `${options.subsystem.replace(/::/g, "--")}.md`);
26561
+ defaultDest = path36.join(diagramsDir, "subsystems", `${options.subsystem.replace(/::/g, "--")}.md`);
26321
26562
  } else {
26322
26563
  mermaid = generateComponentDiagram();
26323
26564
  title = "Component architecture";
26324
- defaultDest = path33.join(diagramsDir, "system.md");
26565
+ defaultDest = path36.join(diagramsDir, "system.md");
26325
26566
  }
26326
26567
  const dest = options.out ?? defaultDest;
26327
- ensureDir(path33.dirname(path33.resolve(dest)));
26568
+ ensureDir(path36.dirname(path36.resolve(dest)));
26328
26569
  const content = dest.endsWith(".mmd") ? `${mermaid}
26329
26570
  ` : toMarkdown({ relPath: dest, title, mermaid });
26330
- fs24.writeFileSync(dest, content, "utf-8");
26571
+ fs25.writeFileSync(dest, content, "utf-8");
26331
26572
  logger.success(`Mermaid diagram written to ${dest}`);
26332
26573
  logger.info("Renders on GitHub/IDE previews; use a .mmd --out path for raw Mermaid.");
26333
26574
  }
@@ -26436,9 +26677,9 @@ Component variants (${variants.length})
26436
26677
  }
26437
26678
 
26438
26679
  // src/commands/packs.ts
26439
- var fs25 = __toESM(require("fs"));
26440
- var os10 = __toESM(require("os"));
26441
- var path34 = __toESM(require("path"));
26680
+ var fs26 = __toESM(require("fs"));
26681
+ var os11 = __toESM(require("os"));
26682
+ var path37 = __toESM(require("path"));
26442
26683
  var import_chalk16 = __toESM(require("chalk"));
26443
26684
  var import_sdk = __toESM(require_dist());
26444
26685
  init_logger();
@@ -26464,11 +26705,11 @@ function describe(probe2) {
26464
26705
  return parts.join(", ");
26465
26706
  }
26466
26707
  function resolveSourceUnit(source) {
26467
- const abs = path34.resolve(source);
26468
- if (!fs25.existsSync(abs)) {
26708
+ const abs = path37.resolve(source);
26709
+ if (!fs26.existsSync(abs)) {
26469
26710
  throw new Error(`Pack source "${source}" does not exist.`);
26470
26711
  }
26471
- const isDir = fs25.statSync(abs).isDirectory();
26712
+ const isDir = fs26.statSync(abs).isDirectory();
26472
26713
  if (isDir && !packDirEntry(abs)) {
26473
26714
  throw new Error(`"${source}" is a directory without a pack entry file (pack.yaml | pack.cjs | index.cjs | ...).`);
26474
26715
  }
@@ -26484,7 +26725,7 @@ async function addPack(source, options = {}) {
26484
26725
  }
26485
26726
  const { abs } = resolveSourceUnit(source);
26486
26727
  const scope = options.global ? "global" : "project";
26487
- const probe2 = probePack(abs, path34.dirname(abs), scope);
26728
+ const probe2 = probePack(abs, path37.dirname(abs), scope);
26488
26729
  if (probe2.error) {
26489
26730
  logger.error(probe2.error);
26490
26731
  process.exitCode = 1;
@@ -26492,10 +26733,10 @@ async function addPack(source, options = {}) {
26492
26733
  }
26493
26734
  if (options.global) {
26494
26735
  const destDir = globalPacksDir();
26495
- const dest2 = path34.join(destDir, path34.basename(abs));
26496
- if (path34.resolve(dest2) !== abs) {
26497
- fs25.mkdirSync(destDir, { recursive: true });
26498
- fs25.cpSync(abs, dest2, { recursive: true, force: true });
26736
+ const dest2 = path37.join(destDir, path37.basename(abs));
26737
+ if (path37.resolve(dest2) !== abs) {
26738
+ fs26.mkdirSync(destDir, { recursive: true });
26739
+ fs26.cpSync(abs, dest2, { recursive: true, force: true });
26499
26740
  }
26500
26741
  logger.success(`Installed pack "${probe2.name}" globally: ${dest2}`);
26501
26742
  logger.info(`${describe(probe2)} \u2014 auto-loaded for every project on this machine (WAIRON_PACKS_DIR / ~/.wairon/packs).`);
@@ -26508,11 +26749,11 @@ async function addPack(source, options = {}) {
26508
26749
  return;
26509
26750
  }
26510
26751
  const root = getProjectRoot();
26511
- const relRef = `.wai/packs/${path34.basename(abs)}`;
26512
- const dest = path34.join(root, ".wai", "packs", path34.basename(abs));
26513
- if (path34.resolve(dest) !== abs) {
26514
- fs25.mkdirSync(path34.dirname(dest), { recursive: true });
26515
- fs25.cpSync(abs, dest, { recursive: true, force: true });
26752
+ const relRef = `.wai/packs/${path37.basename(abs)}`;
26753
+ const dest = path37.join(root, ".wai", "packs", path37.basename(abs));
26754
+ if (path37.resolve(dest) !== abs) {
26755
+ fs26.mkdirSync(path37.dirname(dest), { recursive: true });
26756
+ fs26.cpSync(abs, dest, { recursive: true, force: true });
26516
26757
  }
26517
26758
  const config = loadProjectConfig();
26518
26759
  const packs = config.extensions?.packs ?? [];
@@ -26521,14 +26762,14 @@ async function addPack(source, options = {}) {
26521
26762
  saveProjectConfig(config);
26522
26763
  logger.success(`Vendored pack "${probe2.name}" into ${relRef} and registered it in .wai/project.yaml.`);
26523
26764
  } else {
26524
- fs25.cpSync(abs, dest, { recursive: true, force: true });
26765
+ fs26.cpSync(abs, dest, { recursive: true, force: true });
26525
26766
  logger.success(`Pack "${probe2.name}" already registered \u2014 refreshed ${relRef} from the source.`);
26526
26767
  }
26527
26768
  logger.info(`${describe(probe2)} \u2014 commit .wai/ so CI and every clone enforce it.`);
26528
26769
  }
26529
26770
  async function addPackFromArchive(source, options) {
26530
- const abs = path34.resolve(source);
26531
- if (!fs25.existsSync(abs) || !fs25.statSync(abs).isFile()) {
26771
+ const abs = path37.resolve(source);
26772
+ if (!fs26.existsSync(abs) || !fs26.statSync(abs).isFile()) {
26532
26773
  logger.error(`Pack archive "${source}" does not exist.`);
26533
26774
  process.exitCode = 1;
26534
26775
  return;
@@ -26543,27 +26784,27 @@ async function addPackFromArchive(source, options) {
26543
26784
  process.exitCode = 1;
26544
26785
  return;
26545
26786
  }
26546
- baseDir = path34.join(getProjectRoot(), ".wai", "packs");
26787
+ baseDir = path37.join(getProjectRoot(), ".wai", "packs");
26547
26788
  }
26548
- const bytes = fs25.readFileSync(abs);
26549
- fs25.mkdirSync(baseDir, { recursive: true });
26550
- const staging = fs25.mkdtempSync(path34.join(baseDir, ".wpack-staging-"));
26789
+ const bytes = fs26.readFileSync(abs);
26790
+ fs26.mkdirSync(baseDir, { recursive: true });
26791
+ const staging = fs26.mkdtempSync(path37.join(baseDir, ".wpack-staging-"));
26551
26792
  let result;
26552
26793
  try {
26553
26794
  result = (0, import_sdk.extractPack)(bytes, staging);
26554
26795
  } catch (err) {
26555
- fs25.rmSync(staging, { recursive: true, force: true });
26556
- logger.error(`Failed to extract pack archive "${path34.basename(abs)}": ${err instanceof Error ? err.message : String(err)}`);
26796
+ fs26.rmSync(staging, { recursive: true, force: true });
26797
+ logger.error(`Failed to extract pack archive "${path37.basename(abs)}": ${err instanceof Error ? err.message : String(err)}`);
26557
26798
  process.exitCode = 1;
26558
26799
  return;
26559
26800
  }
26560
26801
  const name = result.name;
26561
- const destDir = path34.join(baseDir, name);
26562
- if (fs25.existsSync(destDir)) fs25.rmSync(destDir, { recursive: true, force: true });
26563
- fs25.renameSync(staging, destDir);
26564
- const probe2 = probePack(destDir, path34.dirname(destDir), scope);
26802
+ const destDir = path37.join(baseDir, name);
26803
+ if (fs26.existsSync(destDir)) fs26.rmSync(destDir, { recursive: true, force: true });
26804
+ fs26.renameSync(staging, destDir);
26805
+ const probe2 = probePack(destDir, path37.dirname(destDir), scope);
26565
26806
  if (probe2.error) {
26566
- fs25.rmSync(destDir, { recursive: true, force: true });
26807
+ fs26.rmSync(destDir, { recursive: true, force: true });
26567
26808
  logger.error(probe2.error);
26568
26809
  process.exitCode = 1;
26569
26810
  return;
@@ -26581,7 +26822,7 @@ async function addPackFromArchive(source, options) {
26581
26822
  saveProjectConfig(config);
26582
26823
  logger.success(`Installed pack "${probe2.name ?? name}" into ${relRef} and registered it in .wai/project.yaml.`);
26583
26824
  } else {
26584
- logger.success(`Pack "${probe2.name ?? name}" already registered \u2014 refreshed ${relRef} from ${path34.basename(abs)}.`);
26825
+ logger.success(`Pack "${probe2.name ?? name}" already registered \u2014 refreshed ${relRef} from ${path37.basename(abs)}.`);
26585
26826
  }
26586
26827
  logger.info(`${describe(probe2)} \u2014 commit .wai/ so CI and every clone enforce it.`);
26587
26828
  }
@@ -26602,7 +26843,7 @@ async function buildPack(source, options = {}) {
26602
26843
  const sourceDir = source && source.length > 0 ? source : ".";
26603
26844
  const result = (0, import_sdk.buildPack)(sourceDir);
26604
26845
  const outPath = options.out ?? result.suggestedFileName;
26605
- fs25.writeFileSync(outPath, result.archive);
26846
+ fs26.writeFileSync(outPath, result.archive);
26606
26847
  logger.success(`Built pack "${result.info.name}" v${result.info.version} \u2192 ${outPath} (${result.archive.byteLength} bytes)`);
26607
26848
  logger.info(`Install it with \`wairon pack add ${outPath}\`, or upload it to a hosted instance.`);
26608
26849
  }
@@ -26613,8 +26854,8 @@ function expandSource(source, version) {
26613
26854
  return source.replace(/\{version\}/g, version ?? "").replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (_, name) => process.env[name] ?? "");
26614
26855
  }
26615
26856
  async function fetchArchive(url) {
26616
- const dir = fs25.mkdtempSync(path34.join(os10.tmpdir(), "wairon-packdl-"));
26617
- const dest = path34.join(dir, "pack.wpack");
26857
+ const dir = fs26.mkdtempSync(path37.join(os11.tmpdir(), "wairon-packdl-"));
26858
+ const dest = path37.join(dir, "pack.wpack");
26618
26859
  await downloadFile(url, dest);
26619
26860
  return dest;
26620
26861
  }
@@ -26633,7 +26874,7 @@ async function installPack(source) {
26633
26874
  }
26634
26875
  const extracted = extractArchiveToTemp(archive);
26635
26876
  try {
26636
- fs25.rmSync(path34.dirname(archive), { recursive: true, force: true });
26877
+ fs26.rmSync(path37.dirname(archive), { recursive: true, force: true });
26637
26878
  } catch {
26638
26879
  }
26639
26880
  if (!extracted) return;
@@ -26645,7 +26886,7 @@ async function installPack(source) {
26645
26886
  process.exitCode = 1;
26646
26887
  } finally {
26647
26888
  try {
26648
- fs25.rmSync(extracted.dir, { recursive: true, force: true });
26889
+ fs26.rmSync(extracted.dir, { recursive: true, force: true });
26649
26890
  } catch {
26650
26891
  }
26651
26892
  }
@@ -26656,7 +26897,7 @@ async function installPack(source) {
26656
26897
  if (!extracted) return;
26657
26898
  sourceDir = extracted.dir;
26658
26899
  cleanup = extracted.dir;
26659
- origin = path34.resolve(source);
26900
+ origin = path37.resolve(source);
26660
26901
  } else {
26661
26902
  let unit;
26662
26903
  try {
@@ -26682,7 +26923,7 @@ async function installPack(source) {
26682
26923
  } finally {
26683
26924
  if (cleanup) {
26684
26925
  try {
26685
- fs25.rmSync(cleanup, { recursive: true, force: true });
26926
+ fs26.rmSync(cleanup, { recursive: true, force: true });
26686
26927
  } catch {
26687
26928
  }
26688
26929
  }
@@ -26699,20 +26940,20 @@ function reportInstalled(installed, origin) {
26699
26940
  }
26700
26941
  }
26701
26942
  function extractArchiveToTemp(source) {
26702
- const abs = path34.resolve(source);
26703
- if (!fs25.existsSync(abs)) {
26943
+ const abs = path37.resolve(source);
26944
+ if (!fs26.existsSync(abs)) {
26704
26945
  logger.error(`Pack archive "${source}" does not exist.`);
26705
26946
  process.exitCode = 1;
26706
26947
  return null;
26707
26948
  }
26708
- const tempDir = fs25.mkdtempSync(path34.join(os10.tmpdir(), "wairon-packinstall-"));
26949
+ const tempDir = fs26.mkdtempSync(path37.join(os11.tmpdir(), "wairon-packinstall-"));
26709
26950
  try {
26710
- const result = (0, import_sdk.extractPack)(new Uint8Array(fs25.readFileSync(abs)), tempDir);
26951
+ const result = (0, import_sdk.extractPack)(new Uint8Array(fs26.readFileSync(abs)), tempDir);
26711
26952
  void result;
26712
26953
  return { dir: tempDir };
26713
26954
  } catch (e) {
26714
26955
  try {
26715
- fs25.rmSync(tempDir, { recursive: true, force: true });
26956
+ fs26.rmSync(tempDir, { recursive: true, force: true });
26716
26957
  } catch {
26717
26958
  }
26718
26959
  logger.error(`Could not extract "${source}": ${e instanceof Error ? e.message : String(e)}`);
@@ -26858,7 +27099,7 @@ async function fetchAndInstall(selection, url) {
26858
27099
  const archive = await fetchArchive(url);
26859
27100
  const extracted = extractArchiveToTemp(archive);
26860
27101
  try {
26861
- fs25.rmSync(path34.dirname(archive), { recursive: true, force: true });
27102
+ fs26.rmSync(path37.dirname(archive), { recursive: true, force: true });
26862
27103
  } catch {
26863
27104
  }
26864
27105
  if (!extracted) return null;
@@ -26870,7 +27111,7 @@ async function fetchAndInstall(selection, url) {
26870
27111
  return pack;
26871
27112
  } finally {
26872
27113
  try {
26873
- fs25.rmSync(extracted.dir, { recursive: true, force: true });
27114
+ fs26.rmSync(extracted.dir, { recursive: true, force: true });
26874
27115
  } catch {
26875
27116
  }
26876
27117
  }
@@ -26881,10 +27122,10 @@ function bundleTargets(selections, name, all) {
26881
27122
  return selections.filter((s) => s.bundle === true);
26882
27123
  }
26883
27124
  function writeBundle(root, resolved) {
26884
- const dest = path34.join(root, ".wai", "packs", resolved.name, resolved.version);
26885
- fs25.rmSync(dest, { recursive: true, force: true });
26886
- fs25.mkdirSync(path34.dirname(dest), { recursive: true });
26887
- fs25.cpSync(resolved.path, dest, { recursive: true });
27125
+ const dest = path37.join(root, ".wai", "packs", resolved.name, resolved.version);
27126
+ fs26.rmSync(dest, { recursive: true, force: true });
27127
+ fs26.mkdirSync(path37.dirname(dest), { recursive: true });
27128
+ fs26.cpSync(resolved.path, dest, { recursive: true });
26888
27129
  return dest;
26889
27130
  }
26890
27131
  async function bundlePack(name, options = {}) {
@@ -26915,7 +27156,7 @@ async function bundlePack(name, options = {}) {
26915
27156
  selection.version = resolved.version;
26916
27157
  selection.bundle = true;
26917
27158
  bundled.push(`${resolved.name}@${resolved.version}`);
26918
- console.log(` ${import_chalk16.default.green("+")} ${import_chalk16.default.dim(path34.relative(root, dest).replace(/\\/g, "/"))}`);
27159
+ console.log(` ${import_chalk16.default.green("+")} ${import_chalk16.default.dim(path37.relative(root, dest).replace(/\\/g, "/"))}`);
26919
27160
  }
26920
27161
  if (bundled.length === 0) return;
26921
27162
  config.extensions = { packs: entries, useGlobalPacks: globalPacksEnabled(config) };
@@ -26957,9 +27198,9 @@ async function listPacks() {
26957
27198
  console.log(import_chalk16.default.bold.cyan(`\u25A0 Global (${globalPacksDir()})${useGlobal ? "" : import_chalk16.default.yellow(" [disabled: extensions.useGlobalPacks: false]")}`));
26958
27199
  if (globalRefs.length === 0) console.log(import_chalk16.default.dim(" (none)"));
26959
27200
  for (const ref of globalRefs) {
26960
- const probe2 = probePack(ref, path34.dirname(ref), "global");
26961
- if (probe2.error) console.log(` ${import_chalk16.default.red("\u2716")} ${path34.basename(ref)} \u2014 ${import_chalk16.default.red(probe2.error)}`);
26962
- else console.log(` ${import_chalk16.default.green("\u25CF")} ${import_chalk16.default.bold(probe2.name ?? path34.basename(ref))} ${import_chalk16.default.dim(describe(probe2))}`);
27201
+ const probe2 = probePack(ref, path37.dirname(ref), "global");
27202
+ if (probe2.error) console.log(` ${import_chalk16.default.red("\u2716")} ${path37.basename(ref)} \u2014 ${import_chalk16.default.red(probe2.error)}`);
27203
+ else console.log(` ${import_chalk16.default.green("\u25CF")} ${import_chalk16.default.bold(probe2.name ?? path37.basename(ref))} ${import_chalk16.default.dim(describe(probe2))}`);
26963
27204
  }
26964
27205
  console.log("");
26965
27206
  if (!inProject) {
@@ -26987,9 +27228,9 @@ async function listPacks() {
26987
27228
  async function removePack(name, options = {}) {
26988
27229
  if (options.global) {
26989
27230
  for (const ref of discoverPacks(globalPacksDir())) {
26990
- const probe2 = probePack(ref, path34.dirname(ref), "global");
26991
- if (probe2.name === name || path34.basename(ref) === name) {
26992
- fs25.rmSync(ref, { recursive: true, force: true });
27231
+ const probe2 = probePack(ref, path37.dirname(ref), "global");
27232
+ if (probe2.name === name || path37.basename(ref) === name) {
27233
+ fs26.rmSync(ref, { recursive: true, force: true });
26993
27234
  logger.success(`Removed global pack "${probe2.name ?? name}" (${ref}).`);
26994
27235
  return;
26995
27236
  }
@@ -27010,16 +27251,16 @@ async function removePack(name, options = {}) {
27010
27251
  if (typeof entry !== "string") continue;
27011
27252
  const ref = entry;
27012
27253
  const probe2 = probePack(ref, root, "project");
27013
- if (probe2.name === name || ref === name || path34.basename(ref) === name) {
27254
+ if (probe2.name === name || ref === name || path37.basename(ref) === name) {
27014
27255
  config.extensions = {
27015
27256
  packs: packs.filter((p) => p !== ref),
27016
27257
  useGlobalPacks: globalPacksEnabled(config)
27017
27258
  };
27018
27259
  saveProjectConfig(config);
27019
- const resolved = path34.resolve(root, ref);
27020
- const vendorDir = path34.resolve(root, ".wai", "packs");
27021
- if (resolved.startsWith(vendorDir + path34.sep)) {
27022
- fs25.rmSync(resolved, { recursive: true, force: true });
27260
+ const resolved = path37.resolve(root, ref);
27261
+ const vendorDir = path37.resolve(root, ".wai", "packs");
27262
+ if (resolved.startsWith(vendorDir + path37.sep)) {
27263
+ fs26.rmSync(resolved, { recursive: true, force: true });
27023
27264
  logger.success(`Deregistered pack "${probe2.name ?? name}" and deleted ${ref}.`);
27024
27265
  } else {
27025
27266
  logger.success(`Deregistered pack "${probe2.name ?? name}" (files at ${ref} left in place).`);
@@ -27032,22 +27273,22 @@ async function removePack(name, options = {}) {
27032
27273
  }
27033
27274
 
27034
27275
  // src/commands/host.ts
27035
- var fs52 = __toESM(require("fs"));
27036
- var path61 = __toESM(require("path"));
27037
- var os11 = __toESM(require("os"));
27038
- var crypto21 = __toESM(require("crypto"));
27276
+ var fs53 = __toESM(require("fs"));
27277
+ var path64 = __toESM(require("path"));
27278
+ var os12 = __toESM(require("os"));
27279
+ var crypto22 = __toESM(require("crypto"));
27039
27280
  var import_child_process5 = require("child_process");
27040
27281
  var import_chalk17 = __toESM(require("chalk"));
27041
27282
  init_logger();
27042
27283
  init_errors();
27043
27284
 
27044
27285
  // src/server/admin.ts
27045
- var crypto8 = __toESM(require("crypto"));
27286
+ var crypto9 = __toESM(require("crypto"));
27046
27287
  init_fs();
27047
27288
  init_defaults();
27048
27289
 
27049
27290
  // src/server/auth.ts
27050
- var crypto6 = __toESM(require("crypto"));
27291
+ var crypto7 = __toESM(require("crypto"));
27051
27292
 
27052
27293
  // src/server/types.ts
27053
27294
  var SSO_ADMIN_ROLE_ID = "sso-admin";
@@ -27060,35 +27301,35 @@ var UNAUTHENTICATED = {
27060
27301
  var WEB_SESSION_PREFIX = "ws_";
27061
27302
 
27062
27303
  // src/server/credentials.ts
27063
- var fs26 = __toESM(require("fs"));
27064
- var path35 = __toESM(require("path"));
27065
- var crypto4 = __toESM(require("crypto"));
27304
+ var fs27 = __toESM(require("fs"));
27305
+ var path38 = __toESM(require("path"));
27306
+ var crypto5 = __toESM(require("crypto"));
27066
27307
  var HASH_NS = "wairon:token:v1";
27067
27308
  function hashToken(token) {
27068
- return crypto4.createHash("sha256").update(`${HASH_NS}:${token}`).digest("hex");
27309
+ return crypto5.createHash("sha256").update(`${HASH_NS}:${token}`).digest("hex");
27069
27310
  }
27070
27311
  function storePath(dataDir) {
27071
- return path35.join(dataDir, "auth", "credentials.json");
27312
+ return path38.join(dataDir, "auth", "credentials.json");
27072
27313
  }
27073
27314
  function load3(dataDir) {
27074
27315
  try {
27075
- return JSON.parse(fs26.readFileSync(storePath(dataDir), "utf8"));
27316
+ return JSON.parse(fs27.readFileSync(storePath(dataDir), "utf8"));
27076
27317
  } catch {
27077
27318
  return [];
27078
27319
  }
27079
27320
  }
27080
27321
  function save(dataDir, records) {
27081
27322
  const p = storePath(dataDir);
27082
- fs26.mkdirSync(path35.dirname(p), { recursive: true });
27323
+ fs27.mkdirSync(path38.dirname(p), { recursive: true });
27083
27324
  const tmp = `${p}.tmp`;
27084
- fs26.writeFileSync(tmp, JSON.stringify(records, null, 2) + "\n");
27085
- fs26.renameSync(tmp, p);
27325
+ fs27.writeFileSync(tmp, JSON.stringify(records, null, 2) + "\n");
27326
+ fs27.renameSync(tmp, p);
27086
27327
  }
27087
27328
  function digestEquals(a, b) {
27088
27329
  const ab = Buffer.from(a, "hex");
27089
27330
  const bb = Buffer.from(b, "hex");
27090
27331
  if (ab.length === 0 || ab.length !== bb.length) return false;
27091
- return crypto4.timingSafeEqual(ab, bb);
27332
+ return crypto5.timingSafeEqual(ab, bb);
27092
27333
  }
27093
27334
  function findByTokenHash(dataDir, tokenHash) {
27094
27335
  return load3(dataDir).find((r) => digestEquals(r.keyHash, tokenHash)) ?? null;
@@ -27127,17 +27368,17 @@ function listByOwner(dataDir, ownerUserId) {
27127
27368
  }
27128
27369
 
27129
27370
  // src/server/websessions.ts
27130
- var fs27 = __toESM(require("fs"));
27131
- var path36 = __toESM(require("path"));
27132
- var crypto5 = __toESM(require("crypto"));
27371
+ var fs28 = __toESM(require("fs"));
27372
+ var path39 = __toESM(require("path"));
27373
+ var crypto6 = __toESM(require("crypto"));
27133
27374
  function storePath2(dataDir) {
27134
- return path36.join(dataDir, "web-sessions.json");
27375
+ return path39.join(dataDir, "web-sessions.json");
27135
27376
  }
27136
27377
  function readSessions(dataDir) {
27137
27378
  const p = storePath2(dataDir);
27138
27379
  let raw;
27139
27380
  try {
27140
- raw = fs27.readFileSync(p, "utf8");
27381
+ raw = fs28.readFileSync(p, "utf8");
27141
27382
  } catch (e) {
27142
27383
  if (e.code === "ENOENT") return [];
27143
27384
  throw new Error(`Failed to read web session store at ${p}: ${e.message}`);
@@ -27152,13 +27393,13 @@ function readSessions(dataDir) {
27152
27393
  }
27153
27394
  function persistSessions(dataDir, sessions) {
27154
27395
  const p = storePath2(dataDir);
27155
- fs27.mkdirSync(path36.dirname(p), { recursive: true });
27396
+ fs28.mkdirSync(path39.dirname(p), { recursive: true });
27156
27397
  const tmp = `${p}.tmp`;
27157
- fs27.writeFileSync(tmp, JSON.stringify(sessions, null, 2) + "\n");
27158
- fs27.renameSync(tmp, p);
27398
+ fs28.writeFileSync(tmp, JSON.stringify(sessions, null, 2) + "\n");
27399
+ fs28.renameSync(tmp, p);
27159
27400
  }
27160
27401
  function mintSessionId() {
27161
- return `${WEB_SESSION_PREFIX}${crypto5.randomBytes(24).toString("hex")}`;
27402
+ return `${WEB_SESSION_PREFIX}${crypto6.randomBytes(24).toString("hex")}`;
27162
27403
  }
27163
27404
  var WebSessionStore = class {
27164
27405
  constructor(dataDir) {
@@ -27316,17 +27557,17 @@ function listWebSessionsBySubject(dataDir, userId) {
27316
27557
  }
27317
27558
 
27318
27559
  // src/server/users.ts
27319
- var fs28 = __toESM(require("fs"));
27320
- var path37 = __toESM(require("path"));
27560
+ var fs29 = __toESM(require("fs"));
27561
+ var path40 = __toESM(require("path"));
27321
27562
  var VALID_STATUSES = ["active", "inactive", "suspended", "deactivated", "disabled"];
27322
27563
  function storePath3(dataDir) {
27323
- return path37.join(dataDir, "users.json");
27564
+ return path40.join(dataDir, "users.json");
27324
27565
  }
27325
27566
  function loadStore(dataDir) {
27326
27567
  const p = storePath3(dataDir);
27327
27568
  let raw;
27328
27569
  try {
27329
- raw = fs28.readFileSync(p, "utf8");
27570
+ raw = fs29.readFileSync(p, "utf8");
27330
27571
  } catch (err) {
27331
27572
  if (err.code === "ENOENT") return [];
27332
27573
  throw new Error(`Cannot read hosted-user store at ${p}: ${err.message}`);
@@ -27344,10 +27585,10 @@ function loadStore(dataDir) {
27344
27585
  }
27345
27586
  function replaceAll(dataDir, records) {
27346
27587
  const p = storePath3(dataDir);
27347
- fs28.mkdirSync(path37.dirname(p), { recursive: true });
27588
+ fs29.mkdirSync(path40.dirname(p), { recursive: true });
27348
27589
  const tmp = `${p}.tmp`;
27349
- fs28.writeFileSync(tmp, JSON.stringify(records, null, 2) + "\n");
27350
- fs28.renameSync(tmp, p);
27590
+ fs29.writeFileSync(tmp, JSON.stringify(records, null, 2) + "\n");
27591
+ fs29.renameSync(tmp, p);
27351
27592
  }
27352
27593
  function registryUpsert(dataDir, record2) {
27353
27594
  const records = loadStore(dataDir);
@@ -27449,11 +27690,11 @@ function remapUnitReferences(dataDir, remap, removedScopeIds) {
27449
27690
  }
27450
27691
 
27451
27692
  // src/server/instance.ts
27452
- var fs29 = __toESM(require("fs"));
27453
- var path38 = __toESM(require("path"));
27693
+ var fs30 = __toESM(require("fs"));
27694
+ var path41 = __toESM(require("path"));
27454
27695
  var import_crypto = require("crypto");
27455
27696
  function storePath4(dataDir) {
27456
- return path38.join(dataDir, "instance.json");
27697
+ return path41.join(dataDir, "instance.json");
27457
27698
  }
27458
27699
  var InstanceIdentityStore = class {
27459
27700
  constructor(dataDir) {
@@ -27470,7 +27711,7 @@ var InstanceIdentityStore = class {
27470
27711
  const p = storePath4(this.dataDir);
27471
27712
  let raw;
27472
27713
  try {
27473
- raw = fs29.readFileSync(p, "utf8");
27714
+ raw = fs30.readFileSync(p, "utf8");
27474
27715
  } catch (err) {
27475
27716
  if (err.code === "ENOENT") return null;
27476
27717
  throw new Error(`Cannot read instance identity at ${p}: ${err.message}`);
@@ -27493,10 +27734,10 @@ var InstanceIdentityStore = class {
27493
27734
  * never truncates the file. Only called by the registry's create-once seed. */
27494
27735
  replace(identity) {
27495
27736
  const p = storePath4(this.dataDir);
27496
- fs29.mkdirSync(path38.dirname(p), { recursive: true });
27737
+ fs30.mkdirSync(path41.dirname(p), { recursive: true });
27497
27738
  const tmp = `${p}.tmp`;
27498
- fs29.writeFileSync(tmp, JSON.stringify(identity, null, 2) + "\n");
27499
- fs29.renameSync(tmp, p);
27739
+ fs30.writeFileSync(tmp, JSON.stringify(identity, null, 2) + "\n");
27740
+ fs30.renameSync(tmp, p);
27500
27741
  }
27501
27742
  };
27502
27743
  var InstanceIdentityRegistry = class {
@@ -27552,8 +27793,8 @@ function getInstanceIdentity(dataDir) {
27552
27793
  }
27553
27794
 
27554
27795
  // src/utils/secrets.ts
27555
- var fs30 = __toESM(require("fs"));
27556
- var path39 = __toESM(require("path"));
27796
+ var fs31 = __toESM(require("fs"));
27797
+ var path42 = __toESM(require("path"));
27557
27798
  var ENV_FALLBACK = {
27558
27799
  "git-token": ["WAIRON_GIT_TOKEN"],
27559
27800
  "notion-token": ["WAIRON_NOTION_TOKEN"],
@@ -27562,13 +27803,13 @@ var ENV_FALLBACK = {
27562
27803
  };
27563
27804
  function storePath5() {
27564
27805
  const dataDir = process.env["WAIRON_DATA_DIR"];
27565
- return dataDir ? path39.join(dataDir, "auth", "secrets.json") : null;
27806
+ return dataDir ? path42.join(dataDir, "auth", "secrets.json") : null;
27566
27807
  }
27567
27808
  function readStore() {
27568
27809
  const p = storePath5();
27569
27810
  if (!p) return {};
27570
27811
  try {
27571
- return JSON.parse(fs30.readFileSync(p, "utf8"));
27812
+ return JSON.parse(fs31.readFileSync(p, "utf8"));
27572
27813
  } catch {
27573
27814
  return {};
27574
27815
  }
@@ -27593,10 +27834,10 @@ function setSecret(key, value) {
27593
27834
  if (!p) throw new Error("WAIRON_DATA_DIR is not set \u2014 a running server needs it to store secrets.");
27594
27835
  const store = readStore();
27595
27836
  store[key] = value;
27596
- fs30.mkdirSync(path39.dirname(p), { recursive: true });
27837
+ fs31.mkdirSync(path42.dirname(p), { recursive: true });
27597
27838
  const tmp = `${p}.tmp`;
27598
- fs30.writeFileSync(tmp, JSON.stringify(store, null, 2) + "\n");
27599
- fs30.renameSync(tmp, p);
27839
+ fs31.writeFileSync(tmp, JSON.stringify(store, null, 2) + "\n");
27840
+ fs31.renameSync(tmp, p);
27600
27841
  }
27601
27842
  function listSecretKeys() {
27602
27843
  return Object.keys(readStore());
@@ -27674,7 +27915,7 @@ function masterMatches(credential) {
27674
27915
  if (!master || !credential) return false;
27675
27916
  const a = Buffer.from(hashToken(credential), "hex");
27676
27917
  const b = Buffer.from(hashToken(master), "hex");
27677
- return a.length === b.length && crypto6.timingSafeEqual(a, b);
27918
+ return a.length === b.length && crypto7.timingSafeEqual(a, b);
27678
27919
  }
27679
27920
  function bootstrapAdminPrincipal() {
27680
27921
  const subject = {
@@ -27722,7 +27963,7 @@ function authenticateMaster(token) {
27722
27963
  function hashedEquals(a, b) {
27723
27964
  const ha = Buffer.from(hashToken(a), "hex");
27724
27965
  const hb = Buffer.from(hashToken(b), "hex");
27725
- return ha.length === hb.length && crypto6.timingSafeEqual(ha, hb);
27966
+ return ha.length === hb.length && crypto7.timingSafeEqual(ha, hb);
27726
27967
  }
27727
27968
  function verifyBuiltinAdmin(cfg, user, password) {
27728
27969
  const configuredUser = cfg.builtinAdminUser ?? "";
@@ -27771,16 +28012,16 @@ function signingKey() {
27771
28012
  }
27772
28013
  function signViewToken(project2, format) {
27773
28014
  const body = Buffer.from(JSON.stringify({ project: project2, format, exp: Date.now() + VIEW_TTL_MS })).toString("base64url");
27774
- const sig = crypto6.createHmac("sha256", signingKey()).update(body).digest("base64url");
28015
+ const sig = crypto7.createHmac("sha256", signingKey()).update(body).digest("base64url");
27775
28016
  return `${body}.${sig}`;
27776
28017
  }
27777
28018
  function verifyViewToken(token) {
27778
28019
  const [body, sig] = String(token).split(".");
27779
28020
  if (!body || !sig) throw new Error("invalid view token");
27780
- const expected = crypto6.createHmac("sha256", signingKey()).update(body).digest("base64url");
28021
+ const expected = crypto7.createHmac("sha256", signingKey()).update(body).digest("base64url");
27781
28022
  const a = Buffer.from(sig);
27782
28023
  const b = Buffer.from(expected);
27783
- if (a.length !== b.length || !crypto6.timingSafeEqual(a, b)) throw new Error("invalid view token");
28024
+ if (a.length !== b.length || !crypto7.timingSafeEqual(a, b)) throw new Error("invalid view token");
27784
28025
  const payload = JSON.parse(Buffer.from(body, "base64url").toString("utf8"));
27785
28026
  if (Date.now() > payload.exp) throw new Error("expired view token");
27786
28027
  return { project: payload.project, format: payload.format, expiresAt: new Date(payload.exp).toISOString() };
@@ -27788,33 +28029,33 @@ function verifyViewToken(token) {
27788
28029
  var SSO_STATE_TTL_MS = 10 * 60 * 1e3;
27789
28030
  function signSsoState(payload) {
27790
28031
  const body = Buffer.from(JSON.stringify({ payload, exp: Date.now() + SSO_STATE_TTL_MS })).toString("base64url");
27791
- const sig = crypto6.createHmac("sha256", signingKey()).update(body).digest("base64url");
28032
+ const sig = crypto7.createHmac("sha256", signingKey()).update(body).digest("base64url");
27792
28033
  return `${body}.${sig}`;
27793
28034
  }
27794
28035
  function verifySsoState(state) {
27795
28036
  const [body, sig] = String(state).split(".");
27796
28037
  if (!body || !sig) throw new Error("invalid SSO state");
27797
- const expected = crypto6.createHmac("sha256", signingKey()).update(body).digest("base64url");
28038
+ const expected = crypto7.createHmac("sha256", signingKey()).update(body).digest("base64url");
27798
28039
  const a = Buffer.from(sig);
27799
28040
  const b = Buffer.from(expected);
27800
- if (a.length !== b.length || !crypto6.timingSafeEqual(a, b)) throw new Error("invalid SSO state");
28041
+ if (a.length !== b.length || !crypto7.timingSafeEqual(a, b)) throw new Error("invalid SSO state");
27801
28042
  const parsed = JSON.parse(Buffer.from(body, "base64url").toString("utf8"));
27802
28043
  if (Date.now() > parsed.exp) throw new Error("expired SSO state");
27803
28044
  return parsed.payload;
27804
28045
  }
27805
28046
 
27806
28047
  // src/server/organization.ts
27807
- var fs31 = __toESM(require("fs"));
27808
- var path40 = __toESM(require("path"));
27809
- var crypto7 = __toESM(require("crypto"));
28048
+ var fs32 = __toESM(require("fs"));
28049
+ var path43 = __toESM(require("path"));
28050
+ var crypto8 = __toESM(require("crypto"));
27810
28051
  function storePath6(dataDir) {
27811
- return path40.join(dataDir, "organization.json");
28052
+ return path43.join(dataDir, "organization.json");
27812
28053
  }
27813
28054
  function readState(dataDir) {
27814
28055
  const p = storePath6(dataDir);
27815
28056
  let raw;
27816
28057
  try {
27817
- raw = fs31.readFileSync(p, "utf8");
28058
+ raw = fs32.readFileSync(p, "utf8");
27818
28059
  } catch (e) {
27819
28060
  if (e.code === "ENOENT") return { units: [], placements: [] };
27820
28061
  throw new Error(`Failed to read organization store at ${p}: ${e.message}`);
@@ -27831,10 +28072,10 @@ function readState(dataDir) {
27831
28072
  }
27832
28073
  function persistState(dataDir, state) {
27833
28074
  const p = storePath6(dataDir);
27834
- fs31.mkdirSync(path40.dirname(p), { recursive: true });
28075
+ fs32.mkdirSync(path43.dirname(p), { recursive: true });
27835
28076
  const tmp = `${p}.tmp`;
27836
- fs31.writeFileSync(tmp, JSON.stringify(state, null, 2) + "\n");
27837
- fs31.renameSync(tmp, p);
28077
+ fs32.writeFileSync(tmp, JSON.stringify(state, null, 2) + "\n");
28078
+ fs32.renameSync(tmp, p);
27838
28079
  }
27839
28080
  var SLUG_PATTERN = /^[a-z0-9-]+$/;
27840
28081
  var UNIT_KINDS = ["business_entity", "department", "team", "group"];
@@ -28129,7 +28370,7 @@ var OrganizationRegistry = class {
28129
28370
  createdAt: placements[existingIdx].createdAt
28130
28371
  } : {
28131
28372
  ...placement,
28132
- id: placement.id || crypto7.randomUUID(),
28373
+ id: placement.id || crypto8.randomUUID(),
28133
28374
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
28134
28375
  };
28135
28376
  const next = isUpdate ? placements.map((p, i) => i === existingIdx ? stored : p) : [...placements, stored];
@@ -28210,11 +28451,11 @@ function getOrganizationUnit(dataDir, id) {
28210
28451
  }
28211
28452
 
28212
28453
  // src/server/permissions.ts
28213
- var fs32 = __toESM(require("fs"));
28214
- var path41 = __toESM(require("path"));
28454
+ var fs33 = __toESM(require("fs"));
28455
+ var path44 = __toESM(require("path"));
28215
28456
  var import_crypto2 = require("crypto");
28216
28457
  function storePath7(dataDir) {
28217
- return path41.join(dataDir, "permissions.json");
28458
+ return path44.join(dataDir, "permissions.json");
28218
28459
  }
28219
28460
  function assignmentKey(a) {
28220
28461
  return [a.subjectKind, a.subjectId ?? "", a.scopeKind, a.scopeId ?? "", a.capability].join("|");
@@ -28223,7 +28464,7 @@ function load4(dataDir) {
28223
28464
  const p = storePath7(dataDir);
28224
28465
  let raw;
28225
28466
  try {
28226
- raw = fs32.readFileSync(p, "utf8");
28467
+ raw = fs33.readFileSync(p, "utf8");
28227
28468
  } catch (err) {
28228
28469
  if (err.code === "ENOENT") return [];
28229
28470
  throw new Error(`Cannot read permission store at ${p}: ${err.message}`);
@@ -28241,10 +28482,10 @@ function load4(dataDir) {
28241
28482
  }
28242
28483
  function replaceAll2(dataDir, assignments) {
28243
28484
  const p = storePath7(dataDir);
28244
- fs32.mkdirSync(path41.dirname(p), { recursive: true });
28485
+ fs33.mkdirSync(path44.dirname(p), { recursive: true });
28245
28486
  const tmp = `${p}.tmp`;
28246
- fs32.writeFileSync(tmp, JSON.stringify(assignments, null, 2) + "\n");
28247
- fs32.renameSync(tmp, p);
28487
+ fs33.writeFileSync(tmp, JSON.stringify(assignments, null, 2) + "\n");
28488
+ fs33.renameSync(tmp, p);
28248
28489
  }
28249
28490
  function registrySet(dataDir, assignment) {
28250
28491
  const assignments = load4(dataDir);
@@ -28330,8 +28571,8 @@ function getAssignment(dataDir, assignmentId) {
28330
28571
  }
28331
28572
 
28332
28573
  // src/server/roles.ts
28333
- var fs33 = __toESM(require("fs"));
28334
- var path42 = __toESM(require("path"));
28574
+ var fs34 = __toESM(require("fs"));
28575
+ var path45 = __toESM(require("path"));
28335
28576
  var BUILTIN_ROLES = [
28336
28577
  {
28337
28578
  id: SSO_ADMIN_ROLE_ID,
@@ -28349,13 +28590,13 @@ function isBuiltinRoleId(roleId) {
28349
28590
  return BUILTIN_ROLE_IDS.has(roleId);
28350
28591
  }
28351
28592
  function storePath8(dataDir) {
28352
- return path42.join(dataDir, "roles.json");
28593
+ return path45.join(dataDir, "roles.json");
28353
28594
  }
28354
28595
  function load5(dataDir) {
28355
28596
  const p = storePath8(dataDir);
28356
28597
  let raw;
28357
28598
  try {
28358
- raw = fs33.readFileSync(p, "utf8");
28599
+ raw = fs34.readFileSync(p, "utf8");
28359
28600
  } catch (err) {
28360
28601
  if (err.code === "ENOENT") return [];
28361
28602
  throw new Error(`Cannot read role store at ${p}: ${err.message}`);
@@ -28373,10 +28614,10 @@ function load5(dataDir) {
28373
28614
  }
28374
28615
  function replaceAll3(dataDir, roles) {
28375
28616
  const p = storePath8(dataDir);
28376
- fs33.mkdirSync(path42.dirname(p), { recursive: true });
28617
+ fs34.mkdirSync(path45.dirname(p), { recursive: true });
28377
28618
  const tmp = `${p}.tmp`;
28378
- fs33.writeFileSync(tmp, JSON.stringify(roles, null, 2) + "\n");
28379
- fs33.renameSync(tmp, p);
28619
+ fs34.writeFileSync(tmp, JSON.stringify(roles, null, 2) + "\n");
28620
+ fs34.renameSync(tmp, p);
28380
28621
  }
28381
28622
  function registryCreate(dataDir, role) {
28382
28623
  if (isBuiltinRoleId(role.id)) {
@@ -28610,8 +28851,8 @@ function actionableUnitIds(scopes) {
28610
28851
  }
28611
28852
 
28612
28853
  // src/server/projects.ts
28613
- var fs37 = __toESM(require("fs"));
28614
- var path46 = __toESM(require("path"));
28854
+ var fs38 = __toESM(require("fs"));
28855
+ var path49 = __toESM(require("path"));
28615
28856
  init_loader();
28616
28857
  init_yaml();
28617
28858
  init_fs();
@@ -28630,37 +28871,37 @@ init_types();
28630
28871
  init_server();
28631
28872
 
28632
28873
  // src/git/config.ts
28633
- var fs34 = __toESM(require("fs"));
28634
- var path43 = __toESM(require("path"));
28874
+ var fs35 = __toESM(require("fs"));
28875
+ var path46 = __toESM(require("path"));
28635
28876
  init_fs();
28636
28877
  function configPath() {
28637
28878
  return aiDir("git.json");
28638
28879
  }
28639
28880
  function readGitConfig() {
28640
28881
  try {
28641
- return JSON.parse(fs34.readFileSync(configPath(), "utf8"));
28882
+ return JSON.parse(fs35.readFileSync(configPath(), "utf8"));
28642
28883
  } catch {
28643
28884
  return null;
28644
28885
  }
28645
28886
  }
28646
28887
  function writeGitConfig(config) {
28647
28888
  const p = configPath();
28648
- fs34.mkdirSync(path43.dirname(p), { recursive: true });
28889
+ fs35.mkdirSync(path46.dirname(p), { recursive: true });
28649
28890
  const tmp = `${p}.tmp`;
28650
- fs34.writeFileSync(tmp, JSON.stringify(config, null, 2) + "\n");
28651
- fs34.renameSync(tmp, p);
28891
+ fs35.writeFileSync(tmp, JSON.stringify(config, null, 2) + "\n");
28892
+ fs35.renameSync(tmp, p);
28652
28893
  }
28653
28894
  function clearGitConfig() {
28654
28895
  try {
28655
- fs34.rmSync(configPath(), { force: true });
28896
+ fs35.rmSync(configPath(), { force: true });
28656
28897
  } catch {
28657
28898
  }
28658
28899
  }
28659
28900
 
28660
28901
  // src/git/adapter.ts
28661
28902
  var import_child_process3 = require("child_process");
28662
- var fs35 = __toESM(require("fs"));
28663
- var path44 = __toESM(require("path"));
28903
+ var fs36 = __toESM(require("fs"));
28904
+ var path47 = __toESM(require("path"));
28664
28905
  init_fs();
28665
28906
  function git(args, cwd) {
28666
28907
  return (0, import_child_process3.execFileSync)("git", args, {
@@ -28712,10 +28953,10 @@ function compareUrl(remote, defaultBranch, workingBranch) {
28712
28953
  return `${web}/compare/${encodeURIComponent(defaultBranch)}...${encodeURIComponent(workingBranch)}`;
28713
28954
  }
28714
28955
  function excludeLocalFiles() {
28715
- const excludePath = path44.join(getProjectRoot(), ".git", "info", "exclude");
28956
+ const excludePath = path47.join(getProjectRoot(), ".git", "info", "exclude");
28716
28957
  try {
28717
- fs35.mkdirSync(path44.dirname(excludePath), { recursive: true });
28718
- fs35.appendFileSync(excludePath, "\n.wai/lock.json\n.wai/git.json\n");
28958
+ fs36.mkdirSync(path47.dirname(excludePath), { recursive: true });
28959
+ fs36.appendFileSync(excludePath, "\n.wai/lock.json\n.wai/git.json\n");
28719
28960
  } catch {
28720
28961
  }
28721
28962
  }
@@ -28780,25 +29021,25 @@ function configureSync(periodicSyncMinutes, skipIfClean) {
28780
29021
  }
28781
29022
 
28782
29023
  // src/producers/config.ts
28783
- var fs36 = __toESM(require("fs"));
28784
- var path45 = __toESM(require("path"));
29024
+ var fs37 = __toESM(require("fs"));
29025
+ var path48 = __toESM(require("path"));
28785
29026
  init_fs();
28786
29027
  function configPath2() {
28787
29028
  return aiDir("producers.json");
28788
29029
  }
28789
29030
  function load6() {
28790
29031
  try {
28791
- return JSON.parse(fs36.readFileSync(configPath2(), "utf8"));
29032
+ return JSON.parse(fs37.readFileSync(configPath2(), "utf8"));
28792
29033
  } catch {
28793
29034
  return [];
28794
29035
  }
28795
29036
  }
28796
29037
  function save2(configs) {
28797
29038
  const p = configPath2();
28798
- fs36.mkdirSync(path45.dirname(p), { recursive: true });
29039
+ fs37.mkdirSync(path48.dirname(p), { recursive: true });
28799
29040
  const tmp = `${p}.tmp`;
28800
- fs36.writeFileSync(tmp, JSON.stringify(configs, null, 2) + "\n");
28801
- fs36.renameSync(tmp, p);
29041
+ fs37.writeFileSync(tmp, JSON.stringify(configs, null, 2) + "\n");
29042
+ fs37.renameSync(tmp, p);
28802
29043
  }
28803
29044
  function readProducerConfig(target) {
28804
29045
  return load6().find((c) => c.target === target) ?? null;
@@ -29216,24 +29457,24 @@ function isValidProjectId(id) {
29216
29457
  return typeof id === "string" && ID_RE.test(id);
29217
29458
  }
29218
29459
  function registryPath(dataDir) {
29219
- return path46.join(dataDir, "projects.json");
29460
+ return path49.join(dataDir, "projects.json");
29220
29461
  }
29221
29462
  function load7(dataDir) {
29222
29463
  try {
29223
- return JSON.parse(fs37.readFileSync(registryPath(dataDir), "utf8"));
29464
+ return JSON.parse(fs38.readFileSync(registryPath(dataDir), "utf8"));
29224
29465
  } catch {
29225
29466
  return [];
29226
29467
  }
29227
29468
  }
29228
29469
  function save3(dataDir, records) {
29229
29470
  const p = registryPath(dataDir);
29230
- fs37.mkdirSync(path46.dirname(p), { recursive: true });
29471
+ fs38.mkdirSync(path49.dirname(p), { recursive: true });
29231
29472
  const tmp = `${p}.tmp`;
29232
- fs37.writeFileSync(tmp, JSON.stringify(records, null, 2) + "\n");
29233
- fs37.renameSync(tmp, p);
29473
+ fs38.writeFileSync(tmp, JSON.stringify(records, null, 2) + "\n");
29474
+ fs38.renameSync(tmp, p);
29234
29475
  }
29235
29476
  function projectRoot(dataDir, id) {
29236
- return path46.join(dataDir, "projects", id);
29477
+ return path49.join(dataDir, "projects", id);
29237
29478
  }
29238
29479
  function existingProjectRoot(dataDir, id) {
29239
29480
  if (!isValidProjectId(id)) return null;
@@ -29249,7 +29490,7 @@ function createProjectRecord(dataDir, id) {
29249
29490
  throw new Error(`Project "${id}" already exists.`);
29250
29491
  }
29251
29492
  const root = projectRoot(dataDir, id);
29252
- fs37.mkdirSync(root, { recursive: true });
29493
+ fs38.mkdirSync(root, { recursive: true });
29253
29494
  const record2 = {
29254
29495
  id,
29255
29496
  rootPath: root,
@@ -29284,7 +29525,7 @@ function removeProjectRecord(dataDir, id) {
29284
29525
  const rec = records.find((r) => r.id === id);
29285
29526
  if (rec) {
29286
29527
  try {
29287
- fs37.rmSync(rec.rootPath, { recursive: true, force: true });
29528
+ fs38.rmSync(rec.rootPath, { recursive: true, force: true });
29288
29529
  } catch {
29289
29530
  }
29290
29531
  }
@@ -29300,7 +29541,7 @@ function parseQualifiedSelector(value) {
29300
29541
  }
29301
29542
  function findSubsystemSpec(root, subsystemId) {
29302
29543
  const specsDir = aiPathsAt(root).specsDir();
29303
- if (!fs37.existsSync(specsDir)) return null;
29544
+ if (!fs38.existsSync(specsDir)) return null;
29304
29545
  for (const file of listFilesRecursive(specsDir, ".yaml")) {
29305
29546
  let raw;
29306
29547
  try {
@@ -29478,9 +29719,9 @@ function mintKey(cfg, credential, project2, role) {
29478
29719
  "instance-wide super-admin (*:*) keys cannot be minted \u2014 the built-in admin account (WAIRON_ADMIN_USER) is the only super-admin"
29479
29720
  );
29480
29721
  }
29481
- const token = "wk_" + crypto8.randomBytes(24).toString("hex");
29722
+ const token = "wk_" + crypto9.randomBytes(24).toString("hex");
29482
29723
  const record2 = {
29483
- id: crypto8.randomBytes(6).toString("hex"),
29724
+ id: crypto9.randomBytes(6).toString("hex"),
29484
29725
  keyHash: hashToken(token),
29485
29726
  role,
29486
29727
  projects: project2 === "*" ? ["*"] : [project2],
@@ -29676,31 +29917,10 @@ function diagramViewLink(cfg, credential, project2) {
29676
29917
  if (!existingProjectRoot(cfg.dataDir, project2)) throw new Error(`Unknown project "${project2}".`);
29677
29918
  return `/view/diagram?token=${signViewToken(project2, "canvas")}`;
29678
29919
  }
29679
- function promoteProject(cfg, credential, project2) {
29680
- const principal = requirePrincipal(cfg, credential);
29681
- if (authorize(cfg.dataDir, principal, "project:write", "project", project2).value !== "yes") {
29682
- throw new AdminAuthError("Forbidden \u2014 promoting a project requires project:write over it");
29683
- }
29684
- return executeApprovedPromote(cfg, project2);
29685
- }
29686
- function executeApprovedPromote(cfg, projectId, subproject) {
29687
- const root = boundLifecycleRoot(cfg, projectId, subproject);
29688
- return runWithProjectRoot(root, () => {
29689
- const { state, record: lock, current: current2 } = hostCore.readLockState();
29690
- if (state === "unlocked" || !lock) {
29691
- return { status: "not-locked", message: "Project is not locked; run lock first." };
29692
- }
29693
- if (state === "stale") {
29694
- return { status: "stale", stateId: current2, message: "Spec tree or governing doctrine changed since lock; re-lock required." };
29695
- }
29696
- hostCore.writeLockRecord({ ...lock, status: "promoted" });
29697
- return { status: "ready", stateId: current2, message: "Locked state matches; change-set marked ready for promotion." };
29698
- });
29699
- }
29700
29920
 
29701
29921
  // src/server/packs.ts
29702
- var fs38 = __toESM(require("fs"));
29703
- var path47 = __toESM(require("path"));
29922
+ var fs39 = __toESM(require("fs"));
29923
+ var path50 = __toESM(require("path"));
29704
29924
  init_fs();
29705
29925
  init_yaml();
29706
29926
  init_loader();
@@ -29746,19 +29966,19 @@ function assertNotCodeArchive(info) {
29746
29966
  function extractDeclarativeArchive(archive, destDir) {
29747
29967
  const result = hostSdk.extractArchive(archive, destDir, HOSTED_STRICT_LIMITS);
29748
29968
  try {
29749
- assertDeclarative(fs38.readFileSync(path47.join(result.directory, result.entryPath), "utf8"));
29969
+ assertDeclarative(fs39.readFileSync(path50.join(result.directory, result.entryPath), "utf8"));
29750
29970
  } catch (e) {
29751
- fs38.rmSync(destDir, { recursive: true, force: true });
29971
+ fs39.rmSync(destDir, { recursive: true, force: true });
29752
29972
  throw e;
29753
29973
  }
29754
29974
  }
29755
29975
  function probe(loadRef, baseRoot, scope, displayRef) {
29756
29976
  const loaded = hostCore.loadExtensionPacks([{ ref: loadRef, scope }], baseRoot);
29757
29977
  if (loaded.errors.length) {
29758
- return { name: path47.basename(displayRef), scope, ref: displayRef, profiles: 0, languages: 0, rules: 0, error: loaded.errors[0] };
29978
+ return { name: path50.basename(displayRef), scope, ref: displayRef, profiles: 0, languages: 0, rules: 0, error: loaded.errors[0] };
29759
29979
  }
29760
29980
  return {
29761
- name: loaded.packNames[0] ?? path47.basename(displayRef),
29981
+ name: loaded.packNames[0] ?? path50.basename(displayRef),
29762
29982
  scope,
29763
29983
  ref: displayRef,
29764
29984
  profiles: Object.keys(loaded.profiles).length,
@@ -29772,20 +29992,20 @@ function probe(loadRef, baseRoot, scope, displayRef) {
29772
29992
  };
29773
29993
  }
29774
29994
  function writeFileAtomic(file, content) {
29775
- fs38.mkdirSync(path47.dirname(file), { recursive: true });
29995
+ fs39.mkdirSync(path50.dirname(file), { recursive: true });
29776
29996
  const tmp = `${file}.tmp`;
29777
- fs38.writeFileSync(tmp, content);
29778
- fs38.renameSync(tmp, file);
29997
+ fs39.writeFileSync(tmp, content);
29998
+ fs39.renameSync(tmp, file);
29779
29999
  }
29780
30000
  function stem(ref) {
29781
- return path47.basename(ref).replace(PACK_EXT_RE, "");
30001
+ return path50.basename(ref).replace(PACK_EXT_RE, "");
29782
30002
  }
29783
30003
  function imagePacksDir() {
29784
30004
  return process.env.WAIRON_IMAGE_PACKS_DIR ?? "/opt/wairon/packs";
29785
30005
  }
29786
30006
  function probeTier(dir, tier) {
29787
30007
  return hostCore.discoverPacks(dir).map((full) => {
29788
- const d = probe(full, path47.dirname(full), "global", path47.basename(full));
30008
+ const d = probe(full, path50.dirname(full), "global", path50.basename(full));
29789
30009
  d.tier = tier;
29790
30010
  return d;
29791
30011
  });
@@ -29803,9 +30023,9 @@ function scanGlobalPackProfiles() {
29803
30023
  for (const dir of [hostCore.globalPacksDir(), imagePacksDir()]) {
29804
30024
  for (const full of hostCore.discoverPacks(dir)) {
29805
30025
  try {
29806
- const loaded = hostCore.loadExtensionPacks([{ ref: full, scope: "global" }], path47.dirname(full));
30026
+ const loaded = hostCore.loadExtensionPacks([{ ref: full, scope: "global" }], path50.dirname(full));
29807
30027
  if (loaded.errors.length) continue;
29808
- const source = loaded.packNames[0] ?? path47.basename(full);
30028
+ const source = loaded.packNames[0] ?? path50.basename(full);
29809
30029
  for (const [id, def] of Object.entries(loaded.profiles)) out.push({ id, source, family: def.family });
29810
30030
  } catch {
29811
30031
  }
@@ -29857,12 +30077,12 @@ function storeListProjectProfiles() {
29857
30077
  return out;
29858
30078
  }
29859
30079
  function readPackContent(full) {
29860
- const st = fs38.statSync(full);
29861
- if (st.isFile()) return fs38.readFileSync(full, "utf8");
30080
+ const st = fs39.statSync(full);
30081
+ if (st.isFile()) return fs39.readFileSync(full, "utf8");
29862
30082
  if (st.isDirectory()) {
29863
30083
  for (const entry of ["pack.yaml", "pack.yml"]) {
29864
- const p = path47.join(full, entry);
29865
- if (fs38.existsSync(p) && fs38.statSync(p).isFile()) return fs38.readFileSync(p, "utf8");
30084
+ const p = path50.join(full, entry);
30085
+ if (fs39.existsSync(p) && fs39.statSync(p).isFile()) return fs39.readFileSync(p, "utf8");
29866
30086
  }
29867
30087
  }
29868
30088
  return null;
@@ -29871,9 +30091,9 @@ function storeResolveGlobalPacks(names) {
29871
30091
  const index = /* @__PURE__ */ new Map();
29872
30092
  const indexTier = (dir, tier) => {
29873
30093
  for (const full of hostCore.discoverPacks(dir)) {
29874
- const manifestName = probe(full, path47.dirname(full), "global", path47.basename(full)).name;
30094
+ const manifestName = probe(full, path50.dirname(full), "global", path50.basename(full)).name;
29875
30095
  const candidate = { full, manifestName, tier };
29876
- for (const key of [manifestName, stem(full), path47.basename(full)]) {
30096
+ for (const key of [manifestName, stem(full), path50.basename(full)]) {
29877
30097
  if (!index.has(key)) index.set(key, candidate);
29878
30098
  }
29879
30099
  }
@@ -29900,7 +30120,7 @@ function storeInstallGlobalPack(name, content) {
29900
30120
  assertName(name);
29901
30121
  assertDeclarative(content);
29902
30122
  const dir = hostCore.globalPacksDir();
29903
- const file = path47.join(dir, `${name}.yaml`);
30123
+ const file = path50.join(dir, `${name}.yaml`);
29904
30124
  writeFileAtomic(file, content);
29905
30125
  const descriptor = probe(file, dir, "global", `${name}.yaml`);
29906
30126
  descriptor.tier = "instance";
@@ -29911,7 +30131,7 @@ function storeInstallGlobalPackArchive(archive, name) {
29911
30131
  assertNotCodeArchive(info);
29912
30132
  const packName = name ?? info.name;
29913
30133
  assertName(packName);
29914
- const dir = path47.join(hostCore.globalPacksDir(), packName);
30134
+ const dir = path50.join(hostCore.globalPacksDir(), packName);
29915
30135
  extractDeclarativeArchive(archive, dir);
29916
30136
  const descriptor = probe(dir, hostCore.globalPacksDir(), "global", packName);
29917
30137
  descriptor.tier = "instance";
@@ -29920,16 +30140,16 @@ function storeInstallGlobalPackArchive(archive, name) {
29920
30140
  function storeRemoveGlobalPack(name) {
29921
30141
  assertName(name);
29922
30142
  const dir = hostCore.globalPacksDir();
29923
- const match = hostCore.discoverPacks(dir).find((ref) => stem(ref) === name || path47.basename(ref) === name);
30143
+ const match = hostCore.discoverPacks(dir).find((ref) => stem(ref) === name || path50.basename(ref) === name);
29924
30144
  if (!match) {
29925
30145
  const inImage = hostCore.discoverPacks(imagePacksDir()).some(
29926
- (ref) => stem(ref) === name || path47.basename(ref) === name
30146
+ (ref) => stem(ref) === name || path50.basename(ref) === name
29927
30147
  );
29928
30148
  throw new Error(
29929
30149
  inImage ? `Pack "${name}" is an immutable image-layer pack (WAIRON_IMAGE_PACKS_DIR) and cannot be removed at runtime; rebuild the extension image without it.` : `No server-global instance pack named "${name}".`
29930
30150
  );
29931
30151
  }
29932
- fs38.rmSync(match, { recursive: true, force: true });
30152
+ fs39.rmSync(match, { recursive: true, force: true });
29933
30153
  }
29934
30154
  function storeListProjectPacks() {
29935
30155
  const root = getProjectRoot();
@@ -29945,7 +30165,7 @@ function storeInstallProjectPack(name, content) {
29945
30165
  assertDeclarative(content);
29946
30166
  const root = getProjectRoot();
29947
30167
  const relRef = `.wai/packs/${name}.yaml`;
29948
- writeFileAtomic(path47.join(root, ".wai", "packs", `${name}.yaml`), content);
30168
+ writeFileAtomic(path50.join(root, ".wai", "packs", `${name}.yaml`), content);
29949
30169
  const config = loadProjectConfig();
29950
30170
  const packs = config.extensions?.packs ?? [];
29951
30171
  if (!packs.includes(relRef)) {
@@ -29961,7 +30181,7 @@ function storeInstallProjectPackArchive(archive, name) {
29961
30181
  assertName(packName);
29962
30182
  const root = getProjectRoot();
29963
30183
  const relRef = `.wai/packs/${packName}`;
29964
- extractDeclarativeArchive(archive, path47.join(root, ".wai", "packs", packName));
30184
+ extractDeclarativeArchive(archive, path50.join(root, ".wai", "packs", packName));
29965
30185
  const config = loadProjectConfig();
29966
30186
  const packs = config.extensions?.packs ?? [];
29967
30187
  if (!packs.includes(relRef)) {
@@ -29976,18 +30196,18 @@ function storeRemoveProjectPack(name) {
29976
30196
  const config = loadProjectConfig();
29977
30197
  const packs = config.extensions?.packs ?? [];
29978
30198
  const relRef = `.wai/packs/${name}.yaml`;
29979
- const match = packs.find((entry) => typeof entry === "string" ? entry === relRef || stem(entry) === name || path47.basename(entry) === name : entry.name === name);
30199
+ const match = packs.find((entry) => typeof entry === "string" ? entry === relRef || stem(entry) === name || path50.basename(entry) === name : entry.name === name);
29980
30200
  if (!match) throw new Error(`Project has no registered pack named "${name}".`);
29981
30201
  config.extensions = { packs: packs.filter((entry) => entry !== match), useGlobalPacks: hostCore.globalPacksEnabled(config) };
29982
30202
  saveProjectConfig(config);
29983
- const resolved = path47.resolve(root, typeof match === "string" ? match : path47.join(".wai", "packs", match.name));
29984
- const vendorDir = path47.resolve(root, ".wai", "packs");
29985
- if (resolved.startsWith(vendorDir + path47.sep)) {
29986
- fs38.rmSync(resolved, { recursive: true, force: true });
30203
+ const resolved = path50.resolve(root, typeof match === "string" ? match : path50.join(".wai", "packs", match.name));
30204
+ const vendorDir = path50.resolve(root, ".wai", "packs");
30205
+ if (resolved.startsWith(vendorDir + path50.sep)) {
30206
+ fs39.rmSync(resolved, { recursive: true, force: true });
29987
30207
  }
29988
30208
  }
29989
30209
  function readProjectReferences(rootPath) {
29990
- const projectId = path47.basename(rootPath);
30210
+ const projectId = path50.basename(rootPath);
29991
30211
  const empty = { projectId, packNames: [] };
29992
30212
  try {
29993
30213
  return runWithProjectRoot(rootPath, () => {
@@ -30110,9 +30330,9 @@ function installProjectPackArchive(cfg, credential, project2, archive, name) {
30110
30330
  }
30111
30331
 
30112
30332
  // src/server/audit.ts
30113
- var fs39 = __toESM(require("fs"));
30114
- var path48 = __toESM(require("path"));
30115
- var crypto9 = __toESM(require("crypto"));
30333
+ var fs40 = __toESM(require("fs"));
30334
+ var path51 = __toESM(require("path"));
30335
+ var crypto10 = __toESM(require("crypto"));
30116
30336
  var LEVEL_ORDER = {
30117
30337
  debug: 0,
30118
30338
  info: 1,
@@ -30134,13 +30354,13 @@ var DEFAULT_AUDIT_POLICY = {
30134
30354
  metadataMode: "redacted"
30135
30355
  };
30136
30356
  function storePath9(dataDir) {
30137
- return path48.join(dataDir, "audit-events.json");
30357
+ return path51.join(dataDir, "audit-events.json");
30138
30358
  }
30139
30359
  function readEvents(dataDir) {
30140
30360
  const p = storePath9(dataDir);
30141
30361
  let raw;
30142
30362
  try {
30143
- raw = fs39.readFileSync(p, "utf8");
30363
+ raw = fs40.readFileSync(p, "utf8");
30144
30364
  } catch (e) {
30145
30365
  if (e.code === "ENOENT") return [];
30146
30366
  throw new Error(`Failed to read audit store at ${p}: ${e.message}`);
@@ -30155,10 +30375,10 @@ function readEvents(dataDir) {
30155
30375
  }
30156
30376
  function persistEvents(dataDir, events) {
30157
30377
  const p = storePath9(dataDir);
30158
- fs39.mkdirSync(path48.dirname(p), { recursive: true });
30378
+ fs40.mkdirSync(path51.dirname(p), { recursive: true });
30159
30379
  const tmp = `${p}.tmp`;
30160
- fs39.writeFileSync(tmp, JSON.stringify(events, null, 2) + "\n");
30161
- fs39.renameSync(tmp, p);
30380
+ fs40.writeFileSync(tmp, JSON.stringify(events, null, 2) + "\n");
30381
+ fs40.renameSync(tmp, p);
30162
30382
  }
30163
30383
  var SECRET_RE = /Bearer\s+\S/i;
30164
30384
  var LONG_HEX_RE = /[0-9a-fA-F]{32,}/;
@@ -30216,7 +30436,7 @@ var AuditRegistry = class {
30216
30436
  }
30217
30437
  const stamped = {
30218
30438
  ...event,
30219
- id: event.id && event.id.length > 0 ? event.id : crypto9.randomUUID(),
30439
+ id: event.id && event.id.length > 0 ? event.id : crypto10.randomUUID(),
30220
30440
  timestamp: event.timestamp && event.timestamp.length > 0 ? event.timestamp : (/* @__PURE__ */ new Date()).toISOString(),
30221
30441
  metadata
30222
30442
  };
@@ -30483,10 +30703,10 @@ function unbindRole(cfg, credential, userId, roleId, scopeKind, scopeId) {
30483
30703
  }
30484
30704
 
30485
30705
  // src/server/identity.ts
30486
- var crypto11 = __toESM(require("crypto"));
30706
+ var crypto12 = __toESM(require("crypto"));
30487
30707
 
30488
30708
  // src/server/idp.ts
30489
- var crypto10 = __toESM(require("crypto"));
30709
+ var crypto11 = __toESM(require("crypto"));
30490
30710
  var REQUESTED_SCOPE = "openid email profile";
30491
30711
  var discoveryCache = /* @__PURE__ */ new Map();
30492
30712
  var jwksCache = /* @__PURE__ */ new Map();
@@ -30713,7 +30933,7 @@ function verifyJwtSignature(alg, signingInput, jwk, sigB64url) {
30713
30933
  if (!digest) return false;
30714
30934
  let keyObject;
30715
30935
  try {
30716
- keyObject = crypto10.createPublicKey({ key: jwk, format: "jwk" });
30936
+ keyObject = crypto11.createPublicKey({ key: jwk, format: "jwk" });
30717
30937
  } catch {
30718
30938
  return false;
30719
30939
  }
@@ -30721,18 +30941,18 @@ function verifyJwtSignature(alg, signingInput, jwk, sigB64url) {
30721
30941
  const sig = Buffer.from(sigB64url, "base64url");
30722
30942
  try {
30723
30943
  if (alg.startsWith("RS")) {
30724
- return crypto10.verify(digest, data, keyObject, sig);
30944
+ return crypto11.verify(digest, data, keyObject, sig);
30725
30945
  }
30726
30946
  if (alg.startsWith("PS")) {
30727
- return crypto10.verify(
30947
+ return crypto11.verify(
30728
30948
  digest,
30729
30949
  data,
30730
- { key: keyObject, padding: crypto10.constants.RSA_PKCS1_PSS_PADDING, saltLength: crypto10.constants.RSA_PSS_SALTLEN_DIGEST },
30950
+ { key: keyObject, padding: crypto11.constants.RSA_PKCS1_PSS_PADDING, saltLength: crypto11.constants.RSA_PSS_SALTLEN_DIGEST },
30731
30951
  sig
30732
30952
  );
30733
30953
  }
30734
30954
  if (alg.startsWith("ES")) {
30735
- return crypto10.verify(digest, data, { key: keyObject, dsaEncoding: "ieee-p1363" }, sig);
30955
+ return crypto11.verify(digest, data, { key: keyObject, dsaEncoding: "ieee-p1363" }, sig);
30736
30956
  }
30737
30957
  } catch {
30738
30958
  return false;
@@ -30846,8 +31066,8 @@ function assertAllowedRedirectUri(provider, redirectUri) {
30846
31066
  }
30847
31067
 
30848
31068
  // src/server/policy.ts
30849
- var fs40 = __toESM(require("fs"));
30850
- var path49 = __toESM(require("path"));
31069
+ var fs41 = __toESM(require("fs"));
31070
+ var path52 = __toESM(require("path"));
30851
31071
  init_fs();
30852
31072
  init_yaml();
30853
31073
  init_loader();
@@ -30866,13 +31086,13 @@ function sendJson(res, status2, body) {
30866
31086
 
30867
31087
  // src/server/policy.ts
30868
31088
  function packPolicyPath(dataDir) {
30869
- return path49.join(dataDir, "pack-policy.json");
31089
+ return path52.join(dataDir, "pack-policy.json");
30870
31090
  }
30871
31091
  function getPackPolicyRecord(dataDir) {
30872
31092
  const p = packPolicyPath(dataDir);
30873
31093
  let raw;
30874
31094
  try {
30875
- raw = fs40.readFileSync(p, "utf8");
31095
+ raw = fs41.readFileSync(p, "utf8");
30876
31096
  } catch (e) {
30877
31097
  if (e.code === "ENOENT") return null;
30878
31098
  throw new Error(`Failed to read pack policy store at ${p}: ${e.message}`);
@@ -30886,14 +31106,14 @@ function getPackPolicyRecord(dataDir) {
30886
31106
  function setPackPolicyRecord(dataDir, policy) {
30887
31107
  const stored = { ...policy, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
30888
31108
  const p = packPolicyPath(dataDir);
30889
- fs40.mkdirSync(path49.dirname(p), { recursive: true });
31109
+ fs41.mkdirSync(path52.dirname(p), { recursive: true });
30890
31110
  const tmp = `${p}.tmp`;
30891
- fs40.writeFileSync(tmp, JSON.stringify(stored, null, 2) + "\n");
30892
- fs40.renameSync(tmp, p);
31111
+ fs41.writeFileSync(tmp, JSON.stringify(stored, null, 2) + "\n");
31112
+ fs41.renameSync(tmp, p);
30893
31113
  return stored;
30894
31114
  }
30895
31115
  function exposurePolicyPath(dataDir) {
30896
- return path49.join(dataDir, "exposure-policy.json");
31116
+ return path52.join(dataDir, "exposure-policy.json");
30897
31117
  }
30898
31118
  var COMPATIBLE_DEFAULT_EXPOSURE = {
30899
31119
  adminApiMode: "local_only",
@@ -30910,7 +31130,7 @@ function getExposurePolicyRecord(dataDir) {
30910
31130
  const p = exposurePolicyPath(dataDir);
30911
31131
  let raw;
30912
31132
  try {
30913
- raw = fs40.readFileSync(p, "utf8");
31133
+ raw = fs41.readFileSync(p, "utf8");
30914
31134
  } catch (e) {
30915
31135
  if (e.code === "ENOENT") return null;
30916
31136
  throw new Error(`Failed to read exposure policy store at ${p}: ${e.message}`);
@@ -30923,10 +31143,10 @@ function getExposurePolicyRecord(dataDir) {
30923
31143
  }
30924
31144
  function setExposurePolicyRecord(dataDir, policy) {
30925
31145
  const p = exposurePolicyPath(dataDir);
30926
- fs40.mkdirSync(path49.dirname(p), { recursive: true });
31146
+ fs41.mkdirSync(path52.dirname(p), { recursive: true });
30927
31147
  const tmp = `${p}.tmp`;
30928
- fs40.writeFileSync(tmp, JSON.stringify(policy, null, 2) + "\n");
30929
- fs40.renameSync(tmp, p);
31148
+ fs41.writeFileSync(tmp, JSON.stringify(policy, null, 2) + "\n");
31149
+ fs41.renameSync(tmp, p);
30930
31150
  return policy;
30931
31151
  }
30932
31152
  var PERMISSIVE_DEFAULT_POLICY = {
@@ -30944,7 +31164,7 @@ function effectivePolicy(dataDir) {
30944
31164
  return getPackPolicyRecord(dataDir) ?? PERMISSIVE_DEFAULT_POLICY;
30945
31165
  }
30946
31166
  function identityProvidersPath(dataDir) {
30947
- return path49.join(dataDir, "identity-providers.json");
31167
+ return path52.join(dataDir, "identity-providers.json");
30948
31168
  }
30949
31169
  function sanitizeIdentityProvider(config) {
30950
31170
  const clean = {
@@ -30968,16 +31188,16 @@ function sanitizeIdentityProvider(config) {
30968
31188
  }
30969
31189
  function writeIdentityProviderRecords(dataDir, records) {
30970
31190
  const p = identityProvidersPath(dataDir);
30971
- fs40.mkdirSync(path49.dirname(p), { recursive: true });
31191
+ fs41.mkdirSync(path52.dirname(p), { recursive: true });
30972
31192
  const tmp = `${p}.tmp`;
30973
- fs40.writeFileSync(tmp, JSON.stringify(records, null, 2) + "\n");
30974
- fs40.renameSync(tmp, p);
31193
+ fs41.writeFileSync(tmp, JSON.stringify(records, null, 2) + "\n");
31194
+ fs41.renameSync(tmp, p);
30975
31195
  }
30976
31196
  function listIdentityProviderRecords(dataDir) {
30977
31197
  const p = identityProvidersPath(dataDir);
30978
31198
  let raw;
30979
31199
  try {
30980
- raw = fs40.readFileSync(p, "utf8");
31200
+ raw = fs41.readFileSync(p, "utf8");
30981
31201
  } catch (e) {
30982
31202
  if (e.code === "ENOENT") return [];
30983
31203
  throw new Error(`Failed to read identity provider store at ${p}: ${e.message}`);
@@ -31604,9 +31824,9 @@ function mintToken(cfg, credential, request) {
31604
31824
  if (owner && owner.status !== "active") {
31605
31825
  throw new ForbiddenError("cannot mint a token for a deactivated user");
31606
31826
  }
31607
- const token = "wk_" + crypto11.randomBytes(24).toString("hex");
31827
+ const token = "wk_" + crypto12.randomBytes(24).toString("hex");
31608
31828
  const record2 = {
31609
- id: crypto11.randomBytes(6).toString("hex"),
31829
+ id: crypto12.randomBytes(6).toString("hex"),
31610
31830
  keyHash: hashToken(token),
31611
31831
  projects,
31612
31832
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -31650,10 +31870,10 @@ function mintSelfToken(cfg, credential, projectId, write) {
31650
31870
  if (parsed.mounts.length > 0) {
31651
31871
  assertMintableNarrowingEntry(cfg.dataDir, projectId);
31652
31872
  }
31653
- const token = "wk_" + crypto11.randomBytes(24).toString("hex");
31873
+ const token = "wk_" + crypto12.randomBytes(24).toString("hex");
31654
31874
  const owner = auditActor(principal);
31655
31875
  const record2 = {
31656
- id: crypto11.randomBytes(6).toString("hex"),
31876
+ id: crypto12.randomBytes(6).toString("hex"),
31657
31877
  keyHash: hashToken(token),
31658
31878
  projects: [projectId],
31659
31879
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -31768,7 +31988,7 @@ function resolveEnabledProvider(cfg, providerId) {
31768
31988
  }
31769
31989
  async function startSsoLogin(cfg, providerId, redirectUri) {
31770
31990
  const provider = resolveEnabledProvider(cfg, providerId);
31771
- const nonce = crypto11.randomBytes(16).toString("hex");
31991
+ const nonce = crypto12.randomBytes(16).toString("hex");
31772
31992
  const payload = { providerId, nonce, redirectUri };
31773
31993
  const state = signSsoState(JSON.stringify(payload));
31774
31994
  const endpoints = await resolveEndpoints(provider);
@@ -31819,9 +32039,9 @@ async function completeSsoLogin(cfg, state, code) {
31819
32039
  ...subject.email ? { email: subject.email } : {}
31820
32040
  });
31821
32041
  }
31822
- const token = "wk_" + crypto11.randomBytes(24).toString("hex");
32042
+ const token = "wk_" + crypto12.randomBytes(24).toString("hex");
31823
32043
  const record2 = {
31824
- id: crypto11.randomBytes(6).toString("hex"),
32044
+ id: crypto12.randomBytes(6).toString("hex"),
31825
32045
  keyHash: hashToken(token),
31826
32046
  projects: ["*"],
31827
32047
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -31953,17 +32173,17 @@ init_yaml();
31953
32173
  init_loader();
31954
32174
 
31955
32175
  // src/server/relations.ts
31956
- var fs41 = __toESM(require("fs"));
31957
- var path50 = __toESM(require("path"));
31958
- var crypto12 = __toESM(require("crypto"));
32176
+ var fs42 = __toESM(require("fs"));
32177
+ var path53 = __toESM(require("path"));
32178
+ var crypto13 = __toESM(require("crypto"));
31959
32179
  function storePath10(dataDir) {
31960
- return path50.join(dataDir, "relations.json");
32180
+ return path53.join(dataDir, "relations.json");
31961
32181
  }
31962
32182
  function readRelations(dataDir) {
31963
32183
  const p = storePath10(dataDir);
31964
32184
  let raw;
31965
32185
  try {
31966
- raw = fs41.readFileSync(p, "utf8");
32186
+ raw = fs42.readFileSync(p, "utf8");
31967
32187
  } catch (e) {
31968
32188
  if (e.code === "ENOENT") return [];
31969
32189
  throw new Error(`Failed to read relation store at ${p}: ${e.message}`);
@@ -31978,10 +32198,10 @@ function readRelations(dataDir) {
31978
32198
  }
31979
32199
  function persistRelations(dataDir, relations) {
31980
32200
  const p = storePath10(dataDir);
31981
- fs41.mkdirSync(path50.dirname(p), { recursive: true });
32201
+ fs42.mkdirSync(path53.dirname(p), { recursive: true });
31982
32202
  const tmp = `${p}.tmp`;
31983
- fs41.writeFileSync(tmp, JSON.stringify(relations, null, 2) + "\n");
31984
- fs41.renameSync(tmp, p);
32203
+ fs42.writeFileSync(tmp, JSON.stringify(relations, null, 2) + "\n");
32204
+ fs42.renameSync(tmp, p);
31985
32205
  }
31986
32206
  var ProjectRelationStore = class {
31987
32207
  constructor(dataDir) {
@@ -32024,7 +32244,7 @@ var ProjectRelationRegistry = class {
32024
32244
  const hasStatus = typeof record2.status === "string" && record2.status.trim().length > 0;
32025
32245
  const stored = {
32026
32246
  ...record2,
32027
- id: hasId ? record2.id : crypto12.randomUUID(),
32247
+ id: hasId ? record2.id : crypto13.randomUUID(),
32028
32248
  status: hasStatus ? record2.status : "active"
32029
32249
  };
32030
32250
  const relations = this.store.all();
@@ -32091,16 +32311,16 @@ function listProjectRelations(dataDir, sourceProjectId, targetProjectId, status2
32091
32311
  }
32092
32312
 
32093
32313
  // src/server/surfaces.ts
32094
- var fs42 = __toESM(require("fs"));
32095
- var path51 = __toESM(require("path"));
32314
+ var fs43 = __toESM(require("fs"));
32315
+ var path54 = __toESM(require("path"));
32096
32316
  function storePath11(dataDir) {
32097
- return path51.join(dataDir, "public-surfaces.json");
32317
+ return path54.join(dataDir, "public-surfaces.json");
32098
32318
  }
32099
32319
  function readSnapshots(dataDir) {
32100
32320
  const p = storePath11(dataDir);
32101
32321
  let raw;
32102
32322
  try {
32103
- raw = fs42.readFileSync(p, "utf8");
32323
+ raw = fs43.readFileSync(p, "utf8");
32104
32324
  } catch (e) {
32105
32325
  if (e.code === "ENOENT") return [];
32106
32326
  throw new Error(`Failed to read public surface store at ${p}: ${e.message}`);
@@ -32115,10 +32335,10 @@ function readSnapshots(dataDir) {
32115
32335
  }
32116
32336
  function persistSnapshots(dataDir, snapshots) {
32117
32337
  const p = storePath11(dataDir);
32118
- fs42.mkdirSync(path51.dirname(p), { recursive: true });
32338
+ fs43.mkdirSync(path54.dirname(p), { recursive: true });
32119
32339
  const tmp = `${p}.tmp`;
32120
- fs42.writeFileSync(tmp, JSON.stringify(snapshots, null, 2) + "\n");
32121
- fs42.renameSync(tmp, p);
32340
+ fs43.writeFileSync(tmp, JSON.stringify(snapshots, null, 2) + "\n");
32341
+ fs43.renameSync(tmp, p);
32122
32342
  }
32123
32343
  var PublicSurfaceStore = class {
32124
32344
  constructor(dataDir) {
@@ -32261,12 +32481,12 @@ function resolveVisibility(observerProjectId, units, placements) {
32261
32481
  const best = /* @__PURE__ */ new Map();
32262
32482
  for (const placement of placements) {
32263
32483
  if (placement.projectId === observerProjectId) continue;
32264
- const path64 = chainOf(placement.unitId, unitById);
32265
- if (!path64.length) continue;
32266
- const closedOk = path64.every((u) => effectivePosture(u, unitById) !== "closed" || observerInside(u.id) || grantedTo(u));
32484
+ const path67 = chainOf(placement.unitId, unitById);
32485
+ if (!path67.length) continue;
32486
+ const closedOk = path67.every((u) => effectivePosture(u, unitById) !== "closed" || observerInside(u.id) || grantedTo(u));
32267
32487
  if (!closedOk) continue;
32268
- const crossTenant = !tenantRoots.has(path64[path64.length - 1].id);
32269
- if (crossTenant && !path64.some(grantedTo)) continue;
32488
+ const crossTenant = !tenantRoots.has(path67[path67.length - 1].id);
32489
+ if (crossTenant && !path67.some(grantedTo)) continue;
32270
32490
  if (crossTenant && directUnits.length === 0) continue;
32271
32491
  const distance = crossTenant ? "partner" : sameBranch(placement.unitId) ? "department" : "instance";
32272
32492
  const existing = best.get(placement.projectId);
@@ -32912,8 +33132,8 @@ function handleLandscapeRequest(cfg, credential, req, res, body, url) {
32912
33132
  }
32913
33133
 
32914
33134
  // src/server/migration.ts
32915
- var fs43 = __toESM(require("fs"));
32916
- var path52 = __toESM(require("path"));
33135
+ var fs44 = __toESM(require("fs"));
33136
+ var path55 = __toESM(require("path"));
32917
33137
  var LEGACY_CAPABILITY_MAP = {
32918
33138
  "mcp:read": "project:read",
32919
33139
  "operations:read": "project:read",
@@ -32945,16 +33165,16 @@ function scopeOf(grant) {
32945
33165
  }
32946
33166
  function readRaw(file) {
32947
33167
  try {
32948
- return JSON.parse(fs43.readFileSync(file, "utf8"));
33168
+ return JSON.parse(fs44.readFileSync(file, "utf8"));
32949
33169
  } catch {
32950
33170
  return null;
32951
33171
  }
32952
33172
  }
32953
33173
  function writeRaw(file, value) {
32954
- fs43.mkdirSync(path52.dirname(file), { recursive: true });
33174
+ fs44.mkdirSync(path55.dirname(file), { recursive: true });
32955
33175
  const tmp = `${file}.tmp`;
32956
- fs43.writeFileSync(tmp, JSON.stringify(value, null, 2) + "\n");
32957
- fs43.renameSync(tmp, file);
33176
+ fs44.writeFileSync(tmp, JSON.stringify(value, null, 2) + "\n");
33177
+ fs44.renameSync(tmp, file);
32958
33178
  }
32959
33179
  function slugify(name) {
32960
33180
  return name.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "") || "unit";
@@ -32988,13 +33208,13 @@ function migratePermissionModel(dataDir, apply) {
32988
33208
  findings.push({ area, detail });
32989
33209
  };
32990
33210
  const grid = readRaw(
32991
- path52.join(dataDir, "permissions.json")
33211
+ path55.join(dataDir, "permissions.json")
32992
33212
  ) ?? [];
32993
33213
  if (!getInstanceIdentity(dataDir)) {
32994
33214
  found("instance", "instance identity is not seeded \u2014 the built-in admin/dev subjects have no persisted UUIDs");
32995
33215
  if (apply) ensureInstanceIdentity(dataDir);
32996
33216
  }
32997
- const orgPath = path52.join(dataDir, "organization.json");
33217
+ const orgPath = path55.join(dataDir, "organization.json");
32998
33218
  const org = readRaw(orgPath);
32999
33219
  if (org?.units?.length) {
33000
33220
  const units = org.units;
@@ -33048,7 +33268,7 @@ function migratePermissionModel(dataDir, apply) {
33048
33268
  found("units", `${remap.length} unit id(s) would be remapped across placements, exposeTo, assignments, and users`);
33049
33269
  }
33050
33270
  }
33051
- const usersPath = path52.join(dataDir, "users.json");
33271
+ const usersPath = path55.join(dataDir, "users.json");
33052
33272
  const users = readRaw(usersPath);
33053
33273
  if (users) {
33054
33274
  let changed = false;
@@ -33075,7 +33295,7 @@ function migratePermissionModel(dataDir, apply) {
33075
33295
  }
33076
33296
  if (apply && changed) writeRaw(usersPath, users);
33077
33297
  }
33078
- const keysPath = path52.join(dataDir, "auth", "credentials.json");
33298
+ const keysPath = path55.join(dataDir, "auth", "credentials.json");
33079
33299
  const keys = readRaw(keysPath);
33080
33300
  if (keys) {
33081
33301
  let changed = false;
@@ -33125,7 +33345,7 @@ function migratePermissionModel(dataDir, apply) {
33125
33345
  }
33126
33346
  if (apply && changed) writeRaw(keysPath, keys);
33127
33347
  }
33128
- const sessionsPath = path52.join(dataDir, "web-sessions.json");
33348
+ const sessionsPath = path55.join(dataDir, "web-sessions.json");
33129
33349
  const sessions = readRaw(sessionsPath);
33130
33350
  if (sessions) {
33131
33351
  let changed = false;
@@ -33204,25 +33424,25 @@ function migratePermissionModel(dataDir, apply) {
33204
33424
 
33205
33425
  // src/server/http.ts
33206
33426
  var http2 = __toESM(require("http"));
33207
- var fs51 = __toESM(require("fs"));
33208
- var path60 = __toESM(require("path"));
33427
+ var fs52 = __toESM(require("fs"));
33428
+ var path63 = __toESM(require("path"));
33209
33429
 
33210
33430
  // src/server/request.ts
33211
33431
  var import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
33212
33432
  init_fs();
33213
33433
 
33214
33434
  // src/server/approvals.ts
33215
- var fs44 = __toESM(require("fs"));
33216
- var path53 = __toESM(require("path"));
33217
- var crypto13 = __toESM(require("crypto"));
33435
+ var fs45 = __toESM(require("fs"));
33436
+ var path56 = __toESM(require("path"));
33437
+ var crypto14 = __toESM(require("crypto"));
33218
33438
  function storePath12(dataDir) {
33219
- return path53.join(dataDir, "approvals.json");
33439
+ return path56.join(dataDir, "approvals.json");
33220
33440
  }
33221
33441
  function readRequests(dataDir) {
33222
33442
  const p = storePath12(dataDir);
33223
33443
  let raw;
33224
33444
  try {
33225
- raw = fs44.readFileSync(p, "utf8");
33445
+ raw = fs45.readFileSync(p, "utf8");
33226
33446
  } catch (e) {
33227
33447
  if (e.code === "ENOENT") return [];
33228
33448
  throw new Error(`Failed to read approval store at ${p}: ${e.message}`);
@@ -33237,10 +33457,10 @@ function readRequests(dataDir) {
33237
33457
  }
33238
33458
  function persistRequests(dataDir, requests) {
33239
33459
  const p = storePath12(dataDir);
33240
- fs44.mkdirSync(path53.dirname(p), { recursive: true });
33460
+ fs45.mkdirSync(path56.dirname(p), { recursive: true });
33241
33461
  const tmp = `${p}.tmp`;
33242
- fs44.writeFileSync(tmp, JSON.stringify(requests, null, 2) + "\n");
33243
- fs44.renameSync(tmp, p);
33462
+ fs45.writeFileSync(tmp, JSON.stringify(requests, null, 2) + "\n");
33463
+ fs45.renameSync(tmp, p);
33244
33464
  }
33245
33465
  var SECRET_RE2 = /Bearer\s+\S/i;
33246
33466
  var LONG_HEX_RE2 = /[0-9a-fA-F]{32,}/;
@@ -33288,7 +33508,7 @@ var ApprovalRegistry = class {
33288
33508
  }
33289
33509
  const stored = {
33290
33510
  ...request,
33291
- id: crypto13.randomUUID(),
33511
+ id: crypto14.randomUUID(),
33292
33512
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
33293
33513
  status: "pending"
33294
33514
  };
@@ -33597,23 +33817,6 @@ function lockProject2(cfg, credential, projectId, subproject) {
33597
33817
  }
33598
33818
  });
33599
33819
  }
33600
- function promoteProject2(cfg, credential, projectId, subproject) {
33601
- return lifecycleAction(cfg, credential, projectId, {
33602
- action: "project:promote",
33603
- verb: "Promote",
33604
- noun: "promotion",
33605
- subproject,
33606
- execute: () => {
33607
- const promo = executeApprovedPromote(cfg, projectId, subproject);
33608
- return {
33609
- status: "completed",
33610
- action: "project:promote",
33611
- summary: `Promotion of project "${projectId}"${subprojectSuffix(subproject)}: ${promo.status} \u2014 ${promo.message}`,
33612
- promote: promo
33613
- };
33614
- }
33615
- });
33616
- }
33617
33820
  function subprojectSuffix(subproject) {
33618
33821
  return subproject ? ` subproject "${subproject}"` : "";
33619
33822
  }
@@ -33737,11 +33940,6 @@ function executeApproved(cfg, req) {
33737
33940
  const lock = executeApprovedLock(cfg, req.projectId ?? "", scope);
33738
33941
  return `Locked project "${req.projectId}"${subprojectSuffix(scope)} (status: ${lock.status}).`;
33739
33942
  }
33740
- case "project:promote": {
33741
- const scope = readSubprojectScope(req);
33742
- const promo = executeApprovedPromote(cfg, req.projectId ?? "", scope);
33743
- return `Promotion of project "${req.projectId}"${subprojectSuffix(scope)}: ${promo.status} \u2014 ${promo.message}`;
33744
- }
33745
33943
  default:
33746
33944
  throw new Error(`Unsupported approval kind "${req.kind}".`);
33747
33945
  }
@@ -33783,7 +33981,7 @@ async function awaitApproval(cfg, credential, requestId, timeoutSeconds) {
33783
33981
  let current2 = req;
33784
33982
  while (current2.status === "pending" && Date.now() < deadline) {
33785
33983
  const remaining = deadline - Date.now();
33786
- await new Promise((resolve26) => setTimeout(resolve26, Math.min(AWAIT_POLL_INTERVAL_MS, remaining)));
33984
+ await new Promise((resolve27) => setTimeout(resolve27, Math.min(AWAIT_POLL_INTERVAL_MS, remaining)));
33787
33985
  expirePendingApprovals(cfg.dataDir, (/* @__PURE__ */ new Date()).toISOString());
33788
33986
  current2 = getApprovalRequestById(cfg.dataDir, requestId) ?? current2;
33789
33987
  }
@@ -34051,12 +34249,12 @@ function handleOperationsRequest(cfg, credential, req, res, url) {
34051
34249
  }
34052
34250
 
34053
34251
  // src/server/gitbacking.ts
34054
- var fs45 = __toESM(require("fs"));
34055
- var path54 = __toESM(require("path"));
34056
- var crypto14 = __toESM(require("crypto"));
34252
+ var fs46 = __toESM(require("fs"));
34253
+ var path57 = __toESM(require("path"));
34254
+ var crypto15 = __toESM(require("crypto"));
34057
34255
  var import_child_process4 = require("child_process");
34058
34256
  function storePath13(dataDir) {
34059
- return path54.join(dataDir, "git-backing.json");
34257
+ return path57.join(dataDir, "git-backing.json");
34060
34258
  }
34061
34259
  var GitBackingStore = class {
34062
34260
  constructor(dataDir) {
@@ -34068,7 +34266,7 @@ var GitBackingStore = class {
34068
34266
  const p = storePath13(this.dataDir);
34069
34267
  let raw;
34070
34268
  try {
34071
- raw = fs45.readFileSync(p, "utf8");
34269
+ raw = fs46.readFileSync(p, "utf8");
34072
34270
  } catch (err) {
34073
34271
  if (err.code === "ENOENT") return [];
34074
34272
  throw new Error(`Cannot read git-backing store at ${p}: ${err.message}`);
@@ -34087,10 +34285,10 @@ var GitBackingStore = class {
34087
34285
  /** Swap the persisted collection wholesale via write-temp-then-rename. */
34088
34286
  replaceAll(bindings) {
34089
34287
  const p = storePath13(this.dataDir);
34090
- fs45.mkdirSync(path54.dirname(p), { recursive: true });
34288
+ fs46.mkdirSync(path57.dirname(p), { recursive: true });
34091
34289
  const tmp = `${p}.tmp`;
34092
- fs45.writeFileSync(tmp, JSON.stringify(bindings, null, 2) + "\n");
34093
- fs45.renameSync(tmp, p);
34290
+ fs46.writeFileSync(tmp, JSON.stringify(bindings, null, 2) + "\n");
34291
+ fs46.renameSync(tmp, p);
34094
34292
  }
34095
34293
  };
34096
34294
  var GitBackingRegistry = class {
@@ -34109,7 +34307,7 @@ var GitBackingRegistry = class {
34109
34307
  const bindings = this.store.load();
34110
34308
  const stored = {
34111
34309
  ...binding,
34112
- id: binding.id || crypto14.randomUUID(),
34310
+ id: binding.id || crypto15.randomUUID(),
34113
34311
  createdAt: binding.createdAt || (/* @__PURE__ */ new Date()).toISOString()
34114
34312
  };
34115
34313
  const sameScope = (b) => b.scopeKind === stored.scopeKind && (b.scopeId ?? "") === (stored.scopeId ?? "");
@@ -34195,8 +34393,8 @@ function checkoutBranch(workdir, branch) {
34195
34393
  }
34196
34394
  }
34197
34395
  function cloneOrOpen(remote, branch, workdir, credentialRef) {
34198
- if (!fs45.existsSync(path54.join(workdir, ".git"))) {
34199
- fs45.mkdirSync(workdir, { recursive: true });
34396
+ if (!fs46.existsSync(path57.join(workdir, ".git"))) {
34397
+ fs46.mkdirSync(workdir, { recursive: true });
34200
34398
  git2(["clone", authRemote2(remote, credentialRef), "."], workdir);
34201
34399
  git2(["config", "user.name", process.env["WAIRON_GIT_NAME"] || "wairon-bot"], workdir);
34202
34400
  git2(["config", "user.email", process.env["WAIRON_GIT_EMAIL"] || "wairon-bot@localhost"], workdir);
@@ -34208,11 +34406,11 @@ function cloneOrOpen(remote, branch, workdir, credentialRef) {
34208
34406
  return workdir;
34209
34407
  }
34210
34408
  function mirrorTree(sourceDir, targetDir) {
34211
- fs45.rmSync(targetDir, { recursive: true, force: true });
34212
- const stat = fs45.statSync(sourceDir, { throwIfNoEntry: false });
34409
+ fs46.rmSync(targetDir, { recursive: true, force: true });
34410
+ const stat = fs46.statSync(sourceDir, { throwIfNoEntry: false });
34213
34411
  if (!stat) return;
34214
- fs45.mkdirSync(path54.dirname(targetDir), { recursive: true });
34215
- fs45.cpSync(sourceDir, targetDir, { recursive: true });
34412
+ fs46.mkdirSync(path57.dirname(targetDir), { recursive: true });
34413
+ fs46.cpSync(sourceDir, targetDir, { recursive: true });
34216
34414
  }
34217
34415
  function commitAndPush(workdir, message) {
34218
34416
  git2(["add", "-A"], workdir);
@@ -34334,7 +34532,7 @@ function unbindScope(cfg, credential, bindingId) {
34334
34532
  tryAppendAudit7(cfg, buildAuditEvent6(principal, "git.backing.unbind", "security", bindingId));
34335
34533
  }
34336
34534
  function runMirrorSync(cfg, binding) {
34337
- const workdir = path54.join(cfg.dataDir, "git-backing", binding.id);
34535
+ const workdir = path57.join(cfg.dataDir, "git-backing", binding.id);
34338
34536
  cloneOrOpen(binding.remote, binding.branch, workdir, binding.credentialRef);
34339
34537
  if (binding.scopeKind === "unit") {
34340
34538
  const units = listOrganizationUnits(cfg.dataDir);
@@ -34342,23 +34540,23 @@ function runMirrorSync(cfg, binding) {
34342
34540
  const placedIds = new Set(
34343
34541
  listProjectPlacements(cfg.dataDir).filter((p) => subtree.has(p.unitId)).map((p) => p.projectId)
34344
34542
  );
34345
- const projectsDir = path54.join(workdir, "projects");
34346
- fs45.rmSync(projectsDir, { recursive: true, force: true });
34543
+ const projectsDir = path57.join(workdir, "projects");
34544
+ fs46.rmSync(projectsDir, { recursive: true, force: true });
34347
34545
  for (const rec of listProjectRecords(cfg.dataDir)) {
34348
34546
  if (!placedIds.has(rec.id)) continue;
34349
- mirrorTree(path54.join(rec.rootPath, ".wai"), path54.join(projectsDir, rec.id, ".wai"));
34547
+ mirrorTree(path57.join(rec.rootPath, ".wai"), path57.join(projectsDir, rec.id, ".wai"));
34350
34548
  }
34351
34549
  } else {
34352
- const instanceDir = path54.join(workdir, "instance");
34353
- fs45.rmSync(instanceDir, { recursive: true, force: true });
34550
+ const instanceDir = path57.join(workdir, "instance");
34551
+ fs46.rmSync(instanceDir, { recursive: true, force: true });
34354
34552
  const files = binding.includeCredentials ? INSTANCE_STRUCTURE_FILES : INSTANCE_STRUCTURE_FILES.filter((rel2) => rel2 !== "auth/credentials.json");
34355
34553
  for (const rel2 of files) {
34356
- mirrorTree(path54.join(cfg.dataDir, rel2), path54.join(instanceDir, rel2));
34554
+ mirrorTree(path57.join(cfg.dataDir, rel2), path57.join(instanceDir, rel2));
34357
34555
  }
34358
- const projectsDir = path54.join(workdir, "projects");
34359
- fs45.rmSync(projectsDir, { recursive: true, force: true });
34556
+ const projectsDir = path57.join(workdir, "projects");
34557
+ fs46.rmSync(projectsDir, { recursive: true, force: true });
34360
34558
  for (const rec of listProjectRecords(cfg.dataDir)) {
34361
- mirrorTree(path54.join(rec.rootPath, ".wai"), path54.join(projectsDir, rec.id, ".wai"));
34559
+ mirrorTree(path57.join(rec.rootPath, ".wai"), path57.join(projectsDir, rec.id, ".wai"));
34362
34560
  }
34363
34561
  }
34364
34562
  const published = commitAndPush(
@@ -34504,7 +34702,7 @@ function setExposurePolicy2(cfg, credential, exposure) {
34504
34702
 
34505
34703
  // src/server/websocket.ts
34506
34704
  var import_events = require("events");
34507
- var crypto15 = __toESM(require("crypto"));
34705
+ var crypto16 = __toESM(require("crypto"));
34508
34706
  var WS_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
34509
34707
  var MAX_PAYLOAD = 1 << 20;
34510
34708
  var OP_CONTINUATION = 0;
@@ -34518,7 +34716,7 @@ function isWebSocketUpgrade(req) {
34518
34716
  function acceptWebSocket(req, socket) {
34519
34717
  const key = req.headers["sec-websocket-key"];
34520
34718
  if (!isWebSocketUpgrade(req) || typeof key !== "string") return null;
34521
- const accept = crypto15.createHash("sha1").update(key + WS_GUID).digest("base64");
34719
+ const accept = crypto16.createHash("sha1").update(key + WS_GUID).digest("base64");
34522
34720
  socket.write(
34523
34721
  `HTTP/1.1 101 Switching Protocols\r
34524
34722
  Upgrade: websocket\r
@@ -34668,9 +34866,9 @@ function encodeFrame(opcode, payload) {
34668
34866
  }
34669
34867
 
34670
34868
  // src/server/web.ts
34671
- var crypto20 = __toESM(require("crypto"));
34672
- var fs50 = __toESM(require("fs"));
34673
- var path59 = __toESM(require("path"));
34869
+ var crypto21 = __toESM(require("crypto"));
34870
+ var fs51 = __toESM(require("fs"));
34871
+ var path62 = __toESM(require("path"));
34674
34872
 
34675
34873
  // src/server/webadmin.ts
34676
34874
  function listUsers3(cfg, sessionId, project2) {
@@ -34912,26 +35110,23 @@ function createProject2(cfg, sessionId, id, unitId, profileSelection) {
34912
35110
  function lockProject3(cfg, sessionId, projectId) {
34913
35111
  return lockProject(cfg, sessionId, projectId);
34914
35112
  }
34915
- function promoteProject3(cfg, sessionId, projectId) {
34916
- return promoteProject(cfg, sessionId, projectId);
34917
- }
34918
35113
  function destroyProject2(cfg, sessionId, id) {
34919
35114
  destroyProject(cfg, sessionId, id);
34920
35115
  }
34921
35116
 
34922
35117
  // src/server/shareadmin.ts
34923
- var crypto19 = __toESM(require("crypto"));
35118
+ var crypto20 = __toESM(require("crypto"));
34924
35119
 
34925
35120
  // src/server/sharesnapshots.ts
34926
- var fs46 = __toESM(require("fs"));
34927
- var path55 = __toESM(require("path"));
34928
- var crypto16 = __toESM(require("crypto"));
35121
+ var fs47 = __toESM(require("fs"));
35122
+ var path58 = __toESM(require("path"));
35123
+ var crypto17 = __toESM(require("crypto"));
34929
35124
  init_fs();
34930
35125
  function snapshotDir(dataDir) {
34931
- return path55.join(dataDir, "share-snapshots");
35126
+ return path58.join(dataDir, "share-snapshots");
34932
35127
  }
34933
35128
  function snapshotPath(dataDir, id) {
34934
- return path55.join(snapshotDir(dataDir), `${id}.json`);
35129
+ return path58.join(snapshotDir(dataDir), `${id}.json`);
34935
35130
  }
34936
35131
  var ShareSnapshotStore = class {
34937
35132
  constructor(dataDir) {
@@ -34939,17 +35134,17 @@ var ShareSnapshotStore = class {
34939
35134
  }
34940
35135
  write(snapshot) {
34941
35136
  const p = snapshotPath(this.dataDir, snapshot.id);
34942
- if (fs46.existsSync(p)) return;
34943
- fs46.mkdirSync(path55.dirname(p), { recursive: true });
35137
+ if (fs47.existsSync(p)) return;
35138
+ fs47.mkdirSync(path58.dirname(p), { recursive: true });
34944
35139
  const tmp = `${p}.tmp`;
34945
- fs46.writeFileSync(tmp, JSON.stringify(snapshot, null, 2) + "\n");
34946
- fs46.renameSync(tmp, p);
35140
+ fs47.writeFileSync(tmp, JSON.stringify(snapshot, null, 2) + "\n");
35141
+ fs47.renameSync(tmp, p);
34947
35142
  }
34948
35143
  read(snapshotId) {
34949
35144
  const p = snapshotPath(this.dataDir, snapshotId);
34950
35145
  let raw;
34951
35146
  try {
34952
- raw = fs46.readFileSync(p, "utf8");
35147
+ raw = fs47.readFileSync(p, "utf8");
34953
35148
  } catch (err) {
34954
35149
  if (err.code === "ENOENT") return null;
34955
35150
  throw new Error(`Cannot read share snapshot at ${p}: ${err.message}`);
@@ -34968,7 +35163,7 @@ var ShareSnapshotRegistry = class {
34968
35163
  put(snapshot) {
34969
35164
  const stored = {
34970
35165
  ...snapshot,
34971
- id: snapshot.id || crypto16.randomUUID(),
35166
+ id: snapshot.id || crypto17.randomUUID(),
34972
35167
  capturedAt: snapshot.capturedAt || (/* @__PURE__ */ new Date()).toISOString()
34973
35168
  };
34974
35169
  this.store.write(stored);
@@ -35041,11 +35236,11 @@ function captureSnapshot(dataDir, principal, projectId, view, artifacts) {
35041
35236
  }
35042
35237
 
35043
35238
  // src/server/sharelinks.ts
35044
- var fs47 = __toESM(require("fs"));
35045
- var path56 = __toESM(require("path"));
35046
- var crypto17 = __toESM(require("crypto"));
35239
+ var fs48 = __toESM(require("fs"));
35240
+ var path59 = __toESM(require("path"));
35241
+ var crypto18 = __toESM(require("crypto"));
35047
35242
  function storePath14(dataDir) {
35048
- return path56.join(dataDir, "share-links.json");
35243
+ return path59.join(dataDir, "share-links.json");
35049
35244
  }
35050
35245
  var ShareLinkStore = class {
35051
35246
  constructor(dataDir) {
@@ -35055,7 +35250,7 @@ var ShareLinkStore = class {
35055
35250
  const p = storePath14(this.dataDir);
35056
35251
  let raw;
35057
35252
  try {
35058
- raw = fs47.readFileSync(p, "utf8");
35253
+ raw = fs48.readFileSync(p, "utf8");
35059
35254
  } catch (err) {
35060
35255
  if (err.code === "ENOENT") return [];
35061
35256
  throw new Error(`Cannot read share-link store at ${p}: ${err.message}`);
@@ -35073,10 +35268,10 @@ var ShareLinkStore = class {
35073
35268
  }
35074
35269
  replaceAll(links) {
35075
35270
  const p = storePath14(this.dataDir);
35076
- fs47.mkdirSync(path56.dirname(p), { recursive: true });
35271
+ fs48.mkdirSync(path59.dirname(p), { recursive: true });
35077
35272
  const tmp = `${p}.tmp`;
35078
- fs47.writeFileSync(tmp, JSON.stringify(links, null, 2) + "\n");
35079
- fs47.renameSync(tmp, p);
35273
+ fs48.writeFileSync(tmp, JSON.stringify(links, null, 2) + "\n");
35274
+ fs48.renameSync(tmp, p);
35080
35275
  }
35081
35276
  };
35082
35277
  var ShareLinkRegistry = class {
@@ -35087,7 +35282,7 @@ var ShareLinkRegistry = class {
35087
35282
  const links = this.store.load();
35088
35283
  const stored = {
35089
35284
  ...link,
35090
- id: link.id || crypto17.randomUUID(),
35285
+ id: link.id || crypto18.randomUUID(),
35091
35286
  createdAt: link.createdAt || (/* @__PURE__ */ new Date()).toISOString()
35092
35287
  };
35093
35288
  this.store.replaceAll([...links, stored]);
@@ -35144,11 +35339,11 @@ function listProjectLinks(dataDir, projectId) {
35144
35339
  }
35145
35340
 
35146
35341
  // src/server/shareaccesslog.ts
35147
- var fs48 = __toESM(require("fs"));
35148
- var path57 = __toESM(require("path"));
35149
- var crypto18 = __toESM(require("crypto"));
35342
+ var fs49 = __toESM(require("fs"));
35343
+ var path60 = __toESM(require("path"));
35344
+ var crypto19 = __toESM(require("crypto"));
35150
35345
  function storePath15(dataDir) {
35151
- return path57.join(dataDir, "share-access.json");
35346
+ return path60.join(dataDir, "share-access.json");
35152
35347
  }
35153
35348
  var ShareAccessStore = class {
35154
35349
  constructor(dataDir) {
@@ -35158,7 +35353,7 @@ var ShareAccessStore = class {
35158
35353
  const p = storePath15(this.dataDir);
35159
35354
  let raw;
35160
35355
  try {
35161
- raw = fs48.readFileSync(p, "utf8");
35356
+ raw = fs49.readFileSync(p, "utf8");
35162
35357
  } catch (err) {
35163
35358
  if (err.code === "ENOENT") return [];
35164
35359
  throw new Error(`Cannot read share-access store at ${p}: ${err.message}`);
@@ -35176,11 +35371,11 @@ var ShareAccessStore = class {
35176
35371
  }
35177
35372
  append(entry) {
35178
35373
  const p = storePath15(this.dataDir);
35179
- fs48.mkdirSync(path57.dirname(p), { recursive: true });
35374
+ fs49.mkdirSync(path60.dirname(p), { recursive: true });
35180
35375
  const next = [...this.load(), entry];
35181
35376
  const tmp = `${p}.tmp`;
35182
- fs48.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n");
35183
- fs48.renameSync(tmp, p);
35377
+ fs49.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n");
35378
+ fs49.renameSync(tmp, p);
35184
35379
  }
35185
35380
  };
35186
35381
  var ShareAccessRegistry = class {
@@ -35190,7 +35385,7 @@ var ShareAccessRegistry = class {
35190
35385
  append(entry) {
35191
35386
  const stored = {
35192
35387
  ...entry,
35193
- id: entry.id || crypto18.randomUUID(),
35388
+ id: entry.id || crypto19.randomUUID(),
35194
35389
  at: entry.at || (/* @__PURE__ */ new Date()).toISOString()
35195
35390
  };
35196
35391
  this.store.append(stored);
@@ -35254,7 +35449,7 @@ function createShareLink(cfg, sessionId, input) {
35254
35449
  const wantsOpenapi = !!input.allowDownloadOpenapi || (input.artifacts ?? []).includes("openapi");
35255
35450
  const artifacts = artifactsFor({ allowDownloadOpenapi: !!input.allowDownloadOpenapi }, wantsOpenapi);
35256
35451
  const snapshot = putSnapshot(cfg.dataDir, captureSnapshot(cfg.dataDir, principal, input.projectId, input.view, artifacts));
35257
- const token = crypto19.randomBytes(32).toString("base64url");
35452
+ const token = crypto20.randomBytes(32).toString("base64url");
35258
35453
  const link = createLink(cfg.dataDir, {
35259
35454
  id: "",
35260
35455
  tokenHash: hashToken(token),
@@ -35331,16 +35526,16 @@ function getShareAccessLog(cfg, sessionId, linkId, limit) {
35331
35526
  init_fs();
35332
35527
 
35333
35528
  // src/server/swagger.ts
35334
- var fs49 = __toESM(require("fs"));
35335
- var path58 = __toESM(require("path"));
35529
+ var fs50 = __toESM(require("fs"));
35530
+ var path61 = __toESM(require("path"));
35336
35531
  var cache;
35337
35532
  function loadAssets() {
35338
35533
  if (cache !== void 0) return cache;
35339
35534
  try {
35340
- const dir = path58.dirname(require.resolve("swagger-ui-dist/package.json"));
35535
+ const dir = path61.dirname(require.resolve("swagger-ui-dist/package.json"));
35341
35536
  cache = {
35342
- css: fs49.readFileSync(path58.join(dir, "swagger-ui.css"), "utf8"),
35343
- js: fs49.readFileSync(path58.join(dir, "swagger-ui-bundle.js"), "utf8")
35537
+ css: fs50.readFileSync(path61.join(dir, "swagger-ui.css"), "utf8"),
35538
+ js: fs50.readFileSync(path61.join(dir, "swagger-ui-bundle.js"), "utf8")
35344
35539
  };
35345
35540
  } catch {
35346
35541
  cache = null;
@@ -35380,7 +35575,7 @@ function getLoginOptions(cfg) {
35380
35575
  async function startSignIn(cfg, providerId, redirectUri) {
35381
35576
  const provider = resolveEnabledProvider(cfg, providerId);
35382
35577
  assertAllowedRedirectUri(provider, redirectUri);
35383
- const nonce = crypto20.randomBytes(16).toString("hex");
35578
+ const nonce = crypto21.randomBytes(16).toString("hex");
35384
35579
  const payload = { providerId, nonce, redirectUri };
35385
35580
  const state = signSsoState(JSON.stringify(payload));
35386
35581
  const endpoints = await resolveEndpoints(provider);
@@ -35732,20 +35927,20 @@ function clearNonceCookie(secure) {
35732
35927
  }
35733
35928
  function nonceMatches(a, b) {
35734
35929
  if (!a || !b || a.length !== b.length) return false;
35735
- return crypto20.timingSafeEqual(Buffer.from(a), Buffer.from(b));
35930
+ return crypto21.timingSafeEqual(Buffer.from(a), Buffer.from(b));
35736
35931
  }
35737
35932
  function loadReactBundle() {
35738
35933
  const candidates = [
35739
- path59.resolve(__dirname, "webapp.html"),
35934
+ path62.resolve(__dirname, "webapp.html"),
35740
35935
  // dist/index.js -> dist/webapp.html
35741
- path59.resolve(__dirname, "..", "webapp.html"),
35936
+ path62.resolve(__dirname, "..", "webapp.html"),
35742
35937
  // dist/cli/index.js -> dist/webapp.html
35743
- path59.resolve(__dirname, "..", "..", "web", "dist", "index.html")
35938
+ path62.resolve(__dirname, "..", "..", "web", "dist", "index.html")
35744
35939
  // tsx dev: src/server -> web/dist
35745
35940
  ];
35746
35941
  for (const candidate of candidates) {
35747
35942
  try {
35748
- if (fs50.existsSync(candidate)) return fs50.readFileSync(candidate, "utf8");
35943
+ if (fs51.existsSync(candidate)) return fs51.readFileSync(candidate, "utf8");
35749
35944
  } catch {
35750
35945
  }
35751
35946
  }
@@ -37432,9 +37627,6 @@ details.adv summary { cursor:pointer; color:var(--dim); font-size:12px; margin-b
37432
37627
  Array.prototype.forEach.call(host.querySelectorAll('[data-lock]'), function (b) {
37433
37628
  b.addEventListener('click', function () { projectAction('/web/projects/lock', { projectId: b.getAttribute('data-lock') }, b, 'Locking\u2026', 'Lock'); });
37434
37629
  });
37435
- Array.prototype.forEach.call(host.querySelectorAll('[data-promote]'), function (b) {
37436
- b.addEventListener('click', function () { projectAction('/web/projects/promote', { projectId: b.getAttribute('data-promote') }, b, 'Promoting\u2026', 'Promote'); });
37437
- });
37438
37630
  Array.prototype.forEach.call(host.querySelectorAll('[data-destroy]'), function (b) {
37439
37631
  b.addEventListener('click', function () {
37440
37632
  if (!confirm('Destroy project "' + b.getAttribute('data-destroy') + '"? This removes its entire spec tree.')) return;
@@ -37738,9 +37930,6 @@ function projectCreate(cfg, sessionId, body, res) {
37738
37930
  function projectLock(cfg, sessionId, body, res) {
37739
37931
  sendJson(res, 200, lockProject3(cfg, sessionId, String(body?.projectId ?? "")));
37740
37932
  }
37741
- function projectPromote(cfg, sessionId, body, res) {
37742
- sendJson(res, 200, promoteProject3(cfg, sessionId, String(body?.projectId ?? "")));
37743
- }
37744
37933
  function projectDestroy(cfg, sessionId, body, res) {
37745
37934
  destroyProject2(cfg, sessionId, String(body?.id ?? ""));
37746
37935
  sendJson(res, 200, { ok: true });
@@ -38020,9 +38209,6 @@ async function handleWebRequest(cfg, req, res, body, url, ctx) {
38020
38209
  if (req.method === "POST" && parts.length === 3 && parts[2] === "lock") {
38021
38210
  return projectLock(cfg, sessionId, body, res);
38022
38211
  }
38023
- if (req.method === "POST" && parts.length === 3 && parts[2] === "promote") {
38024
- return projectPromote(cfg, sessionId, body, res);
38025
- }
38026
38212
  if (req.method === "POST" && parts.length === 3 && parts[2] === "destroy") {
38027
38213
  return projectDestroy(cfg, sessionId, body, res);
38028
38214
  }
@@ -38277,8 +38463,8 @@ var RealtimeHub = class {
38277
38463
  * complete the handshake, and register the connection. A bad path or session
38278
38464
  * destroys the socket. */
38279
38465
  handleUpgrade(cfg, req, socket) {
38280
- const path64 = (req.url ?? "/").split("?")[0];
38281
- if (path64 !== REALTIME_PATH || !isWebSocketUpgrade(req)) {
38466
+ const path67 = (req.url ?? "/").split("?")[0];
38467
+ if (path67 !== REALTIME_PATH || !isWebSocketUpgrade(req)) {
38282
38468
  socket.destroy();
38283
38469
  return;
38284
38470
  }
@@ -38455,7 +38641,6 @@ function auditToolCall(dataDir, principal, projectId, body, outcome, subproject)
38455
38641
  var PROJECT_LIFECYCLE_TOOLS = /* @__PURE__ */ new Set([
38456
38642
  "sdd_host_initialize_project",
38457
38643
  "sdd_host_lock_project",
38458
- "sdd_host_promote_project",
38459
38644
  "sdd_host_get_approval_status",
38460
38645
  "sdd_host_await_approval"
38461
38646
  ]);
@@ -38513,7 +38698,6 @@ function requiredDataPlaneCapability(toolName) {
38513
38698
  var MUTATING_HOST_TOOLS = /* @__PURE__ */ new Set([
38514
38699
  "sdd_host_initialize_project",
38515
38700
  "sdd_host_lock_project",
38516
- "sdd_host_promote_project",
38517
38701
  "sdd_host_await_approval",
38518
38702
  // a decided approval may have executed the action
38519
38703
  "sdd_host_policy_reconcile"
@@ -38583,9 +38767,6 @@ async function dispatchProjectLifecycleTool(cfg, credential, projectId, body, su
38583
38767
  case "sdd_host_lock_project":
38584
38768
  value = lockProject2(cfg, credential, projectId, subproject);
38585
38769
  break;
38586
- case "sdd_host_promote_project":
38587
- value = promoteProject2(cfg, credential, projectId, subproject);
38588
- break;
38589
38770
  case "sdd_host_await_approval":
38590
38771
  value = await awaitApproval(
38591
38772
  cfg,
@@ -39051,7 +39232,6 @@ var WEB_MUTATION_PATHS = /* @__PURE__ */ new Set([
39051
39232
  "/web/tokens/revoke",
39052
39233
  "/web/projects",
39053
39234
  "/web/projects/lock",
39054
- "/web/projects/promote",
39055
39235
  "/web/projects/destroy"
39056
39236
  ]);
39057
39237
  function routeData(cfg, req, res) {
@@ -39063,7 +39243,7 @@ function routeData(cfg, req, res) {
39063
39243
  if (req.method === "GET" && url.pathname === "/readyz") {
39064
39244
  let ready = false;
39065
39245
  try {
39066
- fs51.accessSync(cfg.dataDir, fs51.constants.W_OK);
39246
+ fs52.accessSync(cfg.dataDir, fs52.constants.W_OK);
39067
39247
  ready = true;
39068
39248
  } catch {
39069
39249
  }
@@ -39163,7 +39343,7 @@ function routeData(cfg, req, res) {
39163
39343
  }
39164
39344
  function readExposurePolicyFile(dataDir) {
39165
39345
  try {
39166
- const raw = fs51.readFileSync(path60.join(dataDir, "exposure-policy.json"), "utf8");
39346
+ const raw = fs52.readFileSync(path63.join(dataDir, "exposure-policy.json"), "utf8");
39167
39347
  const parsed = JSON.parse(raw);
39168
39348
  return parsed && typeof parsed === "object" ? parsed : void 0;
39169
39349
  } catch {
@@ -39212,7 +39392,6 @@ async function routeAdmin(cfg, req, res) {
39212
39392
  return sendJson(res, 200, { ok: true });
39213
39393
  }
39214
39394
  if (req.method === "POST" && parts.length === 4 && parts[3] === "lock") return sendJson(res, 200, lockProject(cfg, cred, parts[2]));
39215
- if (req.method === "POST" && parts.length === 4 && parts[3] === "promote") return sendJson(res, 200, promoteProject(cfg, cred, parts[2]));
39216
39395
  if (req.method === "POST" && parts.length === 4 && parts[3] === "git") return sendJson(res, 201, enableGit(cfg, cred, parts[2], body.remote, body.branch ?? "main", body.pat));
39217
39396
  if (req.method === "DELETE" && parts.length === 4 && parts[3] === "git") {
39218
39397
  disableGit(cfg, cred, parts[2]);
@@ -39867,9 +40046,9 @@ function seedDemoTree() {
39867
40046
 
39868
40047
  // src/commands/host.ts
39869
40048
  function resolveHostConfig(options) {
39870
- const dataDir = options.dataDir || process.env["WAIRON_DATA_DIR"] || path61.join(os11.homedir(), ".wairon", "data");
40049
+ const dataDir = options.dataDir || process.env["WAIRON_DATA_DIR"] || path64.join(os12.homedir(), ".wairon", "data");
39871
40050
  if (!process.env["WAIRON_PACKS_DIR"]) {
39872
- process.env["WAIRON_PACKS_DIR"] = path61.join(dataDir, "packs");
40051
+ process.env["WAIRON_PACKS_DIR"] = path64.join(dataDir, "packs");
39873
40052
  }
39874
40053
  const cfg = {
39875
40054
  host: options.host || "0.0.0.0",
@@ -39970,11 +40149,11 @@ async function runServe(options = {}) {
39970
40149
  logger.info(` data dir: ${import_chalk17.default.gray(cfg.dataDir)}`);
39971
40150
  logger.blank();
39972
40151
  logger.info("Press Ctrl+C to stop.");
39973
- await new Promise((resolve26) => {
40152
+ await new Promise((resolve27) => {
39974
40153
  const shutdown = () => {
39975
40154
  logger.info("Shutting down\u2026");
39976
40155
  handle.close();
39977
- resolve26();
40156
+ resolve27();
39978
40157
  };
39979
40158
  process.on("SIGINT", shutdown);
39980
40159
  process.on("SIGTERM", shutdown);
@@ -39994,14 +40173,14 @@ function openBrowser(url) {
39994
40173
  }
39995
40174
  async function runDev(options = {}) {
39996
40175
  const cwd = process.cwd();
39997
- if (!fs52.existsSync(path61.join(cwd, ".wai"))) {
40176
+ if (!fs53.existsSync(path64.join(cwd, ".wai"))) {
39998
40177
  throw new WaironError(
39999
40178
  "No .wai/ found in the current directory. Run `wairon dev` from a wairon project root (or run `wairon init` first)."
40000
40179
  );
40001
40180
  }
40002
- const hash = crypto21.createHash("sha256").update(cwd).digest("hex").slice(0, 16);
40003
- const dataDir = path61.join(os11.tmpdir(), "wairon-dev", hash);
40004
- fs52.mkdirSync(dataDir, { recursive: true });
40181
+ const hash = crypto22.createHash("sha256").update(cwd).digest("hex").slice(0, 16);
40182
+ const dataDir = path64.join(os12.tmpdir(), "wairon-dev", hash);
40183
+ fs53.mkdirSync(dataDir, { recursive: true });
40005
40184
  registerLocalDevProject(dataDir, "local", cwd);
40006
40185
  const port = options.port ? Number(options.port) : 8080;
40007
40186
  const exposurePolicy = {
@@ -40039,11 +40218,11 @@ async function runDev(options = {}) {
40039
40218
  logger.blank();
40040
40219
  logger.info("An agent edits specs; refresh the page to see the live graph. Press Ctrl+C to stop.");
40041
40220
  if (options.open) openBrowser(url);
40042
- await new Promise((resolve26) => {
40221
+ await new Promise((resolve27) => {
40043
40222
  const shutdown = () => {
40044
40223
  logger.info("Shutting down\u2026");
40045
40224
  handle.close();
40046
- resolve26();
40225
+ resolve27();
40047
40226
  };
40048
40227
  process.on("SIGINT", shutdown);
40049
40228
  process.on("SIGTERM", shutdown);
@@ -40313,18 +40492,6 @@ async function runHostLock(options = {}) {
40313
40492
  throw mapAdminError(e);
40314
40493
  }
40315
40494
  }
40316
- async function runHostPromote(options = {}) {
40317
- const cfg = resolveHostConfig(options);
40318
- if (!options.project) throw new WaironError("`--project <id>` is required for `host promote`.");
40319
- try {
40320
- const result = promoteProject(cfg, masterCredential(), options.project);
40321
- const mark = result.status === "ready" ? import_chalk17.default.green("\u2713") : import_chalk17.default.yellow("\u2717");
40322
- logger.info(`${mark} ${result.message}`);
40323
- if (result.status !== "ready") process.exitCode = 1;
40324
- } catch (e) {
40325
- throw mapAdminError(e);
40326
- }
40327
- }
40328
40495
  async function runHostProducer(action, options = {}) {
40329
40496
  const cfg = resolveHostConfig(options);
40330
40497
  const cred = masterCredential();
@@ -40409,8 +40576,8 @@ async function runHostPacks(action, options = {}) {
40409
40576
  }
40410
40577
  case "install": {
40411
40578
  if (!options.file) throw new WaironError("`--file <path>` (a declarative pack YAML) is required for install.");
40412
- const name = options.name ?? path61.basename(options.file).replace(/\.(ya?ml)$/i, "");
40413
- const content = fs52.readFileSync(path61.resolve(options.file), "utf8");
40579
+ const name = options.name ?? path64.basename(options.file).replace(/\.(ya?ml)$/i, "");
40580
+ const content = fs53.readFileSync(path64.resolve(options.file), "utf8");
40414
40581
  const desc = project2 ? installProjectPack(cfg, cred, project2, name, content) : installGlobalPack(cfg, cred, name, content);
40415
40582
  logger.success(`Installed ${scope} pack "${desc.name}" (${desc.profiles} profile(s), ${desc.languages} language(s)).`);
40416
40583
  if (project2) logger.info("Committed with the project \u2014 every clone and CI will enforce it.");
@@ -40636,7 +40803,7 @@ async function runSurface(action, options = {}) {
40636
40803
  }
40637
40804
 
40638
40805
  // src/commands/subsystem.ts
40639
- var path62 = __toESM(require("path"));
40806
+ var path65 = __toESM(require("path"));
40640
40807
  init_logger();
40641
40808
  init_errors();
40642
40809
  init_fs();
@@ -40676,9 +40843,9 @@ async function runSubsystemAdd(id, options = {}) {
40676
40843
  updatedAt: now
40677
40844
  };
40678
40845
  createChainedSubsystem(subsystem, displayName);
40679
- const childDir = path62.resolve(getProjectRoot(), options.projectPath);
40846
+ const childDir = path65.resolve(getProjectRoot(), options.projectPath);
40680
40847
  logger.success(`Added external subsystem "${id}" \u2192 ${options.projectPath}`);
40681
- logger.info(`Scaffolded child project at ${path62.relative(process.cwd(), childDir) || "."}`);
40848
+ logger.info(`Scaffolded child project at ${path65.relative(process.cwd(), childDir) || "."}`);
40682
40849
  logger.info(`Design its spec tree from this parent using namespaced ids (e.g. ${id}::<component>).`);
40683
40850
  }
40684
40851
  async function runSubsystemMove(id, options = {}) {
@@ -40701,9 +40868,9 @@ async function runSubsystemExternalize(id, options = {}) {
40701
40868
  throw new WaironError("--project-path (the subproject destination) is required.");
40702
40869
  }
40703
40870
  externalizeSubsystem(id, options.projectPath);
40704
- const childDir = path62.resolve(getProjectRoot(), options.projectPath);
40871
+ const childDir = path65.resolve(getProjectRoot(), options.projectPath);
40705
40872
  logger.success(`Externalized subsystem "${id}" \u2192 ${options.projectPath}`);
40706
- logger.info(`Moved its specs into ${path62.relative(process.cwd(), childDir) || "."} (now a standalone subproject).`);
40873
+ logger.info(`Moved its specs into ${path65.relative(process.cwd(), childDir) || "."} (now a standalone subproject).`);
40707
40874
  logger.info("Move the source code there yourself, then run `wairon validate` to confirm the tree.");
40708
40875
  }
40709
40876
  async function runSubsystemInternalize(id) {
@@ -40947,7 +41114,7 @@ async function runAgent(action, id) {
40947
41114
  }
40948
41115
  case "customize": {
40949
41116
  const brief = composeAgentBrief3(id);
40950
- const guidancePath = path63.join(AI_PATHS.root(), "agents", `${id}.md`);
41117
+ const guidancePath = path66.join(AI_PATHS.root(), "agents", `${id}.md`);
40951
41118
  const relPath = `.wai/agents/${id}.md`;
40952
41119
  if (pathExists(guidancePath)) {
40953
41120
  throw new GuidanceFileExistsError(relPath);
@@ -41050,9 +41217,6 @@ hostCmd.command("key <action>").description("mint | list | revoke an API key").o
41050
41217
  hostCmd.command("lock").description("validate-as-complete and write the state-scoped lock record for a hosted project").requiredOption("--project <id>", "project id").option("--data-dir <path>", "data root").action(async (opts) => {
41051
41218
  await runHostLock({ project: opts.project, dataDir: opts.dataDir });
41052
41219
  });
41053
- hostCmd.command("promote").description("promote a locked project after re-checking its StateId (never merges to production)").requiredOption("--project <id>", "project id").option("--data-dir <path>", "data root").action(async (opts) => {
41054
- await runHostPromote({ project: opts.project, dataDir: opts.dataDir });
41055
- });
41056
41220
  hostCmd.command("git <action>").description("enable | disable | sync | commit | status | sync-config \u2014 bind a project to its REAL repo (wairon commits ONLY .wai/)").option("--project <id>", "project id").option("--remote <url>", "git remote URL (for enable)").option("--branch <name>", "default branch PRs target (for enable)", "main").option("--subsystem <id>", "narrow a commit to .wai/specs/<subsystem>/ (staging convenience \u2014 history stays per-repo)").option("-m, --message <message>", "commit message (for commit)").option("--interval <minutes>", "periodic-sync interval in minutes (for sync-config; omit to disable)").option("--no-skip-if-clean", "commit on every periodic tick even when the scoped path is clean (for sync-config)").option("--data-dir <path>", "data root").action(async (action, opts) => {
41057
41221
  await runHostGit(action, {
41058
41222
  project: opts.project,