@wairon/cli 5.1.1-dev.75 → 5.1.1-dev.76

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.75";
68
+ WAIRON_VERSION = "5.1.1-dev.76";
69
69
  GITHUB_REPO = "SYW-Apps/Waffle-AIron";
70
70
  SUPPORTED_ALIASES = ["wai"];
71
71
  SCAN_EXCLUDE_DIRS = /* @__PURE__ */ new Set([
@@ -2900,10 +2900,10 @@ function stepGraph(method2) {
2900
2900
  const s = byNum.get(n);
2901
2901
  if (s.type !== "parallel" || s.endStep === void 0 || !s.branches?.length) continue;
2902
2902
  const entries = s.branches.map((b) => b.step).sort((a, b) => a - b);
2903
- const join53 = fallNext(s.endStep);
2903
+ const join54 = fallNext(s.endStep);
2904
2904
  for (let i = 0; i < entries.length; i++) {
2905
2905
  const armEnd = i + 1 < entries.length ? prevOf(entries[i + 1]) : s.endStep;
2906
- if (armEnd !== void 0 && armEnd >= entries[i]) armEndJoin.set(armEnd, join53);
2906
+ if (armEnd !== void 0 && armEnd >= entries[i]) armEndJoin.set(armEnd, join54);
2907
2907
  }
2908
2908
  }
2909
2909
  const successorsOf = (n) => {
@@ -9624,21 +9624,21 @@ function buildCodeIndex(model) {
9624
9624
  const declarations = /* @__PURE__ */ new Map();
9625
9625
  const anchors = /* @__PURE__ */ new Map();
9626
9626
  const findingAnchors = /* @__PURE__ */ new Map();
9627
- const namesAt = (cache2, path72, make) => {
9628
- const cached = cache2.get(path72);
9627
+ const namesAt = (cache2, path73, make) => {
9628
+ const cached = cache2.get(path73);
9629
9629
  if (cached) return cached;
9630
- const f = facts.get(path72);
9630
+ const f = facts.get(path73);
9631
9631
  if (!f) return NO_NAMES;
9632
9632
  const built = make(f);
9633
- cache2.set(path72, built);
9633
+ cache2.set(path73, built);
9634
9634
  return built;
9635
9635
  };
9636
9636
  const republished = /* @__PURE__ */ new Map();
9637
- const republishedFrom = (path72) => {
9638
- const cached = republished.get(path72);
9637
+ const republishedFrom = (path73) => {
9638
+ const cached = republished.get(path73);
9639
9639
  if (cached) return cached;
9640
- const out = /* @__PURE__ */ new Set([path72]);
9641
- const queue = [path72];
9640
+ const out = /* @__PURE__ */ new Set([path73]);
9641
+ const queue = [path73];
9642
9642
  while (queue.length) {
9643
9643
  const from = queue.pop();
9644
9644
  const f = facts.get(from);
@@ -9651,7 +9651,7 @@ function buildCodeIndex(model) {
9651
9651
  }
9652
9652
  }
9653
9653
  }
9654
- republished.set(path72, out);
9654
+ republished.set(path73, out);
9655
9655
  return out;
9656
9656
  };
9657
9657
  const NO_ORIGIN = /* @__PURE__ */ new Set();
@@ -9660,9 +9660,9 @@ function buildCodeIndex(model) {
9660
9660
  return to ? republishedFrom(to) : NO_ORIGIN;
9661
9661
  };
9662
9662
  const scopeOf2 = (site, from) => {
9663
- const path72 = pathKey(site.from ?? from);
9664
- const f = facts.get(path72);
9665
- return f?.status === "analyzed" && f.analysisGrade === "exact" ? { path: path72, facts: f } : void 0;
9663
+ const path73 = pathKey(site.from ?? from);
9664
+ const f = facts.get(path73);
9665
+ return f?.status === "analyzed" && f.analysisGrade === "exact" ? { path: path73, facts: f } : void 0;
9666
9666
  };
9667
9667
  const originOf2 = (site, from) => {
9668
9668
  const resolved = scopeOf2(site, from);
@@ -9701,14 +9701,14 @@ function buildCodeIndex(model) {
9701
9701
  if (site.via) for (const typeName of localTypesOf(f, site.via)) widenThroughType(typeName);
9702
9702
  return out;
9703
9703
  };
9704
- const declarationsAt = (path72) => namesAt(declarations, pathKey(path72), (f) => /* @__PURE__ */ new Set([...f.declaredNames, ...f.exportedNames]));
9704
+ const declarationsAt = (path73) => namesAt(declarations, pathKey(path73), (f) => /* @__PURE__ */ new Set([...f.declaredNames, ...f.exportedNames]));
9705
9705
  return {
9706
9706
  paths,
9707
9707
  exactPaths,
9708
- factsAt: (path72) => facts.get(pathKey(path72)),
9708
+ factsAt: (path73) => facts.get(pathKey(path73)),
9709
9709
  declarationsAt,
9710
- anchorsAt: (path72) => namesAt(anchors, pathKey(path72), (f) => /* @__PURE__ */ new Set([...f.declaredNames, ...f.exportedNames, ...f.anchoredNames])),
9711
- findingAnchorsAt: (path72) => namesAt(findingAnchors, pathKey(path72), (f) => new Set(f.anchoredNames)),
9710
+ anchorsAt: (path73) => namesAt(anchors, pathKey(path73), (f) => /* @__PURE__ */ new Set([...f.declaredNames, ...f.exportedNames, ...f.anchoredNames])),
9711
+ findingAnchorsAt: (path73) => namesAt(findingAnchors, pathKey(path73), (f) => new Set(f.anchoredNames)),
9712
9712
  originOf: originOf2,
9713
9713
  possibleOriginsOf
9714
9714
  };
@@ -9746,10 +9746,10 @@ function buildRealizationIndex(ctx) {
9746
9746
  return {
9747
9747
  paths,
9748
9748
  implementationsOf: (compId) => implsByComponent.get(compId) ?? NONE_IMPL,
9749
- implementationsAt: (path72) => implsByPath.get(pathKey(path72)) ?? NONE_IMPL,
9749
+ implementationsAt: (path73) => implsByPath.get(pathKey(path73)) ?? NONE_IMPL,
9750
9750
  filesOf: (compId) => filesByComponent.get(compId) ?? NONE_PATH,
9751
9751
  filesIn: (subsystemId) => filesBySubsystem.get(subsystemId) ?? NONE_PATH,
9752
- componentsAt: (path72) => componentsByPath.get(pathKey(path72)) ?? NONE_COMP
9752
+ componentsAt: (path73) => componentsByPath.get(pathKey(path73)) ?? NONE_COMP
9753
9753
  };
9754
9754
  }
9755
9755
  function buildImportGraph(index, universe) {
@@ -9761,22 +9761,22 @@ function buildImportGraph(index, universe) {
9761
9761
  if (to && to !== from) into.add(to);
9762
9762
  }
9763
9763
  };
9764
- const importsOf = (path72) => {
9765
- const cached = imports.get(path72);
9764
+ const importsOf = (path73) => {
9765
+ const cached = imports.get(path73);
9766
9766
  if (cached) return cached;
9767
- const facts = index.factsAt(path72);
9767
+ const facts = index.factsAt(path73);
9768
9768
  const out = /* @__PURE__ */ new Set();
9769
- if (facts?.status === "analyzed") resolveAll(path72, facts.imports, out);
9770
- imports.set(path72, out);
9769
+ if (facts?.status === "analyzed") resolveAll(path73, facts.imports, out);
9770
+ imports.set(path73, out);
9771
9771
  return out;
9772
9772
  };
9773
- const tracesOf = (path72) => {
9774
- const cached = traces.get(path72);
9773
+ const tracesOf = (path73) => {
9774
+ const cached = traces.get(path73);
9775
9775
  if (cached) return cached;
9776
- const facts = index.factsAt(path72);
9777
- const out = new Set(importsOf(path72));
9778
- if (facts?.status === "analyzed") resolveAll(path72, facts.reexports, out);
9779
- traces.set(path72, out);
9776
+ const facts = index.factsAt(path73);
9777
+ const out = new Set(importsOf(path73));
9778
+ if (facts?.status === "analyzed") resolveAll(path73, facts.reexports, out);
9779
+ traces.set(path73, out);
9780
9780
  return out;
9781
9781
  };
9782
9782
  return {
@@ -11279,11 +11279,11 @@ var init_unconditional_call_cycles = __esm({
11279
11279
  const memberEdges = keys.flatMap((k) => (adjacency.get(k) ?? []).filter((e) => inScc.has(e.toKey)));
11280
11280
  if (memberEdges.length === 0) continue;
11281
11281
  const anchor = [...memberEdges].sort((a, b) => byCodeUnit(a.fromKey, b.fromKey) || byCodeUnit(a.impl.id, b.impl.id) || a.stepNumber - b.stepNumber)[0];
11282
- const path72 = [...keys].sort(byCodeUnit).join(" \u2192 ");
11282
+ const path73 = [...keys].sort(byCodeUnit).join(" \u2192 ");
11283
11283
  ctx.addIssue(
11284
11284
  "warning",
11285
11285
  "UNCONDITIONAL_CALL_CYCLE",
11286
- `Call cycle with no guard: ${path72} \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.`,
11286
+ `Call cycle with no guard: ${path73} \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.`,
11287
11287
  anchor.impl.id,
11288
11288
  memberEdges.some((e) => ctx.isImplementationDraft(e.impl))
11289
11289
  );
@@ -13183,8 +13183,8 @@ var init_lifecycle_entrypoints = __esm({
13183
13183
  });
13184
13184
 
13185
13185
  // src/core/rules/wiring/portal-mounts.ts
13186
- function liesUnder(path72, prefix) {
13187
- return path72 === prefix || path72.startsWith(prefix + "/");
13186
+ function liesUnder(path73, prefix) {
13187
+ return path73 === prefix || path73.startsWith(prefix + "/");
13188
13188
  }
13189
13189
  var portalMountsRule;
13190
13190
  var init_portal_mounts = __esm({
@@ -14473,11 +14473,11 @@ var init_hidden_state = __esm({
14473
14473
  byPath.set(key, list2);
14474
14474
  }
14475
14475
  }
14476
- for (const path72 of code.exactPaths) {
14477
- const facts = code.factsAt(path72);
14476
+ for (const path73 of code.exactPaths) {
14477
+ const facts = code.factsAt(path73);
14478
14478
  const bindings = facts.topLevelMutableBindings ?? [];
14479
14479
  if (bindings.length === 0) continue;
14480
- const mapped = byPath.get(path72) ?? [];
14480
+ const mapped = byPath.get(path73) ?? [];
14481
14481
  if (mapped.length === 0) continue;
14482
14482
  if (!mapped.every((m) => isStatelessLogic(m.component))) continue;
14483
14483
  const anchor = [...mapped].sort((a, b) => a.impl.id.localeCompare(b.impl.id))[0];
@@ -14550,7 +14550,7 @@ var init_dependency_conformance = __esm({
14550
14550
  }
14551
14551
  return false;
14552
14552
  };
14553
- const draftAt = (path72) => realization.implementationsAt(path72).some((impl) => ctx.isImplementationDraft(impl));
14553
+ const draftAt = (path73) => realization.implementationsAt(path73).some((impl) => ctx.isImplementationDraft(impl));
14554
14554
  for (const fromPath of mappedPaths) {
14555
14555
  const fromComponents = realization.componentsAt(fromPath);
14556
14556
  for (const toPath of graph.importsOf(fromPath)) {
@@ -14641,7 +14641,7 @@ var init_portal_imports = __esm({
14641
14641
  }
14642
14642
  return files;
14643
14643
  };
14644
- const draftAt = (path72) => realization.implementationsAt(path72).some((impl) => ctx.isImplementationDraft(impl));
14644
+ const draftAt = (path73) => realization.implementationsAt(path73).some((impl) => ctx.isImplementationDraft(impl));
14645
14645
  for (const fromPath of mappedPaths) {
14646
14646
  const fromSubsystems = new Set(realization.componentsAt(fromPath).map((c) => c.subsystem));
14647
14647
  for (const toPath of graph.importsOf(fromPath)) {
@@ -15227,8 +15227,8 @@ var init_param_conformance = __esm({
15227
15227
  });
15228
15228
 
15229
15229
  // src/core/rules/conformance/route-coverage.ts
15230
- function liesUnder2(path72, prefix) {
15231
- return path72 === prefix || path72.startsWith(prefix + "/");
15230
+ function liesUnder2(path73, prefix) {
15231
+ return path73 === prefix || path73.startsWith(prefix + "/");
15232
15232
  }
15233
15233
  function normalizeSegment(segment) {
15234
15234
  return /^\{.+\}$/.test(segment) || segment.startsWith(":") ? "*" : segment;
@@ -20126,6 +20126,9 @@ function specChanges(before, after, prefix = "") {
20126
20126
  if (after.length === 0 && before.length > 0) {
20127
20127
  return [{ path: prefix, change: "cleared", before: summarizeValue(before) }];
20128
20128
  }
20129
+ if ((prefix.split(".").pop() ?? prefix) === "narrative" && [...before, ...after].every((i) => i !== null && typeof i === "object" && !Array.isArray(i))) {
20130
+ return narrativeChanges(before, after, prefix);
20131
+ }
20129
20132
  const identified = [...before, ...after].every((i) => reportIdentityOf(prefix.split(".").pop() ?? prefix, i) !== null);
20130
20133
  if (!identified) {
20131
20134
  return JSON.stringify(before) === JSON.stringify(after) ? [] : [{ path: prefix, change: "set", before: summarizeValue(before), after: summarizeValue(after) }];
@@ -20159,6 +20162,150 @@ function specChanges(before, after, prefix = "") {
20159
20162
  if (JSON.stringify(before) === JSON.stringify(after)) return [];
20160
20163
  return [{ path: prefix, change: "set", before: summarizeValue(before), after: summarizeValue(after) }];
20161
20164
  }
20165
+ function jumpsOf(step) {
20166
+ const jumps = /* @__PURE__ */ new Map();
20167
+ for (const field of STEP_JUMP_FIELDS) {
20168
+ if (typeof step[field] === "number") jumps.set(field, step[field]);
20169
+ }
20170
+ for (const [list2, name] of STEP_JUMP_LISTS) {
20171
+ const entries = step[list2];
20172
+ if (!Array.isArray(entries)) continue;
20173
+ entries.forEach((entry, i) => {
20174
+ if (entry && typeof entry.step === "number") jumps.set(`${list2}.${String(entry[name] ?? i)}.step`, entry.step);
20175
+ });
20176
+ }
20177
+ return jumps;
20178
+ }
20179
+ function withoutNumbers(step) {
20180
+ const out = { ...step };
20181
+ delete out.stepNumber;
20182
+ for (const field of STEP_JUMP_FIELDS) delete out[field];
20183
+ for (const [list2] of STEP_JUMP_LISTS) {
20184
+ if (Array.isArray(out[list2])) {
20185
+ out[list2] = out[list2].map((entry) => {
20186
+ if (!entry || typeof entry !== "object") return entry;
20187
+ const { step: _step, ...rest } = entry;
20188
+ return rest;
20189
+ });
20190
+ }
20191
+ }
20192
+ return out;
20193
+ }
20194
+ function canonicalJson(value) {
20195
+ return JSON.stringify(value, (_key, v) => v && typeof v === "object" && !Array.isArray(v) ? Object.fromEntries(Object.keys(v).sort().map((k) => [k, v[k]])) : v);
20196
+ }
20197
+ function commonRun(a, b, same) {
20198
+ const rows = a.length + 1;
20199
+ const cols = b.length + 1;
20200
+ const table = new Uint32Array(rows * cols);
20201
+ for (let i2 = a.length - 1; i2 >= 0; i2--) {
20202
+ for (let j2 = b.length - 1; j2 >= 0; j2--) {
20203
+ table[i2 * cols + j2] = same(a[i2], b[j2]) ? table[(i2 + 1) * cols + j2 + 1] + 1 : Math.max(table[(i2 + 1) * cols + j2], table[i2 * cols + j2 + 1]);
20204
+ }
20205
+ }
20206
+ const pairs = [];
20207
+ let i = 0;
20208
+ let j = 0;
20209
+ while (i < a.length && j < b.length) {
20210
+ if (same(a[i], b[j])) {
20211
+ pairs.push([i, j]);
20212
+ i++;
20213
+ j++;
20214
+ } else if (table[(i + 1) * cols + j] >= table[i * cols + j + 1]) i++;
20215
+ else j++;
20216
+ }
20217
+ return pairs;
20218
+ }
20219
+ function recognisablySame(a, b) {
20220
+ if (typeof a.description === "string" && a.description === b.description) return true;
20221
+ if (typeof a.label === "string" && a.label === b.label) return true;
20222
+ return typeof a.targetComponent === "string" && a.type === b.type && a.targetComponent === b.targetComponent && a.targetMethod === b.targetMethod;
20223
+ }
20224
+ function pairSteps(before, after) {
20225
+ const keysBefore = before.map((s) => canonicalJson(withoutNumbers(s)));
20226
+ const keysAfter = after.map((s) => canonicalJson(withoutNumbers(s)));
20227
+ const anchors = commonRun(keysBefore, keysAfter, (x, y) => x === y);
20228
+ const pairs = [];
20229
+ const bounds2 = [[-1, -1], ...anchors, [before.length, after.length]];
20230
+ for (let g = 0; g < bounds2.length - 1; g++) {
20231
+ const [oi, ni] = bounds2[g];
20232
+ const [oj, nj] = bounds2[g + 1];
20233
+ const gapBefore = before.slice(oi + 1, oj).map((step, k) => ({ step, at: oi + 1 + k }));
20234
+ const gapAfter = after.slice(ni + 1, nj).map((step, k) => ({ step, at: ni + 1 + k }));
20235
+ const similar = commonRun(gapBefore, gapAfter, (x, y) => recognisablySame(x.step, y.step)).map(([x, y]) => [gapBefore[x].at, gapAfter[y].at]);
20236
+ const inner = [[oi, ni], ...similar, [oj, nj]];
20237
+ for (let k = 0; k < inner.length - 1; k++) {
20238
+ const [a0, b0] = inner[k];
20239
+ const [a1, b1] = inner[k + 1];
20240
+ if (a1 - a0 === b1 - b0) for (let d = 1; d < a1 - a0; d++) pairs.push([a0 + d, b0 + d]);
20241
+ if (k < inner.length - 2) pairs.push(inner[k + 1]);
20242
+ }
20243
+ if (g < bounds2.length - 2) pairs.push(bounds2[g + 1]);
20244
+ }
20245
+ return pairs.sort((x, y) => x[0] - y[0]);
20246
+ }
20247
+ function numberOf(step, index) {
20248
+ return typeof step.stepNumber === "number" ? step.stepNumber : index + 1;
20249
+ }
20250
+ function renumberedRuns(moves) {
20251
+ const runs = [];
20252
+ const range = (a, b) => a === b ? `step ${a}` : `steps ${a}-${b}`;
20253
+ let start2 = 0;
20254
+ for (let k = 1; k <= moves.length; k++) {
20255
+ const continues = k < moves.length && moves[k][0] === moves[k - 1][0] + 1 && moves[k][1] - moves[k][0] === moves[start2][1] - moves[start2][0];
20256
+ if (continues) continue;
20257
+ const [firstOld, firstNew] = moves[start2];
20258
+ const [lastOld, lastNew] = moves[k - 1];
20259
+ runs.push({ from: range(firstOld, lastOld), to: range(firstNew, lastNew) });
20260
+ start2 = k;
20261
+ }
20262
+ return runs;
20263
+ }
20264
+ function narrativeChanges(before, after, prefix) {
20265
+ const pairs = pairSteps(before, after);
20266
+ const oldToNew = /* @__PURE__ */ new Map();
20267
+ for (const [o, n] of pairs) oldToNew.set(numberOf(before[o], o), numberOf(after[n], n));
20268
+ const pairedOld = new Set(pairs.map(([o]) => o));
20269
+ const pairedNew = new Set(pairs.map(([, n]) => n));
20270
+ const removed = before.flatMap((step, o) => pairedOld.has(o) ? [] : [{
20271
+ path: `${prefix}.step ${numberOf(step, o)}`,
20272
+ change: "removed",
20273
+ before: summarizeValue(step)
20274
+ }]);
20275
+ const added = after.flatMap((step, n) => pairedNew.has(n) ? [] : [{
20276
+ path: `${prefix}.step ${numberOf(step, n)}`,
20277
+ change: "added",
20278
+ after: summarizeValue(step)
20279
+ }]);
20280
+ const edited = [];
20281
+ const relocated = [];
20282
+ const moves = [];
20283
+ for (const [o, n] of pairs) {
20284
+ const oldNumber = numberOf(before[o], o);
20285
+ const newNumber = numberOf(after[n], n);
20286
+ const at = oldNumber === newNumber ? `${prefix}.step ${newNumber}` : `${prefix}.step ${newNumber} (was ${oldNumber})`;
20287
+ edited.push(...specChanges(withoutNumbers(before[o]), withoutNumbers(after[n]), at));
20288
+ const oldJumps = jumpsOf(before[o]);
20289
+ const newJumps = jumpsOf(after[n]);
20290
+ for (const field of /* @__PURE__ */ new Set([...oldJumps.keys(), ...newJumps.keys()])) {
20291
+ const was = oldJumps.get(field);
20292
+ const now = newJumps.get(field);
20293
+ if (was === now) continue;
20294
+ if (was === void 0) edited.push({ path: `${at}.${field}`, change: "added", after: String(now) });
20295
+ else if (now === void 0) edited.push({ path: `${at}.${field}`, change: "removed", before: String(was) });
20296
+ else if (oldToNew.get(was) === now) relocated.push({ path: `${at}.${field}`, change: "relocated", before: String(was), after: String(now) });
20297
+ else edited.push({ path: `${at}.${field}`, change: "set", before: String(was), after: String(now) });
20298
+ }
20299
+ if (oldNumber !== newNumber && !edited.some((c) => c.path.startsWith(`${at}.`))) moves.push([oldNumber, newNumber]);
20300
+ }
20301
+ const renumbered = renumberedRuns(moves).map(({ from, to }) => ({
20302
+ path: prefix,
20303
+ change: "renumbered",
20304
+ before: from,
20305
+ after: to
20306
+ }));
20307
+ return [...removed, ...added, ...edited, ...renumbered, ...relocated];
20308
+ }
20162
20309
  function identityFieldsOf(field) {
20163
20310
  switch (field) {
20164
20311
  case "dispatch":
@@ -20206,13 +20353,13 @@ function ineffectiveDeltaPaths(delta, merged, stored) {
20206
20353
  const isPlain = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
20207
20354
  const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
20208
20355
  const at = (prefix, key) => prefix ? `${prefix}.${key}` : key;
20209
- const say = (path72, why) => {
20210
- out.push(`${path72} \u2014 ${why}`);
20356
+ const say = (path73, why) => {
20357
+ out.push(`${path73} \u2014 ${why}`);
20211
20358
  };
20212
- const walkValue = (d, m, s, path72, field) => {
20359
+ const walkValue = (d, m, s, path73, field) => {
20213
20360
  if (Array.isArray(d)) {
20214
20361
  if (!Array.isArray(m)) {
20215
- say(path72, "the level does not have this field, so the write dropped it");
20362
+ say(path73, "the level does not have this field, so the write dropped it");
20216
20363
  return;
20217
20364
  }
20218
20365
  if (field === "narrative" && d.some(carriesEditMarker)) return;
@@ -20220,32 +20367,32 @@ function ineffectiveDeltaPaths(delta, merged, stored) {
20220
20367
  if (carriesEditMarker(element)) continue;
20221
20368
  const key = reportIdentityOf(field, element);
20222
20369
  if (key === null) {
20223
- if (!same(m, d)) say(path72, "the level does not keep this value, so the write dropped it");
20224
- else if (same(s, d)) say(path72, "the stored spec already held this value");
20370
+ if (!same(m, d)) say(path73, "the level does not keep this value, so the write dropped it");
20371
+ else if (same(s, d)) say(path73, "the stored spec already held this value");
20225
20372
  return;
20226
20373
  }
20227
20374
  const mMatch = m.find((i) => reportIdentityOf(field, i) === key);
20228
20375
  const sMatch = Array.isArray(s) ? s.find((i) => reportIdentityOf(field, i) === key) : void 0;
20229
20376
  if (mMatch === void 0) {
20230
- say(at(path72, key), "the write did not store this element");
20377
+ say(at(path73, key), "the write did not store this element");
20231
20378
  continue;
20232
20379
  }
20233
- walk2(element, mMatch, sMatch, at(path72, key), field);
20380
+ walk2(element, mMatch, sMatch, at(path73, key), field);
20234
20381
  }
20235
20382
  return;
20236
20383
  }
20237
20384
  if (isPlain(d)) {
20238
20385
  if (!isPlain(m)) {
20239
- say(path72, "the level does not have this field, so the write dropped it");
20386
+ say(path73, "the level does not have this field, so the write dropped it");
20240
20387
  return;
20241
20388
  }
20242
- walk2(d, m, s, path72, field);
20389
+ walk2(d, m, s, path73, field);
20243
20390
  return;
20244
20391
  }
20245
- if (!same(m, d)) say(path72, "the write did not store it \u2014 the level's schema does not keep this value");
20246
- else if (same(s, d)) say(path72, "the stored spec already held this value");
20392
+ if (!same(m, d)) say(path73, "the write did not store it \u2014 the level's schema does not keep this value");
20393
+ else if (same(s, d)) say(path73, "the stored spec already held this value");
20247
20394
  };
20248
- function walk2(d, m, s, path72, container) {
20395
+ function walk2(d, m, s, path73, container) {
20249
20396
  for (const [key, value] of Object.entries(d)) {
20250
20397
  if (DELTA_VERBS.has(key) || JUMP_LABEL_TWINS.has(key)) continue;
20251
20398
  if (key === "label" && LABEL_TWIN_CONTAINERS.has(container)) continue;
@@ -20255,13 +20402,13 @@ function ineffectiveDeltaPaths(delta, merged, stored) {
20255
20402
  if (typeof name !== "string") continue;
20256
20403
  const had = isPlain(s) && s[name] !== void 0;
20257
20404
  const still = isPlain(m) && m[name] !== void 0;
20258
- if (!had) say(at(path72, name), "unset named a field the stored spec did not have");
20259
- else if (still) say(at(path72, name), "unset did not remove it");
20405
+ if (!had) say(at(path73, name), "unset named a field the stored spec did not have");
20406
+ else if (still) say(at(path73, name), "unset did not remove it");
20260
20407
  }
20261
20408
  continue;
20262
20409
  }
20263
20410
  if (value === void 0 || value === null) continue;
20264
- const here = at(path72, key);
20411
+ const here = at(path73, key);
20265
20412
  const mValue = isPlain(m) ? m[key] : void 0;
20266
20413
  const sValue = isPlain(s) ? s[key] : void 0;
20267
20414
  if (mValue === void 0) {
@@ -20337,7 +20484,7 @@ function weighMoveHome(hooks, candidate, reach, dependencyLimit) {
20337
20484
  };
20338
20485
  }
20339
20486
  function moveChangeReports(edits, dryRun) {
20340
- return edits.map((edit) => ({ edit, changes: specChanges(edit.before, edit.after) })).filter(({ changes }) => changes.length > 0).map(({ edit, changes }) => ({
20487
+ return edits.map((edit) => ({ edit, changes: specChanges(edit.before ?? {}, edit.after) })).filter(({ changes }) => changes.length > 0).map(({ edit, changes }) => ({
20341
20488
  kind: edit.kind,
20342
20489
  id: edit.id,
20343
20490
  written: !dryRun,
@@ -20346,9 +20493,57 @@ function moveChangeReports(edits, dryRun) {
20346
20493
  ineffective: [],
20347
20494
  notices: [],
20348
20495
  testsToRevisit: [],
20349
- summary: `${dryRun ? "Would move" : "Moved"} into ${edit.kind} "${edit.id}": ${changes.length} change${changes.length === 1 ? "" : "s"}.`
20496
+ summary: edit.before === null ? `${dryRun ? "Would create" : "Created"} ${edit.kind} "${edit.id}" to receive the moved methods.` : `${dryRun ? "Would move" : "Moved"} into ${edit.kind} "${edit.id}": ${changes.length} change${changes.length === 1 ? "" : "s"}.`
20350
20497
  }));
20351
20498
  }
20499
+ function createdClause(created, verb) {
20500
+ return created.length ? `, ${verb} ${created.join(" and ")}` : "";
20501
+ }
20502
+ function createdContract(target, from, methods, contracts) {
20503
+ const now = (/* @__PURE__ */ new Date()).toISOString();
20504
+ const status2 = statusOfContracts(contracts, from);
20505
+ return {
20506
+ id: `i${target.id}`,
20507
+ name: `${target.name} Interface`,
20508
+ description: `The contract of ${target.name}, created by moving ${namedMethods(methods)} here from "${from}".`,
20509
+ component: target.id,
20510
+ methods: [],
20511
+ ...status2 ? { status: status2 } : {},
20512
+ createdAt: now,
20513
+ updatedAt: now
20514
+ };
20515
+ }
20516
+ function createdImplementation(target, contractId, from, travelling, implementations, contracts) {
20517
+ const ofSource = new Set(contracts.filter((i) => i.component === from).map((i) => i.id));
20518
+ const leaving = implementations.filter((impl) => ofSource.has(impl.contract) && impl.methods.some((m) => travelling.some((t) => t.name === m.name)));
20519
+ const paths = [...new Set(leaving.map((impl) => impl.sourcePath))];
20520
+ const inherited = paths.length === 1 ? paths[0] : void 0;
20521
+ const notices = [];
20522
+ if (paths.length > 1) {
20523
+ for (const entry of travelling) {
20524
+ if (entry.sourcePath) continue;
20525
+ const home = leaving.find((impl) => impl.methods.some((m) => m.name === entry.name));
20526
+ if (home?.sourcePath) entry.sourcePath = home.sourcePath;
20527
+ }
20528
+ notices.push(`"${target.id}_impl" is created without a sourcePath: the moved entries come from implementations with different ones, so each keeps the file it was realized in as its own sourcePath.`);
20529
+ }
20530
+ const now = (/* @__PURE__ */ new Date()).toISOString();
20531
+ const status2 = leaving[0]?.status;
20532
+ const spec = {
20533
+ id: `${target.id}_impl`,
20534
+ name: `${target.name} Implementation`,
20535
+ description: `The implementation of ${target.name}, created by moving methods here from "${from}".`,
20536
+ contract: contractId,
20537
+ ...inherited ? { sourcePath: inherited } : {},
20538
+ methods: travelling,
20539
+ ...status2 ? { status: status2 } : {},
20540
+ createdAt: now,
20541
+ updatedAt: now
20542
+ };
20543
+ const origin = leaving.length === 1 ? ` from "${leaving[0].id}"` : "";
20544
+ const named = inherited ? `implementation "${spec.id}" (sourcePath ${inherited}, inherited${origin})` : `implementation "${spec.id}" (no sourcePath)`;
20545
+ return { spec, named, notices };
20546
+ }
20352
20547
  function refusedMoveSummary(from, to, methods, refusals, alternatives) {
20353
20548
  const cheapest = alternatives.find((c) => c.legal);
20354
20549
  return `Refused: moving ${namedMethods(methods)} from "${from}" to "${to}" is refused by ${refusals.join(", ")}. Nothing was written. ` + (cheapest ? `The cheapest legal home is "${cheapest.component}" (${cheapest.newDependencies.length} new dependenc${cheapest.newDependencies.length === 1 ? "y" : "ies"}, ${cheapest.dependencyCount} of ${cheapest.dependencyLimit}).` : `No component of this subsystem can take them as they stand \u2014 ${alternatives.length} were weighed.`);
@@ -20542,7 +20737,7 @@ function updateSpec(kind, id, delta, hooks, dryRun) {
20542
20737
  function moveMethods(from, to, methods, hooks, dryRun) {
20543
20738
  return current().moveMethods(from, to, methods, hooks, dryRun);
20544
20739
  }
20545
- var fs13, path17, NO_ROOT_SUBSYSTEMS, SIGNATURE_TTL_MS, COMPONENT_AUTH_SOURCE, DELTA_VERBS, JUMP_LABEL_TWINS, LABEL_TWIN_CONTAINERS, SpecWorkspace, DEFAULT_DEPENDENCY_LIMIT, PROSE_FIELDS, workspaces, lastServedBinding;
20740
+ var fs13, path17, NO_ROOT_SUBSYSTEMS, SIGNATURE_TTL_MS, COMPONENT_AUTH_SOURCE, STEP_JUMP_FIELDS, STEP_JUMP_LISTS, DELTA_VERBS, JUMP_LABEL_TWINS, LABEL_TWIN_CONTAINERS, SpecWorkspace, DEFAULT_DEPENDENCY_LIMIT, PROSE_FIELDS, workspaces, lastServedBinding;
20546
20741
  var init_specs2 = __esm({
20547
20742
  "src/core/specs.ts"() {
20548
20743
  "use strict";
@@ -20562,6 +20757,8 @@ var init_specs2 = __esm({
20562
20757
  NO_ROOT_SUBSYSTEMS = /* @__PURE__ */ new Set();
20563
20758
  SIGNATURE_TTL_MS = 2e3;
20564
20759
  COMPONENT_AUTH_SOURCE = "component:";
20760
+ STEP_JUMP_FIELDS = ["onTrueStep", "onFalseStep", "defaultStep", "endStep", "finallyStep", "toStep"];
20761
+ STEP_JUMP_LISTS = [["cases", "value"], ["catches", "error"], ["branches", "name"]];
20565
20762
  DELTA_VERBS = /* @__PURE__ */ new Set(["action", "remove", "captureJumps"]);
20566
20763
  JUMP_LABEL_TWINS = /* @__PURE__ */ new Set([
20567
20764
  "onTrueLabel",
@@ -22530,7 +22727,8 @@ var init_specs2 = __esm({
22530
22727
  notices: plan.notices,
22531
22728
  summary: refusedMoveSummary(from, to, methods, verdict.refusals, alternatives),
22532
22729
  dryRun,
22533
- mentions
22730
+ mentions,
22731
+ created: []
22534
22732
  };
22535
22733
  }
22536
22734
  }
@@ -22546,9 +22744,10 @@ var init_specs2 = __esm({
22546
22744
  refusals: [],
22547
22745
  alternatives: [],
22548
22746
  notices: plan.notices,
22549
- summary: `Dry run: moving ${namedMethods(methods)} from "${from}" to "${to}" would touch ${edits2.length} spec${edits2.length === 1 ? "" : "s"} and re-point ${repointed} reference${repointed === 1 ? "" : "s"}. Nothing was written.`,
22747
+ summary: `Dry run: moving ${namedMethods(methods)} from "${from}" to "${to}" would touch ${edits2.length} spec${edits2.length === 1 ? "" : "s"}${createdClause(plan.created, "would create")} and re-point ${repointed} reference${repointed === 1 ? "" : "s"}. Nothing was written.`,
22550
22748
  dryRun: true,
22551
- mentions
22749
+ mentions,
22750
+ created: plan.created
22552
22751
  };
22553
22752
  }
22554
22753
  const edits = this.writeMoveEdits([...plan.edits.values()]);
@@ -22562,9 +22761,10 @@ var init_specs2 = __esm({
22562
22761
  refusals: [],
22563
22762
  alternatives: [],
22564
22763
  notices: plan.notices,
22565
- summary: `Moved ${namedMethods(methods)} from "${from}" to "${to}": ${edits.length} spec${edits.length === 1 ? "" : "s"} written, ${repointed} reference${repointed === 1 ? "" : "s"} re-pointed${mentions.length ? `, ${mentions.length} still naming the old home in prose or on the wire` : ""}.`,
22764
+ summary: `Moved ${namedMethods(methods)} from "${from}" to "${to}": ${edits.length} spec${edits.length === 1 ? "" : "s"} written${createdClause(plan.created, "created")}, ${repointed} reference${repointed === 1 ? "" : "s"} re-pointed${mentions.length ? `, ${mentions.length} still naming the old home in prose or on the wire` : ""}.`,
22566
22765
  dryRun: false,
22567
- mentions
22766
+ mentions,
22767
+ created: plan.created
22568
22768
  };
22569
22769
  }
22570
22770
  /**
@@ -22597,15 +22797,26 @@ var init_specs2 = __esm({
22597
22797
  }
22598
22798
  const receiving = this.moveTargetContract(to, ofTarget);
22599
22799
  if (typeof receiving === "string") return receiving;
22600
- const travelling = this.loadImplementationSpecs().some((impl) => ofSource.some((i) => i.id === impl.contract) && impl.methods.some((m) => methods.includes(m.name)));
22601
- if (travelling && !this.loadImplementationSpecs().some((i) => i.contract === receiving.id)) {
22602
- return `no implementation realizes "${receiving.id}", so the moved methods' narratives would have nowhere to arrive.`;
22800
+ const contractId = receiving?.id ?? `i${to}`;
22801
+ const holder = contracts.find((i) => i.id === contractId);
22802
+ if (!receiving && holder) {
22803
+ return `"${to}" declares no contract, and the one the move would create for it, "${contractId}", is already the id of "${holder.component}"'s contract \u2014 rename that contract, or give "${to}" its own first.`;
22804
+ }
22805
+ const implementations = this.loadImplementationSpecs();
22806
+ const travelling = implementations.some((impl) => ofSource.some((i) => i.id === impl.contract) && impl.methods.some((m) => methods.includes(m.name)));
22807
+ const implId = `${to}_impl`;
22808
+ const implHolder = implementations.find((i) => i.id === implId);
22809
+ if (travelling && !implementations.some((i) => i.contract === contractId) && implHolder) {
22810
+ return `no implementation realizes "${contractId}", and the one the move would create for it, "${implId}", is already the id of the implementation of "${implHolder.contract}" \u2014 rename it, or realize "${contractId}" first.`;
22603
22811
  }
22604
22812
  return null;
22605
22813
  }
22606
- /** The contract of `to` that receives the methods, or why that cannot be decided. */
22814
+ /**
22815
+ * The contract of `to` that receives the methods; null when it declares none
22816
+ * yet, so the move creates `i<to>`; or why the choice cannot be decided.
22817
+ */
22607
22818
  moveTargetContract(to, ofTarget) {
22608
- if (ofTarget.length === 0) return `"${to}" declares no contract, so the methods would have nowhere to arrive.`;
22819
+ if (ofTarget.length === 0) return null;
22609
22820
  if (ofTarget.length === 1) return ofTarget[0];
22610
22821
  const named = ofTarget.find((i) => i.id === `i${to}` || i.id.endsWith(`::i${to}`));
22611
22822
  return named ?? `"${to}" declares ${ofTarget.length} contracts and none is named "i${to}", so which one receives the methods is not decidable.`;
@@ -22618,7 +22829,7 @@ var init_specs2 = __esm({
22618
22829
  */
22619
22830
  planMethodMove(source, to, methods, contracts) {
22620
22831
  const target = this.loadComponentSpec(to);
22621
- const receiving = this.moveTargetContract(to, contracts.filter((i) => i.component === to));
22832
+ const stated = this.moveTargetContract(to, contracts.filter((i) => i.component === to));
22622
22833
  const implementations = this.loadImplementationSpecs();
22623
22834
  const plan = {
22624
22835
  edits: /* @__PURE__ */ new Map(),
@@ -22627,10 +22838,13 @@ var init_specs2 = __esm({
22627
22838
  reach: [],
22628
22839
  newDependencies: [],
22629
22840
  wireBound: [],
22630
- notices: []
22841
+ notices: [],
22842
+ created: []
22631
22843
  };
22844
+ const receiving = stated ?? createdContract(target, source.id, methods, contracts);
22632
22845
  const arriving = [];
22633
22846
  const travelling = [];
22847
+ const realizedIn = /* @__PURE__ */ new Map();
22634
22848
  for (const contract of contracts.filter((i) => i.component === source.id)) {
22635
22849
  const leaving = contract.methods.filter((m) => methods.includes(m.name));
22636
22850
  if (leaving.length === 0) continue;
@@ -22645,17 +22859,19 @@ var init_specs2 = __esm({
22645
22859
  const moving = impl.methods.filter((m) => methods.includes(m.name));
22646
22860
  if (moving.length === 0) continue;
22647
22861
  travelling.push(...cloneSpec(moving));
22862
+ for (const entry of moving) if (impl.sourcePath) realizedIn.set(entry.name, impl.sourcePath);
22648
22863
  const kept = cloneSpec(impl);
22649
22864
  kept.methods = kept.methods.filter((m) => !methods.includes(m.name));
22650
22865
  this.stageMoveEdit(plan, "implementation", impl.id, impl, kept);
22651
22866
  }
22652
22867
  }
22653
- this.stageMoveEdit(plan, "interface", receiving.id, receiving, {
22868
+ this.stageMoveEdit(plan, "interface", receiving.id, stated, {
22654
22869
  ...cloneSpec(receiving),
22655
22870
  methods: [...cloneSpec(receiving.methods), ...arriving]
22656
22871
  });
22872
+ if (!stated) plan.created.push(`interface "${receiving.id}"`);
22657
22873
  if (arriving.some((m) => m.endpoint)) plan.wireBound.push(receiving.id);
22658
- if (receiving.status !== void 0 && receiving.status !== statusOfContracts(contracts, source.id)) {
22874
+ if (stated && receiving.status !== void 0 && receiving.status !== statusOfContracts(contracts, source.id)) {
22659
22875
  plan.notices.push(`"${receiving.id}" is ${receiving.status} where the methods came from a ${statusOfContracts(contracts, source.id)} contract \u2014 the status of a moved method is the status of its new home.`);
22660
22876
  }
22661
22877
  for (const entry of travelling) {
@@ -22665,10 +22881,21 @@ var init_specs2 = __esm({
22665
22881
  }
22666
22882
  const targetImpl = implementations.find((i) => i.contract === receiving.id);
22667
22883
  if (travelling.length > 0 && targetImpl) {
22884
+ for (const entry of travelling) {
22885
+ const file = realizedIn.get(entry.name);
22886
+ if (entry.sourcePath || !file || file === targetImpl.sourcePath) continue;
22887
+ entry.sourcePath = file;
22888
+ plan.notices.push(`"${entry.name}" keeps ${file} as its own sourcePath: it was realized there by default, and "${targetImpl.id}" names ${targetImpl.sourcePath ? targetImpl.sourcePath : "no file"} \u2014 moving a method is not moving its code.`);
22889
+ }
22668
22890
  this.stageMoveEdit(plan, "implementation", targetImpl.id, targetImpl, {
22669
22891
  ...cloneSpec(targetImpl),
22670
22892
  methods: [...cloneSpec(targetImpl.methods), ...travelling]
22671
22893
  });
22894
+ } else if (travelling.length > 0) {
22895
+ const created = createdImplementation(target, receiving.id, source.id, travelling, implementations, contracts);
22896
+ this.stageMoveEdit(plan, "implementation", created.spec.id, null, created.spec);
22897
+ plan.created.push(created.named);
22898
+ plan.notices.push(...created.notices);
22672
22899
  }
22673
22900
  plan.reach = reachOf(travelling, source.id, new Set(methods)).filter((id) => id !== to);
22674
22901
  const held = /* @__PURE__ */ new Set([...target.dependsOn ?? [], ...target.owns ?? []]);
@@ -22712,6 +22939,9 @@ var init_specs2 = __esm({
22712
22939
  }
22713
22940
  this.stageMoveEdit(plan, kind, id, spec, subject);
22714
22941
  }
22942
+ for (const edit of plan.edits.values()) {
22943
+ if (edit.before === null) rewriteSpecRefs(edit.after, remap);
22944
+ }
22715
22945
  plan.notices.push(...this.callersOwingADependency(to, plan));
22716
22946
  return repointed;
22717
22947
  }
@@ -22805,7 +23035,8 @@ var init_specs2 = __esm({
22805
23035
  } catch (e) {
22806
23036
  for (const edit of [...written].reverse()) {
22807
23037
  try {
22808
- this.saveMovedSpec(edit.kind, edit.before);
23038
+ if (edit.before === null) this.delete(edit.kind, edit.id);
23039
+ else this.saveMovedSpec(edit.kind, edit.before);
22809
23040
  } catch {
22810
23041
  }
22811
23042
  }
@@ -27760,8 +27991,8 @@ var require_dist = __commonJS({
27760
27991
  function slug(name) {
27761
27992
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
27762
27993
  }
27763
- var fs58 = __toESM2(require("fs"));
27764
- var path72 = __toESM2(require("path"));
27994
+ var fs59 = __toESM2(require("fs"));
27995
+ var path73 = __toESM2(require("path"));
27765
27996
  var import_fflate = require_node();
27766
27997
  var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", ".hg", ".svn"]);
27767
27998
  function listEntries(archive) {
@@ -27799,9 +28030,9 @@ var require_dist = __commonJS({
27799
28030
  }
27800
28031
  function writeTree(destDir, files) {
27801
28032
  for (const file of files) {
27802
- const absolute = path72.join(destDir, file.path);
27803
- fs58.mkdirSync(path72.dirname(absolute), { recursive: true });
27804
- fs58.writeFileSync(absolute, file.contents);
28033
+ const absolute = path73.join(destDir, file.path);
28034
+ fs59.mkdirSync(path73.dirname(absolute), { recursive: true });
28035
+ fs59.writeFileSync(absolute, file.contents);
27805
28036
  }
27806
28037
  }
27807
28038
  function classifyKind(name, symlinks) {
@@ -27810,14 +28041,14 @@ var require_dist = __commonJS({
27810
28041
  return "file";
27811
28042
  }
27812
28043
  function walkPackDir(root, current2, out) {
27813
- for (const entry of fs58.readdirSync(current2, { withFileTypes: true })) {
28044
+ for (const entry of fs59.readdirSync(current2, { withFileTypes: true })) {
27814
28045
  if (entry.isDirectory()) {
27815
28046
  if (SKIP_DIRS.has(entry.name)) continue;
27816
- walkPackDir(root, path72.join(current2, entry.name), out);
28047
+ walkPackDir(root, path73.join(current2, entry.name), out);
27817
28048
  } else if (entry.isFile()) {
27818
- const absolute = path72.join(current2, entry.name);
27819
- const relative22 = path72.relative(root, absolute).split(path72.sep).join("/");
27820
- out.push({ path: relative22, contents: fs58.readFileSync(absolute) });
28049
+ const absolute = path73.join(current2, entry.name);
28050
+ const relative22 = path73.relative(root, absolute).split(path73.sep).join("/");
28051
+ out.push({ path: relative22, contents: fs59.readFileSync(absolute) });
27821
28052
  }
27822
28053
  }
27823
28054
  }
@@ -28124,19 +28355,19 @@ function commitStagedTree(stagingDir, destDir, roots, backupExisting) {
28124
28355
  const backupDir = path28.join(root, BACKUP_DIR, timestampSlug());
28125
28356
  let backedUp = false;
28126
28357
  for (const rootRel of roots) {
28127
- const relative15 = rootRel === "." ? "" : rootRel;
28128
- const stagedSpecDir = path28.join(stagingDir, relative15, ".wai");
28358
+ const relative16 = rootRel === "." ? "" : rootRel;
28359
+ const stagedSpecDir = path28.join(stagingDir, relative16, ".wai");
28129
28360
  if (!fs18.existsSync(stagedSpecDir)) continue;
28130
- const liveSpecDir = liveSpecDirFor(path28.join(root, relative15));
28361
+ const liveSpecDir = liveSpecDirFor(path28.join(root, relative16));
28131
28362
  if (backupExisting && liveSpecDir && fs18.existsSync(liveSpecDir)) {
28132
- const backupTarget = path28.join(backupDir, relative15, path28.basename(liveSpecDir));
28363
+ const backupTarget = path28.join(backupDir, relative16, path28.basename(liveSpecDir));
28133
28364
  fs18.mkdirSync(path28.dirname(backupTarget), { recursive: true });
28134
28365
  fs18.renameSync(liveSpecDir, backupTarget);
28135
28366
  backedUp = true;
28136
28367
  } else if (liveSpecDir && fs18.existsSync(liveSpecDir)) {
28137
28368
  fs18.rmSync(liveSpecDir, { recursive: true, force: true });
28138
28369
  }
28139
- const target = path28.join(root, relative15, ".wai");
28370
+ const target = path28.join(root, relative16, ".wai");
28140
28371
  fs18.mkdirSync(path28.dirname(target), { recursive: true });
28141
28372
  if (fs18.existsSync(target)) fs18.rmSync(target, { recursive: true, force: true });
28142
28373
  fs18.renameSync(stagedSpecDir, target);
@@ -29851,6 +30082,78 @@ var init_authoring2 = __esm({
29851
30082
  }
29852
30083
  });
29853
30084
 
30085
+ // src/mcp/build.ts
30086
+ function captureBuildStamp(entryPath) {
30087
+ try {
30088
+ const s = fs21.statSync(entryPath);
30089
+ return { path: entryPath, mtimeMs: s.mtimeMs, size: s.size };
30090
+ } catch {
30091
+ return null;
30092
+ }
30093
+ }
30094
+ function isBuildStale(stamp) {
30095
+ if (!stamp) return false;
30096
+ try {
30097
+ const s = fs21.statSync(stamp.path);
30098
+ return s.mtimeMs !== stamp.mtimeMs || s.size !== stamp.size;
30099
+ } catch {
30100
+ return false;
30101
+ }
30102
+ }
30103
+ function readBuildFingerprint(stamp) {
30104
+ const current2 = fs21.statSync(stamp.path);
30105
+ const key = `${stamp.path}|${current2.mtimeMs}|${current2.size}`;
30106
+ const cached = fingerprintCache.get(key);
30107
+ if (cached !== void 0) return cached;
30108
+ const modulePath = fingerprintModuleFor(stamp.path);
30109
+ const loaderFlags = modulePath.endsWith(".ts") ? process.execArgv : [];
30110
+ let printed;
30111
+ try {
30112
+ printed = (0, import_child_process3.execFileSync)(
30113
+ process.execPath,
30114
+ [...loaderFlags, "-e", "const m = require(process.argv[1]); process.stdout.write(String(m.schemaFingerprint()));", modulePath],
30115
+ { encoding: "utf8", timeout: 6e4, stdio: ["ignore", "pipe", "pipe"], windowsHide: true }
30116
+ ).trim();
30117
+ } catch (e) {
30118
+ const stderr = String(e.stderr ?? "").split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
30119
+ const cause = stderr.find((l) => /^[A-Za-z]*Error\b/.test(l)) ?? stderr[0] ?? e.message;
30120
+ throw new Error(`the build at ${modulePath} could not be asked for its schema fingerprint (${cause})`);
30121
+ }
30122
+ if (!printed) throw new Error(`the build at ${modulePath} answered no schema fingerprint`);
30123
+ fingerprintCache.set(key, printed);
30124
+ return printed;
30125
+ }
30126
+ function fingerprintModuleFor(entryPath) {
30127
+ let dir = path32.dirname(entryPath);
30128
+ for (; ; ) {
30129
+ const manifest = path32.join(dir, "package.json");
30130
+ if (fs21.existsSync(manifest)) {
30131
+ try {
30132
+ const pkg = JSON.parse(fs21.readFileSync(manifest, "utf8"));
30133
+ const inDist = path32.relative(path32.join(dir, "dist"), entryPath);
30134
+ if (pkg.name === "@wairon/cli" && pkg.main && !inDist.startsWith("..") && !path32.isAbsolute(inDist)) {
30135
+ return path32.resolve(dir, pkg.main);
30136
+ }
30137
+ } catch {
30138
+ }
30139
+ return entryPath;
30140
+ }
30141
+ const parent = path32.dirname(dir);
30142
+ if (parent === dir) return entryPath;
30143
+ dir = parent;
30144
+ }
30145
+ }
30146
+ var fs21, path32, import_child_process3, fingerprintCache;
30147
+ var init_build = __esm({
30148
+ "src/mcp/build.ts"() {
30149
+ "use strict";
30150
+ fs21 = __toESM(require("fs"));
30151
+ path32 = __toESM(require("path"));
30152
+ import_child_process3 = require("child_process");
30153
+ fingerprintCache = /* @__PURE__ */ new Map();
30154
+ }
30155
+ });
30156
+
29854
30157
  // src/mcp/adapters/skills.ts
29855
30158
  var init_skills2 = __esm({
29856
30159
  "src/mcp/adapters/skills.ts"() {
@@ -29878,10 +30181,10 @@ var init_validator = __esm({
29878
30181
  // src/mcp/server.ts
29879
30182
  var server_exports = {};
29880
30183
  __export(server_exports, {
29881
- captureBuildStamp: () => captureBuildStamp,
30184
+ assessBuildFreshness: () => assessBuildFreshness,
29882
30185
  createMcpServer: () => createMcpServer,
29883
- isBuildStale: () => isBuildStale,
29884
30186
  markStale: () => markStale,
30187
+ schemaFingerprint: () => schemaFingerprint,
29885
30188
  startMcpServer: () => startMcpServer,
29886
30189
  statusFamilyContext: () => statusFamilyContext
29887
30190
  });
@@ -29954,7 +30257,7 @@ function json(value) {
29954
30257
  return text(JSON.stringify(value, null, 2));
29955
30258
  }
29956
30259
  function errText(message) {
29957
- return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
30260
+ return { content: [{ type: "text", text: `Error: ${message.replace(/^(?:\s*Error:\s*)+/, "")}` }], isError: true };
29958
30261
  }
29959
30262
  function errMessage(e) {
29960
30263
  return errText(e instanceof Error ? e.message : String(e));
@@ -30001,40 +30304,134 @@ NOTICE:
30001
30304
  return structured(`${sentence}${noticeBlock}${testsBlock ? `
30002
30305
  ${testsBlock}` : ""}`, receipt);
30003
30306
  }
30004
- function captureBuildStamp(entryPath) {
30307
+ function schemaShape(schema, seen = /* @__PURE__ */ new Map()) {
30308
+ const def = schema?._def;
30309
+ if (!def) return null;
30310
+ const known = seen.get(schema);
30311
+ if (known !== void 0) return { ref: known };
30312
+ seen.set(schema, seen.size);
30313
+ const inner = (s) => schemaShape(s, seen);
30314
+ const kind = String(def.typeName);
30315
+ switch (kind) {
30316
+ case "ZodObject": {
30317
+ const shape = typeof def.shape === "function" ? def.shape() : def.shape;
30318
+ return {
30319
+ kind,
30320
+ keys: Object.keys(shape).sort().map((key) => [key, inner(shape[key])]),
30321
+ unknownKeys: def.unknownKeys,
30322
+ catchall: inner(def.catchall)
30323
+ };
30324
+ }
30325
+ case "ZodArray":
30326
+ return { kind, of: inner(def.type), min: def.minLength?.value, max: def.maxLength?.value };
30327
+ case "ZodOptional":
30328
+ case "ZodNullable":
30329
+ case "ZodReadonly":
30330
+ case "ZodBranded":
30331
+ case "ZodCatch":
30332
+ return { kind, of: inner(def.innerType ?? def.type) };
30333
+ case "ZodDefault":
30334
+ return { kind, of: inner(def.innerType), default: JSON.stringify(def.defaultValue?.()) };
30335
+ case "ZodEffects":
30336
+ return { kind, effect: def.effect?.type, of: inner(def.schema) };
30337
+ case "ZodLazy":
30338
+ return { kind, of: inner(def.getter()) };
30339
+ case "ZodUnion":
30340
+ case "ZodDiscriminatedUnion": {
30341
+ const options = def.options instanceof Map ? [...def.options.values()] : def.options;
30342
+ return { kind, discriminator: def.discriminator, of: options.map(inner) };
30343
+ }
30344
+ case "ZodIntersection":
30345
+ return { kind, left: inner(def.left), right: inner(def.right) };
30346
+ case "ZodTuple":
30347
+ return { kind, of: def.items.map(inner), rest: inner(def.rest) };
30348
+ case "ZodRecord":
30349
+ case "ZodMap":
30350
+ return { kind, key: inner(def.keyType), value: inner(def.valueType) };
30351
+ case "ZodSet":
30352
+ return { kind, of: inner(def.valueType) };
30353
+ case "ZodEnum":
30354
+ return { kind, values: def.values };
30355
+ case "ZodNativeEnum":
30356
+ return { kind, values: def.values };
30357
+ case "ZodLiteral":
30358
+ return { kind, value: def.value };
30359
+ case "ZodPipeline":
30360
+ return { kind, in: inner(def.in), out: inner(def.out) };
30361
+ default:
30362
+ return { kind, checks: def.checks?.map((c) => [c.kind, c.value ?? null]) ?? [] };
30363
+ }
30364
+ }
30365
+ function schemaFingerprint() {
30366
+ if (runningFingerprint !== void 0) return runningFingerprint;
30367
+ const specs = {
30368
+ system: schemaShape(SystemSpecSchema),
30369
+ subsystem: schemaShape(SubsystemSpecSchema),
30370
+ component: schemaShape(ComponentSpecSchema),
30371
+ interface: schemaShape(InterfaceSpecSchema),
30372
+ implementation: schemaShape(ImplementationSpecSchema),
30373
+ type: schemaShape(TypeSpecSchema)
30374
+ };
30375
+ const registered = createMcpServer()._registeredTools;
30376
+ const tools = [...SPEC_WRITE_TOOLS].sort().map((name) => [name, schemaShape(registered[name]?.inputSchema)]);
30377
+ runningFingerprint = crypto5.createHash("sha256").update(JSON.stringify({ version: FINGERPRINT_VERSION, specs, tools })).digest("hex");
30378
+ return runningFingerprint;
30379
+ }
30380
+ function assessBuildFreshness(stamp) {
30381
+ if (!isBuildStale(stamp)) return { state: "fresh", writesRefused: false, reason: "" };
30382
+ const running = schemaFingerprint();
30383
+ let onDisk;
30005
30384
  try {
30006
- const s = fs21.statSync(entryPath);
30007
- return { path: entryPath, mtimeMs: s.mtimeMs, size: s.size };
30008
- } catch {
30009
- return null;
30385
+ onDisk = readBuildFingerprint(stamp);
30386
+ } catch (e) {
30387
+ return {
30388
+ state: "unreadable",
30389
+ writesRefused: true,
30390
+ reason: `the wairon build on disk changed after this MCP server started, and its schemas could not be compared (${e instanceof Error ? e.message : String(e)}), so a schema change cannot be ruled out. Every spec write through this server is REFUSED and writes nothing. ${RECONNECT}`
30391
+ };
30010
30392
  }
30011
- }
30012
- function isBuildStale(stamp) {
30013
- if (!stamp) return false;
30014
- try {
30015
- const s = fs21.statSync(stamp.path);
30016
- return s.mtimeMs !== stamp.mtimeMs || s.size !== stamp.size;
30017
- } catch {
30018
- return false;
30393
+ if (onDisk === running) {
30394
+ return {
30395
+ state: "build-changed",
30396
+ writesRefused: false,
30397
+ reason: "the wairon build on disk changed after this MCP server started. Its spec and tool schemas did not change, so spec writes still go through; reconnect the server (/mcp reconnect wairon) to run the new code."
30398
+ };
30019
30399
  }
30400
+ return {
30401
+ state: "schema-changed",
30402
+ writesRefused: true,
30403
+ reason: `the wairon build on disk changed after this MCP server started, and its spec or tool schemas changed with it. A write through this server would silently drop the fields only the new build knows, so every spec write is REFUSED and writes nothing. ${RECONNECT}`
30404
+ };
30020
30405
  }
30021
- function markStale(result) {
30022
- const marked = result.structuredContent ? { ...result, structuredContent: { ...result.structuredContent, staleServer: true } } : result;
30406
+ function markStale(result, freshness = assessedAsChanged, placement = "trail") {
30407
+ const marked = result.structuredContent ? {
30408
+ ...result,
30409
+ structuredContent: {
30410
+ ...result.structuredContent,
30411
+ staleServer: true,
30412
+ ...freshness.writesRefused ? { writesRefused: true } : {}
30413
+ }
30414
+ } : result;
30415
+ const banner = `\u26A0 STALE SERVER: ${freshness.reason}`;
30023
30416
  const first = marked.content?.[0];
30024
30417
  if (first && first.type === "text") {
30025
- return {
30026
- ...marked,
30027
- content: [{ ...first, text: `${first.text}${STALE_SERVER_WARNING}` }, ...marked.content.slice(1)]
30028
- };
30418
+ const textWithBanner = placement === "lead" ? `${banner}
30419
+
30420
+ ${first.text}` : `${first.text}
30421
+
30422
+ ${banner}`;
30423
+ return { ...marked, content: [{ ...first, text: textWithBanner }, ...marked.content.slice(1)] };
30029
30424
  }
30030
30425
  return marked;
30031
30426
  }
30032
- function withStaleWarning(result) {
30033
- return isBuildStale(SERVER_BUILD_STAMP) ? markStale(result) : result;
30034
- }
30035
30427
  function reg(server, name, config, cb) {
30036
30428
  const guarded = (args) => {
30037
- const result = withStaleWarning(cb(args));
30429
+ const freshness = assessBuildFreshness(serverBuildStamps.get(server) ?? null);
30430
+ if (freshness.writesRefused && SPEC_WRITE_TOOLS.has(name)) {
30431
+ return errText(`${name} refused \u2014 ${freshness.reason}`);
30432
+ }
30433
+ const answered = cb(args);
30434
+ const result = freshness.state === "fresh" ? answered : markStale(answered, freshness, name === "sdd_get_status" ? "lead" : "trail");
30038
30435
  if (result.isError !== true && SPEC_WRITE_TOOLS.has(name)) listChangedEmitters.get(server)?.();
30039
30436
  return result;
30040
30437
  };
@@ -30152,6 +30549,7 @@ function createMcpServer(options = {}) {
30152
30549
  }, {
30153
30550
  instructions: buildServerInstructions2()
30154
30551
  });
30552
+ serverBuildStamps.set(server, options.buildStamp === void 0 ? SERVER_BUILD_STAMP : options.buildStamp);
30155
30553
  if (!options.hostedTools) {
30156
30554
  listChangedEmitters.set(server, () => {
30157
30555
  try {
@@ -30531,7 +30929,7 @@ ${renderChangeReport(report2)}`,
30531
30929
  server,
30532
30930
  "sdd_move_methods",
30533
30931
  {
30534
- description: "Move contract methods from one component to another, carrying each method's narrative, calls and bindings, and re-pointing every reference that named the old home: narrative call/register/dispatch steps, dispatch-table bindings, lifecycle entrypoints and `calls` entries. The target gains the dependencies the moved narratives call. ONE all-or-nothing gated write: if a rule refuses the move nothing is written and the report names the rule plus where these methods could live instead, cheapest legal home first, with the requested target among them so its shortfall reads beside the others. Prose is never rewritten and a wire endpoint keeps its address \u2014 moving a method between components must not silently re-address an RPC; both are reported as mentions. Refuses before the first write (unmovable request): a component or method that does not exist, a method name already declared on the target, a source and target that are the same component, and a component inside a chained subproject (move it from that project's own root). A dry run runs the whole move, gate included, and reports what it would have done.",
30932
+ description: "Move contract methods from one component to another, carrying each method's narrative, calls and bindings, and re-pointing every reference that named the old home: narrative call/register/dispatch steps, dispatch-table bindings, lifecycle entrypoints and `calls` entries. The target gains the dependencies the moved narratives call. ONE all-or-nothing gated write: if a rule refuses the move nothing is written and the report names the rule plus where these methods could live instead, cheapest legal home first, with the requested target among them so its shortfall reads beside the others. Prose is never rewritten and a wire endpoint keeps its address \u2014 moving a method between components must not silently re-address an RPC; both are reported as mentions. A target that declares no contract yet receives one, i<target>, and when implementation entries travel and no implementation realizes the receiving contract, <target>_impl is created for them, inheriting the source implementation's sourcePath; the report's `created` names every spec the move created. Refuses before the first write (unmovable request): a component or method that does not exist, a method name already declared on the target, a source and target that are the same component, a target with several contracts none named i<target>, a contract or implementation to create whose id another spec already holds, and a component inside a chained subproject (move it from that project's own root). A dry run runs the whole move, gate included, and reports what it would have done.",
30535
30933
  inputSchema: {
30536
30934
  from: import_zod11.z.string().describe("The component the methods belong to (namespaced if needed)"),
30537
30935
  to: import_zod11.z.string().describe("The component that should receive them (namespaced if needed)"),
@@ -31291,7 +31689,7 @@ async function scopeToClientWorkspace(server) {
31291
31689
  } catch {
31292
31690
  dir = null;
31293
31691
  }
31294
- if (dir && (fs21.existsSync(path32.join(dir, ".wai")) || fs21.existsSync(path32.join(dir, ".wairon")))) {
31692
+ if (dir && (fs22.existsSync(path33.join(dir, ".wai")) || fs22.existsSync(path33.join(dir, ".wairon")))) {
31295
31693
  setProjectRoot(dir);
31296
31694
  process.stderr.write(`[wairon mcp] scoped to client workspace root: ${dir}
31297
31695
  `);
@@ -31315,7 +31713,7 @@ async function startMcpServer() {
31315
31713
  } catch {
31316
31714
  }
31317
31715
  }
31318
- var import_mcp, import_stdio, import_zod11, import_types4, fs21, path32, import_url, TYPE_REF_GRAMMAR, staleServerOutput, SPEC_KINDS, STATUS_VALUES, testsToRevisitOutput, specWriteReceiptOutput, specDeletionOutput, specChangeOutput, specChangeReportOutput, validationIssueOutput, validateTreeOutput, getSpecOutput, SERVER_BUILD_STAMP, STALE_SERVER_WARNING, SPEC_WRITE_TOOLS, listChangedEmitters, statusInput, SKILL_RESOURCE_MIME, AGENT_BRIEF_SCHEME;
31716
+ var import_mcp, import_stdio, import_zod11, import_types4, fs22, path33, import_url, crypto5, TYPE_REF_GRAMMAR, staleServerOutput, SPEC_KINDS, STATUS_VALUES, testsToRevisitOutput, specWriteReceiptOutput, specDeletionOutput, specChangeOutput, specChangeReportOutput, validationIssueOutput, validateTreeOutput, getSpecOutput, FINGERPRINT_VERSION, runningFingerprint, RECONNECT, assessedAsChanged, serverBuildStamps, SERVER_BUILD_STAMP, SPEC_WRITE_TOOLS, listChangedEmitters, statusInput, SKILL_RESOURCE_MIME, AGENT_BRIEF_SCHEME;
31319
31717
  var init_server = __esm({
31320
31718
  "src/mcp/server.ts"() {
31321
31719
  "use strict";
@@ -31323,25 +31721,31 @@ var init_server = __esm({
31323
31721
  import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
31324
31722
  import_zod11 = require("zod");
31325
31723
  import_types4 = require("@modelcontextprotocol/sdk/types.js");
31326
- fs21 = __toESM(require("fs"));
31327
- path32 = __toESM(require("path"));
31724
+ fs22 = __toESM(require("fs"));
31725
+ path33 = __toESM(require("path"));
31328
31726
  import_url = require("url");
31329
31727
  init_fs();
31330
31728
  init_yaml();
31331
31729
  init_errors();
31332
31730
  init_defaults();
31731
+ crypto5 = __toESM(require("crypto"));
31732
+ init_specs();
31333
31733
  init_specs();
31334
31734
  init_paths();
31335
31735
  init_execution();
31336
31736
  init_core2();
31337
31737
  init_authoring2();
31738
+ init_build();
31338
31739
  init_skills2();
31339
31740
  init_surfaces2();
31340
31741
  init_validator();
31341
31742
  TYPE_REF_GRAMMAR = (what) => `${what}: a primitive/builtin or a defined type id (qualified across subsystems, e.g. "billing.Invoice" or "billing::Invoice"). Generics, arrays and UNIONS are all read, at any depth: "Invoice | null" (the commonest shape there is), "Invoice | undefined", "Invoice | Receipt", "Promise<Invoice | null>", "Map<string, Invoice | null>", "Invoice[] | null", "(Invoice | null)[]". Every identifier the string names must resolve \u2014 a union of two defined types means BOTH must exist. A union of string literals ("read" | "write") names no type and resolves to nothing.`;
31342
31743
  staleServerOutput = {
31343
31744
  staleServer: import_zod11.z.boolean().optional().describe(
31344
- "True when the wairon build on disk changed after this server started \u2014 the structured twin of the text answer's STALE SERVER banner. Writes through a stale process can silently drop fields a newer schema introduced: restart the MCP session before editing further."
31745
+ "True when the wairon build on disk changed after this server started \u2014 the structured twin of the text answer's STALE SERVER banner. When the rebuild left the spec and tool schemas alone, writes still go through; reconnect to run the new code."
31746
+ ),
31747
+ writesRefused: import_zod11.z.boolean().optional().describe(
31748
+ "True when the rebuild changed a spec or tool schema (or its schemas could not be compared): every spec write through this server is refused and writes nothing, because it would silently drop the fields only the new build knows. The human has to reconnect the server (/mcp reconnect wairon)."
31345
31749
  )
31346
31750
  };
31347
31751
  SPEC_KINDS = ["system", "subsystem", "component", "interface", "implementation", "type"];
@@ -31383,7 +31787,9 @@ var init_server = __esm({
31383
31787
  };
31384
31788
  specChangeOutput = {
31385
31789
  path: import_zod11.z.string().describe("The dotted path the change addresses, with names and indexes."),
31386
- change: import_zod11.z.enum(["set", "added", "removed", "cleared"]).describe("What happened at that path."),
31790
+ change: import_zod11.z.enum(["set", "added", "removed", "cleared", "renumbered", "relocated"]).describe(
31791
+ "What happened at that path. A narrative is compared by step identity: `renumbered` is a run of unchanged steps shifted by an insert or delete (before/after name the ranges), `relocated` a jump field that followed its target to the target's new number."
31792
+ ),
31387
31793
  before: import_zod11.z.string().optional().describe("The previous value, summarized; absent when there was none."),
31388
31794
  after: import_zod11.z.string().optional().describe("The new value, summarized; absent when there is none.")
31389
31795
  };
@@ -31455,8 +31861,15 @@ var init_server = __esm({
31455
31861
  ),
31456
31862
  ...staleServerOutput
31457
31863
  };
31864
+ FINGERPRINT_VERSION = 1;
31865
+ RECONNECT = "The human has to reconnect this MCP server (in Claude Code: /mcp reconnect wairon) \u2014 an agent cannot.";
31866
+ assessedAsChanged = {
31867
+ state: "build-changed",
31868
+ writesRefused: false,
31869
+ reason: "the wairon build on disk changed after this MCP server started. Reconnect the server (/mcp reconnect wairon) before further spec edits \u2014 a write through a stale server can silently drop fields a newer schema introduced."
31870
+ };
31871
+ serverBuildStamps = /* @__PURE__ */ new WeakMap();
31458
31872
  SERVER_BUILD_STAMP = captureBuildStamp(__filename);
31459
- STALE_SERVER_WARNING = "\n\n\u26A0 STALE SERVER: the wairon build on disk changed after this MCP server started. Restart the MCP session (e.g. /mcp reconnect) before further spec edits \u2014 writes through a stale server can silently drop fields introduced by newer schemas.";
31460
31873
  SPEC_WRITE_TOOLS = /* @__PURE__ */ new Set([
31461
31874
  "sdd_initialize_system",
31462
31875
  "sdd_add_subsystem",
@@ -31473,7 +31886,8 @@ var init_server = __esm({
31473
31886
  "sdd_write_narrative",
31474
31887
  "sdd_add_type",
31475
31888
  "sdd_delete_spec",
31476
- "sdd_update_spec"
31889
+ "sdd_update_spec",
31890
+ "sdd_move_methods"
31477
31891
  ]);
31478
31892
  listChangedEmitters = /* @__PURE__ */ new WeakMap();
31479
31893
  statusInput = import_zod11.z.enum(STATUS_VALUES).optional().describe(
@@ -31497,34 +31911,34 @@ __export(mcp_exports, {
31497
31911
  validateConfigDir: () => validateConfigDir
31498
31912
  });
31499
31913
  function geminiGlobalDir(override) {
31500
- return override || process.env["GEMINI_CONFIG_DIR"] || path33.join(os7.homedir(), ".gemini");
31914
+ return override || process.env["GEMINI_CONFIG_DIR"] || path34.join(os7.homedir(), ".gemini");
31501
31915
  }
31502
31916
  function claudeMcpConfigPath(useGlobal, override) {
31503
- if (!useGlobal) return path33.join(process.cwd(), ".mcp.json");
31917
+ if (!useGlobal) return path34.join(process.cwd(), ".mcp.json");
31504
31918
  const dir = override || process.env["CLAUDE_CONFIG_DIR"];
31505
- return dir ? path33.join(dir, ".claude.json") : path33.join(os7.homedir(), ".claude.json");
31919
+ return dir ? path34.join(dir, ".claude.json") : path34.join(os7.homedir(), ".claude.json");
31506
31920
  }
31507
31921
  function validateConfigDir(dir, backend) {
31508
- const resolved = path33.resolve(dir);
31922
+ const resolved = path34.resolve(dir);
31509
31923
  const agent = backend === "claude" ? "Claude" : "Gemini/Antigravity";
31510
- if (!fs22.existsSync(resolved)) {
31511
- const parent = path33.dirname(resolved);
31512
- if (!fs22.existsSync(parent)) {
31924
+ if (!fs23.existsSync(resolved)) {
31925
+ const parent = path34.dirname(resolved);
31926
+ if (!fs23.existsSync(parent)) {
31513
31927
  throw new WaironError(`--config-dir "${dir}" does not exist and its parent is missing \u2014 check the path.`);
31514
31928
  }
31515
31929
  logger.warn(`Config dir "${resolved}" does not exist yet; it will be created.`);
31516
31930
  return;
31517
31931
  }
31518
- if (!fs22.statSync(resolved).isDirectory()) {
31932
+ if (!fs23.statSync(resolved).isDirectory()) {
31519
31933
  throw new WaironError(`--config-dir "${dir}" is not a directory.`);
31520
31934
  }
31521
31935
  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"];
31522
- const entries = fs22.readdirSync(resolved);
31936
+ const entries = fs23.readdirSync(resolved);
31523
31937
  if (entries.length === 0) {
31524
31938
  logger.warn(`Config dir "${resolved}" is empty; proceeding (treating it as a fresh ${agent} config dir).`);
31525
31939
  return;
31526
31940
  }
31527
- if (!markers.some((m) => fs22.existsSync(path33.join(resolved, m)))) {
31941
+ if (!markers.some((m) => fs23.existsSync(path34.join(resolved, m)))) {
31528
31942
  throw new WaironError(
31529
31943
  `"${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.`
31530
31944
  );
@@ -31532,12 +31946,12 @@ function validateConfigDir(dir, backend) {
31532
31946
  }
31533
31947
  async function runMcpServe() {
31534
31948
  const { setProjectRoot: setProjectRoot2, getProjectRoot: getProjectRoot2, findProjectRoot: findProjectRoot2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
31535
- const cwd = path33.resolve(process.cwd());
31949
+ const cwd = path34.resolve(process.cwd());
31536
31950
  const envDir = process.env["WAIRON_PROJECT_DIR"];
31537
31951
  let resolved;
31538
31952
  let how;
31539
- if (envDir && fs22.existsSync(path33.join(envDir, ".wai"))) {
31540
- resolved = path33.resolve(envDir);
31953
+ if (envDir && fs23.existsSync(path34.join(envDir, ".wai"))) {
31954
+ resolved = path34.resolve(envDir);
31541
31955
  how = "WAIRON_PROJECT_DIR (pinned at install)";
31542
31956
  } else {
31543
31957
  const found = findProjectRoot2(cwd);
@@ -31563,18 +31977,18 @@ async function runMcpServe() {
31563
31977
  }
31564
31978
  function mcpConfigCandidates(cwd) {
31565
31979
  return [
31566
- path33.join(cwd, ".mcp.json"),
31980
+ path34.join(cwd, ".mcp.json"),
31567
31981
  claudeMcpConfigPath(true),
31568
- path33.join(cwd, ".gemini", "settings.json"),
31569
- path33.join(geminiGlobalDir(), "antigravity-cli", "mcp_config.json")
31982
+ path34.join(cwd, ".gemini", "settings.json"),
31983
+ path34.join(geminiGlobalDir(), "antigravity-cli", "mcp_config.json")
31570
31984
  ];
31571
31985
  }
31572
31986
  function detectHostedMcpSource(cwd = process.cwd()) {
31573
31987
  for (const configPath3 of mcpConfigCandidates(cwd)) {
31574
31988
  let entry;
31575
31989
  try {
31576
- if (!fs22.existsSync(configPath3)) continue;
31577
- const parsed = JSON.parse(fs22.readFileSync(configPath3, "utf8"));
31990
+ if (!fs23.existsSync(configPath3)) continue;
31991
+ const parsed = JSON.parse(fs23.readFileSync(configPath3, "utf8"));
31578
31992
  entry = parsed.mcpServers?.["wairon"];
31579
31993
  } catch {
31580
31994
  continue;
@@ -31653,20 +32067,20 @@ async function runMcpInstall(options = {}) {
31653
32067
  let settingsPath;
31654
32068
  if (backend === "gemini") {
31655
32069
  if (useGlobal) {
31656
- configBase = path33.join(geminiGlobalDir(options.configDir), "antigravity-cli");
31657
- settingsPath = path33.join(configBase, "mcp_config.json");
32070
+ configBase = path34.join(geminiGlobalDir(options.configDir), "antigravity-cli");
32071
+ settingsPath = path34.join(configBase, "mcp_config.json");
31658
32072
  } else {
31659
- configBase = path33.join(process.cwd(), ".gemini");
31660
- settingsPath = path33.join(configBase, "settings.json");
32073
+ configBase = path34.join(process.cwd(), ".gemini");
32074
+ settingsPath = path34.join(configBase, "settings.json");
31661
32075
  }
31662
32076
  } else {
31663
32077
  settingsPath = claudeMcpConfigPath(useGlobal, options.configDir);
31664
- configBase = path33.dirname(settingsPath);
32078
+ configBase = path34.dirname(settingsPath);
31665
32079
  }
31666
32080
  let settings = {};
31667
- if (fs22.existsSync(settingsPath)) {
32081
+ if (fs23.existsSync(settingsPath)) {
31668
32082
  try {
31669
- settings = JSON.parse(fs22.readFileSync(settingsPath, "utf8"));
32083
+ settings = JSON.parse(fs23.readFileSync(settingsPath, "utf8"));
31670
32084
  } catch {
31671
32085
  logger.warn(`Could not parse ${settingsPath} \u2014 starting fresh.`);
31672
32086
  }
@@ -31674,7 +32088,7 @@ async function runMcpInstall(options = {}) {
31674
32088
  const mcpServers = settings["mcpServers"] ?? {};
31675
32089
  const agentLabel = backend === "gemini" ? "Antigravity" : "Claude";
31676
32090
  const isPackaged = typeof process.pkg !== "undefined";
31677
- const scriptPath = process.argv[1] ? path33.resolve(process.argv[1]).replace(/\\/g, "/") : null;
32091
+ const scriptPath = process.argv[1] ? path34.resolve(process.argv[1]).replace(/\\/g, "/") : null;
31678
32092
  const useDirectNode = !isPackaged && scriptPath && (scriptPath.endsWith(".js") || scriptPath.endsWith(".ts"));
31679
32093
  const env = useGlobal ? {} : { WAIRON_PROJECT_DIR: process.cwd().replace(/\\/g, "/") };
31680
32094
  const desiredEntry = options.hostedUrl ? hostedMcpEntry(options) : useDirectNode ? { command: "node", args: [scriptPath, "mcp", "serve"], env } : { command: "wairon", args: ["mcp", "serve"], env };
@@ -31686,8 +32100,8 @@ async function runMcpInstall(options = {}) {
31686
32100
  const wasStale = !!existingEntry;
31687
32101
  mcpServers["wairon"] = desiredEntry;
31688
32102
  settings["mcpServers"] = mcpServers;
31689
- if (!fs22.existsSync(configBase)) fs22.mkdirSync(configBase, { recursive: true });
31690
- fs22.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
32103
+ if (!fs23.existsSync(configBase)) fs23.mkdirSync(configBase, { recursive: true });
32104
+ fs23.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
31691
32105
  logger.success(`wairon MCP server ${wasStale ? "updated (was stale)" : "registered"} for ${agentLabel} in ${import_chalk3.default.cyan(settingsPath)}.`);
31692
32106
  logger.blank();
31693
32107
  logger.info("AI tools using this config will have access to these wairon tools:");
@@ -31713,8 +32127,8 @@ async function runMcpStatus() {
31713
32127
  if (!projectConfig) throw new ProjectNotInitializedError();
31714
32128
  const claudeProject = claudeMcpConfigPath(false);
31715
32129
  const claudeGlobal = claudeMcpConfigPath(true);
31716
- const geminiProject = path33.join(process.cwd(), ".gemini", "settings.json");
31717
- const geminiGlobal = path33.join(geminiGlobalDir(), "antigravity-cli", "mcp_config.json");
32130
+ const geminiProject = path34.join(process.cwd(), ".gemini", "settings.json");
32131
+ const geminiGlobal = path34.join(geminiGlobalDir(), "antigravity-cli", "mcp_config.json");
31718
32132
  logger.blank();
31719
32133
  logger.info(`${import_chalk3.default.bold("wairon MCP Server")}`);
31720
32134
  logger.blank();
@@ -31725,12 +32139,12 @@ async function runMcpStatus() {
31725
32139
  { label: "Antigravity (global)", filePath: geminiGlobal, fallbackName: "mcp_config.json" }
31726
32140
  ];
31727
32141
  for (const { label, filePath, fallbackName } of checks) {
31728
- if (!fs22.existsSync(filePath)) {
32142
+ if (!fs23.existsSync(filePath)) {
31729
32143
  console.log(` ${label}: ${import_chalk3.default.gray(`${fallbackName} not found`)}`);
31730
32144
  continue;
31731
32145
  }
31732
32146
  try {
31733
- const s = JSON.parse(fs22.readFileSync(filePath, "utf8"));
32147
+ const s = JSON.parse(fs23.readFileSync(filePath, "utf8"));
31734
32148
  const registered = !!s["mcpServers"]?.["wairon"];
31735
32149
  const mark = registered ? import_chalk3.default.green("\u2713 registered") : import_chalk3.default.gray("not registered");
31736
32150
  console.log(` ${label}: ${mark} ${import_chalk3.default.gray(filePath)}`);
@@ -31746,7 +32160,7 @@ async function runMcpStatus() {
31746
32160
  logger.info(`To start manually: ${import_chalk3.default.bold("wairon mcp serve")}`);
31747
32161
  logger.blank();
31748
32162
  const mcpDir = aiDir("mcp");
31749
- if (fs22.existsSync(mcpDir)) {
32163
+ if (fs23.existsSync(mcpDir)) {
31750
32164
  logger.info(`MCP state dir: ${import_chalk3.default.gray(mcpDir)}`);
31751
32165
  }
31752
32166
  }
@@ -31764,10 +32178,10 @@ function hostedMcpEntry(options) {
31764
32178
  }
31765
32179
  function removeLegacyGlobalPlugin() {
31766
32180
  const home = process.env["USERPROFILE"] ?? process.env["HOME"] ?? os7.homedir();
31767
- const pluginDir = path33.join(home, ".gemini", "config", "plugins", "wairon");
32181
+ const pluginDir = path34.join(home, ".gemini", "config", "plugins", "wairon");
31768
32182
  try {
31769
- if (fs22.existsSync(pluginDir)) {
31770
- fs22.rmSync(pluginDir, { recursive: true, force: true });
32183
+ if (fs23.existsSync(pluginDir)) {
32184
+ fs23.rmSync(pluginDir, { recursive: true, force: true });
31771
32185
  logger.info(`Removed legacy global Antigravity plugin at ${import_chalk3.default.gray(pluginDir)} (it collides with the wairon MCP server).`);
31772
32186
  return true;
31773
32187
  }
@@ -31776,13 +32190,13 @@ function removeLegacyGlobalPlugin() {
31776
32190
  }
31777
32191
  return false;
31778
32192
  }
31779
- var fs22, os7, path33, import_chalk3;
32193
+ var fs23, os7, path34, import_chalk3;
31780
32194
  var init_mcp = __esm({
31781
32195
  "src/commands/mcp.ts"() {
31782
32196
  "use strict";
31783
- fs22 = __toESM(require("fs"));
32197
+ fs23 = __toESM(require("fs"));
31784
32198
  os7 = __toESM(require("os"));
31785
- path33 = __toESM(require("path"));
32199
+ path34 = __toESM(require("path"));
31786
32200
  import_chalk3 = __toESM(require("chalk"));
31787
32201
  init_logger();
31788
32202
  init_paths();
@@ -31794,7 +32208,7 @@ var init_mcp = __esm({
31794
32208
  });
31795
32209
 
31796
32210
  // src/cli/index.ts
31797
- var path71 = __toESM(require("path"));
32211
+ var path72 = __toESM(require("path"));
31798
32212
  var import_commander = require("commander");
31799
32213
  init_defaults();
31800
32214
  init_logger();
@@ -32016,7 +32430,7 @@ function isSupportedAlias(name) {
32016
32430
  }
32017
32431
 
32018
32432
  // src/commands/init.ts
32019
- var path34 = __toESM(require("path"));
32433
+ var path35 = __toESM(require("path"));
32020
32434
  var import_chalk4 = __toESM(require("chalk"));
32021
32435
  var import_inquirer = __toESM(require("inquirer"));
32022
32436
  init_logger();
@@ -32041,7 +32455,7 @@ async function runInit(options = {}) {
32041
32455
  logger.header("wairon init");
32042
32456
  const cwd = process.cwd();
32043
32457
  const ancestorRoot = findSystemRoot(cwd);
32044
- if (ancestorRoot && path34.resolve(ancestorRoot) === path34.resolve(cwd)) {
32458
+ if (ancestorRoot && path35.resolve(ancestorRoot) === path35.resolve(cwd)) {
32045
32459
  logger.info("Project already initialized.");
32046
32460
  logger.info("Design your spec tree with the SDD architect skill, then run `wairon generate`.");
32047
32461
  return;
@@ -32057,8 +32471,8 @@ async function runInit(options = {}) {
32057
32471
  await runInitInteractive();
32058
32472
  }
32059
32473
  async function runInitAsExternalSubsystem(parentRoot, cwd, options) {
32060
- const relPath = path34.relative(parentRoot, cwd) || ".";
32061
- const defaultId = path34.basename(cwd);
32474
+ const relPath = path35.relative(parentRoot, cwd) || ".";
32475
+ const defaultId = path35.basename(cwd);
32062
32476
  logger.info(`Detected a parent wairon project at ${parentRoot}`);
32063
32477
  logger.info(`This directory ("${relPath}") is not yet a wairon project.`);
32064
32478
  if (!options.yes) {
@@ -32114,7 +32528,7 @@ async function runInitAsExternalSubsystem(parentRoot, cwd, options) {
32114
32528
  }
32115
32529
  async function runInitNonInteractive() {
32116
32530
  const cwd = process.cwd();
32117
- const projectName = path34.basename(cwd);
32531
+ const projectName = path35.basename(cwd);
32118
32532
  const now = (/* @__PURE__ */ new Date()).toISOString();
32119
32533
  const targets = [defaultTargetConfig("claude"), defaultTargetConfig("agy")];
32120
32534
  const projectConfig = buildProjectConfig(projectName, targets, now, "backend");
@@ -32134,7 +32548,7 @@ async function runInitNonInteractive() {
32134
32548
  }
32135
32549
  async function runInitInteractive() {
32136
32550
  const cwd = process.cwd();
32137
- const defaultProjectName = path34.basename(cwd);
32551
+ const defaultProjectName = path35.basename(cwd);
32138
32552
  const { projectName } = await import_inquirer.default.prompt([
32139
32553
  {
32140
32554
  type: "input",
@@ -32279,7 +32693,7 @@ async function executeInit(projectName, projectConfig, guidePlan) {
32279
32693
  if (guidePlan.claudeLocal) {
32280
32694
  const p = localGuideFilePath(projectRoot2, "claude");
32281
32695
  injectGuide(p, "local");
32282
- logger.success(`Injected wairon guide into ${path34.relative(cwd, p)}`);
32696
+ logger.success(`Injected wairon guide into ${path35.relative(cwd, p)}`);
32283
32697
  writeRootGuideDelegator(projectRoot2, "claude");
32284
32698
  logger.success(`Created root CLAUDE.md delegator pointing to .claude/CLAUDE.md`);
32285
32699
  }
@@ -32291,7 +32705,7 @@ async function executeInit(projectName, projectConfig, guidePlan) {
32291
32705
  if (guidePlan.geminiLocal) {
32292
32706
  const p = localGuideFilePath(projectRoot2, "gemini");
32293
32707
  injectGuide(p, "local");
32294
- logger.success(`Injected wairon guide into ${path34.relative(cwd, p)}`);
32708
+ logger.success(`Injected wairon guide into ${path35.relative(cwd, p)}`);
32295
32709
  writeRootGuideDelegator(projectRoot2, "gemini");
32296
32710
  logger.success(`Created root GEMINI.md delegator pointing to .gemini/GEMINI.md`);
32297
32711
  }
@@ -32506,8 +32920,8 @@ A new project initialized with Wairon.
32506
32920
  }
32507
32921
 
32508
32922
  // src/commands/generate.ts
32509
- var fs23 = __toESM(require("fs"));
32510
- var path35 = __toESM(require("path"));
32923
+ var fs24 = __toESM(require("fs"));
32924
+ var path36 = __toESM(require("path"));
32511
32925
  init_logger();
32512
32926
  init_paths();
32513
32927
  init_errors();
@@ -32516,29 +32930,29 @@ init_fs();
32516
32930
  init_project();
32517
32931
  var WAIRON_AGENT_FILE = /-(owner|implementer|architect)\.md$/;
32518
32932
  function pruneStaleAgents(expectedPaths, scanDirs) {
32519
- const dirs = new Set(scanDirs ?? [...expectedPaths].map((p) => path35.dirname(p)));
32933
+ const dirs = new Set(scanDirs ?? [...expectedPaths].map((p) => path36.dirname(p)));
32520
32934
  let pruned = 0;
32521
32935
  for (const dir of dirs) {
32522
32936
  let entries;
32523
32937
  try {
32524
- entries = fs23.readdirSync(dir);
32938
+ entries = fs24.readdirSync(dir);
32525
32939
  } catch {
32526
32940
  continue;
32527
32941
  }
32528
32942
  for (const name of entries) {
32529
32943
  if (!name.endsWith(".md")) continue;
32530
- const full = path35.resolve(dir, name);
32944
+ const full = path36.resolve(dir, name);
32531
32945
  if (expectedPaths.has(full)) continue;
32532
32946
  let owned = WAIRON_AGENT_FILE.test(name);
32533
32947
  if (!owned) {
32534
32948
  try {
32535
- owned = fs23.readFileSync(full, "utf8").includes(WAIRON_MANAGED_MARKER);
32949
+ owned = fs24.readFileSync(full, "utf8").includes(WAIRON_MANAGED_MARKER);
32536
32950
  } catch {
32537
32951
  owned = false;
32538
32952
  }
32539
32953
  }
32540
32954
  if (!owned) continue;
32541
- fs23.unlinkSync(full);
32955
+ fs24.unlinkSync(full);
32542
32956
  pruned++;
32543
32957
  logger.verbose(`Pruned stale: ${full}`);
32544
32958
  }
@@ -32552,7 +32966,7 @@ async function runGenerate(options = {}) {
32552
32966
  const children = listDirectChainedSubprojects(getProjectRoot());
32553
32967
  for (const child of children) {
32554
32968
  logger.blank();
32555
- logger.info(`\u21B3 Chained subproject "${child.subsystemId}" \u2014 generating its layer in ${path35.relative(getProjectRoot(), child.dir) || "."}/`);
32969
+ logger.info(`\u21B3 Chained subproject "${child.subsystemId}" \u2014 generating its layer in ${path36.relative(getProjectRoot(), child.dir) || "."}/`);
32556
32970
  await runWithProjectRoot(child.dir, async () => {
32557
32971
  ensureProjectInitialized(child.subsystemId);
32558
32972
  await runGenerate(options);
@@ -32573,7 +32987,7 @@ async function generateLayer(options = {}) {
32573
32987
  } else if (options.dryRun) {
32574
32988
  logger.info("Dry run \u2014 rules.materializeAgentFiles is off: no agent files are written; leftover managed files would be removed.");
32575
32989
  } else if (options.prune !== false) {
32576
- const candidateDirs = [...resolveExpectedOutputPaths(agents, projectConfig)].map((p) => path35.dirname(p));
32990
+ const candidateDirs = [...resolveExpectedOutputPaths(agents, projectConfig)].map((p) => path36.dirname(p));
32577
32991
  const removed = pruneStaleAgents(/* @__PURE__ */ new Set(), candidateDirs);
32578
32992
  if (removed > 0) {
32579
32993
  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.`);
@@ -32658,7 +33072,7 @@ function materializeAgentLayer(agents, projectConfig, options) {
32658
33072
  var import_inquirer2 = __toESM(require("inquirer"));
32659
33073
  init_logger();
32660
33074
  init_defaults();
32661
- var path36 = __toESM(require("path"));
33075
+ var path37 = __toESM(require("path"));
32662
33076
  init_core();
32663
33077
  init_lock();
32664
33078
  init_fs();
@@ -32733,7 +33147,7 @@ async function runLock(options = {}, gate) {
32733
33147
  const root = getProjectRoot();
32734
33148
  const scope = options.subsystem ? {
32735
33149
  paths: new Set(
32736
- specPathsInScope(options.subsystem).map((p) => path36.relative(root, p).split(path36.sep).join("/"))
33150
+ specPathsInScope(options.subsystem).map((p) => path37.relative(root, p).split(path37.sep).join("/"))
32737
33151
  )
32738
33152
  } : void 0;
32739
33153
  const record2 = {
@@ -33032,29 +33446,29 @@ init_mcp();
33032
33446
 
33033
33447
  // src/commands/update.ts
33034
33448
  var https2 = __toESM(require("https"));
33035
- var fs25 = __toESM(require("fs"));
33036
- var path37 = __toESM(require("path"));
33449
+ var fs26 = __toESM(require("fs"));
33450
+ var path38 = __toESM(require("path"));
33037
33451
  var os8 = __toESM(require("os"));
33038
- var crypto5 = __toESM(require("crypto"));
33039
- var import_child_process3 = require("child_process");
33452
+ var crypto6 = __toESM(require("crypto"));
33453
+ var import_child_process4 = require("child_process");
33040
33454
  init_logger();
33041
33455
  init_defaults();
33042
33456
  init_version();
33043
33457
 
33044
33458
  // src/utils/download.ts
33045
- var fs24 = __toESM(require("fs"));
33459
+ var fs25 = __toESM(require("fs"));
33046
33460
  var http = __toESM(require("http"));
33047
33461
  var https = __toESM(require("https"));
33048
33462
  init_defaults();
33049
33463
  function downloadFile(url, dest) {
33050
- return new Promise((resolve33, reject) => {
33051
- const file = fs24.createWriteStream(dest);
33464
+ return new Promise((resolve34, reject) => {
33465
+ const file = fs25.createWriteStream(dest);
33052
33466
  const get4 = url.startsWith("https://") ? https.get : http.get;
33053
33467
  get4(url, { headers: { "User-Agent": `wairon/${WAIRON_VERSION}` }, agent: false }, (res) => {
33054
33468
  if (res.statusCode === 301 || res.statusCode === 302) {
33055
33469
  file.close();
33056
33470
  res.destroy();
33057
- downloadFile(res.headers.location, dest).then(resolve33).catch(reject);
33471
+ downloadFile(res.headers.location, dest).then(resolve34).catch(reject);
33058
33472
  return;
33059
33473
  }
33060
33474
  if (res.statusCode !== 200) {
@@ -33066,16 +33480,16 @@ function downloadFile(url, dest) {
33066
33480
  res.pipe(file);
33067
33481
  file.on("finish", () => {
33068
33482
  res.destroy();
33069
- file.close(() => resolve33());
33483
+ file.close(() => resolve34());
33070
33484
  });
33071
33485
  file.on("error", (err) => {
33072
33486
  res.destroy();
33073
- fs24.unlink(dest, () => {
33487
+ fs25.unlink(dest, () => {
33074
33488
  });
33075
33489
  reject(err);
33076
33490
  });
33077
33491
  }).on("error", (err) => {
33078
- fs24.unlink(dest, () => {
33492
+ fs25.unlink(dest, () => {
33079
33493
  });
33080
33494
  reject(err);
33081
33495
  });
@@ -33150,7 +33564,7 @@ async function runUpdate(options = {}) {
33150
33564
  process.exit(1);
33151
33565
  }
33152
33566
  const tmpDir = os8.tmpdir();
33153
- const tmpFile = path37.join(tmpDir, assetName);
33567
+ const tmpFile = path38.join(tmpDir, assetName);
33154
33568
  logger.info(`Downloading ${assetName}...`);
33155
33569
  try {
33156
33570
  await downloadFile(asset.browser_download_url, tmpFile);
@@ -33168,16 +33582,16 @@ async function runUpdate(options = {}) {
33168
33582
  const checksumAssetName = assetName + ".sha256";
33169
33583
  const checksumAsset = release.assets.find((a) => a.name === checksumAssetName);
33170
33584
  if (checksumAsset) {
33171
- const tmpChecksum = path37.join(tmpDir, checksumAssetName);
33585
+ const tmpChecksum = path38.join(tmpDir, checksumAssetName);
33172
33586
  logger.info(`Verifying checksum...`);
33173
33587
  try {
33174
33588
  await downloadFile(checksumAsset.browser_download_url, tmpChecksum);
33175
33589
  verifyChecksum(tmpFile, tmpChecksum, assetName);
33176
- fs25.unlinkSync(tmpChecksum);
33590
+ fs26.unlinkSync(tmpChecksum);
33177
33591
  } catch (err) {
33178
33592
  logger.error(`Checksum verification failed: ${err.message}`);
33179
33593
  try {
33180
- fs25.unlinkSync(tmpFile);
33594
+ fs26.unlinkSync(tmpFile);
33181
33595
  } catch {
33182
33596
  }
33183
33597
  process.exit(1);
@@ -33243,7 +33657,7 @@ function releaseChannelLabel(tag) {
33243
33657
  return version.slice(dash + 1).replace(/\.\d+$/, "") || "stable";
33244
33658
  }
33245
33659
  function fetchReleases(repo) {
33246
- return new Promise((resolve33, reject) => {
33660
+ return new Promise((resolve34, reject) => {
33247
33661
  const url = `https://api.github.com/repos/${repo}/releases?per_page=100`;
33248
33662
  const options = {
33249
33663
  headers: {
@@ -33263,7 +33677,7 @@ function fetchReleases(repo) {
33263
33677
  return;
33264
33678
  }
33265
33679
  try {
33266
- resolve33(JSON.parse(data));
33680
+ resolve34(JSON.parse(data));
33267
33681
  } catch {
33268
33682
  reject(new Error("Failed to parse GitHub API response"));
33269
33683
  }
@@ -33273,10 +33687,10 @@ function fetchReleases(repo) {
33273
33687
  });
33274
33688
  }
33275
33689
  function verifyChecksum(filePath, checksumFile, expectedFilename) {
33276
- const checksumContent = fs25.readFileSync(checksumFile, "utf-8").trim();
33690
+ const checksumContent = fs26.readFileSync(checksumFile, "utf-8").trim();
33277
33691
  const expectedHash = checksumContent.split(/\s+/)[0].toLowerCase();
33278
- const fileBuffer = fs25.readFileSync(filePath);
33279
- const actualHash = crypto5.createHash("sha256").update(fileBuffer).digest("hex").toLowerCase();
33692
+ const fileBuffer = fs26.readFileSync(filePath);
33693
+ const actualHash = crypto6.createHash("sha256").update(fileBuffer).digest("hex").toLowerCase();
33280
33694
  if (actualHash !== expectedHash) {
33281
33695
  throw new Error(
33282
33696
  `SHA-256 mismatch for ${expectedFilename}
@@ -33306,30 +33720,30 @@ function isPkgBinary2() {
33306
33720
  function installBinary(tmpFile, destPath) {
33307
33721
  const platform = process.platform;
33308
33722
  const isZip = tmpFile.endsWith(".zip");
33309
- const extractDir = path37.join(os8.tmpdir(), "wairon-extract");
33310
- if (fs25.existsSync(extractDir)) fs25.rmSync(extractDir, { recursive: true });
33311
- fs25.mkdirSync(extractDir, { recursive: true });
33723
+ const extractDir = path38.join(os8.tmpdir(), "wairon-extract");
33724
+ if (fs26.existsSync(extractDir)) fs26.rmSync(extractDir, { recursive: true });
33725
+ fs26.mkdirSync(extractDir, { recursive: true });
33312
33726
  if (isZip) {
33313
- (0, import_child_process3.execSync)(
33727
+ (0, import_child_process4.execSync)(
33314
33728
  `powershell -NoProfile -NonInteractive -Command "Expand-Archive -Path '${tmpFile}' -DestinationPath '${extractDir}' -Force"`,
33315
33729
  { stdio: ["ignore", "pipe", "pipe"] }
33316
33730
  );
33317
33731
  } else {
33318
- (0, import_child_process3.execSync)(`tar -xzf "${tmpFile}" -C "${extractDir}"`, { stdio: ["ignore", "pipe", "pipe"] });
33732
+ (0, import_child_process4.execSync)(`tar -xzf "${tmpFile}" -C "${extractDir}"`, { stdio: ["ignore", "pipe", "pipe"] });
33319
33733
  }
33320
33734
  const binaryName = platform === "win32" ? "wairon.exe" : "wairon";
33321
- const extractedBinary = path37.join(extractDir, binaryName);
33322
- if (!fs25.existsSync(extractedBinary)) {
33735
+ const extractedBinary = path38.join(extractDir, binaryName);
33736
+ if (!fs26.existsSync(extractedBinary)) {
33323
33737
  throw new Error(`Extracted binary not found at ${extractedBinary}`);
33324
33738
  }
33325
33739
  if (platform === "win32") {
33326
33740
  const oldPath = destPath + ".old";
33327
33741
  try {
33328
33742
  cleanStaleBinary(oldPath);
33329
- fs25.renameSync(destPath, oldPath);
33330
- fs25.copyFileSync(extractedBinary, destPath);
33743
+ fs26.renameSync(destPath, oldPath);
33744
+ fs26.copyFileSync(extractedBinary, destPath);
33331
33745
  try {
33332
- fs25.unlinkSync(oldPath);
33746
+ fs26.unlinkSync(oldPath);
33333
33747
  } catch {
33334
33748
  }
33335
33749
  } catch (err) {
@@ -33343,25 +33757,25 @@ function installBinary(tmpFile, destPath) {
33343
33757
  }
33344
33758
  } else {
33345
33759
  const tmpDest = destPath + ".new";
33346
- fs25.copyFileSync(extractedBinary, tmpDest);
33347
- fs25.chmodSync(tmpDest, 493);
33348
- fs25.renameSync(tmpDest, destPath);
33760
+ fs26.copyFileSync(extractedBinary, tmpDest);
33761
+ fs26.chmodSync(tmpDest, 493);
33762
+ fs26.renameSync(tmpDest, destPath);
33349
33763
  }
33350
33764
  try {
33351
- fs25.unlinkSync(tmpFile);
33765
+ fs26.unlinkSync(tmpFile);
33352
33766
  } catch {
33353
33767
  }
33354
33768
  try {
33355
- fs25.rmSync(extractDir, { recursive: true });
33769
+ fs26.rmSync(extractDir, { recursive: true });
33356
33770
  } catch {
33357
33771
  }
33358
33772
  }
33359
33773
  function cleanStaleBinary(oldPath) {
33360
33774
  const target = oldPath ?? (isPkgBinary2() ? process.execPath + ".old" : null);
33361
33775
  if (!target) return;
33362
- if (fs25.existsSync(target)) {
33776
+ if (fs26.existsSync(target)) {
33363
33777
  try {
33364
- fs25.unlinkSync(target);
33778
+ fs26.unlinkSync(target);
33365
33779
  } catch {
33366
33780
  }
33367
33781
  }
@@ -33490,7 +33904,7 @@ async function filteredCheckbox(config) {
33490
33904
  32,
33491
33905
  Math.max(...items.map((i) => i.label.length))
33492
33906
  );
33493
- return new Promise((resolve33) => {
33907
+ return new Promise((resolve34) => {
33494
33908
  const checked = /* @__PURE__ */ new Set();
33495
33909
  let cursor = 0;
33496
33910
  let filterIdx = 0;
@@ -33557,7 +33971,7 @@ async function filteredCheckbox(config) {
33557
33971
  );
33558
33972
  teardown();
33559
33973
  const result = items.filter((_, idx) => checked.has(idx)).map((i) => i.value);
33560
- resolve33(result);
33974
+ resolve34(result);
33561
33975
  }
33562
33976
  function abort() {
33563
33977
  process.stdout.write("\n");
@@ -33827,9 +34241,9 @@ async function runSkillsInstall() {
33827
34241
  }
33828
34242
 
33829
34243
  // src/commands/doctor.ts
33830
- var fs26 = __toESM(require("fs"));
34244
+ var fs27 = __toESM(require("fs"));
33831
34245
  var os9 = __toESM(require("os"));
33832
- var path38 = __toESM(require("path"));
34246
+ var path39 = __toESM(require("path"));
33833
34247
  var import_chalk12 = __toESM(require("chalk"));
33834
34248
  init_logger();
33835
34249
  init_defaults();
@@ -33861,10 +34275,10 @@ function stampVerdict(content) {
33861
34275
  return { mark: "warn", note: `v${v} \u2014 stale, installed is v${WAIRON_VERSION}` };
33862
34276
  }
33863
34277
  function mcpEntryHealth(settingsPath) {
33864
- if (!fs26.existsSync(settingsPath)) return { mark: "warn", note: "not registered" };
34278
+ if (!fs27.existsSync(settingsPath)) return { mark: "warn", note: "not registered" };
33865
34279
  let entry;
33866
34280
  try {
33867
- const s = JSON.parse(fs26.readFileSync(settingsPath, "utf8"));
34281
+ const s = JSON.parse(fs27.readFileSync(settingsPath, "utf8"));
33868
34282
  entry = s.mcpServers?.["wairon"];
33869
34283
  } catch {
33870
34284
  return { mark: "error", note: "parse error" };
@@ -33872,7 +34286,7 @@ function mcpEntryHealth(settingsPath) {
33872
34286
  if (!entry) return { mark: "warn", note: "not registered" };
33873
34287
  if (entry.command === "node" && Array.isArray(entry.args) && typeof entry.args[0] === "string") {
33874
34288
  const scriptPath = entry.args[0];
33875
- if (!fs26.existsSync(scriptPath)) {
34289
+ if (!fs27.existsSync(scriptPath)) {
33876
34290
  return { mark: "error", note: `registered but the server path is missing \u2014 ${scriptPath}` };
33877
34291
  }
33878
34292
  }
@@ -33923,7 +34337,7 @@ async function runDoctor(options = {}) {
33923
34337
  try {
33924
34338
  const missing = findChainingSubprojectsMissingConfig(getProjectRoot());
33925
34339
  if (missing.length > 0) {
33926
- line(tally, "warn", `${missing.length} chained subproject(s) have specs but no project.yaml (un-runnable standalone): ${missing.map((d) => path38.relative(getProjectRoot(), d) || ".").join(", ")}. Run \`wairon doctor --fix\` to initialize them.`);
34340
+ line(tally, "warn", `${missing.length} chained subproject(s) have specs but no project.yaml (un-runnable standalone): ${missing.map((d) => path39.relative(getProjectRoot(), d) || ".").join(", ")}. Run \`wairon doctor --fix\` to initialize them.`);
33927
34341
  }
33928
34342
  } catch {
33929
34343
  }
@@ -33980,7 +34394,7 @@ async function runDoctor(options = {}) {
33980
34394
  }
33981
34395
  console.log(import_chalk12.default.bold(`Generated files ${import_chalk12.default.gray("(stale = older than installed)")}`));
33982
34396
  for (const p of derivedDocPaths()) {
33983
- const label = path38.relative(getProjectRoot(), p).replace(/\\/g, "/");
34397
+ const label = path39.relative(getProjectRoot(), p).replace(/\\/g, "/");
33984
34398
  if (!pathExists(p)) {
33985
34399
  line(tally, "warn", `${label} \u2014 not generated yet (run \`wairon generate\`)`);
33986
34400
  continue;
@@ -33993,7 +34407,7 @@ async function runDoctor(options = {}) {
33993
34407
  const gp = localGuideFilePath(process.cwd(), t);
33994
34408
  if (!gp || seenGuides.has(gp)) continue;
33995
34409
  seenGuides.add(gp);
33996
- const rel2 = path38.relative(process.cwd(), gp).replace(/\\/g, "/");
34410
+ const rel2 = path39.relative(process.cwd(), gp).replace(/\\/g, "/");
33997
34411
  if (!pathExists(gp)) {
33998
34412
  line(tally, "warn", `${rel2} guide \u2014 not injected (run \`wairon generate\`)`);
33999
34413
  continue;
@@ -34042,8 +34456,8 @@ async function runDoctor(options = {}) {
34042
34456
  }
34043
34457
  }
34044
34458
  try {
34045
- const legacy = path38.join(os9.homedir(), ".wairon", "baselines");
34046
- const leftovers = fs26.existsSync(legacy) ? fs26.readdirSync(legacy).filter((f) => f.endsWith(".json")) : [];
34459
+ const legacy = path39.join(os9.homedir(), ".wairon", "baselines");
34460
+ const leftovers = fs27.existsSync(legacy) ? fs27.readdirSync(legacy).filter((f) => f.endsWith(".json")) : [];
34047
34461
  if (leftovers.length) {
34048
34462
  console.log(import_chalk12.default.bold("Approvals"));
34049
34463
  line(
@@ -34092,17 +34506,17 @@ async function runDoctor(options = {}) {
34092
34506
  line(tally, h.mark, `Claude (project .mcp.json): ${h.note}${h.mark === "ok" ? "" : " \u2014 run `wairon mcp install --backend claude`"}`);
34093
34507
  }
34094
34508
  if (wantGemini) {
34095
- const globalCfg = path38.join(os9.homedir(), ".gemini", "antigravity-cli", "mcp_config.json");
34509
+ const globalCfg = path39.join(os9.homedir(), ".gemini", "antigravity-cli", "mcp_config.json");
34096
34510
  const hg = mcpEntryHealth(globalCfg);
34097
34511
  line(tally, hg.mark, `Antigravity (global mcp_config.json): ${hg.note}${hg.mark === "ok" ? "" : " \u2014 run `wairon mcp install --backend gemini --global`"}`);
34098
34512
  const projPath = fromProjectRoot(".gemini", "settings.json");
34099
- if (fs26.existsSync(projPath)) {
34513
+ if (fs27.existsSync(projPath)) {
34100
34514
  const hp = mcpEntryHealth(projPath);
34101
34515
  line(tally, hp.mark === "error" ? "error" : "ok", `Gemini CLI (project): ${hp.note} ${import_chalk12.default.gray("(Antigravity ignores this file)")}`);
34102
34516
  }
34103
34517
  }
34104
- const pluginDir = path38.join(os9.homedir(), ".gemini", "config", "plugins", "wairon");
34105
- if (fs26.existsSync(pluginDir)) {
34518
+ const pluginDir = path39.join(os9.homedir(), ".gemini", "config", "plugins", "wairon");
34519
+ if (fs27.existsSync(pluginDir)) {
34106
34520
  line(tally, "warn", `Legacy Antigravity plugin present (${pluginDir}) \u2014 it collides with the wairon MCP server. Remove it with \`wairon doctor --fix\`.`);
34107
34521
  }
34108
34522
  logger.blank();
@@ -34141,7 +34555,7 @@ async function applyFixes() {
34141
34555
  const legacySpecs = findLegacySpecFiles();
34142
34556
  if (legacySpecs.length > 0) {
34143
34557
  for (const { path: oldPath, expected: newPath } of legacySpecs) {
34144
- fs26.renameSync(oldPath, newPath);
34558
+ fs27.renameSync(oldPath, newPath);
34145
34559
  }
34146
34560
  console.log(` ${icon("ok")} Migrated ${legacySpecs.length} legacy spec file(s) to the new dot-prefixed unified schema.`);
34147
34561
  }
@@ -34217,14 +34631,14 @@ function printSummary(tally) {
34217
34631
  }
34218
34632
 
34219
34633
  // src/commands/diagram.ts
34220
- var fs27 = __toESM(require("fs"));
34221
- var path40 = __toESM(require("path"));
34634
+ var fs28 = __toESM(require("fs"));
34635
+ var path41 = __toESM(require("path"));
34222
34636
  init_logger();
34223
34637
  init_paths();
34224
34638
  init_fs();
34225
34639
 
34226
34640
  // src/commands/subsystem.ts
34227
- var path39 = __toESM(require("path"));
34641
+ var path40 = __toESM(require("path"));
34228
34642
  init_logger();
34229
34643
  init_errors();
34230
34644
  init_fs();
@@ -34259,10 +34673,10 @@ async function runSubsystemAdd(id, options = {}) {
34259
34673
  const stored = loadSubsystemSpec(id);
34260
34674
  const restatement = subsystemAddRestatement(id, options.projectPath, options.name, stored);
34261
34675
  const receipt = writeSpec(restatement);
34262
- const childDir = path39.resolve(getProjectRoot(), options.projectPath);
34676
+ const childDir = path40.resolve(getProjectRoot(), options.projectPath);
34263
34677
  logger.success(`${receipt.replacedExisting ? "Re-authored" : "Added"} external subsystem "${id}" \u2192 ${options.projectPath}`);
34264
34678
  for (const notice of receipt.notices) logger.info(notice);
34265
- logger.info(`Scaffolded child project at ${path39.relative(process.cwd(), childDir) || "."}`);
34679
+ logger.info(`Scaffolded child project at ${path40.relative(process.cwd(), childDir) || "."}`);
34266
34680
  logger.info(`Design its spec tree from this parent using namespaced ids (e.g. ${id}::<component>).`);
34267
34681
  }
34268
34682
  async function runSubsystemMove(id, options = {}) {
@@ -34285,9 +34699,9 @@ async function runSubsystemExternalize(id, options = {}) {
34285
34699
  throw new WaironError("--project-path (the subproject destination) is required.");
34286
34700
  }
34287
34701
  externalizeSubsystem(id, options.projectPath);
34288
- const childDir = path39.resolve(getProjectRoot(), options.projectPath);
34702
+ const childDir = path40.resolve(getProjectRoot(), options.projectPath);
34289
34703
  logger.success(`Externalized subsystem "${id}" \u2192 ${options.projectPath}`);
34290
- logger.info(`Moved its specs into ${path39.relative(process.cwd(), childDir) || "."} (now a standalone subproject).`);
34704
+ logger.info(`Moved its specs into ${path40.relative(process.cwd(), childDir) || "."} (now a standalone subproject).`);
34291
34705
  logger.info("Move the source code there yourself, then run `wairon validate` to confirm the tree.");
34292
34706
  }
34293
34707
  async function runSubsystemInternalize(id) {
@@ -34318,8 +34732,8 @@ function applyFormat(options) {
34318
34732
  };
34319
34733
  }
34320
34734
  function writeArtifact(dest, content) {
34321
- ensureDir(path40.dirname(path40.resolve(dest)));
34322
- fs27.writeFileSync(dest, content, "utf-8");
34735
+ ensureDir(path41.dirname(path41.resolve(dest)));
34736
+ fs28.writeFileSync(dest, content, "utf-8");
34323
34737
  }
34324
34738
  function parseSequenceRef(ref) {
34325
34739
  const sep9 = ref.includes(":") ? ref.lastIndexOf(":") : ref.lastIndexOf(".");
@@ -34334,21 +34748,21 @@ async function runDiagram(rawOptions = {}) {
34334
34748
  assertProjectInitialized();
34335
34749
  const options = applyFormat(rawOptions);
34336
34750
  if (options.canvas && !options.all) {
34337
- const dest2 = options.out ?? path40.join(AI_PATHS.docsDir(), "diagrams", "canvas.html");
34751
+ const dest2 = options.out ?? path41.join(AI_PATHS.docsDir(), "diagrams", "canvas.html");
34338
34752
  writeArtifact(dest2, renderDiagram("canvas"));
34339
34753
  logger.success(`Interactive canvas written to ${dest2}`);
34340
34754
  logger.info("Open it in a browser \u2014 fully self-contained (works offline).");
34341
34755
  return;
34342
34756
  }
34343
34757
  if (options.drawio && !options.all) {
34344
- const dest2 = options.out ?? path40.join(AI_PATHS.docsDir(), "diagrams", "architecture.drawio");
34758
+ const dest2 = options.out ?? path41.join(AI_PATHS.docsDir(), "diagrams", "architecture.drawio");
34345
34759
  writeArtifact(dest2, renderDiagram("drawio"));
34346
34760
  logger.success(`draw.io diagram written to ${dest2}`);
34347
34761
  logger.info("Open with draw.io / diagrams.net (or import into tools that accept the format).");
34348
34762
  return;
34349
34763
  }
34350
34764
  if (options.excalidraw && !options.all) {
34351
- const dest2 = options.out ?? path40.join(AI_PATHS.docsDir(), "diagrams", "architecture.excalidraw");
34765
+ const dest2 = options.out ?? path41.join(AI_PATHS.docsDir(), "diagrams", "architecture.excalidraw");
34352
34766
  writeArtifact(dest2, renderDiagram("excalidraw"));
34353
34767
  logger.success(`Excalidraw scene written to ${dest2}`);
34354
34768
  logger.info("Open with excalidraw.com or the VS Code extension.");
@@ -34356,27 +34770,27 @@ async function runDiagram(rawOptions = {}) {
34356
34770
  }
34357
34771
  const wantsMermaid = options.format?.toLowerCase().startsWith("mermaid") || !!options.subsystem || !!options.sequence;
34358
34772
  if (!options.all && !options.sequence && !wantsMermaid) {
34359
- const dest2 = options.out ?? path40.join(AI_PATHS.docsDir(), "diagrams", "canvas.html");
34773
+ const dest2 = options.out ?? path41.join(AI_PATHS.docsDir(), "diagrams", "canvas.html");
34360
34774
  writeArtifact(dest2, renderDiagram("canvas"));
34361
34775
  logger.success(`Interactive canvas written to ${dest2}`);
34362
34776
  logger.info("Open it in a browser \u2014 fully self-contained (works offline). Other formats: --format mermaid|drawio|excalidraw.");
34363
34777
  return;
34364
34778
  }
34365
34779
  if (options.all) {
34366
- const outDir = options.out ?? path40.join(AI_PATHS.docsDir(), "diagrams");
34780
+ const outDir = options.out ?? path41.join(AI_PATHS.docsDir(), "diagrams");
34367
34781
  const files = generateDiagramSet();
34368
34782
  if (files.length === 0) {
34369
34783
  logger.warn("No diagrams to generate \u2014 the spec tree has no components yet.");
34370
34784
  return;
34371
34785
  }
34372
34786
  for (const file of files) {
34373
- writeArtifact(path40.join(outDir, file.relPath), toMarkdown(file));
34787
+ writeArtifact(path41.join(outDir, file.relPath), toMarkdown(file));
34374
34788
  }
34375
- writeArtifact(path40.join(outDir, "canvas.html"), renderDiagram("canvas"));
34376
- writeArtifact(path40.join(outDir, "architecture.drawio"), renderDiagram("drawio"));
34377
- writeArtifact(path40.join(outDir, "architecture.excalidraw"), renderDiagram("excalidraw"));
34789
+ writeArtifact(path41.join(outDir, "canvas.html"), renderDiagram("canvas"));
34790
+ writeArtifact(path41.join(outDir, "architecture.drawio"), renderDiagram("drawio"));
34791
+ writeArtifact(path41.join(outDir, "architecture.excalidraw"), renderDiagram("excalidraw"));
34378
34792
  const graph = loadSpecGraph();
34379
- const indexPath = path40.join(outDir, "README.md");
34793
+ const indexPath = path41.join(outDir, "README.md");
34380
34794
  writeArtifact(indexPath, diagramSetIndex(files, graph.systemName));
34381
34795
  logger.success(`Generated ${files.length} diagram(s) + interactive canvas.html + index into ${outDir}`);
34382
34796
  for (const file of files.slice(0, 12)) {
@@ -34388,20 +34802,20 @@ async function runDiagram(rawOptions = {}) {
34388
34802
  let mermaid;
34389
34803
  let title;
34390
34804
  let defaultDest;
34391
- const diagramsDir = path40.join(AI_PATHS.docsDir(), "diagrams");
34805
+ const diagramsDir = path41.join(AI_PATHS.docsDir(), "diagrams");
34392
34806
  if (options.sequence) {
34393
34807
  const { component, method: method2 } = parseSequenceRef(options.sequence);
34394
34808
  mermaid = generateSequenceDiagram(component, method2, { depth: options.depth });
34395
34809
  title = `${component}.${method2} \u2014 narrative sequence`;
34396
- defaultDest = path40.join(diagramsDir, "sequences", `${component.replace(/::/g, "--")}.${method2}.md`);
34810
+ defaultDest = path41.join(diagramsDir, "sequences", `${component.replace(/::/g, "--")}.${method2}.md`);
34397
34811
  } else if (options.subsystem) {
34398
34812
  mermaid = generateComponentDiagram({ subsystem: options.subsystem });
34399
34813
  title = `${options.subsystem} \u2014 components`;
34400
- defaultDest = path40.join(diagramsDir, "subsystems", `${options.subsystem.replace(/::/g, "--")}.md`);
34814
+ defaultDest = path41.join(diagramsDir, "subsystems", `${options.subsystem.replace(/::/g, "--")}.md`);
34401
34815
  } else {
34402
34816
  mermaid = renderDiagram("mermaid");
34403
34817
  title = "Component architecture";
34404
- defaultDest = path40.join(diagramsDir, "system.md");
34818
+ defaultDest = path41.join(diagramsDir, "system.md");
34405
34819
  }
34406
34820
  const dest = options.out ?? defaultDest;
34407
34821
  const content = dest.endsWith(".mmd") ? `${mermaid}
@@ -34514,9 +34928,9 @@ Component variants (${variants.length})
34514
34928
  }
34515
34929
 
34516
34930
  // src/commands/packs.ts
34517
- var fs28 = __toESM(require("fs"));
34931
+ var fs29 = __toESM(require("fs"));
34518
34932
  var os10 = __toESM(require("os"));
34519
- var path41 = __toESM(require("path"));
34933
+ var path42 = __toESM(require("path"));
34520
34934
  var import_chalk16 = __toESM(require("chalk"));
34521
34935
  var import_sdk = __toESM(require_dist());
34522
34936
  init_logger();
@@ -34543,11 +34957,11 @@ function describe(probe2) {
34543
34957
  return parts.join(", ");
34544
34958
  }
34545
34959
  function resolveSourceUnit(source) {
34546
- const abs = path41.resolve(source);
34547
- if (!fs28.existsSync(abs)) {
34960
+ const abs = path42.resolve(source);
34961
+ if (!fs29.existsSync(abs)) {
34548
34962
  throw new Error(`Pack source "${source}" does not exist.`);
34549
34963
  }
34550
- const isDir = fs28.statSync(abs).isDirectory();
34964
+ const isDir = fs29.statSync(abs).isDirectory();
34551
34965
  if (isDir && !packDirEntry(abs)) {
34552
34966
  throw new Error(`"${source}" is a directory without a pack entry file (pack.yaml | pack.cjs | index.cjs | ...).`);
34553
34967
  }
@@ -34563,7 +34977,7 @@ async function addPack(source, options = {}) {
34563
34977
  }
34564
34978
  const { abs } = resolveSourceUnit(source);
34565
34979
  const scope = options.global ? "global" : "project";
34566
- const probe2 = probePack(abs, path41.dirname(abs), scope);
34980
+ const probe2 = probePack(abs, path42.dirname(abs), scope);
34567
34981
  if (probe2.error) {
34568
34982
  logger.error(probe2.error);
34569
34983
  process.exitCode = 1;
@@ -34571,10 +34985,10 @@ async function addPack(source, options = {}) {
34571
34985
  }
34572
34986
  if (options.global) {
34573
34987
  const destDir = globalPacksDir();
34574
- const dest2 = path41.join(destDir, path41.basename(abs));
34575
- if (path41.resolve(dest2) !== abs) {
34576
- fs28.mkdirSync(destDir, { recursive: true });
34577
- fs28.cpSync(abs, dest2, { recursive: true, force: true });
34988
+ const dest2 = path42.join(destDir, path42.basename(abs));
34989
+ if (path42.resolve(dest2) !== abs) {
34990
+ fs29.mkdirSync(destDir, { recursive: true });
34991
+ fs29.cpSync(abs, dest2, { recursive: true, force: true });
34578
34992
  }
34579
34993
  logger.success(`Installed pack "${probe2.name}" globally: ${dest2}`);
34580
34994
  logger.info(`${describe(probe2)} \u2014 auto-loaded for every project on this machine (WAIRON_PACKS_DIR / ~/.wairon/packs).`);
@@ -34587,23 +35001,23 @@ async function addPack(source, options = {}) {
34587
35001
  return;
34588
35002
  }
34589
35003
  const root = getProjectRoot();
34590
- const relRef = `.wai/packs/${path41.basename(abs)}`;
34591
- const dest = path41.join(root, ".wai", "packs", path41.basename(abs));
34592
- if (path41.resolve(dest) !== abs) {
34593
- fs28.mkdirSync(path41.dirname(dest), { recursive: true });
34594
- fs28.cpSync(abs, dest, { recursive: true, force: true });
35004
+ const relRef = `.wai/packs/${path42.basename(abs)}`;
35005
+ const dest = path42.join(root, ".wai", "packs", path42.basename(abs));
35006
+ if (path42.resolve(dest) !== abs) {
35007
+ fs29.mkdirSync(path42.dirname(dest), { recursive: true });
35008
+ fs29.cpSync(abs, dest, { recursive: true, force: true });
34595
35009
  }
34596
35010
  if (registerPackRef(relRef)) {
34597
35011
  logger.success(`Vendored pack "${probe2.name}" into ${relRef} and registered it in .wai/project.yaml.`);
34598
35012
  } else {
34599
- fs28.cpSync(abs, dest, { recursive: true, force: true });
35013
+ fs29.cpSync(abs, dest, { recursive: true, force: true });
34600
35014
  logger.success(`Pack "${probe2.name}" already registered \u2014 refreshed ${relRef} from the source.`);
34601
35015
  }
34602
35016
  logger.info(`${describe(probe2)} \u2014 commit .wai/ so CI and every clone enforce it.`);
34603
35017
  }
34604
35018
  async function addPackFromArchive(source, options) {
34605
- const abs = path41.resolve(source);
34606
- if (!fs28.existsSync(abs) || !fs28.statSync(abs).isFile()) {
35019
+ const abs = path42.resolve(source);
35020
+ if (!fs29.existsSync(abs) || !fs29.statSync(abs).isFile()) {
34607
35021
  logger.error(`Pack archive "${source}" does not exist.`);
34608
35022
  process.exitCode = 1;
34609
35023
  return;
@@ -34618,27 +35032,27 @@ async function addPackFromArchive(source, options) {
34618
35032
  process.exitCode = 1;
34619
35033
  return;
34620
35034
  }
34621
- baseDir = path41.join(getProjectRoot(), ".wai", "packs");
35035
+ baseDir = path42.join(getProjectRoot(), ".wai", "packs");
34622
35036
  }
34623
- const bytes = fs28.readFileSync(abs);
34624
- fs28.mkdirSync(baseDir, { recursive: true });
34625
- const staging = fs28.mkdtempSync(path41.join(baseDir, ".wpack-staging-"));
35037
+ const bytes = fs29.readFileSync(abs);
35038
+ fs29.mkdirSync(baseDir, { recursive: true });
35039
+ const staging = fs29.mkdtempSync(path42.join(baseDir, ".wpack-staging-"));
34626
35040
  let result;
34627
35041
  try {
34628
35042
  result = (0, import_sdk.extractPack)(bytes, staging);
34629
35043
  } catch (err) {
34630
- fs28.rmSync(staging, { recursive: true, force: true });
34631
- logger.error(`Failed to extract pack archive "${path41.basename(abs)}": ${err instanceof Error ? err.message : String(err)}`);
35044
+ fs29.rmSync(staging, { recursive: true, force: true });
35045
+ logger.error(`Failed to extract pack archive "${path42.basename(abs)}": ${err instanceof Error ? err.message : String(err)}`);
34632
35046
  process.exitCode = 1;
34633
35047
  return;
34634
35048
  }
34635
35049
  const name = result.name;
34636
- const destDir = path41.join(baseDir, name);
34637
- if (fs28.existsSync(destDir)) fs28.rmSync(destDir, { recursive: true, force: true });
34638
- fs28.renameSync(staging, destDir);
34639
- const probe2 = probePack(destDir, path41.dirname(destDir), scope);
35050
+ const destDir = path42.join(baseDir, name);
35051
+ if (fs29.existsSync(destDir)) fs29.rmSync(destDir, { recursive: true, force: true });
35052
+ fs29.renameSync(staging, destDir);
35053
+ const probe2 = probePack(destDir, path42.dirname(destDir), scope);
34640
35054
  if (probe2.error) {
34641
- fs28.rmSync(destDir, { recursive: true, force: true });
35055
+ fs29.rmSync(destDir, { recursive: true, force: true });
34642
35056
  logger.error(probe2.error);
34643
35057
  process.exitCode = 1;
34644
35058
  return;
@@ -34652,7 +35066,7 @@ async function addPackFromArchive(source, options) {
34652
35066
  if (registerPackRef(relRef)) {
34653
35067
  logger.success(`Installed pack "${probe2.name ?? name}" into ${relRef} and registered it in .wai/project.yaml.`);
34654
35068
  } else {
34655
- logger.success(`Pack "${probe2.name ?? name}" already registered \u2014 refreshed ${relRef} from ${path41.basename(abs)}.`);
35069
+ logger.success(`Pack "${probe2.name ?? name}" already registered \u2014 refreshed ${relRef} from ${path42.basename(abs)}.`);
34656
35070
  }
34657
35071
  logger.info(`${describe(probe2)} \u2014 commit .wai/ so CI and every clone enforce it.`);
34658
35072
  }
@@ -34673,7 +35087,7 @@ async function buildPack(source, options = {}) {
34673
35087
  const sourceDir = source && source.length > 0 ? source : ".";
34674
35088
  const result = (0, import_sdk.buildPack)(sourceDir);
34675
35089
  const outPath = options.out ?? result.suggestedFileName;
34676
- fs28.writeFileSync(outPath, result.archive);
35090
+ fs29.writeFileSync(outPath, result.archive);
34677
35091
  logger.success(`Built pack "${result.info.name}" v${result.info.version} \u2192 ${outPath} (${result.archive.byteLength} bytes)`);
34678
35092
  logger.info(`Install it with \`wairon pack add ${outPath}\`, or upload it to a hosted instance.`);
34679
35093
  }
@@ -34684,8 +35098,8 @@ function expandSource(source, version) {
34684
35098
  return source.replace(/\{version\}/g, version ?? "").replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (_, name) => process.env[name] ?? "");
34685
35099
  }
34686
35100
  async function fetchArchive(url) {
34687
- const dir = fs28.mkdtempSync(path41.join(os10.tmpdir(), "wairon-packdl-"));
34688
- const dest = path41.join(dir, "pack.wpack");
35101
+ const dir = fs29.mkdtempSync(path42.join(os10.tmpdir(), "wairon-packdl-"));
35102
+ const dest = path42.join(dir, "pack.wpack");
34689
35103
  await downloadFile(url, dest);
34690
35104
  return dest;
34691
35105
  }
@@ -34704,7 +35118,7 @@ async function installPack(source) {
34704
35118
  }
34705
35119
  const extracted = extractArchiveToTemp(archive);
34706
35120
  try {
34707
- fs28.rmSync(path41.dirname(archive), { recursive: true, force: true });
35121
+ fs29.rmSync(path42.dirname(archive), { recursive: true, force: true });
34708
35122
  } catch {
34709
35123
  }
34710
35124
  if (!extracted) return;
@@ -34716,7 +35130,7 @@ async function installPack(source) {
34716
35130
  process.exitCode = 1;
34717
35131
  } finally {
34718
35132
  try {
34719
- fs28.rmSync(extracted.dir, { recursive: true, force: true });
35133
+ fs29.rmSync(extracted.dir, { recursive: true, force: true });
34720
35134
  } catch {
34721
35135
  }
34722
35136
  }
@@ -34727,7 +35141,7 @@ async function installPack(source) {
34727
35141
  if (!extracted) return;
34728
35142
  sourceDir = extracted.dir;
34729
35143
  cleanup = extracted.dir;
34730
- origin = path41.resolve(source);
35144
+ origin = path42.resolve(source);
34731
35145
  } else {
34732
35146
  let unit;
34733
35147
  try {
@@ -34753,7 +35167,7 @@ async function installPack(source) {
34753
35167
  } finally {
34754
35168
  if (cleanup) {
34755
35169
  try {
34756
- fs28.rmSync(cleanup, { recursive: true, force: true });
35170
+ fs29.rmSync(cleanup, { recursive: true, force: true });
34757
35171
  } catch {
34758
35172
  }
34759
35173
  }
@@ -34770,20 +35184,20 @@ function reportInstalled(installed, origin) {
34770
35184
  }
34771
35185
  }
34772
35186
  function extractArchiveToTemp(source) {
34773
- const abs = path41.resolve(source);
34774
- if (!fs28.existsSync(abs)) {
35187
+ const abs = path42.resolve(source);
35188
+ if (!fs29.existsSync(abs)) {
34775
35189
  logger.error(`Pack archive "${source}" does not exist.`);
34776
35190
  process.exitCode = 1;
34777
35191
  return null;
34778
35192
  }
34779
- const tempDir = fs28.mkdtempSync(path41.join(os10.tmpdir(), "wairon-packinstall-"));
35193
+ const tempDir = fs29.mkdtempSync(path42.join(os10.tmpdir(), "wairon-packinstall-"));
34780
35194
  try {
34781
- const result = (0, import_sdk.extractPack)(new Uint8Array(fs28.readFileSync(abs)), tempDir);
35195
+ const result = (0, import_sdk.extractPack)(new Uint8Array(fs29.readFileSync(abs)), tempDir);
34782
35196
  void result;
34783
35197
  return { dir: tempDir };
34784
35198
  } catch (e) {
34785
35199
  try {
34786
- fs28.rmSync(tempDir, { recursive: true, force: true });
35200
+ fs29.rmSync(tempDir, { recursive: true, force: true });
34787
35201
  } catch {
34788
35202
  }
34789
35203
  logger.error(`Could not extract "${source}": ${e instanceof Error ? e.message : String(e)}`);
@@ -34920,7 +35334,7 @@ async function fetchAndInstall(selection, url) {
34920
35334
  const archive = await fetchArchive(url);
34921
35335
  const extracted = extractArchiveToTemp(archive);
34922
35336
  try {
34923
- fs28.rmSync(path41.dirname(archive), { recursive: true, force: true });
35337
+ fs29.rmSync(path42.dirname(archive), { recursive: true, force: true });
34924
35338
  } catch {
34925
35339
  }
34926
35340
  if (!extracted) return null;
@@ -34932,7 +35346,7 @@ async function fetchAndInstall(selection, url) {
34932
35346
  return pack;
34933
35347
  } finally {
34934
35348
  try {
34935
- fs28.rmSync(extracted.dir, { recursive: true, force: true });
35349
+ fs29.rmSync(extracted.dir, { recursive: true, force: true });
34936
35350
  } catch {
34937
35351
  }
34938
35352
  }
@@ -34943,10 +35357,10 @@ function bundleTargets(selections, name, all) {
34943
35357
  return selections.filter((s) => s.bundle === true);
34944
35358
  }
34945
35359
  function writeBundle(root, resolved) {
34946
- const dest = path41.join(root, ".wai", "packs", resolved.name, resolved.version);
34947
- fs28.rmSync(dest, { recursive: true, force: true });
34948
- fs28.mkdirSync(path41.dirname(dest), { recursive: true });
34949
- fs28.cpSync(resolved.path, dest, { recursive: true });
35360
+ const dest = path42.join(root, ".wai", "packs", resolved.name, resolved.version);
35361
+ fs29.rmSync(dest, { recursive: true, force: true });
35362
+ fs29.mkdirSync(path42.dirname(dest), { recursive: true });
35363
+ fs29.cpSync(resolved.path, dest, { recursive: true });
34950
35364
  return dest;
34951
35365
  }
34952
35366
  async function bundlePack(name, options = {}) {
@@ -34977,7 +35391,7 @@ async function bundlePack(name, options = {}) {
34977
35391
  const dest = writeBundle(root, resolved);
34978
35392
  bundledSelections.push({ name: selection.name, version: resolved.version });
34979
35393
  bundled.push(`${resolved.name}@${resolved.version}`);
34980
- console.log(` ${import_chalk16.default.green("+")} ${import_chalk16.default.dim(path41.relative(root, dest).replace(/\\/g, "/"))}`);
35394
+ console.log(` ${import_chalk16.default.green("+")} ${import_chalk16.default.dim(path42.relative(root, dest).replace(/\\/g, "/"))}`);
34981
35395
  }
34982
35396
  if (bundled.length === 0) return;
34983
35397
  markSelectionsBundled(bundledSelections);
@@ -35014,9 +35428,9 @@ async function listPacks() {
35014
35428
  console.log(import_chalk16.default.bold.cyan(`\u25A0 Global (${globalPacksDir()})${useGlobal ? "" : import_chalk16.default.yellow(" [disabled: extensions.useGlobalPacks: false]")}`));
35015
35429
  if (globalRefs.length === 0) console.log(import_chalk16.default.dim(" (none)"));
35016
35430
  for (const ref of globalRefs) {
35017
- const probe2 = probePack(ref, path41.dirname(ref), "global");
35018
- if (probe2.error) console.log(` ${import_chalk16.default.red("\u2716")} ${path41.basename(ref)} \u2014 ${import_chalk16.default.red(probe2.error)}`);
35019
- else console.log(` ${import_chalk16.default.green("\u25CF")} ${import_chalk16.default.bold(probe2.name ?? path41.basename(ref))} ${import_chalk16.default.dim(describe(probe2))}`);
35431
+ const probe2 = probePack(ref, path42.dirname(ref), "global");
35432
+ if (probe2.error) console.log(` ${import_chalk16.default.red("\u2716")} ${path42.basename(ref)} \u2014 ${import_chalk16.default.red(probe2.error)}`);
35433
+ else console.log(` ${import_chalk16.default.green("\u25CF")} ${import_chalk16.default.bold(probe2.name ?? path42.basename(ref))} ${import_chalk16.default.dim(describe(probe2))}`);
35020
35434
  }
35021
35435
  console.log("");
35022
35436
  if (!inProject) {
@@ -35044,9 +35458,9 @@ async function listPacks() {
35044
35458
  async function removePack(name, options = {}) {
35045
35459
  if (options.global) {
35046
35460
  for (const ref of discoverPacks(globalPacksDir())) {
35047
- const probe2 = probePack(ref, path41.dirname(ref), "global");
35048
- if (probe2.name === name || path41.basename(ref) === name) {
35049
- fs28.rmSync(ref, { recursive: true, force: true });
35461
+ const probe2 = probePack(ref, path42.dirname(ref), "global");
35462
+ if (probe2.name === name || path42.basename(ref) === name) {
35463
+ fs29.rmSync(ref, { recursive: true, force: true });
35050
35464
  logger.success(`Removed global pack "${probe2.name ?? name}" (${ref}).`);
35051
35465
  return;
35052
35466
  }
@@ -35067,12 +35481,12 @@ async function removePack(name, options = {}) {
35067
35481
  if (typeof entry !== "string") continue;
35068
35482
  const ref = entry;
35069
35483
  const probe2 = probePack(ref, root, "project");
35070
- if (probe2.name === name || ref === name || path41.basename(ref) === name) {
35484
+ if (probe2.name === name || ref === name || path42.basename(ref) === name) {
35071
35485
  deregisterPackRef(ref);
35072
- const resolved = path41.resolve(root, ref);
35073
- const vendorDir = path41.resolve(root, ".wai", "packs");
35074
- if (resolved.startsWith(vendorDir + path41.sep)) {
35075
- fs28.rmSync(resolved, { recursive: true, force: true });
35486
+ const resolved = path42.resolve(root, ref);
35487
+ const vendorDir = path42.resolve(root, ".wai", "packs");
35488
+ if (resolved.startsWith(vendorDir + path42.sep)) {
35489
+ fs29.rmSync(resolved, { recursive: true, force: true });
35076
35490
  logger.success(`Deregistered pack "${probe2.name ?? name}" and deleted ${ref}.`);
35077
35491
  } else {
35078
35492
  logger.success(`Deregistered pack "${probe2.name ?? name}" (files at ${ref} left in place).`);
@@ -35085,22 +35499,22 @@ async function removePack(name, options = {}) {
35085
35499
  }
35086
35500
 
35087
35501
  // src/commands/host.ts
35088
- var fs55 = __toESM(require("fs"));
35089
- var path68 = __toESM(require("path"));
35502
+ var fs56 = __toESM(require("fs"));
35503
+ var path69 = __toESM(require("path"));
35090
35504
  var os11 = __toESM(require("os"));
35091
- var crypto23 = __toESM(require("crypto"));
35092
- var import_child_process6 = require("child_process");
35505
+ var crypto24 = __toESM(require("crypto"));
35506
+ var import_child_process7 = require("child_process");
35093
35507
  var import_chalk17 = __toESM(require("chalk"));
35094
35508
  init_logger();
35095
35509
  init_errors();
35096
35510
 
35097
35511
  // src/server/admin.ts
35098
- var crypto10 = __toESM(require("crypto"));
35512
+ var crypto11 = __toESM(require("crypto"));
35099
35513
  init_fs();
35100
35514
  init_defaults();
35101
35515
 
35102
35516
  // src/server/auth.ts
35103
- var crypto8 = __toESM(require("crypto"));
35517
+ var crypto9 = __toESM(require("crypto"));
35104
35518
 
35105
35519
  // src/server/types.ts
35106
35520
  var SSO_ADMIN_ROLE_ID = "sso-admin";
@@ -35113,35 +35527,35 @@ var UNAUTHENTICATED = {
35113
35527
  var WEB_SESSION_PREFIX = "ws_";
35114
35528
 
35115
35529
  // src/server/credentials.ts
35116
- var fs29 = __toESM(require("fs"));
35117
- var path42 = __toESM(require("path"));
35118
- var crypto6 = __toESM(require("crypto"));
35530
+ var fs30 = __toESM(require("fs"));
35531
+ var path43 = __toESM(require("path"));
35532
+ var crypto7 = __toESM(require("crypto"));
35119
35533
  var HASH_NS = "wairon:token:v1";
35120
35534
  function hashToken(token) {
35121
- return crypto6.createHash("sha256").update(`${HASH_NS}:${token}`).digest("hex");
35535
+ return crypto7.createHash("sha256").update(`${HASH_NS}:${token}`).digest("hex");
35122
35536
  }
35123
35537
  function storePath(dataDir) {
35124
- return path42.join(dataDir, "auth", "credentials.json");
35538
+ return path43.join(dataDir, "auth", "credentials.json");
35125
35539
  }
35126
35540
  function load3(dataDir) {
35127
35541
  try {
35128
- return JSON.parse(fs29.readFileSync(storePath(dataDir), "utf8"));
35542
+ return JSON.parse(fs30.readFileSync(storePath(dataDir), "utf8"));
35129
35543
  } catch {
35130
35544
  return [];
35131
35545
  }
35132
35546
  }
35133
35547
  function save(dataDir, records) {
35134
35548
  const p = storePath(dataDir);
35135
- fs29.mkdirSync(path42.dirname(p), { recursive: true });
35549
+ fs30.mkdirSync(path43.dirname(p), { recursive: true });
35136
35550
  const tmp = `${p}.tmp`;
35137
- fs29.writeFileSync(tmp, JSON.stringify(records, null, 2) + "\n");
35138
- fs29.renameSync(tmp, p);
35551
+ fs30.writeFileSync(tmp, JSON.stringify(records, null, 2) + "\n");
35552
+ fs30.renameSync(tmp, p);
35139
35553
  }
35140
35554
  function digestEquals(a, b) {
35141
35555
  const ab = Buffer.from(a, "hex");
35142
35556
  const bb = Buffer.from(b, "hex");
35143
35557
  if (ab.length === 0 || ab.length !== bb.length) return false;
35144
- return crypto6.timingSafeEqual(ab, bb);
35558
+ return crypto7.timingSafeEqual(ab, bb);
35145
35559
  }
35146
35560
  function findByTokenHash(dataDir, tokenHash) {
35147
35561
  return load3(dataDir).find((r) => digestEquals(r.keyHash, tokenHash)) ?? null;
@@ -35180,17 +35594,17 @@ function listByOwner(dataDir, ownerUserId) {
35180
35594
  }
35181
35595
 
35182
35596
  // src/server/websessions.ts
35183
- var fs30 = __toESM(require("fs"));
35184
- var path43 = __toESM(require("path"));
35185
- var crypto7 = __toESM(require("crypto"));
35597
+ var fs31 = __toESM(require("fs"));
35598
+ var path44 = __toESM(require("path"));
35599
+ var crypto8 = __toESM(require("crypto"));
35186
35600
  function storePath2(dataDir) {
35187
- return path43.join(dataDir, "web-sessions.json");
35601
+ return path44.join(dataDir, "web-sessions.json");
35188
35602
  }
35189
35603
  function readSessions(dataDir) {
35190
35604
  const p = storePath2(dataDir);
35191
35605
  let raw;
35192
35606
  try {
35193
- raw = fs30.readFileSync(p, "utf8");
35607
+ raw = fs31.readFileSync(p, "utf8");
35194
35608
  } catch (e) {
35195
35609
  if (e.code === "ENOENT") return [];
35196
35610
  throw new Error(`Failed to read web session store at ${p}: ${e.message}`);
@@ -35205,13 +35619,13 @@ function readSessions(dataDir) {
35205
35619
  }
35206
35620
  function persistSessions(dataDir, sessions) {
35207
35621
  const p = storePath2(dataDir);
35208
- fs30.mkdirSync(path43.dirname(p), { recursive: true });
35622
+ fs31.mkdirSync(path44.dirname(p), { recursive: true });
35209
35623
  const tmp = `${p}.tmp`;
35210
- fs30.writeFileSync(tmp, JSON.stringify(sessions, null, 2) + "\n");
35211
- fs30.renameSync(tmp, p);
35624
+ fs31.writeFileSync(tmp, JSON.stringify(sessions, null, 2) + "\n");
35625
+ fs31.renameSync(tmp, p);
35212
35626
  }
35213
35627
  function mintSessionId() {
35214
- return `${WEB_SESSION_PREFIX}${crypto7.randomBytes(24).toString("hex")}`;
35628
+ return `${WEB_SESSION_PREFIX}${crypto8.randomBytes(24).toString("hex")}`;
35215
35629
  }
35216
35630
  var WebSessionStore = class {
35217
35631
  constructor(dataDir) {
@@ -35369,17 +35783,17 @@ function listWebSessionsBySubject(dataDir, userId) {
35369
35783
  }
35370
35784
 
35371
35785
  // src/server/users.ts
35372
- var fs31 = __toESM(require("fs"));
35373
- var path44 = __toESM(require("path"));
35786
+ var fs32 = __toESM(require("fs"));
35787
+ var path45 = __toESM(require("path"));
35374
35788
  var VALID_STATUSES = ["active", "inactive", "suspended", "deactivated", "disabled"];
35375
35789
  function storePath3(dataDir) {
35376
- return path44.join(dataDir, "users.json");
35790
+ return path45.join(dataDir, "users.json");
35377
35791
  }
35378
35792
  function loadStore(dataDir) {
35379
35793
  const p = storePath3(dataDir);
35380
35794
  let raw;
35381
35795
  try {
35382
- raw = fs31.readFileSync(p, "utf8");
35796
+ raw = fs32.readFileSync(p, "utf8");
35383
35797
  } catch (err) {
35384
35798
  if (err.code === "ENOENT") return [];
35385
35799
  throw new Error(`Cannot read hosted-user store at ${p}: ${err.message}`);
@@ -35397,10 +35811,10 @@ function loadStore(dataDir) {
35397
35811
  }
35398
35812
  function replaceAll(dataDir, records) {
35399
35813
  const p = storePath3(dataDir);
35400
- fs31.mkdirSync(path44.dirname(p), { recursive: true });
35814
+ fs32.mkdirSync(path45.dirname(p), { recursive: true });
35401
35815
  const tmp = `${p}.tmp`;
35402
- fs31.writeFileSync(tmp, JSON.stringify(records, null, 2) + "\n");
35403
- fs31.renameSync(tmp, p);
35816
+ fs32.writeFileSync(tmp, JSON.stringify(records, null, 2) + "\n");
35817
+ fs32.renameSync(tmp, p);
35404
35818
  }
35405
35819
  function registryUpsert(dataDir, record2) {
35406
35820
  const records = loadStore(dataDir);
@@ -35502,11 +35916,11 @@ function remapUnitReferences(dataDir, remap, removedScopeIds) {
35502
35916
  }
35503
35917
 
35504
35918
  // src/server/instance.ts
35505
- var fs32 = __toESM(require("fs"));
35506
- var path45 = __toESM(require("path"));
35919
+ var fs33 = __toESM(require("fs"));
35920
+ var path46 = __toESM(require("path"));
35507
35921
  var import_crypto = require("crypto");
35508
35922
  function storePath4(dataDir) {
35509
- return path45.join(dataDir, "instance.json");
35923
+ return path46.join(dataDir, "instance.json");
35510
35924
  }
35511
35925
  var InstanceIdentityStore = class {
35512
35926
  constructor(dataDir) {
@@ -35523,7 +35937,7 @@ var InstanceIdentityStore = class {
35523
35937
  const p = storePath4(this.dataDir);
35524
35938
  let raw;
35525
35939
  try {
35526
- raw = fs32.readFileSync(p, "utf8");
35940
+ raw = fs33.readFileSync(p, "utf8");
35527
35941
  } catch (err) {
35528
35942
  if (err.code === "ENOENT") return null;
35529
35943
  throw new Error(`Cannot read instance identity at ${p}: ${err.message}`);
@@ -35546,10 +35960,10 @@ var InstanceIdentityStore = class {
35546
35960
  * never truncates the file. Only called by the registry's create-once seed. */
35547
35961
  replace(identity) {
35548
35962
  const p = storePath4(this.dataDir);
35549
- fs32.mkdirSync(path45.dirname(p), { recursive: true });
35963
+ fs33.mkdirSync(path46.dirname(p), { recursive: true });
35550
35964
  const tmp = `${p}.tmp`;
35551
- fs32.writeFileSync(tmp, JSON.stringify(identity, null, 2) + "\n");
35552
- fs32.renameSync(tmp, p);
35965
+ fs33.writeFileSync(tmp, JSON.stringify(identity, null, 2) + "\n");
35966
+ fs33.renameSync(tmp, p);
35553
35967
  }
35554
35968
  };
35555
35969
  var InstanceIdentityRegistry = class {
@@ -35605,8 +36019,8 @@ function getInstanceIdentity(dataDir) {
35605
36019
  }
35606
36020
 
35607
36021
  // src/utils/secrets.ts
35608
- var fs33 = __toESM(require("fs"));
35609
- var path46 = __toESM(require("path"));
36022
+ var fs34 = __toESM(require("fs"));
36023
+ var path47 = __toESM(require("path"));
35610
36024
  var ENV_FALLBACK = {
35611
36025
  "git-token": ["WAIRON_GIT_TOKEN"],
35612
36026
  "notion-token": ["WAIRON_NOTION_TOKEN"],
@@ -35615,13 +36029,13 @@ var ENV_FALLBACK = {
35615
36029
  };
35616
36030
  function storePath5() {
35617
36031
  const dataDir = process.env["WAIRON_DATA_DIR"];
35618
- return dataDir ? path46.join(dataDir, "auth", "secrets.json") : null;
36032
+ return dataDir ? path47.join(dataDir, "auth", "secrets.json") : null;
35619
36033
  }
35620
36034
  function readStore() {
35621
36035
  const p = storePath5();
35622
36036
  if (!p) return {};
35623
36037
  try {
35624
- return JSON.parse(fs33.readFileSync(p, "utf8"));
36038
+ return JSON.parse(fs34.readFileSync(p, "utf8"));
35625
36039
  } catch {
35626
36040
  return {};
35627
36041
  }
@@ -35646,10 +36060,10 @@ function setSecret(key, value) {
35646
36060
  if (!p) throw new Error("WAIRON_DATA_DIR is not set \u2014 a running server needs it to store secrets.");
35647
36061
  const store = readStore();
35648
36062
  store[key] = value;
35649
- fs33.mkdirSync(path46.dirname(p), { recursive: true });
36063
+ fs34.mkdirSync(path47.dirname(p), { recursive: true });
35650
36064
  const tmp = `${p}.tmp`;
35651
- fs33.writeFileSync(tmp, JSON.stringify(store, null, 2) + "\n");
35652
- fs33.renameSync(tmp, p);
36065
+ fs34.writeFileSync(tmp, JSON.stringify(store, null, 2) + "\n");
36066
+ fs34.renameSync(tmp, p);
35653
36067
  }
35654
36068
  function listSecretKeys() {
35655
36069
  return Object.keys(readStore());
@@ -35727,7 +36141,7 @@ function masterMatches(credential) {
35727
36141
  if (!master || !credential) return false;
35728
36142
  const a = Buffer.from(hashToken(credential), "hex");
35729
36143
  const b = Buffer.from(hashToken(master), "hex");
35730
- return a.length === b.length && crypto8.timingSafeEqual(a, b);
36144
+ return a.length === b.length && crypto9.timingSafeEqual(a, b);
35731
36145
  }
35732
36146
  function bootstrapAdminPrincipal() {
35733
36147
  const subject = {
@@ -35775,7 +36189,7 @@ function authenticateMaster(token) {
35775
36189
  function hashedEquals(a, b) {
35776
36190
  const ha = Buffer.from(hashToken(a), "hex");
35777
36191
  const hb = Buffer.from(hashToken(b), "hex");
35778
- return ha.length === hb.length && crypto8.timingSafeEqual(ha, hb);
36192
+ return ha.length === hb.length && crypto9.timingSafeEqual(ha, hb);
35779
36193
  }
35780
36194
  function verifyBuiltinAdmin(cfg, user, password) {
35781
36195
  const configuredUser = cfg.builtinAdminUser ?? "";
@@ -35824,16 +36238,16 @@ function signingKey() {
35824
36238
  }
35825
36239
  function signViewToken(project2, format) {
35826
36240
  const body = Buffer.from(JSON.stringify({ project: project2, format, exp: Date.now() + VIEW_TTL_MS })).toString("base64url");
35827
- const sig = crypto8.createHmac("sha256", signingKey()).update(body).digest("base64url");
36241
+ const sig = crypto9.createHmac("sha256", signingKey()).update(body).digest("base64url");
35828
36242
  return `${body}.${sig}`;
35829
36243
  }
35830
36244
  function verifyViewToken(token) {
35831
36245
  const [body, sig] = String(token).split(".");
35832
36246
  if (!body || !sig) throw new Error("invalid view token");
35833
- const expected = crypto8.createHmac("sha256", signingKey()).update(body).digest("base64url");
36247
+ const expected = crypto9.createHmac("sha256", signingKey()).update(body).digest("base64url");
35834
36248
  const a = Buffer.from(sig);
35835
36249
  const b = Buffer.from(expected);
35836
- if (a.length !== b.length || !crypto8.timingSafeEqual(a, b)) throw new Error("invalid view token");
36250
+ if (a.length !== b.length || !crypto9.timingSafeEqual(a, b)) throw new Error("invalid view token");
35837
36251
  const payload = JSON.parse(Buffer.from(body, "base64url").toString("utf8"));
35838
36252
  if (Date.now() > payload.exp) throw new Error("expired view token");
35839
36253
  return { project: payload.project, format: payload.format, expiresAt: new Date(payload.exp).toISOString() };
@@ -35841,33 +36255,33 @@ function verifyViewToken(token) {
35841
36255
  var SSO_STATE_TTL_MS = 10 * 60 * 1e3;
35842
36256
  function signSsoState(payload) {
35843
36257
  const body = Buffer.from(JSON.stringify({ payload, exp: Date.now() + SSO_STATE_TTL_MS })).toString("base64url");
35844
- const sig = crypto8.createHmac("sha256", signingKey()).update(body).digest("base64url");
36258
+ const sig = crypto9.createHmac("sha256", signingKey()).update(body).digest("base64url");
35845
36259
  return `${body}.${sig}`;
35846
36260
  }
35847
36261
  function verifySsoState(state) {
35848
36262
  const [body, sig] = String(state).split(".");
35849
36263
  if (!body || !sig) throw new Error("invalid SSO state");
35850
- const expected = crypto8.createHmac("sha256", signingKey()).update(body).digest("base64url");
36264
+ const expected = crypto9.createHmac("sha256", signingKey()).update(body).digest("base64url");
35851
36265
  const a = Buffer.from(sig);
35852
36266
  const b = Buffer.from(expected);
35853
- if (a.length !== b.length || !crypto8.timingSafeEqual(a, b)) throw new Error("invalid SSO state");
36267
+ if (a.length !== b.length || !crypto9.timingSafeEqual(a, b)) throw new Error("invalid SSO state");
35854
36268
  const parsed = JSON.parse(Buffer.from(body, "base64url").toString("utf8"));
35855
36269
  if (Date.now() > parsed.exp) throw new Error("expired SSO state");
35856
36270
  return parsed.payload;
35857
36271
  }
35858
36272
 
35859
36273
  // src/server/organization.ts
35860
- var fs34 = __toESM(require("fs"));
35861
- var path47 = __toESM(require("path"));
35862
- var crypto9 = __toESM(require("crypto"));
36274
+ var fs35 = __toESM(require("fs"));
36275
+ var path48 = __toESM(require("path"));
36276
+ var crypto10 = __toESM(require("crypto"));
35863
36277
  function storePath6(dataDir) {
35864
- return path47.join(dataDir, "organization.json");
36278
+ return path48.join(dataDir, "organization.json");
35865
36279
  }
35866
36280
  function readState(dataDir) {
35867
36281
  const p = storePath6(dataDir);
35868
36282
  let raw;
35869
36283
  try {
35870
- raw = fs34.readFileSync(p, "utf8");
36284
+ raw = fs35.readFileSync(p, "utf8");
35871
36285
  } catch (e) {
35872
36286
  if (e.code === "ENOENT") return { units: [], placements: [] };
35873
36287
  throw new Error(`Failed to read organization store at ${p}: ${e.message}`);
@@ -35884,10 +36298,10 @@ function readState(dataDir) {
35884
36298
  }
35885
36299
  function persistState(dataDir, state) {
35886
36300
  const p = storePath6(dataDir);
35887
- fs34.mkdirSync(path47.dirname(p), { recursive: true });
36301
+ fs35.mkdirSync(path48.dirname(p), { recursive: true });
35888
36302
  const tmp = `${p}.tmp`;
35889
- fs34.writeFileSync(tmp, JSON.stringify(state, null, 2) + "\n");
35890
- fs34.renameSync(tmp, p);
36303
+ fs35.writeFileSync(tmp, JSON.stringify(state, null, 2) + "\n");
36304
+ fs35.renameSync(tmp, p);
35891
36305
  }
35892
36306
  var SLUG_PATTERN = /^[a-z0-9-]+$/;
35893
36307
  var UNIT_KINDS = ["business_entity", "department", "team", "group"];
@@ -36182,7 +36596,7 @@ var OrganizationRegistry = class {
36182
36596
  createdAt: placements[existingIdx].createdAt
36183
36597
  } : {
36184
36598
  ...placement,
36185
- id: placement.id || crypto9.randomUUID(),
36599
+ id: placement.id || crypto10.randomUUID(),
36186
36600
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
36187
36601
  };
36188
36602
  const next = isUpdate ? placements.map((p, i) => i === existingIdx ? stored : p) : [...placements, stored];
@@ -36263,11 +36677,11 @@ function getOrganizationUnit(dataDir, id) {
36263
36677
  }
36264
36678
 
36265
36679
  // src/server/permissions.ts
36266
- var fs35 = __toESM(require("fs"));
36267
- var path48 = __toESM(require("path"));
36680
+ var fs36 = __toESM(require("fs"));
36681
+ var path49 = __toESM(require("path"));
36268
36682
  var import_crypto2 = require("crypto");
36269
36683
  function storePath7(dataDir) {
36270
- return path48.join(dataDir, "permissions.json");
36684
+ return path49.join(dataDir, "permissions.json");
36271
36685
  }
36272
36686
  function assignmentKey(a) {
36273
36687
  return [a.subjectKind, a.subjectId ?? "", a.scopeKind, a.scopeId ?? "", a.capability].join("|");
@@ -36276,7 +36690,7 @@ function load4(dataDir) {
36276
36690
  const p = storePath7(dataDir);
36277
36691
  let raw;
36278
36692
  try {
36279
- raw = fs35.readFileSync(p, "utf8");
36693
+ raw = fs36.readFileSync(p, "utf8");
36280
36694
  } catch (err) {
36281
36695
  if (err.code === "ENOENT") return [];
36282
36696
  throw new Error(`Cannot read permission store at ${p}: ${err.message}`);
@@ -36294,10 +36708,10 @@ function load4(dataDir) {
36294
36708
  }
36295
36709
  function replaceAll2(dataDir, assignments) {
36296
36710
  const p = storePath7(dataDir);
36297
- fs35.mkdirSync(path48.dirname(p), { recursive: true });
36711
+ fs36.mkdirSync(path49.dirname(p), { recursive: true });
36298
36712
  const tmp = `${p}.tmp`;
36299
- fs35.writeFileSync(tmp, JSON.stringify(assignments, null, 2) + "\n");
36300
- fs35.renameSync(tmp, p);
36713
+ fs36.writeFileSync(tmp, JSON.stringify(assignments, null, 2) + "\n");
36714
+ fs36.renameSync(tmp, p);
36301
36715
  }
36302
36716
  function registrySet(dataDir, assignment) {
36303
36717
  const assignments = load4(dataDir);
@@ -36383,8 +36797,8 @@ function getAssignment(dataDir, assignmentId) {
36383
36797
  }
36384
36798
 
36385
36799
  // src/server/roles.ts
36386
- var fs36 = __toESM(require("fs"));
36387
- var path49 = __toESM(require("path"));
36800
+ var fs37 = __toESM(require("fs"));
36801
+ var path50 = __toESM(require("path"));
36388
36802
  var BUILTIN_ROLES = [
36389
36803
  {
36390
36804
  id: SSO_ADMIN_ROLE_ID,
@@ -36402,13 +36816,13 @@ function isBuiltinRoleId(roleId) {
36402
36816
  return BUILTIN_ROLE_IDS.has(roleId);
36403
36817
  }
36404
36818
  function storePath8(dataDir) {
36405
- return path49.join(dataDir, "roles.json");
36819
+ return path50.join(dataDir, "roles.json");
36406
36820
  }
36407
36821
  function load5(dataDir) {
36408
36822
  const p = storePath8(dataDir);
36409
36823
  let raw;
36410
36824
  try {
36411
- raw = fs36.readFileSync(p, "utf8");
36825
+ raw = fs37.readFileSync(p, "utf8");
36412
36826
  } catch (err) {
36413
36827
  if (err.code === "ENOENT") return [];
36414
36828
  throw new Error(`Cannot read role store at ${p}: ${err.message}`);
@@ -36426,10 +36840,10 @@ function load5(dataDir) {
36426
36840
  }
36427
36841
  function replaceAll3(dataDir, roles) {
36428
36842
  const p = storePath8(dataDir);
36429
- fs36.mkdirSync(path49.dirname(p), { recursive: true });
36843
+ fs37.mkdirSync(path50.dirname(p), { recursive: true });
36430
36844
  const tmp = `${p}.tmp`;
36431
- fs36.writeFileSync(tmp, JSON.stringify(roles, null, 2) + "\n");
36432
- fs36.renameSync(tmp, p);
36845
+ fs37.writeFileSync(tmp, JSON.stringify(roles, null, 2) + "\n");
36846
+ fs37.renameSync(tmp, p);
36433
36847
  }
36434
36848
  function registryCreate(dataDir, role) {
36435
36849
  if (isBuiltinRoleId(role.id)) {
@@ -36663,8 +37077,8 @@ function actionableUnitIds(scopes) {
36663
37077
  }
36664
37078
 
36665
37079
  // src/server/projects.ts
36666
- var fs37 = __toESM(require("fs"));
36667
- var path50 = __toESM(require("path"));
37080
+ var fs38 = __toESM(require("fs"));
37081
+ var path51 = __toESM(require("path"));
36668
37082
  init_paths();
36669
37083
  init_yaml();
36670
37084
  init_fs();
@@ -36678,24 +37092,24 @@ function isValidProjectId(id) {
36678
37092
  return typeof id === "string" && ID_RE.test(id);
36679
37093
  }
36680
37094
  function registryPath(dataDir) {
36681
- return path50.join(dataDir, "projects.json");
37095
+ return path51.join(dataDir, "projects.json");
36682
37096
  }
36683
37097
  function load6(dataDir) {
36684
37098
  try {
36685
- return JSON.parse(fs37.readFileSync(registryPath(dataDir), "utf8"));
37099
+ return JSON.parse(fs38.readFileSync(registryPath(dataDir), "utf8"));
36686
37100
  } catch {
36687
37101
  return [];
36688
37102
  }
36689
37103
  }
36690
37104
  function save2(dataDir, records) {
36691
37105
  const p = registryPath(dataDir);
36692
- fs37.mkdirSync(path50.dirname(p), { recursive: true });
37106
+ fs38.mkdirSync(path51.dirname(p), { recursive: true });
36693
37107
  const tmp = `${p}.tmp`;
36694
- fs37.writeFileSync(tmp, JSON.stringify(records, null, 2) + "\n");
36695
- fs37.renameSync(tmp, p);
37108
+ fs38.writeFileSync(tmp, JSON.stringify(records, null, 2) + "\n");
37109
+ fs38.renameSync(tmp, p);
36696
37110
  }
36697
37111
  function projectRoot(dataDir, id) {
36698
- return path50.join(dataDir, "projects", id);
37112
+ return path51.join(dataDir, "projects", id);
36699
37113
  }
36700
37114
  function existingProjectRoot(dataDir, id) {
36701
37115
  if (!isValidProjectId(id)) return null;
@@ -36711,7 +37125,7 @@ function createProjectRecord(dataDir, id) {
36711
37125
  throw new Error(`Project "${id}" already exists.`);
36712
37126
  }
36713
37127
  const root = projectRoot(dataDir, id);
36714
- fs37.mkdirSync(root, { recursive: true });
37128
+ fs38.mkdirSync(root, { recursive: true });
36715
37129
  const record2 = {
36716
37130
  id,
36717
37131
  rootPath: root,
@@ -36746,7 +37160,7 @@ function removeProjectRecord(dataDir, id) {
36746
37160
  const rec = records.find((r) => r.id === id);
36747
37161
  if (rec) {
36748
37162
  try {
36749
- fs37.rmSync(rec.rootPath, { recursive: true, force: true });
37163
+ fs38.rmSync(rec.rootPath, { recursive: true, force: true });
36750
37164
  } catch {
36751
37165
  }
36752
37166
  }
@@ -36762,7 +37176,7 @@ function parseQualifiedSelector(value) {
36762
37176
  }
36763
37177
  function findSubsystemSpec(root, subsystemId) {
36764
37178
  const specsDir = aiPathsAt(root).specsDir();
36765
- if (!fs37.existsSync(specsDir)) return null;
37179
+ if (!fs38.existsSync(specsDir)) return null;
36766
37180
  for (const file of listFilesRecursive(specsDir, ".yaml")) {
36767
37181
  let raw;
36768
37182
  try {
@@ -36847,40 +37261,40 @@ function resolveProjectRoot(dataDir, principal, selector) {
36847
37261
  }
36848
37262
 
36849
37263
  // src/git/config.ts
36850
- var fs38 = __toESM(require("fs"));
36851
- var path51 = __toESM(require("path"));
37264
+ var fs39 = __toESM(require("fs"));
37265
+ var path52 = __toESM(require("path"));
36852
37266
  init_fs();
36853
37267
  function configPath() {
36854
37268
  return aiDir("git.json");
36855
37269
  }
36856
37270
  function readGitConfig() {
36857
37271
  try {
36858
- return JSON.parse(fs38.readFileSync(configPath(), "utf8"));
37272
+ return JSON.parse(fs39.readFileSync(configPath(), "utf8"));
36859
37273
  } catch {
36860
37274
  return null;
36861
37275
  }
36862
37276
  }
36863
37277
  function writeGitConfig(config) {
36864
37278
  const p = configPath();
36865
- fs38.mkdirSync(path51.dirname(p), { recursive: true });
37279
+ fs39.mkdirSync(path52.dirname(p), { recursive: true });
36866
37280
  const tmp = `${p}.tmp`;
36867
- fs38.writeFileSync(tmp, JSON.stringify(config, null, 2) + "\n");
36868
- fs38.renameSync(tmp, p);
37281
+ fs39.writeFileSync(tmp, JSON.stringify(config, null, 2) + "\n");
37282
+ fs39.renameSync(tmp, p);
36869
37283
  }
36870
37284
  function clearGitConfig() {
36871
37285
  try {
36872
- fs38.rmSync(configPath(), { force: true });
37286
+ fs39.rmSync(configPath(), { force: true });
36873
37287
  } catch {
36874
37288
  }
36875
37289
  }
36876
37290
 
36877
37291
  // src/git/adapter.ts
36878
- var import_child_process4 = require("child_process");
36879
- var fs39 = __toESM(require("fs"));
36880
- var path52 = __toESM(require("path"));
37292
+ var import_child_process5 = require("child_process");
37293
+ var fs40 = __toESM(require("fs"));
37294
+ var path53 = __toESM(require("path"));
36881
37295
  init_fs();
36882
37296
  function git(args, cwd) {
36883
- return (0, import_child_process4.execFileSync)("git", args, {
37297
+ return (0, import_child_process5.execFileSync)("git", args, {
36884
37298
  cwd: cwd ?? getProjectRoot(),
36885
37299
  encoding: "utf8",
36886
37300
  env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
@@ -36928,17 +37342,17 @@ function compareUrl(remote, defaultBranch, workingBranch) {
36928
37342
  return `${web}/compare/${encodeURIComponent(defaultBranch)}...${encodeURIComponent(workingBranch)}`;
36929
37343
  }
36930
37344
  function excludeLocalFiles() {
36931
- const excludePath = path52.join(getProjectRoot(), ".git", "info", "exclude");
37345
+ const excludePath = path53.join(getProjectRoot(), ".git", "info", "exclude");
36932
37346
  try {
36933
- fs39.mkdirSync(path52.dirname(excludePath), { recursive: true });
36934
- const existing = fs39.existsSync(excludePath) ? fs39.readFileSync(excludePath, "utf8") : "";
37347
+ fs40.mkdirSync(path53.dirname(excludePath), { recursive: true });
37348
+ const existing = fs40.existsSync(excludePath) ? fs40.readFileSync(excludePath, "utf8") : "";
36935
37349
  const lines = existing.split(/\r?\n/).filter((line2) => line2.length > 0);
36936
37350
  const hadLegacyLockExclusion = lines.some((line2) => line2.trim() === ".wai/lock.json");
36937
37351
  const kept = lines.filter((line2) => line2.trim() !== ".wai/lock.json");
36938
37352
  if (!kept.some((line2) => line2.trim() === ".wai/git.json")) {
36939
37353
  kept.push(".wai/git.json");
36940
37354
  }
36941
- fs39.writeFileSync(excludePath, kept.join("\n") + "\n");
37355
+ fs40.writeFileSync(excludePath, kept.join("\n") + "\n");
36942
37356
  if (hadLegacyLockExclusion) {
36943
37357
  console.warn(
36944
37358
  "[wairon git] removed a .wai/lock.json exclusion left by an earlier version \u2014 the approval it records is committed with the rest of .wai/ now, so it reaches the remote."
@@ -37008,25 +37422,25 @@ function configureSync(periodicSyncMinutes, skipIfClean) {
37008
37422
  }
37009
37423
 
37010
37424
  // src/producers/config.ts
37011
- var fs40 = __toESM(require("fs"));
37012
- var path53 = __toESM(require("path"));
37425
+ var fs41 = __toESM(require("fs"));
37426
+ var path54 = __toESM(require("path"));
37013
37427
  init_fs();
37014
37428
  function configPath2() {
37015
37429
  return aiDir("producers.json");
37016
37430
  }
37017
37431
  function load7() {
37018
37432
  try {
37019
- return JSON.parse(fs40.readFileSync(configPath2(), "utf8"));
37433
+ return JSON.parse(fs41.readFileSync(configPath2(), "utf8"));
37020
37434
  } catch {
37021
37435
  return [];
37022
37436
  }
37023
37437
  }
37024
37438
  function save3(configs) {
37025
37439
  const p = configPath2();
37026
- fs40.mkdirSync(path53.dirname(p), { recursive: true });
37440
+ fs41.mkdirSync(path54.dirname(p), { recursive: true });
37027
37441
  const tmp = `${p}.tmp`;
37028
- fs40.writeFileSync(tmp, JSON.stringify(configs, null, 2) + "\n");
37029
- fs40.renameSync(tmp, p);
37442
+ fs41.writeFileSync(tmp, JSON.stringify(configs, null, 2) + "\n");
37443
+ fs41.renameSync(tmp, p);
37030
37444
  }
37031
37445
  function readProducerConfig(target) {
37032
37446
  return load7().find((c) => c.target === target) ?? null;
@@ -37450,9 +37864,9 @@ function mintKey(cfg, credential, project2, role) {
37450
37864
  "instance-wide super-admin (*:*) keys cannot be minted \u2014 the built-in admin account (WAIRON_ADMIN_USER) is the only super-admin"
37451
37865
  );
37452
37866
  }
37453
- const token = "wk_" + crypto10.randomBytes(24).toString("hex");
37867
+ const token = "wk_" + crypto11.randomBytes(24).toString("hex");
37454
37868
  const record2 = {
37455
- id: crypto10.randomBytes(6).toString("hex"),
37869
+ id: crypto11.randomBytes(6).toString("hex"),
37456
37870
  keyHash: hashToken(token),
37457
37871
  role,
37458
37872
  projects: project2 === "*" ? ["*"] : [project2],
@@ -37701,8 +38115,8 @@ function diagramViewLink(cfg, credential, project2) {
37701
38115
  }
37702
38116
 
37703
38117
  // src/server/packs.ts
37704
- var fs41 = __toESM(require("fs"));
37705
- var path54 = __toESM(require("path"));
38118
+ var fs42 = __toESM(require("fs"));
38119
+ var path55 = __toESM(require("path"));
37706
38120
  init_fs();
37707
38121
  init_yaml();
37708
38122
 
@@ -37758,19 +38172,19 @@ function assertNotCodeArchive(info) {
37758
38172
  function extractDeclarativeArchive(archive, destDir) {
37759
38173
  const result = extractArchive(archive, destDir, HOSTED_STRICT_LIMITS);
37760
38174
  try {
37761
- assertDeclarative(fs41.readFileSync(path54.join(result.directory, result.entryPath), "utf8"));
38175
+ assertDeclarative(fs42.readFileSync(path55.join(result.directory, result.entryPath), "utf8"));
37762
38176
  } catch (e) {
37763
- fs41.rmSync(destDir, { recursive: true, force: true });
38177
+ fs42.rmSync(destDir, { recursive: true, force: true });
37764
38178
  throw e;
37765
38179
  }
37766
38180
  }
37767
38181
  function probe(loadRef, baseRoot, scope, displayRef) {
37768
38182
  const loaded = loadExtensionPacks([{ ref: loadRef, scope }], baseRoot);
37769
38183
  if (loaded.errors.length) {
37770
- return { name: path54.basename(displayRef), scope, ref: displayRef, profiles: 0, languages: 0, rules: 0, error: loaded.errors[0] };
38184
+ return { name: path55.basename(displayRef), scope, ref: displayRef, profiles: 0, languages: 0, rules: 0, error: loaded.errors[0] };
37771
38185
  }
37772
38186
  return {
37773
- name: loaded.packNames[0] ?? path54.basename(displayRef),
38187
+ name: loaded.packNames[0] ?? path55.basename(displayRef),
37774
38188
  scope,
37775
38189
  ref: displayRef,
37776
38190
  profiles: Object.keys(loaded.profiles).length,
@@ -37784,20 +38198,20 @@ function probe(loadRef, baseRoot, scope, displayRef) {
37784
38198
  };
37785
38199
  }
37786
38200
  function writeFileAtomic(file, content) {
37787
- fs41.mkdirSync(path54.dirname(file), { recursive: true });
38201
+ fs42.mkdirSync(path55.dirname(file), { recursive: true });
37788
38202
  const tmp = `${file}.tmp`;
37789
- fs41.writeFileSync(tmp, content);
37790
- fs41.renameSync(tmp, file);
38203
+ fs42.writeFileSync(tmp, content);
38204
+ fs42.renameSync(tmp, file);
37791
38205
  }
37792
38206
  function stem(ref) {
37793
- return path54.basename(ref).replace(PACK_EXT_RE2, "");
38207
+ return path55.basename(ref).replace(PACK_EXT_RE2, "");
37794
38208
  }
37795
38209
  function imagePacksDir() {
37796
38210
  return process.env.WAIRON_IMAGE_PACKS_DIR ?? "/opt/wairon/packs";
37797
38211
  }
37798
38212
  function probeTier(dir, tier) {
37799
38213
  return discoverPacks(dir).map((full) => {
37800
- const d = probe(full, path54.dirname(full), "global", path54.basename(full));
38214
+ const d = probe(full, path55.dirname(full), "global", path55.basename(full));
37801
38215
  d.tier = tier;
37802
38216
  return d;
37803
38217
  });
@@ -37815,9 +38229,9 @@ function scanGlobalPackProfiles() {
37815
38229
  for (const dir of [globalPacksDir(), imagePacksDir()]) {
37816
38230
  for (const full of discoverPacks(dir)) {
37817
38231
  try {
37818
- const loaded = loadExtensionPacks([{ ref: full, scope: "global" }], path54.dirname(full));
38232
+ const loaded = loadExtensionPacks([{ ref: full, scope: "global" }], path55.dirname(full));
37819
38233
  if (loaded.errors.length) continue;
37820
- const source = loaded.packNames[0] ?? path54.basename(full);
38234
+ const source = loaded.packNames[0] ?? path55.basename(full);
37821
38235
  for (const [id, def] of Object.entries(loaded.profiles)) out.push({ id, source, family: def.family });
37822
38236
  } catch {
37823
38237
  }
@@ -37869,12 +38283,12 @@ function storeListProjectProfiles(config) {
37869
38283
  return out;
37870
38284
  }
37871
38285
  function readPackContent(full) {
37872
- const st = fs41.statSync(full);
37873
- if (st.isFile()) return fs41.readFileSync(full, "utf8");
38286
+ const st = fs42.statSync(full);
38287
+ if (st.isFile()) return fs42.readFileSync(full, "utf8");
37874
38288
  if (st.isDirectory()) {
37875
38289
  for (const entry of ["pack.yaml", "pack.yml"]) {
37876
- const p = path54.join(full, entry);
37877
- if (fs41.existsSync(p) && fs41.statSync(p).isFile()) return fs41.readFileSync(p, "utf8");
38290
+ const p = path55.join(full, entry);
38291
+ if (fs42.existsSync(p) && fs42.statSync(p).isFile()) return fs42.readFileSync(p, "utf8");
37878
38292
  }
37879
38293
  }
37880
38294
  return null;
@@ -37883,9 +38297,9 @@ function storeResolveGlobalPacks(names) {
37883
38297
  const index = /* @__PURE__ */ new Map();
37884
38298
  const indexTier = (dir, tier) => {
37885
38299
  for (const full of discoverPacks(dir)) {
37886
- const manifestName = probe(full, path54.dirname(full), "global", path54.basename(full)).name;
38300
+ const manifestName = probe(full, path55.dirname(full), "global", path55.basename(full)).name;
37887
38301
  const candidate = { full, manifestName, tier };
37888
- for (const key of [manifestName, stem(full), path54.basename(full)]) {
38302
+ for (const key of [manifestName, stem(full), path55.basename(full)]) {
37889
38303
  if (!index.has(key)) index.set(key, candidate);
37890
38304
  }
37891
38305
  }
@@ -37912,7 +38326,7 @@ function storeInstallGlobalPack(name, content) {
37912
38326
  assertName(name);
37913
38327
  assertDeclarative(content);
37914
38328
  const dir = globalPacksDir();
37915
- const file = path54.join(dir, `${name}.yaml`);
38329
+ const file = path55.join(dir, `${name}.yaml`);
37916
38330
  writeFileAtomic(file, content);
37917
38331
  const descriptor = probe(file, dir, "global", `${name}.yaml`);
37918
38332
  descriptor.tier = "instance";
@@ -37923,7 +38337,7 @@ function storeInstallGlobalPackArchive(archive, name) {
37923
38337
  assertNotCodeArchive(info);
37924
38338
  const packName = name ?? info.name;
37925
38339
  assertName(packName);
37926
- const dir = path54.join(globalPacksDir(), packName);
38340
+ const dir = path55.join(globalPacksDir(), packName);
37927
38341
  extractDeclarativeArchive(archive, dir);
37928
38342
  const descriptor = probe(dir, globalPacksDir(), "global", packName);
37929
38343
  descriptor.tier = "instance";
@@ -37934,7 +38348,7 @@ function declaredName2(loadRef, baseRoot, scope) {
37934
38348
  return d.error ? void 0 : d.name;
37935
38349
  }
37936
38350
  function pickByName(candidates, name, fileOf, manifestOf) {
37937
- const byFile = candidates.find((c) => stem(fileOf(c)) === name || path54.basename(fileOf(c)) === name);
38351
+ const byFile = candidates.find((c) => stem(fileOf(c)) === name || path55.basename(fileOf(c)) === name);
37938
38352
  if (byFile !== void 0) return byFile;
37939
38353
  const byManifest = candidates.filter((c) => manifestOf(c) === name);
37940
38354
  if (byManifest.length > 1) {
@@ -37947,17 +38361,17 @@ function pickByName(candidates, name, fileOf, manifestOf) {
37947
38361
  function storeRemoveGlobalPack(name) {
37948
38362
  assertName(name);
37949
38363
  const dir = globalPacksDir();
37950
- const manifestOf = (ref) => declaredName2(ref, path54.dirname(ref), "global");
37951
- const match = pickByName(discoverPacks(dir), name, path54.basename, manifestOf);
38364
+ const manifestOf = (ref) => declaredName2(ref, path55.dirname(ref), "global");
38365
+ const match = pickByName(discoverPacks(dir), name, path55.basename, manifestOf);
37952
38366
  if (!match) {
37953
38367
  const inImage = discoverPacks(imagePacksDir()).some(
37954
- (ref) => stem(ref) === name || path54.basename(ref) === name || manifestOf(ref) === name
38368
+ (ref) => stem(ref) === name || path55.basename(ref) === name || manifestOf(ref) === name
37955
38369
  );
37956
38370
  throw new Error(
37957
38371
  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}".`
37958
38372
  );
37959
38373
  }
37960
- fs41.rmSync(match, { recursive: true, force: true });
38374
+ fs42.rmSync(match, { recursive: true, force: true });
37961
38375
  }
37962
38376
  function storeListProjectPacks(config) {
37963
38377
  const root = getProjectRoot();
@@ -37973,7 +38387,7 @@ function storeInstallProjectPack(name, content) {
37973
38387
  assertDeclarative(content);
37974
38388
  const root = getProjectRoot();
37975
38389
  const relRef = `.wai/packs/${name}.yaml`;
37976
- writeFileAtomic(path54.join(root, ".wai", "packs", `${name}.yaml`), content);
38390
+ writeFileAtomic(path55.join(root, ".wai", "packs", `${name}.yaml`), content);
37977
38391
  return probe(relRef, root, "project", relRef);
37978
38392
  }
37979
38393
  function storeInstallProjectPackArchive(archive, name) {
@@ -37983,16 +38397,16 @@ function storeInstallProjectPackArchive(archive, name) {
37983
38397
  assertName(packName);
37984
38398
  const root = getProjectRoot();
37985
38399
  const relRef = `.wai/packs/${packName}`;
37986
- extractDeclarativeArchive(archive, path54.join(root, ".wai", "packs", packName));
38400
+ extractDeclarativeArchive(archive, path55.join(root, ".wai", "packs", packName));
37987
38401
  return probe(relRef, root, "project", relRef);
37988
38402
  }
37989
38403
  function storeRemoveProjectPack(name, ref) {
37990
38404
  assertName(name);
37991
38405
  const root = getProjectRoot();
37992
- const resolved = path54.resolve(root, ref ?? path54.join(".wai", "packs", name));
37993
- const vendorDir = path54.resolve(root, ".wai", "packs");
37994
- if (resolved.startsWith(vendorDir + path54.sep)) {
37995
- fs41.rmSync(resolved, { recursive: true, force: true });
38406
+ const resolved = path55.resolve(root, ref ?? path55.join(".wai", "packs", name));
38407
+ const vendorDir = path55.resolve(root, ".wai", "packs");
38408
+ if (resolved.startsWith(vendorDir + path55.sep)) {
38409
+ fs42.rmSync(resolved, { recursive: true, force: true });
37996
38410
  }
37997
38411
  }
37998
38412
  function requirePrincipal2(cfg, credential) {
@@ -38014,7 +38428,7 @@ function boundProject2(cfg, project2) {
38014
38428
  function findPackRegistration(config, name) {
38015
38429
  const relRef = `.wai/packs/${name}.yaml`;
38016
38430
  const entries = config?.extensions?.packs ?? [];
38017
- const direct = entries.find((entry) => typeof entry === "string" ? entry === relRef || stem(entry) === name || path54.basename(entry) === name : entry.name === name);
38431
+ const direct = entries.find((entry) => typeof entry === "string" ? entry === relRef || stem(entry) === name || path55.basename(entry) === name : entry.name === name);
38018
38432
  if (direct !== void 0) return direct;
38019
38433
  const root = getProjectRoot();
38020
38434
  const refs = entries.filter((entry) => typeof entry === "string");
@@ -38128,9 +38542,9 @@ function installProjectPackArchive(cfg, credential, project2, archive, name) {
38128
38542
  }
38129
38543
 
38130
38544
  // src/server/audit.ts
38131
- var fs42 = __toESM(require("fs"));
38132
- var path55 = __toESM(require("path"));
38133
- var crypto11 = __toESM(require("crypto"));
38545
+ var fs43 = __toESM(require("fs"));
38546
+ var path56 = __toESM(require("path"));
38547
+ var crypto12 = __toESM(require("crypto"));
38134
38548
  var LEVEL_ORDER = {
38135
38549
  debug: 0,
38136
38550
  info: 1,
@@ -38152,13 +38566,13 @@ var DEFAULT_AUDIT_POLICY = {
38152
38566
  metadataMode: "redacted"
38153
38567
  };
38154
38568
  function storePath9(dataDir) {
38155
- return path55.join(dataDir, "audit-events.json");
38569
+ return path56.join(dataDir, "audit-events.json");
38156
38570
  }
38157
38571
  function readEvents(dataDir) {
38158
38572
  const p = storePath9(dataDir);
38159
38573
  let raw;
38160
38574
  try {
38161
- raw = fs42.readFileSync(p, "utf8");
38575
+ raw = fs43.readFileSync(p, "utf8");
38162
38576
  } catch (e) {
38163
38577
  if (e.code === "ENOENT") return [];
38164
38578
  throw new Error(`Failed to read audit store at ${p}: ${e.message}`);
@@ -38173,10 +38587,10 @@ function readEvents(dataDir) {
38173
38587
  }
38174
38588
  function persistEvents(dataDir, events) {
38175
38589
  const p = storePath9(dataDir);
38176
- fs42.mkdirSync(path55.dirname(p), { recursive: true });
38590
+ fs43.mkdirSync(path56.dirname(p), { recursive: true });
38177
38591
  const tmp = `${p}.tmp`;
38178
- fs42.writeFileSync(tmp, JSON.stringify(events, null, 2) + "\n");
38179
- fs42.renameSync(tmp, p);
38592
+ fs43.writeFileSync(tmp, JSON.stringify(events, null, 2) + "\n");
38593
+ fs43.renameSync(tmp, p);
38180
38594
  }
38181
38595
  var SECRET_RE = /Bearer\s+\S/i;
38182
38596
  var LONG_HEX_RE = /[0-9a-fA-F]{32,}/;
@@ -38234,7 +38648,7 @@ var AuditRegistry = class {
38234
38648
  }
38235
38649
  const stamped = {
38236
38650
  ...event,
38237
- id: event.id && event.id.length > 0 ? event.id : crypto11.randomUUID(),
38651
+ id: event.id && event.id.length > 0 ? event.id : crypto12.randomUUID(),
38238
38652
  timestamp: event.timestamp && event.timestamp.length > 0 ? event.timestamp : (/* @__PURE__ */ new Date()).toISOString(),
38239
38653
  metadata
38240
38654
  };
@@ -38501,10 +38915,10 @@ function unbindRole(cfg, credential, userId, roleId, scopeKind, scopeId) {
38501
38915
  }
38502
38916
 
38503
38917
  // src/server/identity.ts
38504
- var crypto13 = __toESM(require("crypto"));
38918
+ var crypto14 = __toESM(require("crypto"));
38505
38919
 
38506
38920
  // src/server/idp.ts
38507
- var crypto12 = __toESM(require("crypto"));
38921
+ var crypto13 = __toESM(require("crypto"));
38508
38922
  var REQUESTED_SCOPE = "openid email profile";
38509
38923
  var discoveryCache = /* @__PURE__ */ new Map();
38510
38924
  var jwksCache = /* @__PURE__ */ new Map();
@@ -38731,7 +39145,7 @@ function verifyJwtSignature(alg, signingInput, jwk, sigB64url) {
38731
39145
  if (!digest2) return false;
38732
39146
  let keyObject;
38733
39147
  try {
38734
- keyObject = crypto12.createPublicKey({ key: jwk, format: "jwk" });
39148
+ keyObject = crypto13.createPublicKey({ key: jwk, format: "jwk" });
38735
39149
  } catch {
38736
39150
  return false;
38737
39151
  }
@@ -38739,18 +39153,18 @@ function verifyJwtSignature(alg, signingInput, jwk, sigB64url) {
38739
39153
  const sig = Buffer.from(sigB64url, "base64url");
38740
39154
  try {
38741
39155
  if (alg.startsWith("RS")) {
38742
- return crypto12.verify(digest2, data, keyObject, sig);
39156
+ return crypto13.verify(digest2, data, keyObject, sig);
38743
39157
  }
38744
39158
  if (alg.startsWith("PS")) {
38745
- return crypto12.verify(
39159
+ return crypto13.verify(
38746
39160
  digest2,
38747
39161
  data,
38748
- { key: keyObject, padding: crypto12.constants.RSA_PKCS1_PSS_PADDING, saltLength: crypto12.constants.RSA_PSS_SALTLEN_DIGEST },
39162
+ { key: keyObject, padding: crypto13.constants.RSA_PKCS1_PSS_PADDING, saltLength: crypto13.constants.RSA_PSS_SALTLEN_DIGEST },
38749
39163
  sig
38750
39164
  );
38751
39165
  }
38752
39166
  if (alg.startsWith("ES")) {
38753
- return crypto12.verify(digest2, data, { key: keyObject, dsaEncoding: "ieee-p1363" }, sig);
39167
+ return crypto13.verify(digest2, data, { key: keyObject, dsaEncoding: "ieee-p1363" }, sig);
38754
39168
  }
38755
39169
  } catch {
38756
39170
  return false;
@@ -38864,8 +39278,8 @@ function assertAllowedRedirectUri(provider, redirectUri) {
38864
39278
  }
38865
39279
 
38866
39280
  // src/server/policy.ts
38867
- var fs43 = __toESM(require("fs"));
38868
- var path56 = __toESM(require("path"));
39281
+ var fs44 = __toESM(require("fs"));
39282
+ var path57 = __toESM(require("path"));
38869
39283
  init_fs();
38870
39284
 
38871
39285
  // src/server/httpio.ts
@@ -38882,13 +39296,13 @@ function sendJson(res, status2, body) {
38882
39296
 
38883
39297
  // src/server/policy.ts
38884
39298
  function packPolicyPath(dataDir) {
38885
- return path56.join(dataDir, "pack-policy.json");
39299
+ return path57.join(dataDir, "pack-policy.json");
38886
39300
  }
38887
39301
  function getPackPolicyRecord(dataDir) {
38888
39302
  const p = packPolicyPath(dataDir);
38889
39303
  let raw;
38890
39304
  try {
38891
- raw = fs43.readFileSync(p, "utf8");
39305
+ raw = fs44.readFileSync(p, "utf8");
38892
39306
  } catch (e) {
38893
39307
  if (e.code === "ENOENT") return null;
38894
39308
  throw new Error(`Failed to read pack policy store at ${p}: ${e.message}`);
@@ -38902,14 +39316,14 @@ function getPackPolicyRecord(dataDir) {
38902
39316
  function setPackPolicyRecord(dataDir, policy) {
38903
39317
  const stored = { ...policy, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
38904
39318
  const p = packPolicyPath(dataDir);
38905
- fs43.mkdirSync(path56.dirname(p), { recursive: true });
39319
+ fs44.mkdirSync(path57.dirname(p), { recursive: true });
38906
39320
  const tmp = `${p}.tmp`;
38907
- fs43.writeFileSync(tmp, JSON.stringify(stored, null, 2) + "\n");
38908
- fs43.renameSync(tmp, p);
39321
+ fs44.writeFileSync(tmp, JSON.stringify(stored, null, 2) + "\n");
39322
+ fs44.renameSync(tmp, p);
38909
39323
  return stored;
38910
39324
  }
38911
39325
  function exposurePolicyPath(dataDir) {
38912
- return path56.join(dataDir, "exposure-policy.json");
39326
+ return path57.join(dataDir, "exposure-policy.json");
38913
39327
  }
38914
39328
  var COMPATIBLE_DEFAULT_EXPOSURE = {
38915
39329
  adminApiMode: "local_only",
@@ -38926,7 +39340,7 @@ function getExposurePolicyRecord(dataDir) {
38926
39340
  const p = exposurePolicyPath(dataDir);
38927
39341
  let raw;
38928
39342
  try {
38929
- raw = fs43.readFileSync(p, "utf8");
39343
+ raw = fs44.readFileSync(p, "utf8");
38930
39344
  } catch (e) {
38931
39345
  if (e.code === "ENOENT") return null;
38932
39346
  throw new Error(`Failed to read exposure policy store at ${p}: ${e.message}`);
@@ -38939,10 +39353,10 @@ function getExposurePolicyRecord(dataDir) {
38939
39353
  }
38940
39354
  function setExposurePolicyRecord(dataDir, policy) {
38941
39355
  const p = exposurePolicyPath(dataDir);
38942
- fs43.mkdirSync(path56.dirname(p), { recursive: true });
39356
+ fs44.mkdirSync(path57.dirname(p), { recursive: true });
38943
39357
  const tmp = `${p}.tmp`;
38944
- fs43.writeFileSync(tmp, JSON.stringify(policy, null, 2) + "\n");
38945
- fs43.renameSync(tmp, p);
39358
+ fs44.writeFileSync(tmp, JSON.stringify(policy, null, 2) + "\n");
39359
+ fs44.renameSync(tmp, p);
38946
39360
  return policy;
38947
39361
  }
38948
39362
  var PERMISSIVE_DEFAULT_POLICY = {
@@ -38960,7 +39374,7 @@ function effectivePolicy(dataDir) {
38960
39374
  return getPackPolicyRecord(dataDir) ?? PERMISSIVE_DEFAULT_POLICY;
38961
39375
  }
38962
39376
  function identityProvidersPath(dataDir) {
38963
- return path56.join(dataDir, "identity-providers.json");
39377
+ return path57.join(dataDir, "identity-providers.json");
38964
39378
  }
38965
39379
  function sanitizeIdentityProvider(config) {
38966
39380
  const clean = {
@@ -38984,16 +39398,16 @@ function sanitizeIdentityProvider(config) {
38984
39398
  }
38985
39399
  function writeIdentityProviderRecords(dataDir, records) {
38986
39400
  const p = identityProvidersPath(dataDir);
38987
- fs43.mkdirSync(path56.dirname(p), { recursive: true });
39401
+ fs44.mkdirSync(path57.dirname(p), { recursive: true });
38988
39402
  const tmp = `${p}.tmp`;
38989
- fs43.writeFileSync(tmp, JSON.stringify(records, null, 2) + "\n");
38990
- fs43.renameSync(tmp, p);
39403
+ fs44.writeFileSync(tmp, JSON.stringify(records, null, 2) + "\n");
39404
+ fs44.renameSync(tmp, p);
38991
39405
  }
38992
39406
  function listIdentityProviderRecords(dataDir) {
38993
39407
  const p = identityProvidersPath(dataDir);
38994
39408
  let raw;
38995
39409
  try {
38996
- raw = fs43.readFileSync(p, "utf8");
39410
+ raw = fs44.readFileSync(p, "utf8");
38997
39411
  } catch (e) {
38998
39412
  if (e.code === "ENOENT") return [];
38999
39413
  throw new Error(`Failed to read identity provider store at ${p}: ${e.message}`);
@@ -39626,9 +40040,9 @@ function mintToken(cfg, credential, request) {
39626
40040
  if (owner && owner.status !== "active") {
39627
40041
  throw new ForbiddenError("cannot mint a token for a deactivated user");
39628
40042
  }
39629
- const token = "wk_" + crypto13.randomBytes(24).toString("hex");
40043
+ const token = "wk_" + crypto14.randomBytes(24).toString("hex");
39630
40044
  const record2 = {
39631
- id: crypto13.randomBytes(6).toString("hex"),
40045
+ id: crypto14.randomBytes(6).toString("hex"),
39632
40046
  keyHash: hashToken(token),
39633
40047
  projects,
39634
40048
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -39672,10 +40086,10 @@ function mintSelfToken(cfg, credential, projectId, write) {
39672
40086
  if (parsed.mounts.length > 0) {
39673
40087
  assertMintableNarrowingEntry(cfg.dataDir, projectId);
39674
40088
  }
39675
- const token = "wk_" + crypto13.randomBytes(24).toString("hex");
40089
+ const token = "wk_" + crypto14.randomBytes(24).toString("hex");
39676
40090
  const owner = auditActor(principal);
39677
40091
  const record2 = {
39678
- id: crypto13.randomBytes(6).toString("hex"),
40092
+ id: crypto14.randomBytes(6).toString("hex"),
39679
40093
  keyHash: hashToken(token),
39680
40094
  projects: [projectId],
39681
40095
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -39790,7 +40204,7 @@ function resolveEnabledProvider(cfg, providerId) {
39790
40204
  }
39791
40205
  async function startSsoLogin(cfg, providerId, redirectUri) {
39792
40206
  const provider = resolveEnabledProvider(cfg, providerId);
39793
- const nonce = crypto13.randomBytes(16).toString("hex");
40207
+ const nonce = crypto14.randomBytes(16).toString("hex");
39794
40208
  const payload = { providerId, nonce, redirectUri };
39795
40209
  const state = signSsoState(JSON.stringify(payload));
39796
40210
  const endpoints = await resolveEndpoints(provider);
@@ -39841,9 +40255,9 @@ async function completeSsoLogin(cfg, state, code) {
39841
40255
  ...subject.email ? { email: subject.email } : {}
39842
40256
  });
39843
40257
  }
39844
- const token = "wk_" + crypto13.randomBytes(24).toString("hex");
40258
+ const token = "wk_" + crypto14.randomBytes(24).toString("hex");
39845
40259
  const record2 = {
39846
- id: crypto13.randomBytes(6).toString("hex"),
40260
+ id: crypto14.randomBytes(6).toString("hex"),
39847
40261
  keyHash: hashToken(token),
39848
40262
  projects: ["*"],
39849
40263
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -40031,17 +40445,17 @@ init_yaml();
40031
40445
  init_paths();
40032
40446
 
40033
40447
  // src/server/relations.ts
40034
- var fs44 = __toESM(require("fs"));
40035
- var path57 = __toESM(require("path"));
40036
- var crypto14 = __toESM(require("crypto"));
40448
+ var fs45 = __toESM(require("fs"));
40449
+ var path58 = __toESM(require("path"));
40450
+ var crypto15 = __toESM(require("crypto"));
40037
40451
  function storePath10(dataDir) {
40038
- return path57.join(dataDir, "relations.json");
40452
+ return path58.join(dataDir, "relations.json");
40039
40453
  }
40040
40454
  function readRelations(dataDir) {
40041
40455
  const p = storePath10(dataDir);
40042
40456
  let raw;
40043
40457
  try {
40044
- raw = fs44.readFileSync(p, "utf8");
40458
+ raw = fs45.readFileSync(p, "utf8");
40045
40459
  } catch (e) {
40046
40460
  if (e.code === "ENOENT") return [];
40047
40461
  throw new Error(`Failed to read relation store at ${p}: ${e.message}`);
@@ -40056,10 +40470,10 @@ function readRelations(dataDir) {
40056
40470
  }
40057
40471
  function persistRelations(dataDir, relations) {
40058
40472
  const p = storePath10(dataDir);
40059
- fs44.mkdirSync(path57.dirname(p), { recursive: true });
40473
+ fs45.mkdirSync(path58.dirname(p), { recursive: true });
40060
40474
  const tmp = `${p}.tmp`;
40061
- fs44.writeFileSync(tmp, JSON.stringify(relations, null, 2) + "\n");
40062
- fs44.renameSync(tmp, p);
40475
+ fs45.writeFileSync(tmp, JSON.stringify(relations, null, 2) + "\n");
40476
+ fs45.renameSync(tmp, p);
40063
40477
  }
40064
40478
  var ProjectRelationStore = class {
40065
40479
  constructor(dataDir) {
@@ -40102,7 +40516,7 @@ var ProjectRelationRegistry = class {
40102
40516
  const hasStatus = typeof record2.status === "string" && record2.status.trim().length > 0;
40103
40517
  const stored = {
40104
40518
  ...record2,
40105
- id: hasId ? record2.id : crypto14.randomUUID(),
40519
+ id: hasId ? record2.id : crypto15.randomUUID(),
40106
40520
  status: hasStatus ? record2.status : "active"
40107
40521
  };
40108
40522
  const relations = this.store.all();
@@ -40169,16 +40583,16 @@ function listProjectRelations(dataDir, sourceProjectId, targetProjectId, status2
40169
40583
  }
40170
40584
 
40171
40585
  // src/server/surfaces.ts
40172
- var fs45 = __toESM(require("fs"));
40173
- var path58 = __toESM(require("path"));
40586
+ var fs46 = __toESM(require("fs"));
40587
+ var path59 = __toESM(require("path"));
40174
40588
  function storePath11(dataDir) {
40175
- return path58.join(dataDir, "public-surfaces.json");
40589
+ return path59.join(dataDir, "public-surfaces.json");
40176
40590
  }
40177
40591
  function readSnapshots(dataDir) {
40178
40592
  const p = storePath11(dataDir);
40179
40593
  let raw;
40180
40594
  try {
40181
- raw = fs45.readFileSync(p, "utf8");
40595
+ raw = fs46.readFileSync(p, "utf8");
40182
40596
  } catch (e) {
40183
40597
  if (e.code === "ENOENT") return [];
40184
40598
  throw new Error(`Failed to read public surface store at ${p}: ${e.message}`);
@@ -40193,10 +40607,10 @@ function readSnapshots(dataDir) {
40193
40607
  }
40194
40608
  function persistSnapshots(dataDir, snapshots) {
40195
40609
  const p = storePath11(dataDir);
40196
- fs45.mkdirSync(path58.dirname(p), { recursive: true });
40610
+ fs46.mkdirSync(path59.dirname(p), { recursive: true });
40197
40611
  const tmp = `${p}.tmp`;
40198
- fs45.writeFileSync(tmp, JSON.stringify(snapshots, null, 2) + "\n");
40199
- fs45.renameSync(tmp, p);
40612
+ fs46.writeFileSync(tmp, JSON.stringify(snapshots, null, 2) + "\n");
40613
+ fs46.renameSync(tmp, p);
40200
40614
  }
40201
40615
  var PublicSurfaceStore = class {
40202
40616
  constructor(dataDir) {
@@ -40339,12 +40753,12 @@ function resolveVisibility(observerProjectId, units, placements) {
40339
40753
  const best = /* @__PURE__ */ new Map();
40340
40754
  for (const placement of placements) {
40341
40755
  if (placement.projectId === observerProjectId) continue;
40342
- const path72 = chainOf(placement.unitId, unitById);
40343
- if (!path72.length) continue;
40344
- const closedOk = path72.every((u) => effectivePosture(u, unitById) !== "closed" || observerInside(u.id) || grantedTo(u));
40756
+ const path73 = chainOf(placement.unitId, unitById);
40757
+ if (!path73.length) continue;
40758
+ const closedOk = path73.every((u) => effectivePosture(u, unitById) !== "closed" || observerInside(u.id) || grantedTo(u));
40345
40759
  if (!closedOk) continue;
40346
- const crossTenant = !tenantRoots.has(path72[path72.length - 1].id);
40347
- if (crossTenant && !path72.some(grantedTo)) continue;
40760
+ const crossTenant = !tenantRoots.has(path73[path73.length - 1].id);
40761
+ if (crossTenant && !path73.some(grantedTo)) continue;
40348
40762
  if (crossTenant && directUnits.length === 0) continue;
40349
40763
  const distance = crossTenant ? "partner" : sameBranch(placement.unitId) ? "department" : "instance";
40350
40764
  const existing = best.get(placement.projectId);
@@ -40993,8 +41407,8 @@ function handleLandscapeRequest(cfg, credential, req, res, body, url) {
40993
41407
  }
40994
41408
 
40995
41409
  // src/server/migration.ts
40996
- var fs46 = __toESM(require("fs"));
40997
- var path59 = __toESM(require("path"));
41410
+ var fs47 = __toESM(require("fs"));
41411
+ var path60 = __toESM(require("path"));
40998
41412
  var LEGACY_CAPABILITY_MAP = {
40999
41413
  "mcp:read": "project:read",
41000
41414
  "operations:read": "project:read",
@@ -41026,16 +41440,16 @@ function scopeOf(grant) {
41026
41440
  }
41027
41441
  function readRaw(file) {
41028
41442
  try {
41029
- return JSON.parse(fs46.readFileSync(file, "utf8"));
41443
+ return JSON.parse(fs47.readFileSync(file, "utf8"));
41030
41444
  } catch {
41031
41445
  return null;
41032
41446
  }
41033
41447
  }
41034
41448
  function writeRaw(file, value) {
41035
- fs46.mkdirSync(path59.dirname(file), { recursive: true });
41449
+ fs47.mkdirSync(path60.dirname(file), { recursive: true });
41036
41450
  const tmp = `${file}.tmp`;
41037
- fs46.writeFileSync(tmp, JSON.stringify(value, null, 2) + "\n");
41038
- fs46.renameSync(tmp, file);
41451
+ fs47.writeFileSync(tmp, JSON.stringify(value, null, 2) + "\n");
41452
+ fs47.renameSync(tmp, file);
41039
41453
  }
41040
41454
  function slugify(name) {
41041
41455
  return name.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "") || "unit";
@@ -41069,13 +41483,13 @@ function migratePermissionModel(dataDir, apply) {
41069
41483
  findings.push({ area, detail });
41070
41484
  };
41071
41485
  const grid = readRaw(
41072
- path59.join(dataDir, "permissions.json")
41486
+ path60.join(dataDir, "permissions.json")
41073
41487
  ) ?? [];
41074
41488
  if (!getInstanceIdentity(dataDir)) {
41075
41489
  found("instance", "instance identity is not seeded \u2014 the built-in admin/dev subjects have no persisted UUIDs");
41076
41490
  if (apply) ensureInstanceIdentity(dataDir);
41077
41491
  }
41078
- const orgPath = path59.join(dataDir, "organization.json");
41492
+ const orgPath = path60.join(dataDir, "organization.json");
41079
41493
  const org = readRaw(orgPath);
41080
41494
  if (org?.units?.length) {
41081
41495
  const units = org.units;
@@ -41129,7 +41543,7 @@ function migratePermissionModel(dataDir, apply) {
41129
41543
  found("units", `${remap.length} unit id(s) would be remapped across placements, exposeTo, assignments, and users`);
41130
41544
  }
41131
41545
  }
41132
- const usersPath = path59.join(dataDir, "users.json");
41546
+ const usersPath = path60.join(dataDir, "users.json");
41133
41547
  const users = readRaw(usersPath);
41134
41548
  if (users) {
41135
41549
  let changed = false;
@@ -41156,7 +41570,7 @@ function migratePermissionModel(dataDir, apply) {
41156
41570
  }
41157
41571
  if (apply && changed) writeRaw(usersPath, users);
41158
41572
  }
41159
- const keysPath = path59.join(dataDir, "auth", "credentials.json");
41573
+ const keysPath = path60.join(dataDir, "auth", "credentials.json");
41160
41574
  const keys = readRaw(keysPath);
41161
41575
  if (keys) {
41162
41576
  let changed = false;
@@ -41206,7 +41620,7 @@ function migratePermissionModel(dataDir, apply) {
41206
41620
  }
41207
41621
  if (apply && changed) writeRaw(keysPath, keys);
41208
41622
  }
41209
- const sessionsPath = path59.join(dataDir, "web-sessions.json");
41623
+ const sessionsPath = path60.join(dataDir, "web-sessions.json");
41210
41624
  const sessions = readRaw(sessionsPath);
41211
41625
  if (sessions) {
41212
41626
  let changed = false;
@@ -41285,8 +41699,8 @@ function migratePermissionModel(dataDir, apply) {
41285
41699
 
41286
41700
  // src/server/http.ts
41287
41701
  var http2 = __toESM(require("http"));
41288
- var fs54 = __toESM(require("fs"));
41289
- var path67 = __toESM(require("path"));
41702
+ var fs55 = __toESM(require("fs"));
41703
+ var path68 = __toESM(require("path"));
41290
41704
 
41291
41705
  // src/server/request.ts
41292
41706
  var import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
@@ -41299,17 +41713,17 @@ function createScopedServer() {
41299
41713
  }
41300
41714
 
41301
41715
  // src/server/approvals.ts
41302
- var fs47 = __toESM(require("fs"));
41303
- var path60 = __toESM(require("path"));
41304
- var crypto15 = __toESM(require("crypto"));
41716
+ var fs48 = __toESM(require("fs"));
41717
+ var path61 = __toESM(require("path"));
41718
+ var crypto16 = __toESM(require("crypto"));
41305
41719
  function storePath12(dataDir) {
41306
- return path60.join(dataDir, "approvals.json");
41720
+ return path61.join(dataDir, "approvals.json");
41307
41721
  }
41308
41722
  function readRequests(dataDir) {
41309
41723
  const p = storePath12(dataDir);
41310
41724
  let raw;
41311
41725
  try {
41312
- raw = fs47.readFileSync(p, "utf8");
41726
+ raw = fs48.readFileSync(p, "utf8");
41313
41727
  } catch (e) {
41314
41728
  if (e.code === "ENOENT") return [];
41315
41729
  throw new Error(`Failed to read approval store at ${p}: ${e.message}`);
@@ -41324,10 +41738,10 @@ function readRequests(dataDir) {
41324
41738
  }
41325
41739
  function persistRequests(dataDir, requests) {
41326
41740
  const p = storePath12(dataDir);
41327
- fs47.mkdirSync(path60.dirname(p), { recursive: true });
41741
+ fs48.mkdirSync(path61.dirname(p), { recursive: true });
41328
41742
  const tmp = `${p}.tmp`;
41329
- fs47.writeFileSync(tmp, JSON.stringify(requests, null, 2) + "\n");
41330
- fs47.renameSync(tmp, p);
41743
+ fs48.writeFileSync(tmp, JSON.stringify(requests, null, 2) + "\n");
41744
+ fs48.renameSync(tmp, p);
41331
41745
  }
41332
41746
  var SECRET_RE2 = /Bearer\s+\S/i;
41333
41747
  var LONG_HEX_RE2 = /[0-9a-fA-F]{32,}/;
@@ -41375,7 +41789,7 @@ var ApprovalRegistry = class {
41375
41789
  }
41376
41790
  const stored = {
41377
41791
  ...request,
41378
- id: crypto15.randomUUID(),
41792
+ id: crypto16.randomUUID(),
41379
41793
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
41380
41794
  status: "pending"
41381
41795
  };
@@ -41848,7 +42262,7 @@ async function awaitApproval(cfg, credential, requestId, timeoutSeconds) {
41848
42262
  let current2 = req;
41849
42263
  while (current2.status === "pending" && Date.now() < deadline) {
41850
42264
  const remaining = deadline - Date.now();
41851
- await new Promise((resolve33) => setTimeout(resolve33, Math.min(AWAIT_POLL_INTERVAL_MS, remaining)));
42265
+ await new Promise((resolve34) => setTimeout(resolve34, Math.min(AWAIT_POLL_INTERVAL_MS, remaining)));
41852
42266
  expirePendingApprovals(cfg.dataDir, (/* @__PURE__ */ new Date()).toISOString());
41853
42267
  current2 = getApprovalRequestById(cfg.dataDir, requestId) ?? current2;
41854
42268
  }
@@ -42135,12 +42549,12 @@ function handleOperationsRequest(cfg, credential, req, res, url) {
42135
42549
  }
42136
42550
 
42137
42551
  // src/server/gitbacking.ts
42138
- var fs48 = __toESM(require("fs"));
42139
- var path61 = __toESM(require("path"));
42140
- var crypto16 = __toESM(require("crypto"));
42141
- var import_child_process5 = require("child_process");
42552
+ var fs49 = __toESM(require("fs"));
42553
+ var path62 = __toESM(require("path"));
42554
+ var crypto17 = __toESM(require("crypto"));
42555
+ var import_child_process6 = require("child_process");
42142
42556
  function storePath13(dataDir) {
42143
- return path61.join(dataDir, "git-backing.json");
42557
+ return path62.join(dataDir, "git-backing.json");
42144
42558
  }
42145
42559
  var GitBackingStore = class {
42146
42560
  constructor(dataDir) {
@@ -42152,7 +42566,7 @@ var GitBackingStore = class {
42152
42566
  const p = storePath13(this.dataDir);
42153
42567
  let raw;
42154
42568
  try {
42155
- raw = fs48.readFileSync(p, "utf8");
42569
+ raw = fs49.readFileSync(p, "utf8");
42156
42570
  } catch (err) {
42157
42571
  if (err.code === "ENOENT") return [];
42158
42572
  throw new Error(`Cannot read git-backing store at ${p}: ${err.message}`);
@@ -42171,10 +42585,10 @@ var GitBackingStore = class {
42171
42585
  /** Swap the persisted collection wholesale via write-temp-then-rename. */
42172
42586
  replaceAll(bindings) {
42173
42587
  const p = storePath13(this.dataDir);
42174
- fs48.mkdirSync(path61.dirname(p), { recursive: true });
42588
+ fs49.mkdirSync(path62.dirname(p), { recursive: true });
42175
42589
  const tmp = `${p}.tmp`;
42176
- fs48.writeFileSync(tmp, JSON.stringify(bindings, null, 2) + "\n");
42177
- fs48.renameSync(tmp, p);
42590
+ fs49.writeFileSync(tmp, JSON.stringify(bindings, null, 2) + "\n");
42591
+ fs49.renameSync(tmp, p);
42178
42592
  }
42179
42593
  };
42180
42594
  var GitBackingRegistry = class {
@@ -42193,7 +42607,7 @@ var GitBackingRegistry = class {
42193
42607
  const bindings = this.store.load();
42194
42608
  const stored = {
42195
42609
  ...binding,
42196
- id: binding.id || crypto16.randomUUID(),
42610
+ id: binding.id || crypto17.randomUUID(),
42197
42611
  createdAt: binding.createdAt || (/* @__PURE__ */ new Date()).toISOString()
42198
42612
  };
42199
42613
  const sameScope = (b) => b.scopeKind === stored.scopeKind && (b.scopeId ?? "") === (stored.scopeId ?? "");
@@ -42248,7 +42662,7 @@ function getBinding(dataDir, bindingId) {
42248
42662
  return new GitBackingIndex(new GitBackingStore(dataDir)).getBinding(bindingId);
42249
42663
  }
42250
42664
  function git2(args, cwd) {
42251
- return (0, import_child_process5.execFileSync)("git", args, {
42665
+ return (0, import_child_process6.execFileSync)("git", args, {
42252
42666
  cwd,
42253
42667
  encoding: "utf8",
42254
42668
  env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
@@ -42279,8 +42693,8 @@ function checkoutBranch(workdir, branch) {
42279
42693
  }
42280
42694
  }
42281
42695
  function cloneOrOpen(remote, branch, workdir, credentialRef) {
42282
- if (!fs48.existsSync(path61.join(workdir, ".git"))) {
42283
- fs48.mkdirSync(workdir, { recursive: true });
42696
+ if (!fs49.existsSync(path62.join(workdir, ".git"))) {
42697
+ fs49.mkdirSync(workdir, { recursive: true });
42284
42698
  git2(["clone", authRemote2(remote, credentialRef), "."], workdir);
42285
42699
  git2(["config", "user.name", process.env["WAIRON_GIT_NAME"] || "wairon-bot"], workdir);
42286
42700
  git2(["config", "user.email", process.env["WAIRON_GIT_EMAIL"] || "wairon-bot@localhost"], workdir);
@@ -42292,11 +42706,11 @@ function cloneOrOpen(remote, branch, workdir, credentialRef) {
42292
42706
  return workdir;
42293
42707
  }
42294
42708
  function mirrorTree(sourceDir, targetDir) {
42295
- fs48.rmSync(targetDir, { recursive: true, force: true });
42296
- const stat = fs48.statSync(sourceDir, { throwIfNoEntry: false });
42709
+ fs49.rmSync(targetDir, { recursive: true, force: true });
42710
+ const stat = fs49.statSync(sourceDir, { throwIfNoEntry: false });
42297
42711
  if (!stat) return;
42298
- fs48.mkdirSync(path61.dirname(targetDir), { recursive: true });
42299
- fs48.cpSync(sourceDir, targetDir, { recursive: true });
42712
+ fs49.mkdirSync(path62.dirname(targetDir), { recursive: true });
42713
+ fs49.cpSync(sourceDir, targetDir, { recursive: true });
42300
42714
  }
42301
42715
  function commitAndPush(workdir, message) {
42302
42716
  git2(["add", "-A"], workdir);
@@ -42418,7 +42832,7 @@ function unbindScope(cfg, credential, bindingId) {
42418
42832
  tryAppendAudit7(cfg, buildAuditEvent6(principal, "git.backing.unbind", "security", bindingId));
42419
42833
  }
42420
42834
  function runMirrorSync(cfg, binding) {
42421
- const workdir = path61.join(cfg.dataDir, "git-backing", binding.id);
42835
+ const workdir = path62.join(cfg.dataDir, "git-backing", binding.id);
42422
42836
  cloneOrOpen(binding.remote, binding.branch, workdir, binding.credentialRef);
42423
42837
  if (binding.scopeKind === "unit") {
42424
42838
  const units = listOrganizationUnits(cfg.dataDir);
@@ -42426,23 +42840,23 @@ function runMirrorSync(cfg, binding) {
42426
42840
  const placedIds = new Set(
42427
42841
  listProjectPlacements(cfg.dataDir).filter((p) => subtree.has(p.unitId)).map((p) => p.projectId)
42428
42842
  );
42429
- const projectsDir = path61.join(workdir, "projects");
42430
- fs48.rmSync(projectsDir, { recursive: true, force: true });
42843
+ const projectsDir = path62.join(workdir, "projects");
42844
+ fs49.rmSync(projectsDir, { recursive: true, force: true });
42431
42845
  for (const rec of listProjectRecords(cfg.dataDir)) {
42432
42846
  if (!placedIds.has(rec.id)) continue;
42433
- mirrorTree(path61.join(rec.rootPath, ".wai"), path61.join(projectsDir, rec.id, ".wai"));
42847
+ mirrorTree(path62.join(rec.rootPath, ".wai"), path62.join(projectsDir, rec.id, ".wai"));
42434
42848
  }
42435
42849
  } else {
42436
- const instanceDir = path61.join(workdir, "instance");
42437
- fs48.rmSync(instanceDir, { recursive: true, force: true });
42850
+ const instanceDir = path62.join(workdir, "instance");
42851
+ fs49.rmSync(instanceDir, { recursive: true, force: true });
42438
42852
  const files = binding.includeCredentials ? INSTANCE_STRUCTURE_FILES : INSTANCE_STRUCTURE_FILES.filter((rel2) => rel2 !== "auth/credentials.json");
42439
42853
  for (const rel2 of files) {
42440
- mirrorTree(path61.join(cfg.dataDir, rel2), path61.join(instanceDir, rel2));
42854
+ mirrorTree(path62.join(cfg.dataDir, rel2), path62.join(instanceDir, rel2));
42441
42855
  }
42442
- const projectsDir = path61.join(workdir, "projects");
42443
- fs48.rmSync(projectsDir, { recursive: true, force: true });
42856
+ const projectsDir = path62.join(workdir, "projects");
42857
+ fs49.rmSync(projectsDir, { recursive: true, force: true });
42444
42858
  for (const rec of listProjectRecords(cfg.dataDir)) {
42445
- mirrorTree(path61.join(rec.rootPath, ".wai"), path61.join(projectsDir, rec.id, ".wai"));
42859
+ mirrorTree(path62.join(rec.rootPath, ".wai"), path62.join(projectsDir, rec.id, ".wai"));
42446
42860
  }
42447
42861
  }
42448
42862
  const published = commitAndPush(
@@ -42594,7 +43008,7 @@ function setExposurePolicy2(cfg, credential, exposure) {
42594
43008
 
42595
43009
  // src/server/websocket.ts
42596
43010
  var import_events = require("events");
42597
- var crypto17 = __toESM(require("crypto"));
43011
+ var crypto18 = __toESM(require("crypto"));
42598
43012
  var WS_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
42599
43013
  var MAX_PAYLOAD = 1 << 20;
42600
43014
  var OP_CONTINUATION = 0;
@@ -42608,7 +43022,7 @@ function isWebSocketUpgrade(req) {
42608
43022
  function acceptWebSocket(req, socket) {
42609
43023
  const key = req.headers["sec-websocket-key"];
42610
43024
  if (!isWebSocketUpgrade(req) || typeof key !== "string") return null;
42611
- const accept = crypto17.createHash("sha1").update(key + WS_GUID).digest("base64");
43025
+ const accept = crypto18.createHash("sha1").update(key + WS_GUID).digest("base64");
42612
43026
  socket.write(
42613
43027
  `HTTP/1.1 101 Switching Protocols\r
42614
43028
  Upgrade: websocket\r
@@ -42758,9 +43172,9 @@ function encodeFrame(opcode, payload) {
42758
43172
  }
42759
43173
 
42760
43174
  // src/server/web.ts
42761
- var crypto22 = __toESM(require("crypto"));
42762
- var fs53 = __toESM(require("fs"));
42763
- var path66 = __toESM(require("path"));
43175
+ var crypto23 = __toESM(require("crypto"));
43176
+ var fs54 = __toESM(require("fs"));
43177
+ var path67 = __toESM(require("path"));
42764
43178
 
42765
43179
  // src/server/webadmin.ts
42766
43180
  function listUsers3(cfg, sessionId, project2) {
@@ -43011,18 +43425,18 @@ function destroyProject2(cfg, sessionId, id) {
43011
43425
  }
43012
43426
 
43013
43427
  // src/server/shareadmin.ts
43014
- var crypto21 = __toESM(require("crypto"));
43428
+ var crypto22 = __toESM(require("crypto"));
43015
43429
 
43016
43430
  // src/server/sharesnapshots.ts
43017
- var fs49 = __toESM(require("fs"));
43018
- var path62 = __toESM(require("path"));
43019
- var crypto18 = __toESM(require("crypto"));
43431
+ var fs50 = __toESM(require("fs"));
43432
+ var path63 = __toESM(require("path"));
43433
+ var crypto19 = __toESM(require("crypto"));
43020
43434
  init_fs();
43021
43435
  function snapshotDir(dataDir) {
43022
- return path62.join(dataDir, "share-snapshots");
43436
+ return path63.join(dataDir, "share-snapshots");
43023
43437
  }
43024
43438
  function snapshotPath(dataDir, id) {
43025
- return path62.join(snapshotDir(dataDir), `${id}.json`);
43439
+ return path63.join(snapshotDir(dataDir), `${id}.json`);
43026
43440
  }
43027
43441
  var ShareSnapshotStore = class {
43028
43442
  constructor(dataDir) {
@@ -43030,17 +43444,17 @@ var ShareSnapshotStore = class {
43030
43444
  }
43031
43445
  write(snapshot) {
43032
43446
  const p = snapshotPath(this.dataDir, snapshot.id);
43033
- if (fs49.existsSync(p)) return;
43034
- fs49.mkdirSync(path62.dirname(p), { recursive: true });
43447
+ if (fs50.existsSync(p)) return;
43448
+ fs50.mkdirSync(path63.dirname(p), { recursive: true });
43035
43449
  const tmp = `${p}.tmp`;
43036
- fs49.writeFileSync(tmp, JSON.stringify(snapshot, null, 2) + "\n");
43037
- fs49.renameSync(tmp, p);
43450
+ fs50.writeFileSync(tmp, JSON.stringify(snapshot, null, 2) + "\n");
43451
+ fs50.renameSync(tmp, p);
43038
43452
  }
43039
43453
  read(snapshotId) {
43040
43454
  const p = snapshotPath(this.dataDir, snapshotId);
43041
43455
  let raw;
43042
43456
  try {
43043
- raw = fs49.readFileSync(p, "utf8");
43457
+ raw = fs50.readFileSync(p, "utf8");
43044
43458
  } catch (err) {
43045
43459
  if (err.code === "ENOENT") return null;
43046
43460
  throw new Error(`Cannot read share snapshot at ${p}: ${err.message}`);
@@ -43059,7 +43473,7 @@ var ShareSnapshotRegistry = class {
43059
43473
  put(snapshot) {
43060
43474
  const stored = {
43061
43475
  ...snapshot,
43062
- id: snapshot.id || crypto18.randomUUID(),
43476
+ id: snapshot.id || crypto19.randomUUID(),
43063
43477
  capturedAt: snapshot.capturedAt || (/* @__PURE__ */ new Date()).toISOString()
43064
43478
  };
43065
43479
  this.store.write(stored);
@@ -43132,11 +43546,11 @@ function captureSnapshot(dataDir, principal, projectId, view, artifacts) {
43132
43546
  }
43133
43547
 
43134
43548
  // src/server/sharelinks.ts
43135
- var fs50 = __toESM(require("fs"));
43136
- var path63 = __toESM(require("path"));
43137
- var crypto19 = __toESM(require("crypto"));
43549
+ var fs51 = __toESM(require("fs"));
43550
+ var path64 = __toESM(require("path"));
43551
+ var crypto20 = __toESM(require("crypto"));
43138
43552
  function storePath14(dataDir) {
43139
- return path63.join(dataDir, "share-links.json");
43553
+ return path64.join(dataDir, "share-links.json");
43140
43554
  }
43141
43555
  var ShareLinkStore = class {
43142
43556
  constructor(dataDir) {
@@ -43146,7 +43560,7 @@ var ShareLinkStore = class {
43146
43560
  const p = storePath14(this.dataDir);
43147
43561
  let raw;
43148
43562
  try {
43149
- raw = fs50.readFileSync(p, "utf8");
43563
+ raw = fs51.readFileSync(p, "utf8");
43150
43564
  } catch (err) {
43151
43565
  if (err.code === "ENOENT") return [];
43152
43566
  throw new Error(`Cannot read share-link store at ${p}: ${err.message}`);
@@ -43164,10 +43578,10 @@ var ShareLinkStore = class {
43164
43578
  }
43165
43579
  replaceAll(links) {
43166
43580
  const p = storePath14(this.dataDir);
43167
- fs50.mkdirSync(path63.dirname(p), { recursive: true });
43581
+ fs51.mkdirSync(path64.dirname(p), { recursive: true });
43168
43582
  const tmp = `${p}.tmp`;
43169
- fs50.writeFileSync(tmp, JSON.stringify(links, null, 2) + "\n");
43170
- fs50.renameSync(tmp, p);
43583
+ fs51.writeFileSync(tmp, JSON.stringify(links, null, 2) + "\n");
43584
+ fs51.renameSync(tmp, p);
43171
43585
  }
43172
43586
  };
43173
43587
  var ShareLinkRegistry = class {
@@ -43178,7 +43592,7 @@ var ShareLinkRegistry = class {
43178
43592
  const links = this.store.load();
43179
43593
  const stored = {
43180
43594
  ...link,
43181
- id: link.id || crypto19.randomUUID(),
43595
+ id: link.id || crypto20.randomUUID(),
43182
43596
  createdAt: link.createdAt || (/* @__PURE__ */ new Date()).toISOString()
43183
43597
  };
43184
43598
  this.store.replaceAll([...links, stored]);
@@ -43235,11 +43649,11 @@ function listProjectLinks(dataDir, projectId) {
43235
43649
  }
43236
43650
 
43237
43651
  // src/server/shareaccesslog.ts
43238
- var fs51 = __toESM(require("fs"));
43239
- var path64 = __toESM(require("path"));
43240
- var crypto20 = __toESM(require("crypto"));
43652
+ var fs52 = __toESM(require("fs"));
43653
+ var path65 = __toESM(require("path"));
43654
+ var crypto21 = __toESM(require("crypto"));
43241
43655
  function storePath15(dataDir) {
43242
- return path64.join(dataDir, "share-access.json");
43656
+ return path65.join(dataDir, "share-access.json");
43243
43657
  }
43244
43658
  var ShareAccessStore = class {
43245
43659
  constructor(dataDir) {
@@ -43249,7 +43663,7 @@ var ShareAccessStore = class {
43249
43663
  const p = storePath15(this.dataDir);
43250
43664
  let raw;
43251
43665
  try {
43252
- raw = fs51.readFileSync(p, "utf8");
43666
+ raw = fs52.readFileSync(p, "utf8");
43253
43667
  } catch (err) {
43254
43668
  if (err.code === "ENOENT") return [];
43255
43669
  throw new Error(`Cannot read share-access store at ${p}: ${err.message}`);
@@ -43267,11 +43681,11 @@ var ShareAccessStore = class {
43267
43681
  }
43268
43682
  append(entry) {
43269
43683
  const p = storePath15(this.dataDir);
43270
- fs51.mkdirSync(path64.dirname(p), { recursive: true });
43684
+ fs52.mkdirSync(path65.dirname(p), { recursive: true });
43271
43685
  const next = [...this.load(), entry];
43272
43686
  const tmp = `${p}.tmp`;
43273
- fs51.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n");
43274
- fs51.renameSync(tmp, p);
43687
+ fs52.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n");
43688
+ fs52.renameSync(tmp, p);
43275
43689
  }
43276
43690
  };
43277
43691
  var ShareAccessRegistry = class {
@@ -43281,7 +43695,7 @@ var ShareAccessRegistry = class {
43281
43695
  append(entry) {
43282
43696
  const stored = {
43283
43697
  ...entry,
43284
- id: entry.id || crypto20.randomUUID(),
43698
+ id: entry.id || crypto21.randomUUID(),
43285
43699
  at: entry.at || (/* @__PURE__ */ new Date()).toISOString()
43286
43700
  };
43287
43701
  this.store.append(stored);
@@ -43345,7 +43759,7 @@ function createShareLink(cfg, sessionId, input) {
43345
43759
  const wantsOpenapi = !!input.allowDownloadOpenapi || (input.artifacts ?? []).includes("openapi");
43346
43760
  const artifacts = artifactsFor({ allowDownloadOpenapi: !!input.allowDownloadOpenapi }, wantsOpenapi);
43347
43761
  const snapshot = putSnapshot(cfg.dataDir, captureSnapshot(cfg.dataDir, principal, input.projectId, input.view, artifacts));
43348
- const token = crypto21.randomBytes(32).toString("base64url");
43762
+ const token = crypto22.randomBytes(32).toString("base64url");
43349
43763
  const link = createLink(cfg.dataDir, {
43350
43764
  id: "",
43351
43765
  tokenHash: hashToken(token),
@@ -43422,16 +43836,16 @@ function getShareAccessLog(cfg, sessionId, linkId, limit) {
43422
43836
  init_fs();
43423
43837
 
43424
43838
  // src/server/swagger.ts
43425
- var fs52 = __toESM(require("fs"));
43426
- var path65 = __toESM(require("path"));
43839
+ var fs53 = __toESM(require("fs"));
43840
+ var path66 = __toESM(require("path"));
43427
43841
  var cache;
43428
43842
  function loadAssets() {
43429
43843
  if (cache !== void 0) return cache;
43430
43844
  try {
43431
- const dir = path65.dirname(require.resolve("swagger-ui-dist/package.json"));
43845
+ const dir = path66.dirname(require.resolve("swagger-ui-dist/package.json"));
43432
43846
  cache = {
43433
- css: fs52.readFileSync(path65.join(dir, "swagger-ui.css"), "utf8"),
43434
- js: fs52.readFileSync(path65.join(dir, "swagger-ui-bundle.js"), "utf8")
43847
+ css: fs53.readFileSync(path66.join(dir, "swagger-ui.css"), "utf8"),
43848
+ js: fs53.readFileSync(path66.join(dir, "swagger-ui-bundle.js"), "utf8")
43435
43849
  };
43436
43850
  } catch {
43437
43851
  cache = null;
@@ -43471,7 +43885,7 @@ function getLoginOptions(cfg) {
43471
43885
  async function startSignIn(cfg, providerId, redirectUri) {
43472
43886
  const provider = resolveEnabledProvider(cfg, providerId);
43473
43887
  assertAllowedRedirectUri(provider, redirectUri);
43474
- const nonce = crypto22.randomBytes(16).toString("hex");
43888
+ const nonce = crypto23.randomBytes(16).toString("hex");
43475
43889
  const payload = { providerId, nonce, redirectUri };
43476
43890
  const state = signSsoState(JSON.stringify(payload));
43477
43891
  const endpoints = await resolveEndpoints(provider);
@@ -43830,20 +44244,20 @@ function clearNonceCookie(secure) {
43830
44244
  }
43831
44245
  function nonceMatches(a, b) {
43832
44246
  if (!a || !b || a.length !== b.length) return false;
43833
- return crypto22.timingSafeEqual(Buffer.from(a), Buffer.from(b));
44247
+ return crypto23.timingSafeEqual(Buffer.from(a), Buffer.from(b));
43834
44248
  }
43835
44249
  function loadReactBundle() {
43836
44250
  const candidates = [
43837
- path66.resolve(__dirname, "webapp.html"),
44251
+ path67.resolve(__dirname, "webapp.html"),
43838
44252
  // dist/index.js -> dist/webapp.html
43839
- path66.resolve(__dirname, "..", "webapp.html"),
44253
+ path67.resolve(__dirname, "..", "webapp.html"),
43840
44254
  // dist/cli/index.js -> dist/webapp.html
43841
- path66.resolve(__dirname, "..", "..", "web", "dist", "index.html")
44255
+ path67.resolve(__dirname, "..", "..", "web", "dist", "index.html")
43842
44256
  // tsx dev: src/server -> web/dist
43843
44257
  ];
43844
44258
  for (const candidate of candidates) {
43845
44259
  try {
43846
- if (fs53.existsSync(candidate)) return fs53.readFileSync(candidate, "utf8");
44260
+ if (fs54.existsSync(candidate)) return fs54.readFileSync(candidate, "utf8");
43847
44261
  } catch {
43848
44262
  }
43849
44263
  }
@@ -46417,8 +46831,8 @@ var RealtimeHub = class {
46417
46831
  * complete the handshake, and register the connection. A bad path or session
46418
46832
  * destroys the socket. */
46419
46833
  handleUpgrade(cfg, req, socket) {
46420
- const path72 = (req.url ?? "/").split("?")[0];
46421
- if (path72 !== REALTIME_PATH || !isWebSocketUpgrade(req)) {
46834
+ const path73 = (req.url ?? "/").split("?")[0];
46835
+ if (path73 !== REALTIME_PATH || !isWebSocketUpgrade(req)) {
46422
46836
  socket.destroy();
46423
46837
  return;
46424
46838
  }
@@ -47311,7 +47725,7 @@ function routeData(cfg, req, res) {
47311
47725
  if (req.method === "GET" && url.pathname === "/readyz") {
47312
47726
  let ready = false;
47313
47727
  try {
47314
- fs54.accessSync(cfg.dataDir, fs54.constants.W_OK);
47728
+ fs55.accessSync(cfg.dataDir, fs55.constants.W_OK);
47315
47729
  ready = true;
47316
47730
  } catch {
47317
47731
  }
@@ -47413,7 +47827,7 @@ function routeData(cfg, req, res) {
47413
47827
  }
47414
47828
  function readExposurePolicyFile(dataDir) {
47415
47829
  try {
47416
- const raw = fs54.readFileSync(path67.join(dataDir, "exposure-policy.json"), "utf8");
47830
+ const raw = fs55.readFileSync(path68.join(dataDir, "exposure-policy.json"), "utf8");
47417
47831
  const parsed = JSON.parse(raw);
47418
47832
  return parsed && typeof parsed === "object" ? parsed : void 0;
47419
47833
  } catch {
@@ -48105,9 +48519,9 @@ function seedDemoTree() {
48105
48519
 
48106
48520
  // src/commands/host.ts
48107
48521
  function resolveHostConfig(options) {
48108
- const dataDir = options.dataDir || process.env["WAIRON_DATA_DIR"] || path68.join(os11.homedir(), ".wairon", "data");
48522
+ const dataDir = options.dataDir || process.env["WAIRON_DATA_DIR"] || path69.join(os11.homedir(), ".wairon", "data");
48109
48523
  if (!process.env["WAIRON_PACKS_DIR"]) {
48110
- process.env["WAIRON_PACKS_DIR"] = path68.join(dataDir, "packs");
48524
+ process.env["WAIRON_PACKS_DIR"] = path69.join(dataDir, "packs");
48111
48525
  }
48112
48526
  const cfg = {
48113
48527
  host: options.host || "0.0.0.0",
@@ -48164,11 +48578,11 @@ async function runServe(options = {}) {
48164
48578
  logger.info(` data dir: ${import_chalk17.default.gray(cfg.dataDir)}`);
48165
48579
  logger.blank();
48166
48580
  logger.info("Press Ctrl+C to stop.");
48167
- await new Promise((resolve33) => {
48581
+ await new Promise((resolve34) => {
48168
48582
  const shutdown = () => {
48169
48583
  logger.info("Shutting down\u2026");
48170
48584
  handle.close();
48171
- resolve33();
48585
+ resolve34();
48172
48586
  };
48173
48587
  process.on("SIGINT", shutdown);
48174
48588
  process.on("SIGTERM", shutdown);
@@ -48179,7 +48593,7 @@ function openBrowser(url) {
48179
48593
  const platform = process.platform;
48180
48594
  const cmd = platform === "win32" ? "cmd" : platform === "darwin" ? "open" : "xdg-open";
48181
48595
  const args = platform === "win32" ? ["/c", "start", "", url] : [url];
48182
- const child = (0, import_child_process6.spawn)(cmd, args, { stdio: "ignore", detached: true });
48596
+ const child = (0, import_child_process7.spawn)(cmd, args, { stdio: "ignore", detached: true });
48183
48597
  child.on("error", () => {
48184
48598
  });
48185
48599
  child.unref();
@@ -48188,14 +48602,14 @@ function openBrowser(url) {
48188
48602
  }
48189
48603
  async function runDev(options = {}) {
48190
48604
  const cwd = process.cwd();
48191
- if (!fs55.existsSync(path68.join(cwd, ".wai"))) {
48605
+ if (!fs56.existsSync(path69.join(cwd, ".wai"))) {
48192
48606
  throw new WaironError(
48193
48607
  "No .wai/ found in the current directory. Run `wairon dev` from a wairon project root (or run `wairon init` first)."
48194
48608
  );
48195
48609
  }
48196
- const hash = crypto23.createHash("sha256").update(cwd).digest("hex").slice(0, 16);
48197
- const dataDir = path68.join(os11.tmpdir(), "wairon-dev", hash);
48198
- fs55.mkdirSync(dataDir, { recursive: true });
48610
+ const hash = crypto24.createHash("sha256").update(cwd).digest("hex").slice(0, 16);
48611
+ const dataDir = path69.join(os11.tmpdir(), "wairon-dev", hash);
48612
+ fs56.mkdirSync(dataDir, { recursive: true });
48199
48613
  const port = options.port ? Number(options.port) : 8080;
48200
48614
  const exposurePolicy = {
48201
48615
  adminApiMode: "local_only",
@@ -48233,11 +48647,11 @@ async function runDev(options = {}) {
48233
48647
  logger.blank();
48234
48648
  logger.info("An agent edits specs; refresh the page to see the live graph. Press Ctrl+C to stop.");
48235
48649
  if (options.open) openBrowser(url);
48236
- await new Promise((resolve33) => {
48650
+ await new Promise((resolve34) => {
48237
48651
  const shutdown = () => {
48238
48652
  logger.info("Shutting down\u2026");
48239
48653
  handle.close();
48240
- resolve33();
48654
+ resolve34();
48241
48655
  };
48242
48656
  process.on("SIGINT", shutdown);
48243
48657
  process.on("SIGTERM", shutdown);
@@ -48591,8 +49005,8 @@ async function runHostPacks(action, options = {}) {
48591
49005
  }
48592
49006
  case "install": {
48593
49007
  if (!options.file) throw new WaironError("`--file <path>` (a declarative pack YAML) is required for install.");
48594
- const name = options.name ?? path68.basename(options.file).replace(/\.(ya?ml)$/i, "");
48595
- const content = fs55.readFileSync(path68.resolve(options.file), "utf8");
49008
+ const name = options.name ?? path69.basename(options.file).replace(/\.(ya?ml)$/i, "");
49009
+ const content = fs56.readFileSync(path69.resolve(options.file), "utf8");
48596
49010
  const desc = project2 ? installProjectPack(cfg, cred, project2, name, content) : installGlobalPack(cfg, cred, name, content);
48597
49011
  logger.success(`Installed ${scope} pack "${desc.name}" (${desc.profiles} profile(s), ${desc.languages} language(s)).`);
48598
49012
  if (project2) logger.info("Committed with the project \u2014 every clone and CI will enforce it.");
@@ -48825,8 +49239,8 @@ async function runSurface(action, options = {}) {
48825
49239
  }
48826
49240
 
48827
49241
  // src/commands/remote.ts
48828
- var fs57 = __toESM(require("fs"));
48829
- var path70 = __toESM(require("path"));
49242
+ var fs58 = __toESM(require("fs"));
49243
+ var path71 = __toESM(require("path"));
48830
49244
  var import_chalk20 = __toESM(require("chalk"));
48831
49245
  init_logger();
48832
49246
  init_errors();
@@ -48835,37 +49249,37 @@ init_fs();
48835
49249
  init_mcp();
48836
49250
 
48837
49251
  // src/commands/remotebinding.ts
48838
- var fs56 = __toESM(require("fs"));
49252
+ var fs57 = __toESM(require("fs"));
48839
49253
  var os12 = __toESM(require("os"));
48840
- var path69 = __toESM(require("path"));
49254
+ var path70 = __toESM(require("path"));
48841
49255
  init_paths();
48842
49256
  var BINDING_FILE = "remote.json";
48843
49257
  var CREDENTIALS_FILE = "credentials.json";
48844
49258
  function bindingPath(root) {
48845
- return path69.join(aiPathsAt(root).root(), BINDING_FILE);
49259
+ return path70.join(aiPathsAt(root).root(), BINDING_FILE);
48846
49260
  }
48847
49261
  function credentialsPath() {
48848
- return path69.join(os12.homedir(), ".wairon", CREDENTIALS_FILE);
49262
+ return path70.join(os12.homedir(), ".wairon", CREDENTIALS_FILE);
48849
49263
  }
48850
49264
  function normalizeInstanceUrl(url) {
48851
49265
  return url.trim().replace(/\/+$/, "").toLowerCase();
48852
49266
  }
48853
49267
  function readJson(file) {
48854
49268
  try {
48855
- const text2 = fs56.readFileSync(file, "utf8");
49269
+ const text2 = fs57.readFileSync(file, "utf8");
48856
49270
  return text2 ? JSON.parse(text2) : null;
48857
49271
  } catch {
48858
49272
  return null;
48859
49273
  }
48860
49274
  }
48861
49275
  function writeJsonAtomic(file, value, mode) {
48862
- fs56.mkdirSync(path69.dirname(file), { recursive: true });
49276
+ fs57.mkdirSync(path70.dirname(file), { recursive: true });
48863
49277
  const tmp = `${file}.tmp`;
48864
- fs56.writeFileSync(tmp, JSON.stringify(value, null, 2) + "\n", mode !== void 0 ? { mode } : void 0);
48865
- fs56.renameSync(tmp, file);
49278
+ fs57.writeFileSync(tmp, JSON.stringify(value, null, 2) + "\n", mode !== void 0 ? { mode } : void 0);
49279
+ fs57.renameSync(tmp, file);
48866
49280
  if (mode !== void 0) {
48867
49281
  try {
48868
- fs56.chmodSync(file, mode);
49282
+ fs57.chmodSync(file, mode);
48869
49283
  } catch {
48870
49284
  }
48871
49285
  }
@@ -48887,7 +49301,7 @@ function writeBinding(root, binding) {
48887
49301
  }
48888
49302
  function clearBinding(root) {
48889
49303
  try {
48890
- fs56.rmSync(bindingPath(root), { force: true });
49304
+ fs57.rmSync(bindingPath(root), { force: true });
48891
49305
  } catch {
48892
49306
  }
48893
49307
  }
@@ -49201,7 +49615,7 @@ async function runRemote(action, options = {}) {
49201
49615
  allowPartial: options.allowPartial === true
49202
49616
  };
49203
49617
  if (options.archive) transfer.archivePath = options.archive;
49204
- if (options.dir) transfer.destDir = path70.resolve(options.dir);
49618
+ if (options.dir) transfer.destDir = path71.resolve(options.dir);
49205
49619
  report(await pullTree(target, transfer));
49206
49620
  return;
49207
49621
  }
@@ -49285,10 +49699,10 @@ function topProjectId2(selector) {
49285
49699
  }
49286
49700
  function writeArchiveIfAsked(archive, archivePath, suggestedFileName) {
49287
49701
  if (!archivePath) return void 0;
49288
- const resolved = path70.resolve(archivePath);
49289
- const target = fs57.existsSync(resolved) && fs57.statSync(resolved).isDirectory() ? path70.join(resolved, suggestedFileName) : resolved;
49290
- fs57.mkdirSync(path70.dirname(target), { recursive: true });
49291
- fs57.writeFileSync(target, Buffer.from(archive));
49702
+ const resolved = path71.resolve(archivePath);
49703
+ const target = fs58.existsSync(resolved) && fs58.statSync(resolved).isDirectory() ? path71.join(resolved, suggestedFileName) : resolved;
49704
+ fs58.mkdirSync(path71.dirname(target), { recursive: true });
49705
+ fs58.writeFileSync(target, Buffer.from(archive));
49292
49706
  return target;
49293
49707
  }
49294
49708
  function report(outcome) {
@@ -49703,7 +50117,7 @@ async function runAgent(action, id) {
49703
50117
  }
49704
50118
  case "customize": {
49705
50119
  const brief = composeAgentBrief(id);
49706
- const guidancePath = path71.join(AI_PATHS.root(), "agents", `${id}.md`);
50120
+ const guidancePath = path72.join(AI_PATHS.root(), "agents", `${id}.md`);
49707
50121
  const relPath = `.wai/agents/${id}.md`;
49708
50122
  if (pathExists(guidancePath)) {
49709
50123
  throw new GuidanceFileExistsError(relPath);