@wairon/cli 5.1.1-dev.76 → 5.1.1-dev.77
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 +566 -45
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +553 -42
- 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.77";
|
|
69
69
|
GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
70
70
|
SUPPORTED_ALIASES = ["wai"];
|
|
71
71
|
SCAN_EXCLUDE_DIRS = /* @__PURE__ */ new Set([
|
|
@@ -359,6 +359,46 @@ var init_yaml = __esm({
|
|
|
359
359
|
}
|
|
360
360
|
});
|
|
361
361
|
|
|
362
|
+
// src/models/identity-rename.ts
|
|
363
|
+
function movedComponent(rename, id) {
|
|
364
|
+
return rename.components?.find((c) => c.from === id)?.to ?? id;
|
|
365
|
+
}
|
|
366
|
+
function rekeyUnit(rename, unit) {
|
|
367
|
+
if (unit.includes(EDGE)) return unit.split(EDGE).map((side) => movedComponent(rename, side)).join(EDGE);
|
|
368
|
+
const qualified = QUALIFIED_UNIT.exec(unit);
|
|
369
|
+
if (!qualified) return unit;
|
|
370
|
+
const [, step = "", component, method2] = qualified;
|
|
371
|
+
const moved = rename.methods?.find((m) => m.component === component && m.method === method2);
|
|
372
|
+
if (moved) return `${step}${moved.toComponent}.${moved.toMethod}`;
|
|
373
|
+
return `${step}${movedComponent(rename, component)}.${method2}`;
|
|
374
|
+
}
|
|
375
|
+
function rekeyAnchor(rename, anchor) {
|
|
376
|
+
const { spec, at, covers } = anchor;
|
|
377
|
+
const movedSpec = rename.specs?.find((s) => s.from === spec && (!s.sites || at !== void 0 && s.sites.includes(at)));
|
|
378
|
+
let site = at;
|
|
379
|
+
if (at !== void 0) {
|
|
380
|
+
if (at.includes(EDGE)) {
|
|
381
|
+
site = rekeyUnit(rename, at);
|
|
382
|
+
} else {
|
|
383
|
+
const moved = rename.methods?.find((m) => m.method === at && m.specs?.includes(spec));
|
|
384
|
+
if (moved) site = moved.toMethod;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return {
|
|
388
|
+
spec: movedSpec?.to ?? spec,
|
|
389
|
+
...site !== void 0 ? { at: site } : {},
|
|
390
|
+
...covers !== void 0 ? { covers: covers.map((unit) => rekeyUnit(rename, unit)) } : {}
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
var EDGE, QUALIFIED_UNIT;
|
|
394
|
+
var init_identity_rename = __esm({
|
|
395
|
+
"src/models/identity-rename.ts"() {
|
|
396
|
+
"use strict";
|
|
397
|
+
EDGE = " -> ";
|
|
398
|
+
QUALIFIED_UNIT = /^(\d+:)?([^.\s]+)\.([^.\s]+)$/;
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
|
|
362
402
|
// src/models/execution.ts
|
|
363
403
|
function summarize(budget, profile) {
|
|
364
404
|
const lines = [
|
|
@@ -1002,6 +1042,12 @@ function projectConfigFsAdapterAt(rootDir) {
|
|
|
1002
1042
|
},
|
|
1003
1043
|
documentExists() {
|
|
1004
1044
|
return fs4.existsSync(file());
|
|
1045
|
+
},
|
|
1046
|
+
readText() {
|
|
1047
|
+
return readFileOrNull(file());
|
|
1048
|
+
},
|
|
1049
|
+
writeText(text2) {
|
|
1050
|
+
writeFile(file(), text2);
|
|
1005
1051
|
}
|
|
1006
1052
|
};
|
|
1007
1053
|
}
|
|
@@ -1027,8 +1073,157 @@ function storeOver(adapter, root) {
|
|
|
1027
1073
|
},
|
|
1028
1074
|
readField(field) {
|
|
1029
1075
|
return valueAt(currentDocument(), field);
|
|
1076
|
+
},
|
|
1077
|
+
rewriteScalars(edits, dryRun = false) {
|
|
1078
|
+
if (edits.length === 0) return;
|
|
1079
|
+
const text2 = adapter.readText();
|
|
1080
|
+
if (text2 === null) throw new ProjectNotInitializedError();
|
|
1081
|
+
const next = rewriteScalarsInText(text2, edits, root);
|
|
1082
|
+
if (!dryRun) adapter.writeText(next);
|
|
1083
|
+
}
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1086
|
+
function tokenize(lines) {
|
|
1087
|
+
const tokens = [];
|
|
1088
|
+
let blockAbove = null;
|
|
1089
|
+
lines.forEach((raw, line2) => {
|
|
1090
|
+
const content = raw.replace(/\r?\n$/, "");
|
|
1091
|
+
const indent = content.length - content.trimStart().length;
|
|
1092
|
+
const trimmed = content.trim();
|
|
1093
|
+
if (blockAbove !== null) {
|
|
1094
|
+
if (trimmed === "" || indent > blockAbove) return;
|
|
1095
|
+
blockAbove = null;
|
|
1096
|
+
}
|
|
1097
|
+
if (trimmed === "" || trimmed.startsWith("#")) return;
|
|
1098
|
+
let col = indent;
|
|
1099
|
+
let rest = content.slice(indent);
|
|
1100
|
+
while (rest === "-" || rest.startsWith("- ")) {
|
|
1101
|
+
tokens.push({ kind: "item", col, line: line2 });
|
|
1102
|
+
const after = rest.slice(1);
|
|
1103
|
+
const pad = after.length - after.trimStart().length;
|
|
1104
|
+
col += 1 + pad;
|
|
1105
|
+
rest = after.trimStart();
|
|
1106
|
+
}
|
|
1107
|
+
if (rest === "") return;
|
|
1108
|
+
const key = KEY_RE.exec(rest);
|
|
1109
|
+
if (key) {
|
|
1110
|
+
const name = key[1].startsWith("'") ? key[1].slice(1, -1).replace(/''/g, "'") : key[1].startsWith('"') ? JSON.parse(key[1]) : key[1].trim();
|
|
1111
|
+
const afterKey = rest.slice(key[0].length);
|
|
1112
|
+
const value = afterKey.trimStart();
|
|
1113
|
+
const token = { kind: "key", col, line: line2, name };
|
|
1114
|
+
if (value !== "" && !value.startsWith("#")) token.valueStart = col + key[0].length + (afterKey.length - value.length);
|
|
1115
|
+
tokens.push(token);
|
|
1116
|
+
if (/^[|>][-+0-9]*\s*(#.*)?$/.test(value)) blockAbove = col;
|
|
1117
|
+
return;
|
|
1030
1118
|
}
|
|
1031
|
-
|
|
1119
|
+
tokens.push({ kind: "scalar", col, line: line2, valueStart: col });
|
|
1120
|
+
if (/^[|>][-+0-9]*\s*(#.*)?$/.test(rest)) blockAbove = col - 2;
|
|
1121
|
+
});
|
|
1122
|
+
return tokens;
|
|
1123
|
+
}
|
|
1124
|
+
function childrenOf(tokens, index) {
|
|
1125
|
+
const parent = tokens[index];
|
|
1126
|
+
const out = [];
|
|
1127
|
+
for (let i = index + 1; i < tokens.length; i += 1) {
|
|
1128
|
+
const t = tokens[i];
|
|
1129
|
+
const nested = t.col > parent.col || parent.kind === "key" && t.kind === "item" && t.col === parent.col;
|
|
1130
|
+
if (!nested) break;
|
|
1131
|
+
out.push(t);
|
|
1132
|
+
}
|
|
1133
|
+
return out;
|
|
1134
|
+
}
|
|
1135
|
+
function locateScalar(tokens, path73) {
|
|
1136
|
+
let region = tokens;
|
|
1137
|
+
for (let k = 0; k < path73.length; k += 1) {
|
|
1138
|
+
const segment = path73[k];
|
|
1139
|
+
if (region.length === 0) return `nothing is nested at ${path73.slice(0, k).join(".")}`;
|
|
1140
|
+
const base = Math.min(...region.map((t) => t.col));
|
|
1141
|
+
const last = k === path73.length - 1;
|
|
1142
|
+
let at;
|
|
1143
|
+
if (typeof segment === "string") {
|
|
1144
|
+
at = region.findIndex((t) => t.kind === "key" && t.col === base && t.name === segment);
|
|
1145
|
+
if (at < 0) return `no block key "${segment}" at ${path73.slice(0, k).join(".") || "the document root"}`;
|
|
1146
|
+
if (last) return region[at].valueStart !== void 0 ? region[at] : `"${segment}" holds no inline scalar`;
|
|
1147
|
+
} else {
|
|
1148
|
+
const items = region.map((t, i) => ({ t, i })).filter(({ t }) => t.kind === "item" && t.col === base);
|
|
1149
|
+
if (segment >= items.length) return `no block sequence item ${segment} at ${path73.slice(0, k).join(".")}`;
|
|
1150
|
+
at = items[segment].i;
|
|
1151
|
+
if (last) {
|
|
1152
|
+
const value = region[at + 1];
|
|
1153
|
+
return value && value.kind === "scalar" && value.line === region[at].line ? value : `item ${segment} holds no inline scalar`;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
const regionStart = tokens.indexOf(region[at]);
|
|
1157
|
+
region = childrenOf(tokens, regionStart);
|
|
1158
|
+
}
|
|
1159
|
+
return "an empty path addresses no scalar";
|
|
1160
|
+
}
|
|
1161
|
+
function readScalar(text2) {
|
|
1162
|
+
if (text2.startsWith("'")) {
|
|
1163
|
+
let i = 1;
|
|
1164
|
+
let value = "";
|
|
1165
|
+
while (i < text2.length) {
|
|
1166
|
+
if (text2[i] === "'") {
|
|
1167
|
+
if (text2[i + 1] === "'") {
|
|
1168
|
+
value += "'";
|
|
1169
|
+
i += 2;
|
|
1170
|
+
continue;
|
|
1171
|
+
}
|
|
1172
|
+
return { value, style: "single", end: i + 1 };
|
|
1173
|
+
}
|
|
1174
|
+
value += text2[i];
|
|
1175
|
+
i += 1;
|
|
1176
|
+
}
|
|
1177
|
+
return null;
|
|
1178
|
+
}
|
|
1179
|
+
if (text2.startsWith('"')) {
|
|
1180
|
+
const closing = /^"(?:[^"\\]|\\.)*"/.exec(text2);
|
|
1181
|
+
if (!closing) return null;
|
|
1182
|
+
try {
|
|
1183
|
+
return { value: JSON.parse(closing[0]), style: "double", end: closing[0].length };
|
|
1184
|
+
} catch {
|
|
1185
|
+
return null;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
const comment = text2.search(/\s#/);
|
|
1189
|
+
const body = (comment < 0 ? text2 : text2.slice(0, comment)).trimEnd();
|
|
1190
|
+
return { value: body, style: "plain", end: body.length };
|
|
1191
|
+
}
|
|
1192
|
+
function writeScalar(value, style) {
|
|
1193
|
+
if (style === "double") return JSON.stringify(value);
|
|
1194
|
+
if (style === "plain" && /^[A-Za-z0-9_][A-Za-z0-9_./-]*$/.test(value)) return value;
|
|
1195
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
1196
|
+
}
|
|
1197
|
+
function setAt(document, path73, value) {
|
|
1198
|
+
let node = document;
|
|
1199
|
+
for (const segment of path73.slice(0, -1)) node = node[segment];
|
|
1200
|
+
node[path73[path73.length - 1]] = value;
|
|
1201
|
+
}
|
|
1202
|
+
function rewriteScalarsInText(text2, edits, root) {
|
|
1203
|
+
const refuse = (why) => {
|
|
1204
|
+
throw new WaironError(`Cannot rewrite .wai/project.yaml at ${root} without disturbing its formatting: ${why}. Nothing was written.`);
|
|
1205
|
+
};
|
|
1206
|
+
const lines = text2.split(/(?<=\n)/);
|
|
1207
|
+
const tokens = tokenize(lines);
|
|
1208
|
+
const expected = parseYaml(text2);
|
|
1209
|
+
for (const edit of edits) {
|
|
1210
|
+
const where = edit.path.join(".");
|
|
1211
|
+
const token = locateScalar(tokens, edit.path);
|
|
1212
|
+
if (typeof token === "string") refuse(`${where}: ${token}`);
|
|
1213
|
+
const { line: line2, valueStart } = token;
|
|
1214
|
+
const content = lines[line2].replace(/\r?\n$/, "");
|
|
1215
|
+
const ending = lines[line2].slice(content.length);
|
|
1216
|
+
const scalar = readScalar(content.slice(valueStart));
|
|
1217
|
+
if (!scalar) refuse(`${where}: the scalar there is not written on one line`);
|
|
1218
|
+
if (scalar.value !== edit.from) refuse(`${where} holds "${scalar.value}", not "${edit.from}"`);
|
|
1219
|
+
lines[line2] = content.slice(0, valueStart) + writeScalar(edit.to, scalar.style) + content.slice(valueStart + scalar.end) + ending;
|
|
1220
|
+
setAt(expected, edit.path, edit.to);
|
|
1221
|
+
}
|
|
1222
|
+
const next = lines.join("");
|
|
1223
|
+
if (JSON.stringify(parseYaml(next)) !== JSON.stringify(expected)) {
|
|
1224
|
+
refuse("the edited text does not read back as exactly the intended change");
|
|
1225
|
+
}
|
|
1226
|
+
return next;
|
|
1032
1227
|
}
|
|
1033
1228
|
function parseConfig(document, root) {
|
|
1034
1229
|
try {
|
|
@@ -1170,6 +1365,35 @@ function registryOver(store, root) {
|
|
|
1170
1365
|
...config,
|
|
1171
1366
|
extensions: { ...config.extensions, packs: [...packsOf(config), ...selections], useGlobalPacks: false }
|
|
1172
1367
|
});
|
|
1368
|
+
},
|
|
1369
|
+
rekeyCarried(rename, dryRun = false) {
|
|
1370
|
+
const groups = store.readField("rules.conformance.carried");
|
|
1371
|
+
if (!Array.isArray(groups)) return [];
|
|
1372
|
+
const edits = [];
|
|
1373
|
+
const rekeys = [];
|
|
1374
|
+
groups.forEach((group, g) => {
|
|
1375
|
+
const findings = group?.findings;
|
|
1376
|
+
if (!Array.isArray(findings)) return;
|
|
1377
|
+
findings.forEach((finding, f) => {
|
|
1378
|
+
const entry = finding;
|
|
1379
|
+
if (!entry || typeof entry.spec !== "string") return;
|
|
1380
|
+
const at = typeof entry.at === "string" ? entry.at : void 0;
|
|
1381
|
+
const covers = Array.isArray(entry.covers) ? entry.covers.filter((u) => typeof u === "string") : void 0;
|
|
1382
|
+
const next = rekeyAnchor(rename, { spec: entry.spec, at, covers });
|
|
1383
|
+
const base = ["rules", "conformance", "carried", g, "findings", f];
|
|
1384
|
+
const named = { code: String(entry.code), spec: entry.spec, at: at ?? "" };
|
|
1385
|
+
const change = (path73, field, from, to) => {
|
|
1386
|
+
if (from === to) return;
|
|
1387
|
+
edits.push({ path: [...base, ...path73], from, to });
|
|
1388
|
+
rekeys.push({ ...named, field, from, to });
|
|
1389
|
+
};
|
|
1390
|
+
change(["spec"], "spec", entry.spec, next.spec);
|
|
1391
|
+
if (at !== void 0) change(["at"], "at", at, next.at);
|
|
1392
|
+
(covers ?? []).forEach((unit, u) => change(["covers", u], "covers", unit, next.covers[u]));
|
|
1393
|
+
});
|
|
1394
|
+
});
|
|
1395
|
+
store.rewriteScalars(edits, dryRun);
|
|
1396
|
+
return rekeys;
|
|
1173
1397
|
}
|
|
1174
1398
|
};
|
|
1175
1399
|
}
|
|
@@ -1254,13 +1478,16 @@ function projectConfigRepositoryOver(adapter, rootDir) {
|
|
|
1254
1478
|
},
|
|
1255
1479
|
pinGlobalPacksAsSelections(selections) {
|
|
1256
1480
|
registry.pinGlobalPacksAsSelections(selections);
|
|
1481
|
+
},
|
|
1482
|
+
rekeyCarried(rename, dryRun) {
|
|
1483
|
+
return registry.rekeyCarried(rename, dryRun);
|
|
1257
1484
|
}
|
|
1258
1485
|
};
|
|
1259
1486
|
}
|
|
1260
1487
|
function projectConfigRepositoryAt(rootDir) {
|
|
1261
1488
|
return projectConfigRepositoryOver(projectConfigFsAdapterAt(rootDir), rootDir);
|
|
1262
1489
|
}
|
|
1263
|
-
var fs4, path6, import_zod4, USE_GLOBAL_PACKS_DEFAULT, bound, projectConfigRepository;
|
|
1490
|
+
var fs4, path6, import_zod4, KEY_RE, USE_GLOBAL_PACKS_DEFAULT, bound, projectConfigRepository;
|
|
1264
1491
|
var init_project_config = __esm({
|
|
1265
1492
|
"src/config/project-config.ts"() {
|
|
1266
1493
|
"use strict";
|
|
@@ -1269,8 +1496,11 @@ var init_project_config = __esm({
|
|
|
1269
1496
|
import_zod4 = require("zod");
|
|
1270
1497
|
init_fs();
|
|
1271
1498
|
init_yaml();
|
|
1499
|
+
init_fs();
|
|
1272
1500
|
init_errors();
|
|
1501
|
+
init_identity_rename();
|
|
1273
1502
|
init_project();
|
|
1503
|
+
KEY_RE = /^('(?:[^']|'')*'|"(?:[^"\\]|\\.)*"|[^\s'"#{}[\],&*!|>%@`][^:#]*?)\s*:(?=\s|$)/;
|
|
1274
1504
|
USE_GLOBAL_PACKS_DEFAULT = ProjectConfigSchema.shape.extensions.unwrap().parse({}).useGlobalPacks;
|
|
1275
1505
|
bound = () => projectConfigRepositoryAt(getProjectRoot());
|
|
1276
1506
|
projectConfigRepository = {
|
|
@@ -1315,6 +1545,9 @@ var init_project_config = __esm({
|
|
|
1315
1545
|
},
|
|
1316
1546
|
pinGlobalPacksAsSelections(selections) {
|
|
1317
1547
|
bound().pinGlobalPacksAsSelections(selections);
|
|
1548
|
+
},
|
|
1549
|
+
rekeyCarried(rename, dryRun) {
|
|
1550
|
+
return bound().rekeyCarried(rename, dryRun);
|
|
1318
1551
|
}
|
|
1319
1552
|
};
|
|
1320
1553
|
}
|
|
@@ -9702,6 +9935,28 @@ function buildCodeIndex(model) {
|
|
|
9702
9935
|
return out;
|
|
9703
9936
|
};
|
|
9704
9937
|
const declarationsAt = (path73) => namesAt(declarations, pathKey(path73), (f) => /* @__PURE__ */ new Set([...f.declaredNames, ...f.exportedNames]));
|
|
9938
|
+
const forwardsOf = (start2, name) => {
|
|
9939
|
+
const out = [];
|
|
9940
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9941
|
+
const queue = [{ file: pathKey(start2), name }];
|
|
9942
|
+
while (queue.length) {
|
|
9943
|
+
const at = queue.shift();
|
|
9944
|
+
const key = `${at.file}#${at.name}`;
|
|
9945
|
+
if (seen.has(key)) continue;
|
|
9946
|
+
seen.add(key);
|
|
9947
|
+
out.push(at);
|
|
9948
|
+
for (const binding of facts.get(at.file)?.reexportBindings ?? []) {
|
|
9949
|
+
const star = binding.exported === "*";
|
|
9950
|
+
if (!star && binding.exported !== at.name) continue;
|
|
9951
|
+
if (star && at.name === "default") continue;
|
|
9952
|
+
const to = resolveImport(at.file, binding.from, paths);
|
|
9953
|
+
if (!to) continue;
|
|
9954
|
+
if (star && !facts.get(to)?.exportedNames.includes(at.name)) continue;
|
|
9955
|
+
queue.push({ file: to, name: star ? at.name : binding.local });
|
|
9956
|
+
}
|
|
9957
|
+
}
|
|
9958
|
+
return out;
|
|
9959
|
+
};
|
|
9705
9960
|
return {
|
|
9706
9961
|
paths,
|
|
9707
9962
|
exactPaths,
|
|
@@ -9710,7 +9965,8 @@ function buildCodeIndex(model) {
|
|
|
9710
9965
|
anchorsAt: (path73) => namesAt(anchors, pathKey(path73), (f) => /* @__PURE__ */ new Set([...f.declaredNames, ...f.exportedNames, ...f.anchoredNames])),
|
|
9711
9966
|
findingAnchorsAt: (path73) => namesAt(findingAnchors, pathKey(path73), (f) => new Set(f.anchoredNames)),
|
|
9712
9967
|
originOf: originOf2,
|
|
9713
|
-
possibleOriginsOf
|
|
9968
|
+
possibleOriginsOf,
|
|
9969
|
+
forwardsOf
|
|
9714
9970
|
};
|
|
9715
9971
|
}
|
|
9716
9972
|
function buildRealizationIndex(ctx) {
|
|
@@ -14281,6 +14537,25 @@ function resolveCallTarget(ctx, componentId, methodName) {
|
|
|
14281
14537
|
}
|
|
14282
14538
|
return { accepted, files };
|
|
14283
14539
|
}
|
|
14540
|
+
function isTarget(pairs, target) {
|
|
14541
|
+
return pairs.some((p) => target.files.has(p.file) && target.accepted.has(p.name));
|
|
14542
|
+
}
|
|
14543
|
+
function invokedAs(code, site, file) {
|
|
14544
|
+
const scope = pathKey(site.from ?? file);
|
|
14545
|
+
const facts = code.factsAt(scope);
|
|
14546
|
+
if (!facts || facts.status !== "analyzed" || facts.analysisGrade !== "exact") return [];
|
|
14547
|
+
if (!site.member) {
|
|
14548
|
+
const binding = importBindingOf(facts, site.name);
|
|
14549
|
+
if (!binding || binding.namespace) return [];
|
|
14550
|
+
const module3 = resolveImport(scope, binding.from, code.paths);
|
|
14551
|
+
return module3 ? code.forwardsOf(module3, binding.imported ?? site.name) : [];
|
|
14552
|
+
}
|
|
14553
|
+
if (!site.via) return [];
|
|
14554
|
+
const receiver = importBindingOf(facts, site.via);
|
|
14555
|
+
if (!receiver?.namespace) return [];
|
|
14556
|
+
const module2 = resolveImport(scope, receiver.from, code.paths);
|
|
14557
|
+
return module2 ? code.forwardsOf(module2, site.name) : [];
|
|
14558
|
+
}
|
|
14284
14559
|
function claimsOf(implMethod) {
|
|
14285
14560
|
const claims = [];
|
|
14286
14561
|
for (const step of implMethod.narrative) {
|
|
@@ -14351,6 +14626,7 @@ var init_call_conformance = __esm({
|
|
|
14351
14626
|
if (!ctx.componentMap.has(claim.component)) continue;
|
|
14352
14627
|
const target = resolveCallTarget(ctx, claim.component, claim.method);
|
|
14353
14628
|
if (target.accepted.has(fnSymbol)) continue;
|
|
14629
|
+
if (isTarget(code.forwardsOf(file, fnSymbol), target)) continue;
|
|
14354
14630
|
const matching = sites.filter((s) => target.accepted.has(s.name));
|
|
14355
14631
|
const ref = `${claim.component}.${claim.method}`;
|
|
14356
14632
|
if (target.files.size === 0) {
|
|
@@ -14359,6 +14635,7 @@ var init_call_conformance = __esm({
|
|
|
14359
14635
|
}
|
|
14360
14636
|
continue;
|
|
14361
14637
|
}
|
|
14638
|
+
if (sites.some((s) => !target.accepted.has(s.name) && isTarget(invokedAs(code, s, file), target))) continue;
|
|
14362
14639
|
const landed = /* @__PURE__ */ new Set();
|
|
14363
14640
|
let realized = false;
|
|
14364
14641
|
for (const site of matching) {
|
|
@@ -17795,6 +18072,10 @@ function buildCodeModel(implementations, types, projectRoot2, sourceRoots = [],
|
|
|
17795
18072
|
exportedNames: [...facts.exported],
|
|
17796
18073
|
imports: [...facts.imports],
|
|
17797
18074
|
reexports: [...facts.reexports],
|
|
18075
|
+
reexportBindings: [
|
|
18076
|
+
...facts.namedReexports.map(({ exported, local, from }) => ({ exported, local, from })),
|
|
18077
|
+
...facts.starExports.map((from) => ({ exported: "*", local: "*", from }))
|
|
18078
|
+
],
|
|
17798
18079
|
functionComplexity: Object.fromEntries(facts.complexity),
|
|
17799
18080
|
functionCallSites: Object.fromEntries([...facts.calls].map(([k, v]) => [k, [...v.values()]])),
|
|
17800
18081
|
importBindings: Object.fromEntries(facts.importBindings),
|
|
@@ -17822,6 +18103,25 @@ function buildCodeModel(implementations, types, projectRoot2, sourceRoots = [],
|
|
|
17822
18103
|
}
|
|
17823
18104
|
return { files, projectRoot: projectRoot2, rootFiles };
|
|
17824
18105
|
}
|
|
18106
|
+
function clauseBindings(clause, specifier) {
|
|
18107
|
+
const out = [];
|
|
18108
|
+
const body = clause.replace(/^\s*type\s+/, "");
|
|
18109
|
+
const named = /\{([^}]*)\}/.exec(body);
|
|
18110
|
+
if (named) {
|
|
18111
|
+
for (const piece of named[1].split(",")) {
|
|
18112
|
+
const sides = piece.replace(/^\s*type\s+/, "").split(/\s+as\s+/).map((s) => s.trim());
|
|
18113
|
+
const exported = sides[0];
|
|
18114
|
+
const local = sides[1] ?? exported;
|
|
18115
|
+
if (IDENTIFIER_ONLY_RE.test(exported) && IDENTIFIER_ONLY_RE.test(local)) out.push({ exported, local, specifier });
|
|
18116
|
+
}
|
|
18117
|
+
}
|
|
18118
|
+
const namespace = /\*\s*as\s+([A-Za-z_$][\w$]*)/.exec(body);
|
|
18119
|
+
if (namespace) out.push({ exported: "*", local: namespace[1], specifier });
|
|
18120
|
+
const head = body.replace(/\{[^}]*\}/, "").replace(/\*\s*as\s+[A-Za-z_$][\w$]*/, "");
|
|
18121
|
+
const defaulted = /^\s*([A-Za-z_$][\w$]*)/.exec(head);
|
|
18122
|
+
if (defaulted) out.push({ exported: "default", local: defaulted[1], specifier });
|
|
18123
|
+
return out;
|
|
18124
|
+
}
|
|
17825
18125
|
function readTestFiles(testRoots, projectRoot2) {
|
|
17826
18126
|
const scanned = [];
|
|
17827
18127
|
for (const key of walkDeclaredRoots(testRoots, [], projectRoot2)) {
|
|
@@ -17837,25 +18137,98 @@ function readTestFiles(testRoots, projectRoot2) {
|
|
|
17837
18137
|
for (const m of text2.matchAll(NAMED_IMPORT_BINDINGS_RE)) {
|
|
17838
18138
|
for (const name of boundNames(m[1] ?? "", false)) imports.add(name);
|
|
17839
18139
|
}
|
|
18140
|
+
const code = stripComments(text2, JS_PATTERNS);
|
|
18141
|
+
const bindings = [];
|
|
18142
|
+
for (const m of code.matchAll(IMPORT_FROM_RE)) bindings.push(...clauseBindings(m[1], m[2]));
|
|
18143
|
+
for (const m of code.matchAll(DYNAMIC_IMPORT_RE)) bindings.push(...clauseBindings(`{${m[1].replace(/:/g, " as ")}}`, m[2]));
|
|
17840
18144
|
const words2 = /* @__PURE__ */ new Set();
|
|
17841
18145
|
for (const m of text2.matchAll(IDENTIFIER_RE)) words2.add(m[0]);
|
|
17842
|
-
scanned.push({ path: key, imports, words: words2 });
|
|
18146
|
+
scanned.push({ path: key, imports, bindings, words: words2 });
|
|
17843
18147
|
}
|
|
17844
18148
|
return scanned;
|
|
17845
18149
|
}
|
|
18150
|
+
function reexportReader() {
|
|
18151
|
+
const cache2 = /* @__PURE__ */ new Map();
|
|
18152
|
+
return (file) => {
|
|
18153
|
+
const cached = cache2.get(file);
|
|
18154
|
+
if (cached) return cached;
|
|
18155
|
+
const found = { named: [], stars: [] };
|
|
18156
|
+
try {
|
|
18157
|
+
const code = stripComments(fs12.readFileSync(file, "utf8"), JS_PATTERNS);
|
|
18158
|
+
for (const m of code.matchAll(NAMED_REEXPORT_RE)) {
|
|
18159
|
+
for (const piece of m[1].split(",")) {
|
|
18160
|
+
const sides = piece.replace(/^\s*type\s+/, "").split(/\s+as\s+/).map((s) => s.trim());
|
|
18161
|
+
if (!IDENTIFIER_ONLY_RE.test(sides[0] ?? "")) continue;
|
|
18162
|
+
found.named.push({ local: sides[0], exported: sides[1] ?? sides[0], specifier: m[2] });
|
|
18163
|
+
}
|
|
18164
|
+
}
|
|
18165
|
+
for (const m of code.matchAll(STAR_REEXPORT_RE)) found.stars.push(m[1]);
|
|
18166
|
+
} catch {
|
|
18167
|
+
}
|
|
18168
|
+
cache2.set(file, found);
|
|
18169
|
+
return found;
|
|
18170
|
+
};
|
|
18171
|
+
}
|
|
18172
|
+
function publishesFrom(module2, name, target, symbol, readReexports, visited = /* @__PURE__ */ new Set()) {
|
|
18173
|
+
if (path15.resolve(module2) === target && name === symbol) return true;
|
|
18174
|
+
const key = `${module2}#${name}`;
|
|
18175
|
+
if (visited.has(key)) return false;
|
|
18176
|
+
visited.add(key);
|
|
18177
|
+
const reexports = readReexports(module2);
|
|
18178
|
+
for (const re of reexports.named) {
|
|
18179
|
+
if (re.exported !== name) continue;
|
|
18180
|
+
const next = resolveRelativeModule(module2, re.specifier);
|
|
18181
|
+
if (next && publishesFrom(next, re.local, target, symbol, readReexports, visited)) return true;
|
|
18182
|
+
}
|
|
18183
|
+
if (name === "default") return false;
|
|
18184
|
+
for (const specifier of reexports.stars) {
|
|
18185
|
+
const next = resolveRelativeModule(module2, specifier);
|
|
18186
|
+
if (next && publishesFrom(next, name, target, symbol, readReexports, visited)) return true;
|
|
18187
|
+
}
|
|
18188
|
+
return false;
|
|
18189
|
+
}
|
|
17846
18190
|
function findTestsReferencing(methods, projectRoot2, testRoots = []) {
|
|
17847
18191
|
const scanned = readTestFiles(testRoots, projectRoot2);
|
|
17848
18192
|
if (scanned.length === 0) return [];
|
|
17849
18193
|
const indiscriminateAbove = scanned.length / 10;
|
|
17850
|
-
const
|
|
18194
|
+
const searches = [];
|
|
17851
18195
|
for (const method2 of methods) {
|
|
17852
18196
|
const symbol = method2.symbol ?? method2.name;
|
|
17853
|
-
|
|
17854
|
-
|
|
18197
|
+
let search = searches.find((s) => s.method === method2.name && s.symbol === symbol);
|
|
18198
|
+
if (!search) {
|
|
18199
|
+
search = { method: method2.name, symbol, files: [] };
|
|
18200
|
+
searches.push(search);
|
|
18201
|
+
}
|
|
18202
|
+
const file = method2.sourcePath ? path15.resolve(projectRoot2, method2.sourcePath) : void 0;
|
|
18203
|
+
if (file && !search.files.includes(file)) search.files.push(file);
|
|
18204
|
+
}
|
|
18205
|
+
const readReexports = reexportReader();
|
|
18206
|
+
const found = [];
|
|
18207
|
+
for (const { method: method2, symbol, files } of searches) {
|
|
18208
|
+
const imported = [];
|
|
18209
|
+
const mentioned = [];
|
|
18210
|
+
for (const test of scanned) {
|
|
18211
|
+
if (files.length === 0) {
|
|
18212
|
+
if (test.imports.has(symbol)) imported.push(test.path);
|
|
18213
|
+
else if (test.words.has(symbol)) mentioned.push(test.path);
|
|
18214
|
+
continue;
|
|
18215
|
+
}
|
|
18216
|
+
const testFile = path15.resolve(projectRoot2, test.path);
|
|
18217
|
+
const fromMethod = (binding, name) => {
|
|
18218
|
+
const module2 = resolveRelativeModule(testFile, binding.specifier);
|
|
18219
|
+
return module2 !== null && files.some((target) => publishesFrom(module2, name, target, symbol, readReexports));
|
|
18220
|
+
};
|
|
18221
|
+
const naming = test.bindings.filter((b) => b.exported === symbol || b.local === symbol);
|
|
18222
|
+
if (test.bindings.some((b) => b.exported !== "*" && fromMethod(b, b.exported)) || test.words.has(symbol) && test.bindings.some((b) => b.exported === "*" && fromMethod(b, symbol))) {
|
|
18223
|
+
imported.push(test.path);
|
|
18224
|
+
} else if (naming.length === 0 && test.words.has(symbol)) {
|
|
18225
|
+
mentioned.push(test.path);
|
|
18226
|
+
}
|
|
18227
|
+
}
|
|
17855
18228
|
const indiscriminate = mentioned.length > indiscriminateAbove;
|
|
17856
18229
|
if (imported.length === 0 && mentioned.length === 0) continue;
|
|
17857
18230
|
found.push({
|
|
17858
|
-
method: method2
|
|
18231
|
+
method: method2,
|
|
17859
18232
|
symbol,
|
|
17860
18233
|
imported,
|
|
17861
18234
|
mentioned: indiscriminate ? [] : mentioned,
|
|
@@ -17864,7 +18237,7 @@ function findTestsReferencing(methods, projectRoot2, testRoots = []) {
|
|
|
17864
18237
|
}
|
|
17865
18238
|
return found;
|
|
17866
18239
|
}
|
|
17867
|
-
var fs12, path15, 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;
|
|
18240
|
+
var fs12, path15, 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, IMPORT_FROM_RE, DYNAMIC_IMPORT_RE, IDENTIFIER_ONLY_RE, NAMED_REEXPORT_RE, STAR_REEXPORT_RE;
|
|
17868
18241
|
var init_source_analysis = __esm({
|
|
17869
18242
|
"src/core/source-analysis.ts"() {
|
|
17870
18243
|
"use strict";
|
|
@@ -17997,6 +18370,11 @@ var init_source_analysis = __esm({
|
|
|
17997
18370
|
STRING_RE = /'([^'\\\n]*(?:\\.[^'\\\n]*)*)'|"([^"\\\n]*(?:\\.[^"\\\n]*)*)"|`([^`\\]*(?:\\.[^`\\]*)*)`/g;
|
|
17998
18371
|
tsResolutionCache = /* @__PURE__ */ new Map();
|
|
17999
18372
|
TS_RESOLUTION_RETRY_MS = 3e4;
|
|
18373
|
+
IMPORT_FROM_RE = /(?:^|;)[ \t]*import\s+(?!\()([^'";]*?)\s*from\s*['"]([^'"]+)['"]/gm;
|
|
18374
|
+
DYNAMIC_IMPORT_RE = /\{([^{}]*)\}\s*=\s*await\s+import\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
18375
|
+
IDENTIFIER_ONLY_RE = /^[A-Za-z_$][\w$]*$/;
|
|
18376
|
+
NAMED_REEXPORT_RE = /\bexport\s+(?:type\s+)?\{([^}]*)\}\s*from\s*['"]([^'"]+)['"]/g;
|
|
18377
|
+
STAR_REEXPORT_RE = /\bexport\s+\*\s+from\s*['"]([^'"]+)['"]/g;
|
|
18000
18378
|
}
|
|
18001
18379
|
});
|
|
18002
18380
|
|
|
@@ -20496,6 +20874,15 @@ function moveChangeReports(edits, dryRun) {
|
|
|
20496
20874
|
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"}.`
|
|
20497
20875
|
}));
|
|
20498
20876
|
}
|
|
20877
|
+
function moveRename(from, to, methods, plan) {
|
|
20878
|
+
return {
|
|
20879
|
+
specs: plan.rehomed.map(({ from: left, to: arrived }) => ({ from: left, to: arrived, sites: [...methods] })),
|
|
20880
|
+
methods: methods.map((method2) => ({ component: from, method: method2, toComponent: to, toMethod: method2 }))
|
|
20881
|
+
};
|
|
20882
|
+
}
|
|
20883
|
+
function registerClause(carried, verb) {
|
|
20884
|
+
return carried.length ? `, ${verb} ${carried.length} debt-register key${carried.length === 1 ? "" : "s"}` : "";
|
|
20885
|
+
}
|
|
20499
20886
|
function createdClause(created, verb) {
|
|
20500
20887
|
return created.length ? `, ${verb} ${created.join(" and ")}` : "";
|
|
20501
20888
|
}
|
|
@@ -20751,6 +21138,7 @@ var init_specs2 = __esm({
|
|
|
20751
21138
|
init_lockfile();
|
|
20752
21139
|
init_yaml();
|
|
20753
21140
|
init_spec_files();
|
|
21141
|
+
init_identity_rename();
|
|
20754
21142
|
init_models();
|
|
20755
21143
|
init_narrative_labels();
|
|
20756
21144
|
init_diagram();
|
|
@@ -22710,6 +23098,8 @@ var init_specs2 = __esm({
|
|
|
22710
23098
|
const plan = this.planMethodMove(source, to, methods, contracts);
|
|
22711
23099
|
const repointed = this.repointToNewHome(from, to, methods, plan);
|
|
22712
23100
|
const mentions = this.moveMentions(from, plan);
|
|
23101
|
+
const rename = moveRename(from, to, methods, plan);
|
|
23102
|
+
this.rekeyMoveAllows(plan, rename);
|
|
22713
23103
|
if (hooks) {
|
|
22714
23104
|
const verdict = judgeMoveResult(hooks, plan);
|
|
22715
23105
|
plan.notices.push(...verdict.notices);
|
|
@@ -22728,10 +23118,12 @@ var init_specs2 = __esm({
|
|
|
22728
23118
|
summary: refusedMoveSummary(from, to, methods, verdict.refusals, alternatives),
|
|
22729
23119
|
dryRun,
|
|
22730
23120
|
mentions,
|
|
22731
|
-
created: []
|
|
23121
|
+
created: [],
|
|
23122
|
+
carried: []
|
|
22732
23123
|
};
|
|
22733
23124
|
}
|
|
22734
23125
|
}
|
|
23126
|
+
const carried = projectConfigRepository.rekeyCarried(rename, true);
|
|
22735
23127
|
if (dryRun) {
|
|
22736
23128
|
const edits2 = moveChangeReports([...plan.edits.values()], true);
|
|
22737
23129
|
return {
|
|
@@ -22744,13 +23136,16 @@ var init_specs2 = __esm({
|
|
|
22744
23136
|
refusals: [],
|
|
22745
23137
|
alternatives: [],
|
|
22746
23138
|
notices: plan.notices,
|
|
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.`,
|
|
23139
|
+
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"}${registerClause(carried, "would rekey")}. Nothing was written.`,
|
|
22748
23140
|
dryRun: true,
|
|
22749
23141
|
mentions,
|
|
22750
|
-
created: plan.created
|
|
23142
|
+
created: plan.created,
|
|
23143
|
+
carried
|
|
22751
23144
|
};
|
|
22752
23145
|
}
|
|
22753
|
-
const edits = this.writeMoveEdits([...plan.edits.values()])
|
|
23146
|
+
const edits = this.writeMoveEdits([...plan.edits.values()], () => {
|
|
23147
|
+
projectConfigRepository.rekeyCarried(rename);
|
|
23148
|
+
});
|
|
22754
23149
|
return {
|
|
22755
23150
|
moved: true,
|
|
22756
23151
|
from,
|
|
@@ -22761,12 +23156,49 @@ var init_specs2 = __esm({
|
|
|
22761
23156
|
refusals: [],
|
|
22762
23157
|
alternatives: [],
|
|
22763
23158
|
notices: plan.notices,
|
|
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` : ""}.`,
|
|
23159
|
+
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${registerClause(carried, "rekeyed")}${mentions.length ? `, ${mentions.length} still naming the old home in prose or on the wire` : ""}.`,
|
|
22765
23160
|
dryRun: false,
|
|
22766
23161
|
mentions,
|
|
22767
|
-
created: plan.created
|
|
23162
|
+
created: plan.created,
|
|
23163
|
+
carried
|
|
22768
23164
|
};
|
|
22769
23165
|
}
|
|
23166
|
+
/**
|
|
23167
|
+
* Rekey every lint allow keyed on a moved method, staging each spec it
|
|
23168
|
+
* changes like any other reference the move follows. An allow anchored at a
|
|
23169
|
+
* moved method on a spec the method left moves to the spec it arrived in; a
|
|
23170
|
+
* covered `<from>.<method>` unit anywhere names `<to>.<method>`. An allow
|
|
23171
|
+
* whose new home the plan does not stage stays where it is.
|
|
23172
|
+
*/
|
|
23173
|
+
rekeyMoveAllows(plan, rename) {
|
|
23174
|
+
const subjects = [...this.everySpecInTree()];
|
|
23175
|
+
for (const edit of plan.edits.values()) if (edit.before === null) subjects.push({ kind: edit.kind, id: edit.id, spec: edit.after });
|
|
23176
|
+
const stagedAfter = (kind, id) => plan.edits.get(`${kind}:${id}`)?.after;
|
|
23177
|
+
for (const { kind, id, spec } of subjects) {
|
|
23178
|
+
if (id.includes("::")) continue;
|
|
23179
|
+
const allows = spec?.lint?.allow ?? [];
|
|
23180
|
+
if (allows.length === 0) continue;
|
|
23181
|
+
const staged = plan.edits.get(`${kind}:${id}`);
|
|
23182
|
+
const subject = staged ? staged.after : cloneSpec(spec);
|
|
23183
|
+
const kept = [];
|
|
23184
|
+
let changed = false;
|
|
23185
|
+
for (const allow of subject.lint?.allow ?? []) {
|
|
23186
|
+
const next = rekeyAnchor(rename, { spec: id, ...allow.at !== void 0 ? { at: allow.at } : {}, ...allow.covers ? { covers: allow.covers } : {} });
|
|
23187
|
+
const rekeyed = { ...allow, ...next.at !== void 0 ? { at: next.at } : {}, ...next.covers ? { covers: next.covers } : {} };
|
|
23188
|
+
if (JSON.stringify(rekeyed) !== JSON.stringify(allow)) changed = true;
|
|
23189
|
+
const home = next.spec !== id ? stagedAfter(kind, next.spec) : void 0;
|
|
23190
|
+
if (home) {
|
|
23191
|
+
home.lint = { ...home.lint ?? {}, allow: [...home.lint?.allow ?? [], rekeyed] };
|
|
23192
|
+
changed = true;
|
|
23193
|
+
continue;
|
|
23194
|
+
}
|
|
23195
|
+
kept.push(rekeyed);
|
|
23196
|
+
}
|
|
23197
|
+
if (!changed) continue;
|
|
23198
|
+
subject.lint = { ...subject.lint, allow: kept };
|
|
23199
|
+
if (!staged) this.stageMoveEdit(plan, kind, id, spec, subject);
|
|
23200
|
+
}
|
|
23201
|
+
}
|
|
22770
23202
|
/**
|
|
22771
23203
|
* Why this move cannot be attempted at all, or null when the request is
|
|
22772
23204
|
* answerable. Every check here is about what the CALLER named, so its answer
|
|
@@ -22839,8 +23271,10 @@ var init_specs2 = __esm({
|
|
|
22839
23271
|
newDependencies: [],
|
|
22840
23272
|
wireBound: [],
|
|
22841
23273
|
notices: [],
|
|
22842
|
-
created: []
|
|
23274
|
+
created: [],
|
|
23275
|
+
rehomed: []
|
|
22843
23276
|
};
|
|
23277
|
+
const leftImplementations = [];
|
|
22844
23278
|
const receiving = stated ?? createdContract(target, source.id, methods, contracts);
|
|
22845
23279
|
const arriving = [];
|
|
22846
23280
|
const travelling = [];
|
|
@@ -22852,6 +23286,7 @@ var init_specs2 = __esm({
|
|
|
22852
23286
|
const remaining = cloneSpec(contract);
|
|
22853
23287
|
remaining.methods = remaining.methods.filter((m) => !methods.includes(m.name));
|
|
22854
23288
|
this.stageMoveEdit(plan, "interface", contract.id, contract, remaining);
|
|
23289
|
+
plan.rehomed.push({ from: contract.id, to: receiving.id });
|
|
22855
23290
|
if (contract.methods.length === leaving.length) {
|
|
22856
23291
|
plan.notices.push(`"${contract.id}" is left with no methods \u2014 "${source.id}" no longer declares anything on it.`);
|
|
22857
23292
|
}
|
|
@@ -22863,6 +23298,7 @@ var init_specs2 = __esm({
|
|
|
22863
23298
|
const kept = cloneSpec(impl);
|
|
22864
23299
|
kept.methods = kept.methods.filter((m) => !methods.includes(m.name));
|
|
22865
23300
|
this.stageMoveEdit(plan, "implementation", impl.id, impl, kept);
|
|
23301
|
+
leftImplementations.push(impl.id);
|
|
22866
23302
|
}
|
|
22867
23303
|
}
|
|
22868
23304
|
this.stageMoveEdit(plan, "interface", receiving.id, stated, {
|
|
@@ -22891,9 +23327,11 @@ var init_specs2 = __esm({
|
|
|
22891
23327
|
...cloneSpec(targetImpl),
|
|
22892
23328
|
methods: [...cloneSpec(targetImpl.methods), ...travelling]
|
|
22893
23329
|
});
|
|
23330
|
+
for (const id of leftImplementations) plan.rehomed.push({ from: id, to: targetImpl.id });
|
|
22894
23331
|
} else if (travelling.length > 0) {
|
|
22895
23332
|
const created = createdImplementation(target, receiving.id, source.id, travelling, implementations, contracts);
|
|
22896
23333
|
this.stageMoveEdit(plan, "implementation", created.spec.id, null, created.spec);
|
|
23334
|
+
for (const id of leftImplementations) plan.rehomed.push({ from: id, to: created.spec.id });
|
|
22897
23335
|
plan.created.push(created.named);
|
|
22898
23336
|
plan.notices.push(...created.notices);
|
|
22899
23337
|
}
|
|
@@ -23023,7 +23461,7 @@ var init_specs2 = __esm({
|
|
|
23023
23461
|
* here: every save does it already, and a second call would only be a hop
|
|
23024
23462
|
* across a component boundary that no narrative claims.
|
|
23025
23463
|
*/
|
|
23026
|
-
writeMoveEdits(edits) {
|
|
23464
|
+
writeMoveEdits(edits, finish) {
|
|
23027
23465
|
const reports = moveChangeReports(edits, false);
|
|
23028
23466
|
const written = [];
|
|
23029
23467
|
try {
|
|
@@ -23032,6 +23470,7 @@ var init_specs2 = __esm({
|
|
|
23032
23470
|
report2.notices.push(...this.saveMovedSpec(edit.kind, edit.after));
|
|
23033
23471
|
written.push(edit);
|
|
23034
23472
|
}
|
|
23473
|
+
finish?.();
|
|
23035
23474
|
} catch (e) {
|
|
23036
23475
|
for (const edit of [...written].reverse()) {
|
|
23037
23476
|
try {
|
|
@@ -23544,6 +23983,42 @@ function rewriteRefFields(specsDir, remap, excludeDir) {
|
|
|
23544
23983
|
}
|
|
23545
23984
|
return rewritten;
|
|
23546
23985
|
}
|
|
23986
|
+
function rekeyLintAllows(specsDir, rename) {
|
|
23987
|
+
const rewritten = [];
|
|
23988
|
+
for (const file of listFilesRecursive(specsDir, ".yaml")) {
|
|
23989
|
+
let raw;
|
|
23990
|
+
try {
|
|
23991
|
+
raw = readYamlFile(file);
|
|
23992
|
+
} catch {
|
|
23993
|
+
continue;
|
|
23994
|
+
}
|
|
23995
|
+
const allows = raw?.lint?.allow;
|
|
23996
|
+
const kind = raw && typeof raw === "object" ? specKind(raw) : null;
|
|
23997
|
+
if (!kind || !Array.isArray(allows)) continue;
|
|
23998
|
+
const specId = kind === "system" ? "system" : String(raw.id);
|
|
23999
|
+
let changed = false;
|
|
24000
|
+
for (const allow of allows) {
|
|
24001
|
+
if (!allow || typeof allow !== "object") continue;
|
|
24002
|
+
const next = rekeyAnchor(rename, {
|
|
24003
|
+
spec: specId,
|
|
24004
|
+
...typeof allow.at === "string" ? { at: allow.at } : {},
|
|
24005
|
+
...Array.isArray(allow.covers) ? { covers: allow.covers } : {}
|
|
24006
|
+
});
|
|
24007
|
+
if (next.at !== void 0 && next.at !== allow.at) {
|
|
24008
|
+
allow.at = next.at;
|
|
24009
|
+
changed = true;
|
|
24010
|
+
}
|
|
24011
|
+
if (next.covers && JSON.stringify(next.covers) !== JSON.stringify(allow.covers)) {
|
|
24012
|
+
allow.covers = next.covers;
|
|
24013
|
+
changed = true;
|
|
24014
|
+
}
|
|
24015
|
+
}
|
|
24016
|
+
if (!changed) continue;
|
|
24017
|
+
writeYamlFile(file, raw);
|
|
24018
|
+
rewritten.push({ kind, id: specId });
|
|
24019
|
+
}
|
|
24020
|
+
return rewritten;
|
|
24021
|
+
}
|
|
23547
24022
|
function rebaseImplementationPaths(specsDir, fromRoot, toRoot) {
|
|
23548
24023
|
for (const file of listFilesRecursive(specsDir, ".yaml")) {
|
|
23549
24024
|
let raw;
|
|
@@ -23613,24 +24088,32 @@ function renameComponent(componentId, newId) {
|
|
|
23613
24088
|
...movingInterface ? [{ kind: "interface", from: movingInterface.id, to: interfaceId }] : [],
|
|
23614
24089
|
...movingImplementation ? [{ kind: "implementation", from: movingImplementation.id, to: implementationId }] : []
|
|
23615
24090
|
];
|
|
23616
|
-
const
|
|
24091
|
+
const rename = {
|
|
24092
|
+
specs: renamed.map(({ from, to }) => ({ from, to })),
|
|
24093
|
+
components: [{ from: componentId, to: newId }]
|
|
24094
|
+
};
|
|
24095
|
+
projectConfigRepository.rekeyCarried(rename, true);
|
|
24096
|
+
const rewrittenRefs = rewriteRefFields(aiPathsAt(getProjectRoot()).specsDir(), (ref, position) => {
|
|
23617
24097
|
if (position === "component" || position === "entity-class" || position === "auth-source") {
|
|
23618
24098
|
return ref === componentId ? newId : ref;
|
|
23619
24099
|
}
|
|
23620
24100
|
if (position === "interface" && ref === movingInterface?.id) return interfaceId;
|
|
23621
24101
|
return ref;
|
|
23622
|
-
})
|
|
24102
|
+
});
|
|
24103
|
+
const allowsRekeyed = rekeyLintAllows(aiPathsAt(getProjectRoot()).specsDir(), rename);
|
|
24104
|
+
const rewritten = [...new Set([...rewrittenRefs, ...allowsRekeyed].filter((spec) => !renamed.some((moved) => moved.kind === spec.kind && moved.from === spec.id)).map((spec) => spec.id))];
|
|
23623
24105
|
invalidateSpecCache();
|
|
23624
24106
|
moveRenamedSpecs(componentId, newId, component, movingInterface, movingImplementation);
|
|
23625
|
-
|
|
24107
|
+
const carried = projectConfigRepository.rekeyCarried(rename);
|
|
24108
|
+
return { renamed, rewritten, carried };
|
|
23626
24109
|
}
|
|
23627
24110
|
function moveRenamedSpecs(componentId, newId, component, movingInterface, movingImplementation) {
|
|
23628
24111
|
const interfaceId = `i${newId}`;
|
|
23629
24112
|
const implementationId = `${newId}_impl`;
|
|
23630
|
-
const
|
|
24113
|
+
const movedComponent2 = loadComponentSpec(componentId) ?? component;
|
|
23631
24114
|
const movedInterface = movingInterface ? loadInterfaceSpec(movingInterface.id) ?? movingInterface : null;
|
|
23632
24115
|
const movedImplementation = movingImplementation ? loadImplementationSpec(movingImplementation.id) ?? movingImplementation : null;
|
|
23633
|
-
saveComponentSpec({ ...
|
|
24116
|
+
saveComponentSpec({ ...movedComponent2, id: newId });
|
|
23634
24117
|
if (movedInterface) saveInterfaceSpec({ ...movedInterface, id: interfaceId, component: newId });
|
|
23635
24118
|
if (movedImplementation) {
|
|
23636
24119
|
const oldFile = getImplementationPath(movedImplementation.id);
|
|
@@ -23683,6 +24166,19 @@ function renameMethod(componentId, methodName, newName, pinSymbol) {
|
|
|
23683
24166
|
const implementations = loadImplementationSpecs();
|
|
23684
24167
|
const movingContracts = new Set(moving.map((i) => i.id));
|
|
23685
24168
|
const renamed = [];
|
|
24169
|
+
const rename = {
|
|
24170
|
+
methods: [{
|
|
24171
|
+
component: componentId,
|
|
24172
|
+
method: methodName,
|
|
24173
|
+
toComponent: componentId,
|
|
24174
|
+
toMethod: newName,
|
|
24175
|
+
specs: [
|
|
24176
|
+
...moving.map((i) => i.id),
|
|
24177
|
+
...implementations.filter((impl) => movingContracts.has(impl.contract) && impl.methods.some((m) => m.name === methodName)).map((impl) => impl.id)
|
|
24178
|
+
]
|
|
24179
|
+
}]
|
|
24180
|
+
};
|
|
24181
|
+
projectConfigRepository.rekeyCarried(rename, true);
|
|
23686
24182
|
for (const contract of moving) {
|
|
23687
24183
|
saveInterfaceSpec({
|
|
23688
24184
|
...contract,
|
|
@@ -23705,8 +24201,11 @@ function renameMethod(componentId, methodName, newName, pinSymbol) {
|
|
|
23705
24201
|
}
|
|
23706
24202
|
invalidateSpecCache();
|
|
23707
24203
|
const specsDir = aiPathsAt(getProjectRoot()).specsDir();
|
|
23708
|
-
const
|
|
24204
|
+
const retargeted = rewriteRefFields(specsDir, (ref, position, owner) => position === "method" && owner === componentId && ref === methodName ? newName : ref);
|
|
24205
|
+
const allowsRekeyed = rekeyLintAllows(specsDir, rename);
|
|
24206
|
+
const rewritten = [...new Set([...retargeted, ...allowsRekeyed].map((spec) => spec.id))];
|
|
23709
24207
|
const mentions = collectMentions(specsDir, methodName, moving);
|
|
24208
|
+
const carried = projectConfigRepository.rekeyCarried(rename);
|
|
23710
24209
|
return {
|
|
23711
24210
|
component: componentId,
|
|
23712
24211
|
from: methodName,
|
|
@@ -23714,7 +24213,8 @@ function renameMethod(componentId, methodName, newName, pinSymbol) {
|
|
|
23714
24213
|
renamed,
|
|
23715
24214
|
rewritten,
|
|
23716
24215
|
mentions,
|
|
23717
|
-
...pinnedSymbol ? { pinnedSymbol } : {}
|
|
24216
|
+
...pinnedSymbol ? { pinnedSymbol } : {},
|
|
24217
|
+
carried
|
|
23718
24218
|
};
|
|
23719
24219
|
}
|
|
23720
24220
|
function renameInSignature(signature, from, to) {
|
|
@@ -23764,6 +24264,7 @@ var init_provision = __esm({
|
|
|
23764
24264
|
init_fs();
|
|
23765
24265
|
init_yaml();
|
|
23766
24266
|
init_errors();
|
|
24267
|
+
init_identity_rename();
|
|
23767
24268
|
init_models();
|
|
23768
24269
|
METHOD_NAME = /^[a-z][a-zA-Z0-9]*$/;
|
|
23769
24270
|
PROSE_FIELDS2 = /* @__PURE__ */ new Set([
|
|
@@ -29744,6 +30245,8 @@ function restatementParent(restatement) {
|
|
|
29744
30245
|
return { kind: "component", id: spec.component };
|
|
29745
30246
|
case "implementation":
|
|
29746
30247
|
return { kind: "interface", id: spec.contract };
|
|
30248
|
+
case "type":
|
|
30249
|
+
return typeof spec.subsystem === "string" && spec.subsystem !== "" ? { kind: "subsystem", id: spec.subsystem } : null;
|
|
29747
30250
|
default:
|
|
29748
30251
|
return null;
|
|
29749
30252
|
}
|
|
@@ -29934,7 +30437,7 @@ function writeSpec(restatement) {
|
|
|
29934
30437
|
if (application.refusal !== void 0) throw new Error(application.refusal);
|
|
29935
30438
|
const gateNotices = restatement.kind === "component" ? judgeComponent(application.spec, bound2) : [];
|
|
29936
30439
|
const persisted = persistCandidate(restatement.kind, application.spec);
|
|
29937
|
-
const testsToRevisit = testsInvalidatedBy(application.changedMethods, [existing, application.spec], bound2);
|
|
30440
|
+
const testsToRevisit = testsInvalidatedBy(restatement.kind, id, application.changedMethods, [existing, application.spec], bound2);
|
|
29938
30441
|
return {
|
|
29939
30442
|
kind: restatement.kind,
|
|
29940
30443
|
id,
|
|
@@ -29959,42 +30462,59 @@ function persistCandidate(kind, spec) {
|
|
|
29959
30462
|
}
|
|
29960
30463
|
return { notices: saveSpec(kind, spec) };
|
|
29961
30464
|
}
|
|
29962
|
-
function testsInvalidatedBy(methods, specs, options) {
|
|
30465
|
+
function testsInvalidatedBy(kind, id, methods, specs, options, written = []) {
|
|
29963
30466
|
const testRoots = options.rules?.conformance?.testRoots ?? [];
|
|
29964
30467
|
if (methods.length === 0 || testRoots.length === 0) return [];
|
|
29965
|
-
|
|
29966
|
-
|
|
30468
|
+
return findTestsReferencing2(searchedMethods(kind, id, methods, specs, written), getProjectRoot(), testRoots);
|
|
30469
|
+
}
|
|
30470
|
+
function searchedMethods(kind, id, names, specs, written) {
|
|
30471
|
+
const stated = (name) => written.find((m) => m?.name === name)?.symbol;
|
|
30472
|
+
if (kind === "interface") {
|
|
30473
|
+
const realizations = loadImplementationSpecs().filter((impl) => impl.contract === id);
|
|
30474
|
+
return names.flatMap((name) => {
|
|
30475
|
+
const found = realizations.flatMap((impl) => impl.methods.filter((m) => m.name === name).map((m) => ({ name, symbol: stated(name) ?? m.symbol, sourcePath: m.sourcePath ?? impl.sourcePath })));
|
|
30476
|
+
return found.length > 0 ? found : [{ name, symbol: stated(name) }];
|
|
30477
|
+
});
|
|
30478
|
+
}
|
|
30479
|
+
return names.map((name) => {
|
|
30480
|
+
const holders = specs.map((spec) => {
|
|
30481
|
+
const holder = spec;
|
|
30482
|
+
const method2 = holder?.methods?.find((m) => m.name === name);
|
|
30483
|
+
return method2 ? { method: method2, file: method2.sourcePath ?? holder?.sourcePath } : null;
|
|
30484
|
+
}).filter((h) => h !== null);
|
|
30485
|
+
const symbol = stated(name) ?? holders.map((h) => h.method.symbol).find((s) => s !== void 0);
|
|
30486
|
+
const sourcePath = holders.map((h) => h.file).find((f) => f !== void 0) ?? specs.map((spec) => spec?.sourcePath).find((f) => f !== void 0);
|
|
30487
|
+
return { name, symbol, sourcePath };
|
|
30488
|
+
});
|
|
29967
30489
|
}
|
|
29968
30490
|
function deleteSpec2(kind, id) {
|
|
29969
30491
|
const bound2 = candidateOptions();
|
|
29970
30492
|
const stored = loadSpec(kind, id);
|
|
29971
30493
|
const deleted = deleteSpec(kind, id);
|
|
29972
30494
|
const methods = deleted ? (stored?.methods ?? []).map((m) => m.name) : [];
|
|
29973
|
-
const testsToRevisit = testsInvalidatedBy(methods, [stored], bound2);
|
|
30495
|
+
const testsToRevisit = testsInvalidatedBy(kind, id, methods, [stored], bound2);
|
|
29974
30496
|
return { kind, id, deleted, testsToRevisit };
|
|
29975
30497
|
}
|
|
29976
30498
|
function updateSpecGated(kind, id, delta, dryRun) {
|
|
29977
30499
|
const bound2 = candidateOptions();
|
|
29978
30500
|
const gate = componentCandidateGate(bound2);
|
|
29979
|
-
const report2 = updateSpec(kind, id, delta, gate, dryRun);
|
|
29980
30501
|
const testRoots = bound2.rules?.conformance?.testRoots ?? [];
|
|
29981
|
-
const
|
|
30502
|
+
const stored = testRoots.length > 0 ? loadSpec(kind, id) : null;
|
|
30503
|
+
const report2 = updateSpec(kind, id, delta, gate, dryRun);
|
|
30504
|
+
const changed = changedMethods(report2);
|
|
29982
30505
|
if (changed.length > 0 && testRoots.length > 0) {
|
|
29983
|
-
|
|
30506
|
+
const written = Array.isArray(delta?.methods) ? delta.methods : [];
|
|
30507
|
+
report2.testsToRevisit = testsInvalidatedBy(kind, id, changed, [stored], bound2, written);
|
|
29984
30508
|
}
|
|
29985
30509
|
return report2;
|
|
29986
30510
|
}
|
|
29987
|
-
function changedMethods(report2
|
|
30511
|
+
function changedMethods(report2) {
|
|
29988
30512
|
const named = /* @__PURE__ */ new Set();
|
|
29989
30513
|
for (const change of report2.changes) {
|
|
29990
30514
|
const [field, name] = change.path.split(".");
|
|
29991
30515
|
if (field === "methods" && name) named.add(name);
|
|
29992
30516
|
}
|
|
29993
|
-
|
|
29994
|
-
return [...named].map((name) => ({
|
|
29995
|
-
name,
|
|
29996
|
-
symbol: written.find((m) => m?.name === name)?.symbol
|
|
29997
|
-
}));
|
|
30517
|
+
return [...named];
|
|
29998
30518
|
}
|
|
29999
30519
|
function methodMoveGate(source) {
|
|
30000
30520
|
const bound2 = candidateOptions();
|
|
@@ -30040,7 +30560,8 @@ var init_authoring = __esm({
|
|
|
30040
30560
|
subsystem: () => "System spec must be initialized (sdd_initialize_system) first.",
|
|
30041
30561
|
component: (id) => `Parent subsystem "${id}" does not exist.`,
|
|
30042
30562
|
interface: (id) => `Component "${id}" does not exist.`,
|
|
30043
|
-
implementation: (id) => `Interface contract "${id}" does not exist
|
|
30563
|
+
implementation: (id) => `Interface contract "${id}" does not exist.`,
|
|
30564
|
+
type: (id) => `Owning subsystem "${id}" does not exist \u2014 name a subsystem the tree has, or omit subsystem for a system-level value object.`
|
|
30044
30565
|
};
|
|
30045
30566
|
REWRITE_LABEL = {
|
|
30046
30567
|
system: "System spec",
|
|
@@ -30891,7 +31412,7 @@ ${renderChangeReport(report2)}`,
|
|
|
30891
31412
|
server,
|
|
30892
31413
|
"sdd_rename_component",
|
|
30893
31414
|
{
|
|
30894
|
-
description: "Rename a component and rewrite every reference to it in the bound tree: dependsOn, owns and dispatch entries, lifecycle entrypoints, published interfaces at L1 and L0, narrative call/dispatch/register targets, an interface's component, an implementation's contract and an entity's componentClass. The interface named i<id> and the implementation named <id>_impl move to the new ids and files; interfaces and implementations named otherwise keep their ids. Display names are left as they are. Refuses, writing nothing: a component that does not exist (component-missing), one inside a chained subproject (chained-component \u2014 rename it from that project's own root), a new id that is not a lowercase identifier without a namespace separator (invalid-id), and a new id \u2014 or i<newId> or <newId>_impl \u2014 already in use (id-taken). Returns the specs moved, each with its old and new id,
|
|
31415
|
+
description: "Rename a component and rewrite every reference to it in the bound tree: dependsOn, owns and dispatch entries, lifecycle entrypoints, published interfaces at L1 and L0, narrative call/dispatch/register targets, an interface's component, an implementation's contract and an entity's componentClass. The interface named i<id> and the implementation named <id>_impl move to the new ids and files; interfaces and implementations named otherwise keep their ids. Findings keyed on the component follow it too: every lint allow naming it on an edge site or in a covered unit, and every entry of the debt register (.wai/project.yaml rules.conformance.carried) anchored on a renamed spec or naming the component in its site or units \u2014 rewritten in place, every comment and all other formatting of the register kept, so unchanged debt never reads as paid and new at once. A register that cannot be rewritten that precisely is refused before the first write. Display names are left as they are. Refuses, writing nothing: a component that does not exist (component-missing), one inside a chained subproject (chained-component \u2014 rename it from that project's own root), a new id that is not a lowercase identifier without a namespace separator (invalid-id), and a new id \u2014 or i<newId> or <newId>_impl \u2014 already in use (id-taken). Returns the specs moved, each with its old and new id, the ids of the other specs rewritten (lint allows included), and `carried`: each register edit \u2014 the entry by code, spec and site as it stood, the key changed (spec, at or covers), from and to.",
|
|
30895
31416
|
inputSchema: {
|
|
30896
31417
|
id: import_zod11.z.string().describe("The component to rename (namespaced if needed)"),
|
|
30897
31418
|
newId: import_zod11.z.string().describe("Its new id: a lowercase identifier with no namespace separator")
|
|
@@ -30909,7 +31430,7 @@ ${renderChangeReport(report2)}`,
|
|
|
30909
31430
|
server,
|
|
30910
31431
|
"sdd_rename_method",
|
|
30911
31432
|
{
|
|
30912
|
-
description: "Rename a contract method and retarget every reference to it in the bound tree. The method moves on every interface of the component that declares it \u2014 its name, and the name inside its signature \u2014 and on the implementations of those contracts, carrying narrative, sourcePath, symbol, detail, intent and findings unchanged; an implementation that declared no symbol is pinned to the old name unless pinSymbol is false, so the function it already binds to keeps binding. Narrative call, register and dispatch steps naming this component and method, dispatch-table bindings and lifecycle entrypoints are retargeted. Prose is never rewritten and a gRPC endpoint binding keeps its wire method \u2014 renaming a contract method must not silently rename an RPC; both are reported as mentions. Refuses, writing nothing: a component that does not exist (component-missing), one inside a chained subproject (chained-component \u2014 rename its method from that project's own root), a new name that is not a camel-case identifier (invalid-name), a method the component does not declare (method-missing), and a name a moving contract already declares (name-taken). Returns the specs the method moved in, the specs retargeted, the specs whose prose still names it,
|
|
31433
|
+
description: "Rename a contract method and retarget every reference to it in the bound tree. The method moves on every interface of the component that declares it \u2014 its name, and the name inside its signature \u2014 and on the implementations of those contracts, carrying narrative, sourcePath, symbol, detail, intent and findings unchanged; an implementation that declared no symbol is pinned to the old name unless pinSymbol is false, so the function it already binds to keeps binding. Narrative call, register and dispatch steps naming this component and method, dispatch-table bindings and lifecycle entrypoints are retargeted, and so are the findings keyed on it: a lint allow at the method on a spec it moved in or covering `<component>.<method>`, and every debt-register entry (.wai/project.yaml rules.conformance.carried) keyed the same way \u2014 rewritten in place with every comment and all other formatting kept (a register that cannot be rewritten that precisely is refused before the first write). Prose is never rewritten and a gRPC endpoint binding keeps its wire method \u2014 renaming a contract method must not silently rename an RPC; both are reported as mentions. Refuses, writing nothing: a component that does not exist (component-missing), one inside a chained subproject (chained-component \u2014 rename its method from that project's own root), a new name that is not a camel-case identifier (invalid-name), a method the component does not declare (method-missing), and a name a moving contract already declares (name-taken). Returns the specs the method moved in, the specs retargeted (lint allows included), the specs whose prose still names it, the pinned symbol when one was set, and `carried`: each register edit.",
|
|
30913
31434
|
inputSchema: {
|
|
30914
31435
|
id: import_zod11.z.string().describe("The component whose method is renamed (namespaced if needed)"),
|
|
30915
31436
|
method: import_zod11.z.string().describe("The method name as it stands"),
|
|
@@ -30929,7 +31450,7 @@ ${renderChangeReport(report2)}`,
|
|
|
30929
31450
|
server,
|
|
30930
31451
|
"sdd_move_methods",
|
|
30931
31452
|
{
|
|
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.",
|
|
31453
|
+
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. Findings keyed on a moved method follow it: a lint allow anchored at it moves to the receiving spec, one covering `<from>.<method>` names `<to>.<method>`, and the debt register (.wai/project.yaml rules.conformance.carried) is rekeyed the same way in place, every comment and all other formatting kept \u2014 the report's `carried` lists each register edit, and a register that cannot be rewritten that precisely is refused before the first write. 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.",
|
|
30933
31454
|
inputSchema: {
|
|
30934
31455
|
from: import_zod11.z.string().describe("The component the methods belong to (namespaced if needed)"),
|
|
30935
31456
|
to: import_zod11.z.string().describe("The component that should receive them (namespaced if needed)"),
|
|
@@ -31282,7 +31803,7 @@ ${renderChangeReport(report2)}`,
|
|
|
31282
31803
|
id: import_zod11.z.string().describe("Lowercase identifier"),
|
|
31283
31804
|
name: import_zod11.z.string().describe("Human-readable name"),
|
|
31284
31805
|
description: import_zod11.z.string().optional(),
|
|
31285
|
-
subsystem: import_zod11.z.string().optional().describe("Owning subsystem id; omit for a system-level shared value object"),
|
|
31806
|
+
subsystem: import_zod11.z.string().optional().describe("Owning subsystem id; omit for a system-level shared value object. A subsystem the tree does not have is refused and nothing is written"),
|
|
31286
31807
|
group: import_zod11.z.string().optional().describe("Optional logical group ID to organize this type in subfolders"),
|
|
31287
31808
|
fields: import_zod11.z.array(import_zod11.z.object({
|
|
31288
31809
|
name: import_zod11.z.string(),
|
|
@@ -31316,7 +31837,7 @@ ${renderChangeReport(report2)}`,
|
|
|
31316
31837
|
server,
|
|
31317
31838
|
"sdd_add_type",
|
|
31318
31839
|
{
|
|
31319
|
-
description: "Define an entity or value-object type (the data components operate on). Entities are owned by a subsystem; shared value objects omit subsystem (system-level). Fields are data; methods are PURE intrinsic behaviour only \u2014 anything needing a collaborator belongs on a component, taking the entity as an argument. A type may also CLAIM code: sourcePath names the file holding its declaration (and each method may name its own), symbol binds the code-level name when it differs \u2014 the file must then resolve and the declaration must be anchored in it. Re-defining an existing id REPLACES fields/methods/invariants and restates sourcePath/symbol (an omitted list or path is CLEARED, and a dropped member is reported); lint/ext are carried forward. The answer carries a write receipt as structured content beside the sentence \u2014 whether a spec already held the id, and the notices a restatement raised, each as its own entry. A type carries no lifecycle status, so the receipt states none.",
|
|
31840
|
+
description: "Define an entity or value-object type (the data components operate on). Entities are owned by a subsystem; shared value objects omit subsystem (system-level). Fields are data; methods are PURE intrinsic behaviour only \u2014 anything needing a collaborator belongs on a component, taking the entity as an argument. A type may also CLAIM code: sourcePath names the file holding its declaration (and each method may name its own), symbol binds the code-level name when it differs \u2014 the file must then resolve and the declaration must be anchored in it. An owning subsystem the tree does not have is refused, writing nothing, exactly as a component under an unknown subsystem is. Re-defining an existing id REPLACES fields/methods/invariants and restates sourcePath/symbol (an omitted list or path is CLEARED, and a dropped member is reported); lint/ext are carried forward. The answer carries a write receipt as structured content beside the sentence \u2014 whether a spec already held the id, and the notices a restatement raised, each as its own entry. A type carries no lifecycle status, so the receipt states none.",
|
|
31320
31841
|
inputSchema: typeInput,
|
|
31321
31842
|
outputSchema: specWriteReceiptOutput
|
|
31322
31843
|
},
|