@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 +1074 -660
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +3062 -176
- package/dist/index.js.map +1 -1
- package/dist/templates/skills/sdd-implement.md +10 -5
- package/package.json +1 -1
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.
|
|
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
|
|
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,
|
|
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,
|
|
9628
|
-
const cached = cache2.get(
|
|
9627
|
+
const namesAt = (cache2, path73, make) => {
|
|
9628
|
+
const cached = cache2.get(path73);
|
|
9629
9629
|
if (cached) return cached;
|
|
9630
|
-
const f = facts.get(
|
|
9630
|
+
const f = facts.get(path73);
|
|
9631
9631
|
if (!f) return NO_NAMES;
|
|
9632
9632
|
const built = make(f);
|
|
9633
|
-
cache2.set(
|
|
9633
|
+
cache2.set(path73, built);
|
|
9634
9634
|
return built;
|
|
9635
9635
|
};
|
|
9636
9636
|
const republished = /* @__PURE__ */ new Map();
|
|
9637
|
-
const republishedFrom = (
|
|
9638
|
-
const cached = republished.get(
|
|
9637
|
+
const republishedFrom = (path73) => {
|
|
9638
|
+
const cached = republished.get(path73);
|
|
9639
9639
|
if (cached) return cached;
|
|
9640
|
-
const out = /* @__PURE__ */ new Set([
|
|
9641
|
-
const queue = [
|
|
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(
|
|
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
|
|
9664
|
-
const f = facts.get(
|
|
9665
|
-
return f?.status === "analyzed" && f.analysisGrade === "exact" ? { path:
|
|
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 = (
|
|
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: (
|
|
9708
|
+
factsAt: (path73) => facts.get(pathKey(path73)),
|
|
9709
9709
|
declarationsAt,
|
|
9710
|
-
anchorsAt: (
|
|
9711
|
-
findingAnchorsAt: (
|
|
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: (
|
|
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: (
|
|
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 = (
|
|
9765
|
-
const cached = imports.get(
|
|
9764
|
+
const importsOf = (path73) => {
|
|
9765
|
+
const cached = imports.get(path73);
|
|
9766
9766
|
if (cached) return cached;
|
|
9767
|
-
const facts = index.factsAt(
|
|
9767
|
+
const facts = index.factsAt(path73);
|
|
9768
9768
|
const out = /* @__PURE__ */ new Set();
|
|
9769
|
-
if (facts?.status === "analyzed") resolveAll(
|
|
9770
|
-
imports.set(
|
|
9769
|
+
if (facts?.status === "analyzed") resolveAll(path73, facts.imports, out);
|
|
9770
|
+
imports.set(path73, out);
|
|
9771
9771
|
return out;
|
|
9772
9772
|
};
|
|
9773
|
-
const tracesOf = (
|
|
9774
|
-
const cached = traces.get(
|
|
9773
|
+
const tracesOf = (path73) => {
|
|
9774
|
+
const cached = traces.get(path73);
|
|
9775
9775
|
if (cached) return cached;
|
|
9776
|
-
const facts = index.factsAt(
|
|
9777
|
-
const out = new Set(importsOf(
|
|
9778
|
-
if (facts?.status === "analyzed") resolveAll(
|
|
9779
|
-
traces.set(
|
|
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
|
|
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: ${
|
|
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(
|
|
13187
|
-
return
|
|
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
|
|
14477
|
-
const facts = code.factsAt(
|
|
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(
|
|
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 = (
|
|
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 = (
|
|
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(
|
|
15231
|
-
return
|
|
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 = (
|
|
20210
|
-
out.push(`${
|
|
20356
|
+
const say = (path73, why) => {
|
|
20357
|
+
out.push(`${path73} \u2014 ${why}`);
|
|
20211
20358
|
};
|
|
20212
|
-
const walkValue = (d, m, s,
|
|
20359
|
+
const walkValue = (d, m, s, path73, field) => {
|
|
20213
20360
|
if (Array.isArray(d)) {
|
|
20214
20361
|
if (!Array.isArray(m)) {
|
|
20215
|
-
say(
|
|
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(
|
|
20224
|
-
else if (same(s, d)) say(
|
|
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(
|
|
20377
|
+
say(at(path73, key), "the write did not store this element");
|
|
20231
20378
|
continue;
|
|
20232
20379
|
}
|
|
20233
|
-
walk2(element, mMatch, sMatch, at(
|
|
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(
|
|
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,
|
|
20389
|
+
walk2(d, m, s, path73, field);
|
|
20243
20390
|
return;
|
|
20244
20391
|
}
|
|
20245
|
-
if (!same(m, d)) say(
|
|
20246
|
-
else if (same(s, d)) say(
|
|
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,
|
|
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(
|
|
20259
|
-
else if (still) say(at(
|
|
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(
|
|
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
|
|
22601
|
-
|
|
22602
|
-
|
|
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
|
-
/**
|
|
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
|
|
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
|
|
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,
|
|
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.
|
|
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
|
|
27764
|
-
var
|
|
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 =
|
|
27803
|
-
|
|
27804
|
-
|
|
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
|
|
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,
|
|
28047
|
+
walkPackDir(root, path73.join(current2, entry.name), out);
|
|
27817
28048
|
} else if (entry.isFile()) {
|
|
27818
|
-
const absolute =
|
|
27819
|
-
const relative22 =
|
|
27820
|
-
out.push({ path: relative22, contents:
|
|
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
|
|
28128
|
-
const stagedSpecDir = path28.join(stagingDir,
|
|
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,
|
|
28361
|
+
const liveSpecDir = liveSpecDirFor(path28.join(root, relative16));
|
|
28131
28362
|
if (backupExisting && liveSpecDir && fs18.existsSync(liveSpecDir)) {
|
|
28132
|
-
const backupTarget = path28.join(backupDir,
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
30007
|
-
|
|
30008
|
-
|
|
30009
|
-
|
|
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
|
-
|
|
30013
|
-
|
|
30014
|
-
|
|
30015
|
-
|
|
30016
|
-
|
|
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 ? {
|
|
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
|
-
|
|
30026
|
-
|
|
30027
|
-
|
|
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
|
|
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 && (
|
|
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,
|
|
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
|
-
|
|
31327
|
-
|
|
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.
|
|
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(
|
|
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"] ||
|
|
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
|
|
31917
|
+
if (!useGlobal) return path34.join(process.cwd(), ".mcp.json");
|
|
31504
31918
|
const dir = override || process.env["CLAUDE_CONFIG_DIR"];
|
|
31505
|
-
return dir ?
|
|
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 =
|
|
31922
|
+
const resolved = path34.resolve(dir);
|
|
31509
31923
|
const agent = backend === "claude" ? "Claude" : "Gemini/Antigravity";
|
|
31510
|
-
if (!
|
|
31511
|
-
const parent =
|
|
31512
|
-
if (!
|
|
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 (!
|
|
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 =
|
|
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) =>
|
|
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 =
|
|
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 &&
|
|
31540
|
-
resolved =
|
|
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
|
-
|
|
31980
|
+
path34.join(cwd, ".mcp.json"),
|
|
31567
31981
|
claudeMcpConfigPath(true),
|
|
31568
|
-
|
|
31569
|
-
|
|
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 (!
|
|
31577
|
-
const parsed = JSON.parse(
|
|
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 =
|
|
31657
|
-
settingsPath =
|
|
32070
|
+
configBase = path34.join(geminiGlobalDir(options.configDir), "antigravity-cli");
|
|
32071
|
+
settingsPath = path34.join(configBase, "mcp_config.json");
|
|
31658
32072
|
} else {
|
|
31659
|
-
configBase =
|
|
31660
|
-
settingsPath =
|
|
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 =
|
|
32078
|
+
configBase = path34.dirname(settingsPath);
|
|
31665
32079
|
}
|
|
31666
32080
|
let settings = {};
|
|
31667
|
-
if (
|
|
32081
|
+
if (fs23.existsSync(settingsPath)) {
|
|
31668
32082
|
try {
|
|
31669
|
-
settings = JSON.parse(
|
|
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] ?
|
|
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 (!
|
|
31690
|
-
|
|
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 =
|
|
31717
|
-
const geminiGlobal =
|
|
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 (!
|
|
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(
|
|
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 (
|
|
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 =
|
|
32181
|
+
const pluginDir = path34.join(home, ".gemini", "config", "plugins", "wairon");
|
|
31768
32182
|
try {
|
|
31769
|
-
if (
|
|
31770
|
-
|
|
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
|
|
32193
|
+
var fs23, os7, path34, import_chalk3;
|
|
31780
32194
|
var init_mcp = __esm({
|
|
31781
32195
|
"src/commands/mcp.ts"() {
|
|
31782
32196
|
"use strict";
|
|
31783
|
-
|
|
32197
|
+
fs23 = __toESM(require("fs"));
|
|
31784
32198
|
os7 = __toESM(require("os"));
|
|
31785
|
-
|
|
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
|
|
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
|
|
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 &&
|
|
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 =
|
|
32061
|
-
const defaultId =
|
|
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 =
|
|
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 =
|
|
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 ${
|
|
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 ${
|
|
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
|
|
32510
|
-
var
|
|
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) =>
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 ${
|
|
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) =>
|
|
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
|
|
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) =>
|
|
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
|
|
33036
|
-
var
|
|
33449
|
+
var fs26 = __toESM(require("fs"));
|
|
33450
|
+
var path38 = __toESM(require("path"));
|
|
33037
33451
|
var os8 = __toESM(require("os"));
|
|
33038
|
-
var
|
|
33039
|
-
var
|
|
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
|
|
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((
|
|
33051
|
-
const file =
|
|
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(
|
|
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(() =>
|
|
33483
|
+
file.close(() => resolve34());
|
|
33070
33484
|
});
|
|
33071
33485
|
file.on("error", (err) => {
|
|
33072
33486
|
res.destroy();
|
|
33073
|
-
|
|
33487
|
+
fs25.unlink(dest, () => {
|
|
33074
33488
|
});
|
|
33075
33489
|
reject(err);
|
|
33076
33490
|
});
|
|
33077
33491
|
}).on("error", (err) => {
|
|
33078
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
33590
|
+
fs26.unlinkSync(tmpChecksum);
|
|
33177
33591
|
} catch (err) {
|
|
33178
33592
|
logger.error(`Checksum verification failed: ${err.message}`);
|
|
33179
33593
|
try {
|
|
33180
|
-
|
|
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((
|
|
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
|
-
|
|
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 =
|
|
33690
|
+
const checksumContent = fs26.readFileSync(checksumFile, "utf-8").trim();
|
|
33277
33691
|
const expectedHash = checksumContent.split(/\s+/)[0].toLowerCase();
|
|
33278
|
-
const fileBuffer =
|
|
33279
|
-
const actualHash =
|
|
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 =
|
|
33310
|
-
if (
|
|
33311
|
-
|
|
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,
|
|
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,
|
|
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 =
|
|
33322
|
-
if (!
|
|
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
|
-
|
|
33330
|
-
|
|
33743
|
+
fs26.renameSync(destPath, oldPath);
|
|
33744
|
+
fs26.copyFileSync(extractedBinary, destPath);
|
|
33331
33745
|
try {
|
|
33332
|
-
|
|
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
|
-
|
|
33347
|
-
|
|
33348
|
-
|
|
33760
|
+
fs26.copyFileSync(extractedBinary, tmpDest);
|
|
33761
|
+
fs26.chmodSync(tmpDest, 493);
|
|
33762
|
+
fs26.renameSync(tmpDest, destPath);
|
|
33349
33763
|
}
|
|
33350
33764
|
try {
|
|
33351
|
-
|
|
33765
|
+
fs26.unlinkSync(tmpFile);
|
|
33352
33766
|
} catch {
|
|
33353
33767
|
}
|
|
33354
33768
|
try {
|
|
33355
|
-
|
|
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 (
|
|
33776
|
+
if (fs26.existsSync(target)) {
|
|
33363
33777
|
try {
|
|
33364
|
-
|
|
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((
|
|
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
|
-
|
|
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
|
|
34244
|
+
var fs27 = __toESM(require("fs"));
|
|
33831
34245
|
var os9 = __toESM(require("os"));
|
|
33832
|
-
var
|
|
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 (!
|
|
34278
|
+
if (!fs27.existsSync(settingsPath)) return { mark: "warn", note: "not registered" };
|
|
33865
34279
|
let entry;
|
|
33866
34280
|
try {
|
|
33867
|
-
const s = JSON.parse(
|
|
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 (!
|
|
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) =>
|
|
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 =
|
|
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 =
|
|
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 =
|
|
34046
|
-
const leftovers =
|
|
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 =
|
|
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 (
|
|
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 =
|
|
34105
|
-
if (
|
|
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
|
-
|
|
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
|
|
34221
|
-
var
|
|
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
|
|
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 =
|
|
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 ${
|
|
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 =
|
|
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 ${
|
|
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(
|
|
34322
|
-
|
|
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 ??
|
|
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 ??
|
|
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 ??
|
|
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 ??
|
|
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 ??
|
|
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(
|
|
34787
|
+
writeArtifact(path41.join(outDir, file.relPath), toMarkdown(file));
|
|
34374
34788
|
}
|
|
34375
|
-
writeArtifact(
|
|
34376
|
-
writeArtifact(
|
|
34377
|
-
writeArtifact(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
34931
|
+
var fs29 = __toESM(require("fs"));
|
|
34518
34932
|
var os10 = __toESM(require("os"));
|
|
34519
|
-
var
|
|
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 =
|
|
34547
|
-
if (!
|
|
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 =
|
|
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,
|
|
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 =
|
|
34575
|
-
if (
|
|
34576
|
-
|
|
34577
|
-
|
|
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/${
|
|
34591
|
-
const dest =
|
|
34592
|
-
if (
|
|
34593
|
-
|
|
34594
|
-
|
|
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
|
-
|
|
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 =
|
|
34606
|
-
if (!
|
|
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 =
|
|
35035
|
+
baseDir = path42.join(getProjectRoot(), ".wai", "packs");
|
|
34622
35036
|
}
|
|
34623
|
-
const bytes =
|
|
34624
|
-
|
|
34625
|
-
const 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
|
-
|
|
34631
|
-
logger.error(`Failed to extract pack archive "${
|
|
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 =
|
|
34637
|
-
if (
|
|
34638
|
-
|
|
34639
|
-
const probe2 = probePack(destDir,
|
|
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
|
-
|
|
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 ${
|
|
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
|
-
|
|
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 =
|
|
34688
|
-
const dest =
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
34774
|
-
if (!
|
|
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 =
|
|
35193
|
+
const tempDir = fs29.mkdtempSync(path42.join(os10.tmpdir(), "wairon-packinstall-"));
|
|
34780
35194
|
try {
|
|
34781
|
-
const result = (0, import_sdk.extractPack)(new Uint8Array(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
34947
|
-
|
|
34948
|
-
|
|
34949
|
-
|
|
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(
|
|
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,
|
|
35018
|
-
if (probe2.error) console.log(` ${import_chalk16.default.red("\u2716")} ${
|
|
35019
|
-
else console.log(` ${import_chalk16.default.green("\u25CF")} ${import_chalk16.default.bold(probe2.name ??
|
|
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,
|
|
35048
|
-
if (probe2.name === name ||
|
|
35049
|
-
|
|
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 ||
|
|
35484
|
+
if (probe2.name === name || ref === name || path42.basename(ref) === name) {
|
|
35071
35485
|
deregisterPackRef(ref);
|
|
35072
|
-
const resolved =
|
|
35073
|
-
const vendorDir =
|
|
35074
|
-
if (resolved.startsWith(vendorDir +
|
|
35075
|
-
|
|
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
|
|
35089
|
-
var
|
|
35502
|
+
var fs56 = __toESM(require("fs"));
|
|
35503
|
+
var path69 = __toESM(require("path"));
|
|
35090
35504
|
var os11 = __toESM(require("os"));
|
|
35091
|
-
var
|
|
35092
|
-
var
|
|
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
|
|
35512
|
+
var crypto11 = __toESM(require("crypto"));
|
|
35099
35513
|
init_fs();
|
|
35100
35514
|
init_defaults();
|
|
35101
35515
|
|
|
35102
35516
|
// src/server/auth.ts
|
|
35103
|
-
var
|
|
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
|
|
35117
|
-
var
|
|
35118
|
-
var
|
|
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
|
|
35535
|
+
return crypto7.createHash("sha256").update(`${HASH_NS}:${token}`).digest("hex");
|
|
35122
35536
|
}
|
|
35123
35537
|
function storePath(dataDir) {
|
|
35124
|
-
return
|
|
35538
|
+
return path43.join(dataDir, "auth", "credentials.json");
|
|
35125
35539
|
}
|
|
35126
35540
|
function load3(dataDir) {
|
|
35127
35541
|
try {
|
|
35128
|
-
return JSON.parse(
|
|
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
|
-
|
|
35549
|
+
fs30.mkdirSync(path43.dirname(p), { recursive: true });
|
|
35136
35550
|
const tmp = `${p}.tmp`;
|
|
35137
|
-
|
|
35138
|
-
|
|
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
|
|
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
|
|
35184
|
-
var
|
|
35185
|
-
var
|
|
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
|
|
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 =
|
|
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
|
-
|
|
35622
|
+
fs31.mkdirSync(path44.dirname(p), { recursive: true });
|
|
35209
35623
|
const tmp = `${p}.tmp`;
|
|
35210
|
-
|
|
35211
|
-
|
|
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}${
|
|
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
|
|
35373
|
-
var
|
|
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
|
|
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 =
|
|
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
|
-
|
|
35814
|
+
fs32.mkdirSync(path45.dirname(p), { recursive: true });
|
|
35401
35815
|
const tmp = `${p}.tmp`;
|
|
35402
|
-
|
|
35403
|
-
|
|
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
|
|
35506
|
-
var
|
|
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
|
|
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 =
|
|
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
|
-
|
|
35963
|
+
fs33.mkdirSync(path46.dirname(p), { recursive: true });
|
|
35550
35964
|
const tmp = `${p}.tmp`;
|
|
35551
|
-
|
|
35552
|
-
|
|
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
|
|
35609
|
-
var
|
|
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 ?
|
|
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(
|
|
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
|
-
|
|
36063
|
+
fs34.mkdirSync(path47.dirname(p), { recursive: true });
|
|
35650
36064
|
const tmp = `${p}.tmp`;
|
|
35651
|
-
|
|
35652
|
-
|
|
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 &&
|
|
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 &&
|
|
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 =
|
|
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 =
|
|
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 || !
|
|
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 =
|
|
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 =
|
|
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 || !
|
|
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
|
|
35861
|
-
var
|
|
35862
|
-
var
|
|
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
|
|
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 =
|
|
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
|
-
|
|
36301
|
+
fs35.mkdirSync(path48.dirname(p), { recursive: true });
|
|
35888
36302
|
const tmp = `${p}.tmp`;
|
|
35889
|
-
|
|
35890
|
-
|
|
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 ||
|
|
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
|
|
36267
|
-
var
|
|
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
|
|
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 =
|
|
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
|
-
|
|
36711
|
+
fs36.mkdirSync(path49.dirname(p), { recursive: true });
|
|
36298
36712
|
const tmp = `${p}.tmp`;
|
|
36299
|
-
|
|
36300
|
-
|
|
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
|
|
36387
|
-
var
|
|
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
|
|
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 =
|
|
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
|
-
|
|
36843
|
+
fs37.mkdirSync(path50.dirname(p), { recursive: true });
|
|
36430
36844
|
const tmp = `${p}.tmp`;
|
|
36431
|
-
|
|
36432
|
-
|
|
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
|
|
36667
|
-
var
|
|
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
|
|
37095
|
+
return path51.join(dataDir, "projects.json");
|
|
36682
37096
|
}
|
|
36683
37097
|
function load6(dataDir) {
|
|
36684
37098
|
try {
|
|
36685
|
-
return JSON.parse(
|
|
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
|
-
|
|
37106
|
+
fs38.mkdirSync(path51.dirname(p), { recursive: true });
|
|
36693
37107
|
const tmp = `${p}.tmp`;
|
|
36694
|
-
|
|
36695
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 (!
|
|
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
|
|
36851
|
-
var
|
|
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(
|
|
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
|
-
|
|
37279
|
+
fs39.mkdirSync(path52.dirname(p), { recursive: true });
|
|
36866
37280
|
const tmp = `${p}.tmp`;
|
|
36867
|
-
|
|
36868
|
-
|
|
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
|
-
|
|
37286
|
+
fs39.rmSync(configPath(), { force: true });
|
|
36873
37287
|
} catch {
|
|
36874
37288
|
}
|
|
36875
37289
|
}
|
|
36876
37290
|
|
|
36877
37291
|
// src/git/adapter.ts
|
|
36878
|
-
var
|
|
36879
|
-
var
|
|
36880
|
-
var
|
|
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,
|
|
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 =
|
|
37345
|
+
const excludePath = path53.join(getProjectRoot(), ".git", "info", "exclude");
|
|
36932
37346
|
try {
|
|
36933
|
-
|
|
36934
|
-
const existing =
|
|
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
|
-
|
|
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
|
|
37012
|
-
var
|
|
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(
|
|
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
|
-
|
|
37440
|
+
fs41.mkdirSync(path54.dirname(p), { recursive: true });
|
|
37027
37441
|
const tmp = `${p}.tmp`;
|
|
37028
|
-
|
|
37029
|
-
|
|
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_" +
|
|
37867
|
+
const token = "wk_" + crypto11.randomBytes(24).toString("hex");
|
|
37454
37868
|
const record2 = {
|
|
37455
|
-
id:
|
|
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
|
|
37705
|
-
var
|
|
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(
|
|
38175
|
+
assertDeclarative(fs42.readFileSync(path55.join(result.directory, result.entryPath), "utf8"));
|
|
37762
38176
|
} catch (e) {
|
|
37763
|
-
|
|
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:
|
|
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] ??
|
|
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
|
-
|
|
38201
|
+
fs42.mkdirSync(path55.dirname(file), { recursive: true });
|
|
37788
38202
|
const tmp = `${file}.tmp`;
|
|
37789
|
-
|
|
37790
|
-
|
|
38203
|
+
fs42.writeFileSync(tmp, content);
|
|
38204
|
+
fs42.renameSync(tmp, file);
|
|
37791
38205
|
}
|
|
37792
38206
|
function stem(ref) {
|
|
37793
|
-
return
|
|
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,
|
|
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" }],
|
|
38232
|
+
const loaded = loadExtensionPacks([{ ref: full, scope: "global" }], path55.dirname(full));
|
|
37819
38233
|
if (loaded.errors.length) continue;
|
|
37820
|
-
const source = loaded.packNames[0] ??
|
|
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 =
|
|
37873
|
-
if (st.isFile()) return
|
|
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 =
|
|
37877
|
-
if (
|
|
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,
|
|
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),
|
|
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 =
|
|
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 =
|
|
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 ||
|
|
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,
|
|
37951
|
-
const match = pickByName(discoverPacks(dir), name,
|
|
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 ||
|
|
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
|
-
|
|
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(
|
|
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,
|
|
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 =
|
|
37993
|
-
const vendorDir =
|
|
37994
|
-
if (resolved.startsWith(vendorDir +
|
|
37995
|
-
|
|
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 ||
|
|
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
|
|
38132
|
-
var
|
|
38133
|
-
var
|
|
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
|
|
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 =
|
|
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
|
-
|
|
38590
|
+
fs43.mkdirSync(path56.dirname(p), { recursive: true });
|
|
38177
38591
|
const tmp = `${p}.tmp`;
|
|
38178
|
-
|
|
38179
|
-
|
|
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 :
|
|
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
|
|
38918
|
+
var crypto14 = __toESM(require("crypto"));
|
|
38505
38919
|
|
|
38506
38920
|
// src/server/idp.ts
|
|
38507
|
-
var
|
|
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 =
|
|
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
|
|
39156
|
+
return crypto13.verify(digest2, data, keyObject, sig);
|
|
38743
39157
|
}
|
|
38744
39158
|
if (alg.startsWith("PS")) {
|
|
38745
|
-
return
|
|
39159
|
+
return crypto13.verify(
|
|
38746
39160
|
digest2,
|
|
38747
39161
|
data,
|
|
38748
|
-
{ key: keyObject, padding:
|
|
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
|
|
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
|
|
38868
|
-
var
|
|
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
|
|
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 =
|
|
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
|
-
|
|
39319
|
+
fs44.mkdirSync(path57.dirname(p), { recursive: true });
|
|
38906
39320
|
const tmp = `${p}.tmp`;
|
|
38907
|
-
|
|
38908
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
39356
|
+
fs44.mkdirSync(path57.dirname(p), { recursive: true });
|
|
38943
39357
|
const tmp = `${p}.tmp`;
|
|
38944
|
-
|
|
38945
|
-
|
|
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
|
|
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
|
-
|
|
39401
|
+
fs44.mkdirSync(path57.dirname(p), { recursive: true });
|
|
38988
39402
|
const tmp = `${p}.tmp`;
|
|
38989
|
-
|
|
38990
|
-
|
|
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 =
|
|
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_" +
|
|
40043
|
+
const token = "wk_" + crypto14.randomBytes(24).toString("hex");
|
|
39630
40044
|
const record2 = {
|
|
39631
|
-
id:
|
|
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_" +
|
|
40089
|
+
const token = "wk_" + crypto14.randomBytes(24).toString("hex");
|
|
39676
40090
|
const owner = auditActor(principal);
|
|
39677
40091
|
const record2 = {
|
|
39678
|
-
id:
|
|
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 =
|
|
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_" +
|
|
40258
|
+
const token = "wk_" + crypto14.randomBytes(24).toString("hex");
|
|
39845
40259
|
const record2 = {
|
|
39846
|
-
id:
|
|
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
|
|
40035
|
-
var
|
|
40036
|
-
var
|
|
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
|
|
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 =
|
|
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
|
-
|
|
40473
|
+
fs45.mkdirSync(path58.dirname(p), { recursive: true });
|
|
40060
40474
|
const tmp = `${p}.tmp`;
|
|
40061
|
-
|
|
40062
|
-
|
|
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 :
|
|
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
|
|
40173
|
-
var
|
|
40586
|
+
var fs46 = __toESM(require("fs"));
|
|
40587
|
+
var path59 = __toESM(require("path"));
|
|
40174
40588
|
function storePath11(dataDir) {
|
|
40175
|
-
return
|
|
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 =
|
|
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
|
-
|
|
40610
|
+
fs46.mkdirSync(path59.dirname(p), { recursive: true });
|
|
40197
40611
|
const tmp = `${p}.tmp`;
|
|
40198
|
-
|
|
40199
|
-
|
|
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
|
|
40343
|
-
if (!
|
|
40344
|
-
const closedOk =
|
|
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(
|
|
40347
|
-
if (crossTenant && !
|
|
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
|
|
40997
|
-
var
|
|
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(
|
|
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
|
-
|
|
41449
|
+
fs47.mkdirSync(path60.dirname(file), { recursive: true });
|
|
41036
41450
|
const tmp = `${file}.tmp`;
|
|
41037
|
-
|
|
41038
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
41289
|
-
var
|
|
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
|
|
41303
|
-
var
|
|
41304
|
-
var
|
|
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
|
|
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 =
|
|
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
|
-
|
|
41741
|
+
fs48.mkdirSync(path61.dirname(p), { recursive: true });
|
|
41328
41742
|
const tmp = `${p}.tmp`;
|
|
41329
|
-
|
|
41330
|
-
|
|
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:
|
|
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((
|
|
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
|
|
42139
|
-
var
|
|
42140
|
-
var
|
|
42141
|
-
var
|
|
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
|
|
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 =
|
|
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
|
-
|
|
42588
|
+
fs49.mkdirSync(path62.dirname(p), { recursive: true });
|
|
42175
42589
|
const tmp = `${p}.tmp`;
|
|
42176
|
-
|
|
42177
|
-
|
|
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 ||
|
|
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,
|
|
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 (!
|
|
42283
|
-
|
|
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
|
-
|
|
42296
|
-
const stat =
|
|
42709
|
+
fs49.rmSync(targetDir, { recursive: true, force: true });
|
|
42710
|
+
const stat = fs49.statSync(sourceDir, { throwIfNoEntry: false });
|
|
42297
42711
|
if (!stat) return;
|
|
42298
|
-
|
|
42299
|
-
|
|
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 =
|
|
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 =
|
|
42430
|
-
|
|
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(
|
|
42847
|
+
mirrorTree(path62.join(rec.rootPath, ".wai"), path62.join(projectsDir, rec.id, ".wai"));
|
|
42434
42848
|
}
|
|
42435
42849
|
} else {
|
|
42436
|
-
const instanceDir =
|
|
42437
|
-
|
|
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(
|
|
42854
|
+
mirrorTree(path62.join(cfg.dataDir, rel2), path62.join(instanceDir, rel2));
|
|
42441
42855
|
}
|
|
42442
|
-
const projectsDir =
|
|
42443
|
-
|
|
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(
|
|
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
|
|
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 =
|
|
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
|
|
42762
|
-
var
|
|
42763
|
-
var
|
|
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
|
|
43428
|
+
var crypto22 = __toESM(require("crypto"));
|
|
43015
43429
|
|
|
43016
43430
|
// src/server/sharesnapshots.ts
|
|
43017
|
-
var
|
|
43018
|
-
var
|
|
43019
|
-
var
|
|
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
|
|
43436
|
+
return path63.join(dataDir, "share-snapshots");
|
|
43023
43437
|
}
|
|
43024
43438
|
function snapshotPath(dataDir, id) {
|
|
43025
|
-
return
|
|
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 (
|
|
43034
|
-
|
|
43447
|
+
if (fs50.existsSync(p)) return;
|
|
43448
|
+
fs50.mkdirSync(path63.dirname(p), { recursive: true });
|
|
43035
43449
|
const tmp = `${p}.tmp`;
|
|
43036
|
-
|
|
43037
|
-
|
|
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 =
|
|
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 ||
|
|
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
|
|
43136
|
-
var
|
|
43137
|
-
var
|
|
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
|
|
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 =
|
|
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
|
-
|
|
43581
|
+
fs51.mkdirSync(path64.dirname(p), { recursive: true });
|
|
43168
43582
|
const tmp = `${p}.tmp`;
|
|
43169
|
-
|
|
43170
|
-
|
|
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 ||
|
|
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
|
|
43239
|
-
var
|
|
43240
|
-
var
|
|
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
|
|
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 =
|
|
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
|
-
|
|
43684
|
+
fs52.mkdirSync(path65.dirname(p), { recursive: true });
|
|
43271
43685
|
const next = [...this.load(), entry];
|
|
43272
43686
|
const tmp = `${p}.tmp`;
|
|
43273
|
-
|
|
43274
|
-
|
|
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 ||
|
|
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 =
|
|
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
|
|
43426
|
-
var
|
|
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 =
|
|
43845
|
+
const dir = path66.dirname(require.resolve("swagger-ui-dist/package.json"));
|
|
43432
43846
|
cache = {
|
|
43433
|
-
css:
|
|
43434
|
-
js:
|
|
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 =
|
|
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
|
|
44247
|
+
return crypto23.timingSafeEqual(Buffer.from(a), Buffer.from(b));
|
|
43834
44248
|
}
|
|
43835
44249
|
function loadReactBundle() {
|
|
43836
44250
|
const candidates = [
|
|
43837
|
-
|
|
44251
|
+
path67.resolve(__dirname, "webapp.html"),
|
|
43838
44252
|
// dist/index.js -> dist/webapp.html
|
|
43839
|
-
|
|
44253
|
+
path67.resolve(__dirname, "..", "webapp.html"),
|
|
43840
44254
|
// dist/cli/index.js -> dist/webapp.html
|
|
43841
|
-
|
|
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 (
|
|
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
|
|
46421
|
-
if (
|
|
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
|
-
|
|
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 =
|
|
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"] ||
|
|
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"] =
|
|
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((
|
|
48581
|
+
await new Promise((resolve34) => {
|
|
48168
48582
|
const shutdown = () => {
|
|
48169
48583
|
logger.info("Shutting down\u2026");
|
|
48170
48584
|
handle.close();
|
|
48171
|
-
|
|
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,
|
|
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 (!
|
|
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 =
|
|
48197
|
-
const dataDir =
|
|
48198
|
-
|
|
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((
|
|
48650
|
+
await new Promise((resolve34) => {
|
|
48237
48651
|
const shutdown = () => {
|
|
48238
48652
|
logger.info("Shutting down\u2026");
|
|
48239
48653
|
handle.close();
|
|
48240
|
-
|
|
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 ??
|
|
48595
|
-
const content =
|
|
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
|
|
48829
|
-
var
|
|
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
|
|
49252
|
+
var fs57 = __toESM(require("fs"));
|
|
48839
49253
|
var os12 = __toESM(require("os"));
|
|
48840
|
-
var
|
|
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
|
|
49259
|
+
return path70.join(aiPathsAt(root).root(), BINDING_FILE);
|
|
48846
49260
|
}
|
|
48847
49261
|
function credentialsPath() {
|
|
48848
|
-
return
|
|
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 =
|
|
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
|
-
|
|
49276
|
+
fs57.mkdirSync(path70.dirname(file), { recursive: true });
|
|
48863
49277
|
const tmp = `${file}.tmp`;
|
|
48864
|
-
|
|
48865
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
49289
|
-
const target =
|
|
49290
|
-
|
|
49291
|
-
|
|
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 =
|
|
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);
|