@wairon/cli 5.1.1-dev.49 → 5.1.1-dev.50
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 +128 -13
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +85 -10
- package/dist/index.js.map +1 -1
- 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.50";
|
|
69
69
|
GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
70
70
|
SUPPORTED_ALIASES = ["wai"];
|
|
71
71
|
SCAN_EXCLUDE_DIRS = /* @__PURE__ */ new Set([
|
|
@@ -934,6 +934,17 @@ var init_project = __esm({
|
|
|
934
934
|
* carried as debt.
|
|
935
935
|
*/
|
|
936
936
|
exclude: import_zod4.z.array(import_zod4.z.string()).optional(),
|
|
937
|
+
/**
|
|
938
|
+
* Project-relative directories holding this project's TESTS. Declaring none
|
|
939
|
+
* means no test scan and no `testsToRevisit` on any write — opt-in on the
|
|
940
|
+
* same terms as `sourceRoots`, so a project that never asked for it never
|
|
941
|
+
* pays for it.
|
|
942
|
+
*
|
|
943
|
+
* Separate from `sourceRoots` deliberately: tests are not code the specs are
|
|
944
|
+
* expected to claim, and putting them there would make every test file an
|
|
945
|
+
* UNCLAIMED_SOURCE_FILE.
|
|
946
|
+
*/
|
|
947
|
+
testRoots: import_zod4.z.array(import_zod4.z.string()).optional(),
|
|
937
948
|
/**
|
|
938
949
|
* The files under the source roots that no spec names yet, frozen. A listed
|
|
939
950
|
* file is not reported; an unlisted one is UNCLAIMED_SOURCE_FILE; an entry
|
|
@@ -15821,6 +15832,17 @@ function stripComments(text2, patterns) {
|
|
|
15821
15832
|
function escapeRe(s) {
|
|
15822
15833
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
15823
15834
|
}
|
|
15835
|
+
function boundNames(captured, localOnly) {
|
|
15836
|
+
const names = [];
|
|
15837
|
+
for (const piece of captured.split(",")) {
|
|
15838
|
+
const sides = piece.split(" as ");
|
|
15839
|
+
for (const side of localOnly ? sides.slice(-1) : sides) {
|
|
15840
|
+
const name = side.trim();
|
|
15841
|
+
if (/^[A-Za-z_$][\w$]*$/.test(name)) names.push(name);
|
|
15842
|
+
}
|
|
15843
|
+
}
|
|
15844
|
+
return names;
|
|
15845
|
+
}
|
|
15824
15846
|
function collectStrings(text2) {
|
|
15825
15847
|
const anchors = /* @__PURE__ */ new Set();
|
|
15826
15848
|
for (const m of text2.matchAll(STRING_RE)) {
|
|
@@ -15838,10 +15860,7 @@ function analyzeWithPatterns(text2, patterns) {
|
|
|
15838
15860
|
for (const m of stripped.matchAll(re)) {
|
|
15839
15861
|
const captured = m[1];
|
|
15840
15862
|
if (!captured) continue;
|
|
15841
|
-
for (const
|
|
15842
|
-
const name = (piece.includes(" as ") ? piece.split(" as ")[1] : piece).trim();
|
|
15843
|
-
if (name && /^[A-Za-z_$][\w$]*$/.test(name)) declared.add(name);
|
|
15844
|
-
}
|
|
15863
|
+
for (const name of boundNames(captured, true)) declared.add(name);
|
|
15845
15864
|
}
|
|
15846
15865
|
}
|
|
15847
15866
|
for (const re of patterns.imports) {
|
|
@@ -15856,6 +15875,7 @@ function analyzeWithPatterns(text2, patterns) {
|
|
|
15856
15875
|
for (const re of patterns.declarations) {
|
|
15857
15876
|
re.lastIndex = 0;
|
|
15858
15877
|
const m = re.exec(line2);
|
|
15878
|
+
re.lastIndex = 0;
|
|
15859
15879
|
if (m?.[1]) exported.add(m[1]);
|
|
15860
15880
|
}
|
|
15861
15881
|
}
|
|
@@ -16173,7 +16193,7 @@ function looksBinary(buffer) {
|
|
|
16173
16193
|
const probe2 = buffer.subarray(0, Math.min(buffer.length, 4096));
|
|
16174
16194
|
return probe2.includes(0);
|
|
16175
16195
|
}
|
|
16176
|
-
function
|
|
16196
|
+
function walkDeclaredRoots(roots, exclude, projectRoot2) {
|
|
16177
16197
|
const found = [];
|
|
16178
16198
|
const seen = /* @__PURE__ */ new Set();
|
|
16179
16199
|
const excluded = exclude.map(pathKey);
|
|
@@ -16203,7 +16223,7 @@ function walkSourceRoots(sourceRoots, exclude, projectRoot2) {
|
|
|
16203
16223
|
}
|
|
16204
16224
|
}
|
|
16205
16225
|
};
|
|
16206
|
-
for (const root of
|
|
16226
|
+
for (const root of roots) {
|
|
16207
16227
|
const key = pathKey(root);
|
|
16208
16228
|
if (path13.isAbsolute(key) || path13.normalize(key).split(path13.sep)[0] === "..") continue;
|
|
16209
16229
|
const absolute = path13.resolve(projectRoot2, key);
|
|
@@ -16224,7 +16244,7 @@ function buildCodeModel(implementations, types, projectRoot2, sourceRoots = [],
|
|
|
16224
16244
|
const files = [];
|
|
16225
16245
|
const seen = /* @__PURE__ */ new Set();
|
|
16226
16246
|
const exactCache = /* @__PURE__ */ new Map();
|
|
16227
|
-
const rootFiles =
|
|
16247
|
+
const rootFiles = walkDeclaredRoots(sourceRoots, exclude, projectRoot2);
|
|
16228
16248
|
const declaredPaths = [];
|
|
16229
16249
|
for (const impl of implementations) {
|
|
16230
16250
|
declaredPaths.push(...implementationSourceFiles(impl));
|
|
@@ -16302,7 +16322,49 @@ function buildCodeModel(implementations, types, projectRoot2, sourceRoots = [],
|
|
|
16302
16322
|
}
|
|
16303
16323
|
return { files, projectRoot: projectRoot2, rootFiles };
|
|
16304
16324
|
}
|
|
16305
|
-
|
|
16325
|
+
function readTestFiles(testRoots, projectRoot2) {
|
|
16326
|
+
const scanned = [];
|
|
16327
|
+
for (const key of walkDeclaredRoots(testRoots, [], projectRoot2)) {
|
|
16328
|
+
let text2;
|
|
16329
|
+
try {
|
|
16330
|
+
const buffer = fs10.readFileSync(path13.resolve(projectRoot2, key));
|
|
16331
|
+
if (looksBinary(buffer)) continue;
|
|
16332
|
+
text2 = buffer.toString("utf8");
|
|
16333
|
+
} catch {
|
|
16334
|
+
continue;
|
|
16335
|
+
}
|
|
16336
|
+
const imports = /* @__PURE__ */ new Set();
|
|
16337
|
+
for (const m of text2.matchAll(NAMED_IMPORT_BINDINGS_RE)) {
|
|
16338
|
+
for (const name of boundNames(m[1] ?? "", false)) imports.add(name);
|
|
16339
|
+
}
|
|
16340
|
+
const words2 = /* @__PURE__ */ new Set();
|
|
16341
|
+
for (const m of text2.matchAll(IDENTIFIER_RE)) words2.add(m[0]);
|
|
16342
|
+
scanned.push({ path: key, imports, words: words2 });
|
|
16343
|
+
}
|
|
16344
|
+
return scanned;
|
|
16345
|
+
}
|
|
16346
|
+
function findTestsReferencing(methods, projectRoot2, testRoots = []) {
|
|
16347
|
+
const scanned = readTestFiles(testRoots, projectRoot2);
|
|
16348
|
+
if (scanned.length === 0) return [];
|
|
16349
|
+
const indiscriminateAbove = scanned.length / 10;
|
|
16350
|
+
const found = [];
|
|
16351
|
+
for (const method2 of methods) {
|
|
16352
|
+
const symbol = method2.symbol ?? method2.name;
|
|
16353
|
+
const imported = scanned.filter((f) => f.imports.has(symbol)).map((f) => f.path);
|
|
16354
|
+
const mentioned = scanned.filter((f) => !f.imports.has(symbol) && f.words.has(symbol)).map((f) => f.path);
|
|
16355
|
+
const indiscriminate = mentioned.length > indiscriminateAbove;
|
|
16356
|
+
if (imported.length === 0 && mentioned.length === 0) continue;
|
|
16357
|
+
found.push({
|
|
16358
|
+
method: method2.name,
|
|
16359
|
+
symbol,
|
|
16360
|
+
imported,
|
|
16361
|
+
mentioned: indiscriminate ? [] : mentioned,
|
|
16362
|
+
indiscriminate
|
|
16363
|
+
});
|
|
16364
|
+
}
|
|
16365
|
+
return found;
|
|
16366
|
+
}
|
|
16367
|
+
var fs10, path13, import_module2, EXTENSION_LANGUAGE, C_FAMILY_COMMENTS, NAMED_IMPORT_BINDINGS_RE, JS_PATTERNS, LANGUAGE_PATTERNS, PATTERN_ANALYSIS_MAX_BYTES, IDENTIFIER_RE, STRING_RE, tsResolutionCache, TS_RESOLUTION_RETRY_MS;
|
|
16306
16368
|
var init_source_analysis = __esm({
|
|
16307
16369
|
"src/core/source-analysis.ts"() {
|
|
16308
16370
|
"use strict";
|
|
@@ -16335,6 +16397,7 @@ var init_source_analysis = __esm({
|
|
|
16335
16397
|
".swift": "swift"
|
|
16336
16398
|
};
|
|
16337
16399
|
C_FAMILY_COMMENTS = { lineComments: ["//"], blockComments: [["/*", "*/"]] };
|
|
16400
|
+
NAMED_IMPORT_BINDINGS_RE = /\bimport\s*\{([^}]*)\}/g;
|
|
16338
16401
|
JS_PATTERNS = {
|
|
16339
16402
|
...C_FAMILY_COMMENTS,
|
|
16340
16403
|
declarations: [
|
|
@@ -16344,7 +16407,7 @@ var init_source_analysis = __esm({
|
|
|
16344
16407
|
/([A-Za-z_$][\w$]*)\s*[:=]\s*(?:async\s+)?(?:function\b|\()/g,
|
|
16345
16408
|
/(?:^|\s)(?:public|private|protected|static|async|get|set)\s+([A-Za-z_$][\w$]*)\s*\(/g,
|
|
16346
16409
|
// named import bindings realize forwarding adapters
|
|
16347
|
-
|
|
16410
|
+
NAMED_IMPORT_BINDINGS_RE
|
|
16348
16411
|
],
|
|
16349
16412
|
imports: [
|
|
16350
16413
|
/\b(?:import|export)\b[^'"\n]*['"]([^'"]+)['"]/g,
|
|
@@ -23097,6 +23160,7 @@ var init_gate_identity = __esm({
|
|
|
23097
23160
|
var validation_exports = {};
|
|
23098
23161
|
__export(validation_exports, {
|
|
23099
23162
|
computeGateStateId: () => computeGateStateId,
|
|
23163
|
+
findTestsReferencing: () => findTestsReferencing2,
|
|
23100
23164
|
listRules: () => listRules2,
|
|
23101
23165
|
loadProjectConfig: () => loadProjectConfig3,
|
|
23102
23166
|
validateAsComplete: () => validateAsComplete,
|
|
@@ -23121,6 +23185,9 @@ function projectPackSelections() {
|
|
|
23121
23185
|
return [];
|
|
23122
23186
|
}
|
|
23123
23187
|
}
|
|
23188
|
+
function findTestsReferencing2(methods, projectRoot2, testRoots = []) {
|
|
23189
|
+
return findTestsReferencing(methods, projectRoot2, testRoots);
|
|
23190
|
+
}
|
|
23124
23191
|
function issueKey(issue2) {
|
|
23125
23192
|
return `${issue2.code}|${issue2.specId ?? ""}`;
|
|
23126
23193
|
}
|
|
@@ -24887,6 +24954,7 @@ function moveChangeReports(edits, dryRun) {
|
|
|
24887
24954
|
changes,
|
|
24888
24955
|
ineffective: [],
|
|
24889
24956
|
notices: [],
|
|
24957
|
+
testsToRevisit: [],
|
|
24890
24958
|
summary: `${dryRun ? "Would move" : "Moved"} into ${edit.kind} "${edit.id}": ${changes.length} change${changes.length === 1 ? "" : "s"}.`
|
|
24891
24959
|
}));
|
|
24892
24960
|
}
|
|
@@ -26951,6 +27019,7 @@ var init_specs2 = __esm({
|
|
|
26951
27019
|
changes,
|
|
26952
27020
|
ineffective,
|
|
26953
27021
|
notices,
|
|
27022
|
+
testsToRevisit: [],
|
|
26954
27023
|
summary: `No change to ${kind} "${id}" \u2014 the delta matches what is stored, so nothing ${dryRun ? "would be" : "was"} written.`
|
|
26955
27024
|
};
|
|
26956
27025
|
}
|
|
@@ -26965,6 +27034,7 @@ var init_specs2 = __esm({
|
|
|
26965
27034
|
changes,
|
|
26966
27035
|
ineffective,
|
|
26967
27036
|
notices,
|
|
27037
|
+
testsToRevisit: [],
|
|
26968
27038
|
summary: `Dry run on ${kind} "${id}": ${changes.length} change${changes.length === 1 ? "" : "s"} would be made. Nothing was written.`
|
|
26969
27039
|
};
|
|
26970
27040
|
}
|
|
@@ -27000,6 +27070,10 @@ var init_specs2 = __esm({
|
|
|
27000
27070
|
changes,
|
|
27001
27071
|
ineffective,
|
|
27002
27072
|
notices,
|
|
27073
|
+
// The store never searches for tests: it holds the tree and knows
|
|
27074
|
+
// nothing about the rule engine that reads code. The GATED write above
|
|
27075
|
+
// it fills this in, which is also the only write path a human drives.
|
|
27076
|
+
testsToRevisit: [],
|
|
27003
27077
|
summary: `Updated ${kind} "${id}": ${changes.length} change${changes.length === 1 ? "" : "s"}.`
|
|
27004
27078
|
};
|
|
27005
27079
|
}
|
|
@@ -28228,11 +28302,11 @@ function candidateOptions() {
|
|
|
28228
28302
|
function noticesFrom(verdict) {
|
|
28229
28303
|
return verdict.warnings.map((w) => `${w.code}: ${w.message}`);
|
|
28230
28304
|
}
|
|
28231
|
-
function componentCandidateGate() {
|
|
28305
|
+
function componentCandidateGate(options = candidateOptions()) {
|
|
28232
28306
|
return {
|
|
28233
28307
|
gate: (kind, merged) => {
|
|
28234
28308
|
if (kind !== "component") return;
|
|
28235
|
-
const verdict = validateComponentCandidate(merged,
|
|
28309
|
+
const verdict = validateComponentCandidate(merged, options);
|
|
28236
28310
|
if (verdict.errors.length) throw new Error(formatCandidateRefusal(verdict));
|
|
28237
28311
|
return noticesFrom(verdict);
|
|
28238
28312
|
}
|
|
@@ -28244,7 +28318,27 @@ function addComponent(candidate) {
|
|
|
28244
28318
|
return [...noticesFrom(verdict), ...saveComponentSpec(candidate)];
|
|
28245
28319
|
}
|
|
28246
28320
|
function updateSpecGated(kind, id, delta, dryRun) {
|
|
28247
|
-
|
|
28321
|
+
const bound2 = candidateOptions();
|
|
28322
|
+
const gate = componentCandidateGate(bound2);
|
|
28323
|
+
const report2 = updateSpec(kind, id, delta, gate, dryRun);
|
|
28324
|
+
const testRoots = bound2.rules?.conformance?.testRoots ?? [];
|
|
28325
|
+
const changed = changedMethods(report2, delta);
|
|
28326
|
+
if (changed.length > 0 && testRoots.length > 0) {
|
|
28327
|
+
report2.testsToRevisit = findTestsReferencing2(changed, getProjectRoot(), testRoots);
|
|
28328
|
+
}
|
|
28329
|
+
return report2;
|
|
28330
|
+
}
|
|
28331
|
+
function changedMethods(report2, delta) {
|
|
28332
|
+
const named = /* @__PURE__ */ new Set();
|
|
28333
|
+
for (const change of report2.changes) {
|
|
28334
|
+
const [field, name] = change.path.split(".");
|
|
28335
|
+
if (field === "methods" && name) named.add(name);
|
|
28336
|
+
}
|
|
28337
|
+
const written = Array.isArray(delta?.methods) ? delta.methods : [];
|
|
28338
|
+
return [...named].map((name) => ({
|
|
28339
|
+
name,
|
|
28340
|
+
symbol: written.find((m) => m?.name === name)?.symbol
|
|
28341
|
+
}));
|
|
28248
28342
|
}
|
|
28249
28343
|
function methodMoveGate(source) {
|
|
28250
28344
|
const bound2 = candidateOptions();
|
|
@@ -28279,6 +28373,7 @@ var init_authoring = __esm({
|
|
|
28279
28373
|
init_validation();
|
|
28280
28374
|
init_candidate();
|
|
28281
28375
|
init_core();
|
|
28376
|
+
init_fs();
|
|
28282
28377
|
}
|
|
28283
28378
|
});
|
|
28284
28379
|
|
|
@@ -28386,6 +28481,17 @@ function renderChangeReport(report2) {
|
|
|
28386
28481
|
lines.push("", "NO EFFECT:", ...report2.ineffective.map((i) => `- ${i}`));
|
|
28387
28482
|
}
|
|
28388
28483
|
if (report2.notices.length) lines.push("", "NOTICE:", ...report2.notices.map((n) => `- ${n}`));
|
|
28484
|
+
if (report2.testsToRevisit.length) {
|
|
28485
|
+
lines.push("", "TESTS TO REVISIT:");
|
|
28486
|
+
for (const entry of report2.testsToRevisit) {
|
|
28487
|
+
lines.push(`- ${entry.method} (searched as "${entry.symbol}")`);
|
|
28488
|
+
if (entry.imported.length) lines.push(` imports it: ${entry.imported.join(", ")}`);
|
|
28489
|
+
if (entry.mentioned.length) lines.push(` names it: ${entry.mentioned.join(", ")}`);
|
|
28490
|
+
if (entry.indiscriminate) {
|
|
28491
|
+
lines.push(" names it: withheld \u2014 the bare name matches more than a tenth of the suite, so the list carries no signal.");
|
|
28492
|
+
}
|
|
28493
|
+
}
|
|
28494
|
+
}
|
|
28389
28495
|
return lines.join("\n");
|
|
28390
28496
|
}
|
|
28391
28497
|
function writeReceipt(sentence, receipt) {
|
|
@@ -29990,6 +30096,15 @@ var init_server = __esm({
|
|
|
29990
30096
|
),
|
|
29991
30097
|
notices: import_zod11.z.array(import_zod11.z.string()).describe("Store placement notices, gate warnings and delta notices."),
|
|
29992
30098
|
summary: import_zod11.z.string().describe("One line for people."),
|
|
30099
|
+
testsToRevisit: import_zod11.z.array(import_zod11.z.object({
|
|
30100
|
+
method: import_zod11.z.string().describe("The contract method this write changed or deleted."),
|
|
30101
|
+
symbol: import_zod11.z.string().describe("The code-level name searched for: the method's `symbol` when it declares one, else its name."),
|
|
30102
|
+
imported: import_zod11.z.array(import_zod11.z.string()).describe("Test files that IMPORT that symbol \u2014 the high-confidence list, because an import is a binding and not a coincidence."),
|
|
30103
|
+
mentioned: import_zod11.z.array(import_zod11.z.string()).describe("Test files that name the symbol without importing it \u2014 usually a test driving it through a portal. Empty when `indiscriminate` is true."),
|
|
30104
|
+
indiscriminate: import_zod11.z.boolean().describe("True when the bare name matched more than a tenth of the test suite, so the mention list was withheld as noise.")
|
|
30105
|
+
})).describe(
|
|
30106
|
+
"The tests that encode a method this write changed or deleted, one entry per such method. Empty when the write touched no method, when the project declares no `rules.conformance.testRoots`, or when nothing references them. Read it before promising that existing tests still pass."
|
|
30107
|
+
),
|
|
29993
30108
|
...staleServerOutput
|
|
29994
30109
|
};
|
|
29995
30110
|
validationIssueOutput = {
|