@wairon/cli 5.1.1-dev.64 → 5.1.1-dev.65
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 +211 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +199 -5
- 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.65";
|
|
69
69
|
GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
70
70
|
SUPPORTED_ALIASES = ["wai"];
|
|
71
71
|
SCAN_EXCLUDE_DIRS = /* @__PURE__ */ new Set([
|
|
@@ -2423,6 +2423,24 @@ var init_specs = __esm({
|
|
|
2423
2423
|
* stereotypes should bind tech directly (TECH_ON_LOGIC_COMPONENT).
|
|
2424
2424
|
*/
|
|
2425
2425
|
technologies: import_zod8.z.array(import_zod8.z.string()).optional(),
|
|
2426
|
+
/**
|
|
2427
|
+
* The parameter names THIS realization takes BEFORE the ones its contract
|
|
2428
|
+
* declares — a config object, a data root, the transport handles a portal is
|
|
2429
|
+
* handed. Supplied by whatever wires the component up, never by the caller
|
|
2430
|
+
* the contract describes, which is why they belong to the realization and
|
|
2431
|
+
* not to the contract: another realization of the same contract may hold
|
|
2432
|
+
* them as fields instead.
|
|
2433
|
+
*
|
|
2434
|
+
* Declared rather than guessed, because a leading parameter the contract
|
|
2435
|
+
* does not name is otherwise indistinguishable from one it named under a
|
|
2436
|
+
* different name — `seed(config)` realized as `bootstrapInstance(cfg)` reads
|
|
2437
|
+
* as a dropped parameter to anything that infers. A leading parameter this
|
|
2438
|
+
* list does not name is a finding (UNDECLARED_PARAM), and only a LEADING run
|
|
2439
|
+
* is dropped: one of these names appearing after the contract's own
|
|
2440
|
+
* parameters is not wiring, it is an argument in the middle of the caller's
|
|
2441
|
+
* list.
|
|
2442
|
+
*/
|
|
2443
|
+
injectedParams: import_zod8.z.array(import_zod8.z.string()).optional(),
|
|
2426
2444
|
methods: import_zod8.z.array(MethodImplementationSchema).default([]).superRefine((methods, ctx) => {
|
|
2427
2445
|
methods.forEach((m, i) => {
|
|
2428
2446
|
if (!m.calls?.length || m.narrative.length === 0) return;
|
|
@@ -14080,6 +14098,173 @@ var init_type_shape = __esm({
|
|
|
14080
14098
|
}
|
|
14081
14099
|
});
|
|
14082
14100
|
|
|
14101
|
+
// src/core/rules/conformance/param-conformance.ts
|
|
14102
|
+
function omittable(optional) {
|
|
14103
|
+
return optional ? "may be left out" : "is required";
|
|
14104
|
+
}
|
|
14105
|
+
function unitOf2(parameter, position) {
|
|
14106
|
+
return parameter.name ?? `#${position + 1}`;
|
|
14107
|
+
}
|
|
14108
|
+
function judge(declared, realized, injected, typeAgrees) {
|
|
14109
|
+
let wiring = 0;
|
|
14110
|
+
while (wiring < realized.length && realized[wiring].name !== void 0 && injected.has(realized[wiring].name)) wiring++;
|
|
14111
|
+
const taken = realized.slice(wiring);
|
|
14112
|
+
const matched = Math.min(declared.length, taken.length);
|
|
14113
|
+
const found = {
|
|
14114
|
+
unrealized: /* @__PURE__ */ new Map(),
|
|
14115
|
+
undeclared: /* @__PURE__ */ new Map(),
|
|
14116
|
+
renamed: /* @__PURE__ */ new Map(),
|
|
14117
|
+
optionality: /* @__PURE__ */ new Map()
|
|
14118
|
+
};
|
|
14119
|
+
for (const param of declared.slice(matched)) {
|
|
14120
|
+
found.unrealized.set(param.name, { unit: param.name, told: `"${param.name}"` });
|
|
14121
|
+
}
|
|
14122
|
+
taken.slice(matched).forEach((param, index) => {
|
|
14123
|
+
const unit = unitOf2(param, wiring + matched + index);
|
|
14124
|
+
found.undeclared.set(unit, { unit, told: `"${unit}"` });
|
|
14125
|
+
});
|
|
14126
|
+
for (let position = 0; position < matched; position++) {
|
|
14127
|
+
const param = declared[position];
|
|
14128
|
+
const at = taken[position];
|
|
14129
|
+
if (at.name !== void 0 && at.name !== param.name && typeAgrees(param, at)) {
|
|
14130
|
+
found.renamed.set(`${param.name}\u2192${at.name}`, {
|
|
14131
|
+
unit: param.name,
|
|
14132
|
+
told: `"${param.name}" (the code calls it "${at.name}")`
|
|
14133
|
+
});
|
|
14134
|
+
}
|
|
14135
|
+
if (!!param.optional !== at.optional) {
|
|
14136
|
+
found.optionality.set(`${param.name}:${at.optional}`, {
|
|
14137
|
+
unit: param.name,
|
|
14138
|
+
told: `"${param.name}" (the contract says it ${omittable(!!param.optional)}, the code says it ${omittable(at.optional)})`
|
|
14139
|
+
});
|
|
14140
|
+
}
|
|
14141
|
+
}
|
|
14142
|
+
return found;
|
|
14143
|
+
}
|
|
14144
|
+
function agreed(judgements, reading) {
|
|
14145
|
+
const [first, ...rest] = judgements;
|
|
14146
|
+
return [...first[reading]].filter(([fact]) => rest.every((other) => other[reading].has(fact))).map(([, finding]) => finding);
|
|
14147
|
+
}
|
|
14148
|
+
var paramConformanceRule;
|
|
14149
|
+
var init_param_conformance = __esm({
|
|
14150
|
+
"src/core/rules/conformance/param-conformance.ts"() {
|
|
14151
|
+
"use strict";
|
|
14152
|
+
init_models();
|
|
14153
|
+
paramConformanceRule = {
|
|
14154
|
+
name: "param-conformance",
|
|
14155
|
+
description: "Code-to-contract for the SIGNATURE, the last of the three readings a spec-driven gate never made: a contract declares `params`, and nothing ever compared them to the parameters of the function that realizes the method. A contract could promise an argument the code does not take, take one the contract never mentions \u2014 including a secret \u2014 or name the same argument two different things, and the brief handed to an implementer would carry the contract's version. Parameters are matched by POSITION against the tail of the realization's list, and the declared type is what tells a rename from a dropped argument: `seed(config: HostConfig)` realized as `bootstrapInstance(cfg: HostConfig)` is one parameter under two names, which anything matching on names alone reads as a parameter the code lost. What a realization takes BEFORE the contract's own parameters is wiring, and it is declared on the implementation as `injectedParams` rather than inferred, because an inferred prefix cannot be told from a renamed first argument. A method the named file only CALLS is left to `methodRealization`, which already reports that the body is not here.",
|
|
14156
|
+
codes: [
|
|
14157
|
+
{
|
|
14158
|
+
code: "UNREALIZED_PARAM",
|
|
14159
|
+
defaultSeverity: "warning",
|
|
14160
|
+
summary: "A contract declares a parameter the function realizing the method does not take \u2014 the contract promises an argument that would go nowhere, and every brief and caller built from it passes one",
|
|
14161
|
+
// Measured code↔spec drift, parameter by parameter, at a site the
|
|
14162
|
+
// finding names — which is why every one of them hands over `parts`.
|
|
14163
|
+
carryable: true
|
|
14164
|
+
},
|
|
14165
|
+
{
|
|
14166
|
+
code: "UNDECLARED_PARAM",
|
|
14167
|
+
defaultSeverity: "warning",
|
|
14168
|
+
summary: "The realizing function takes a parameter no contract parameter names and no declared injection accounts for \u2014 an argument a caller must supply that the design never mentions",
|
|
14169
|
+
carryable: true
|
|
14170
|
+
},
|
|
14171
|
+
{
|
|
14172
|
+
code: "PARAM_NAME_MISMATCH",
|
|
14173
|
+
defaultSeverity: "warning",
|
|
14174
|
+
summary: "A contract parameter and the one realizing it agree on position and type but not on name \u2014 the contract, the ERD and every brief say one word while the code says another",
|
|
14175
|
+
carryable: true
|
|
14176
|
+
},
|
|
14177
|
+
{
|
|
14178
|
+
code: "PARAM_OPTIONALITY",
|
|
14179
|
+
defaultSeverity: "warning",
|
|
14180
|
+
summary: "A contract and its realization disagree about whether a parameter may be left out \u2014 one of them is telling a caller an argument is required when it is not, or the reverse",
|
|
14181
|
+
carryable: true
|
|
14182
|
+
}
|
|
14183
|
+
],
|
|
14184
|
+
check(ctx) {
|
|
14185
|
+
const code = ctx.codeIndex();
|
|
14186
|
+
const codeNameOf = /* @__PURE__ */ new Map();
|
|
14187
|
+
for (const type of ctx.types) {
|
|
14188
|
+
const named = type.symbol ?? type.name;
|
|
14189
|
+
codeNameOf.set(type.id, named);
|
|
14190
|
+
if (type.subsystem) codeNameOf.set(`${type.subsystem}.${type.id}`, named);
|
|
14191
|
+
}
|
|
14192
|
+
const normalize3 = (text2) => text2.replace(/\s+/g, " ").trim();
|
|
14193
|
+
const typeAgrees = (declared, realized) => {
|
|
14194
|
+
if (!realized.type) return false;
|
|
14195
|
+
const stated = normalize3(declared.type);
|
|
14196
|
+
return stated === realized.type || codeNameOf.get(stated) === realized.type;
|
|
14197
|
+
};
|
|
14198
|
+
for (const { implementation, method: method2, sourceFile, draftContext } of ctx.implementationMethods()) {
|
|
14199
|
+
const contract = ctx.interfaceMap.get(implementation.contract);
|
|
14200
|
+
const declared = contract?.methods.find((m) => m.name === method2.name)?.params ?? [];
|
|
14201
|
+
if (declared.length === 0 || !sourceFile) continue;
|
|
14202
|
+
const file = pathKey(sourceFile);
|
|
14203
|
+
const facts = code.factsAt(file);
|
|
14204
|
+
if (!facts || facts.status !== "analyzed" || facts.analysisGrade !== "exact") continue;
|
|
14205
|
+
const symbol = method2.symbol ?? method2.name;
|
|
14206
|
+
const signatures = facts.functionParams;
|
|
14207
|
+
if (!signatures || !Object.prototype.hasOwnProperty.call(signatures, symbol)) continue;
|
|
14208
|
+
const candidates = signatures[symbol];
|
|
14209
|
+
if (candidates.length === 0) continue;
|
|
14210
|
+
const injected = new Set(implementation.injectedParams ?? []);
|
|
14211
|
+
const judgements = candidates.map((realized) => judge(declared, realized, injected, typeAgrees));
|
|
14212
|
+
const subject = candidates.length > 1 ? `every function called "${symbol}" in "${file}"` : `the function "${symbol}" in "${file}"`;
|
|
14213
|
+
const opening = subject.charAt(0).toUpperCase() + subject.slice(1);
|
|
14214
|
+
const unrealized = agreed(judgements, "unrealized");
|
|
14215
|
+
if (unrealized.length > 0) {
|
|
14216
|
+
ctx.addIssue(
|
|
14217
|
+
"warning",
|
|
14218
|
+
"UNREALIZED_PARAM",
|
|
14219
|
+
`Method "${method2.name}" of contract "${implementation.contract}" declares ${unrealized.length} parameter(s) ${subject} does not take \u2014 ${unrealized.map((found) => found.told).join(", ")}. The contract is promising an argument that would go nowhere, and nothing breaks at a call site to correct it: every brief and every caller built from the contract passes one. Take the parameter in the code, or drop it from the contract.`,
|
|
14220
|
+
implementation.id,
|
|
14221
|
+
draftContext,
|
|
14222
|
+
void 0,
|
|
14223
|
+
{ at: method2.name, covers: unrealized.map((found) => found.unit) }
|
|
14224
|
+
);
|
|
14225
|
+
}
|
|
14226
|
+
const undeclared = agreed(judgements, "undeclared");
|
|
14227
|
+
if (undeclared.length > 0) {
|
|
14228
|
+
ctx.addIssue(
|
|
14229
|
+
"warning",
|
|
14230
|
+
"UNDECLARED_PARAM",
|
|
14231
|
+
`${opening} realizing method "${method2.name}" of contract "${implementation.contract}" takes ${undeclared.length} parameter(s) the contract does not declare and no declared injection accounts for \u2014 ${undeclared.map((found) => found.told).join(", ")}. An argument a caller must supply that the design never mentions is how a credential ends up in a signature nobody has read against its contract. Declare it on the contract, name it in the implementation's \`injectedParams\` when whatever wires this component up supplies it (a LEADING run only), or take it out of the signature.`,
|
|
14232
|
+
implementation.id,
|
|
14233
|
+
draftContext,
|
|
14234
|
+
void 0,
|
|
14235
|
+
{ at: method2.name, covers: undeclared.map((found) => found.unit) }
|
|
14236
|
+
);
|
|
14237
|
+
}
|
|
14238
|
+
const renamed = agreed(judgements, "renamed");
|
|
14239
|
+
if (renamed.length > 0) {
|
|
14240
|
+
ctx.addIssue(
|
|
14241
|
+
"warning",
|
|
14242
|
+
"PARAM_NAME_MISMATCH",
|
|
14243
|
+
`Method "${method2.name}" of contract "${implementation.contract}" and ${subject} agree on position and type but not on name for ${renamed.length} parameter(s) \u2014 ${renamed.map((f) => f.told).join("; ")}. The contract, the ERD and every brief carry one word and the code answers to another, which is a rename nobody recorded rather than a different argument \u2014 the declared type agreeing is what says so. Rename one side to the other.`,
|
|
14244
|
+
implementation.id,
|
|
14245
|
+
draftContext,
|
|
14246
|
+
void 0,
|
|
14247
|
+
{ at: method2.name, covers: renamed.map((found) => found.unit) }
|
|
14248
|
+
);
|
|
14249
|
+
}
|
|
14250
|
+
const disagreed = agreed(judgements, "optionality");
|
|
14251
|
+
if (disagreed.length > 0) {
|
|
14252
|
+
ctx.addIssue(
|
|
14253
|
+
"warning",
|
|
14254
|
+
"PARAM_OPTIONALITY",
|
|
14255
|
+
`Method "${method2.name}" of contract "${implementation.contract}" and ${subject} disagree about whether ${disagreed.length} parameter(s) may be left out \u2014 ${disagreed.map((f) => f.told).join("; ")}. One of them is telling a caller an argument is required when it is not, or the reverse. Omittable is the code's word for it: a default value and a rest parameter make an argument omittable exactly as a question mark does.`,
|
|
14256
|
+
implementation.id,
|
|
14257
|
+
draftContext,
|
|
14258
|
+
void 0,
|
|
14259
|
+
{ at: method2.name, covers: disagreed.map((found) => found.unit) }
|
|
14260
|
+
);
|
|
14261
|
+
}
|
|
14262
|
+
}
|
|
14263
|
+
}
|
|
14264
|
+
};
|
|
14265
|
+
}
|
|
14266
|
+
});
|
|
14267
|
+
|
|
14083
14268
|
// src/core/rules/conformance/unclaimed-source.ts
|
|
14084
14269
|
var unclaimedSourceRule;
|
|
14085
14270
|
var init_unclaimed_source = __esm({
|
|
@@ -15584,6 +15769,7 @@ var init_repository = __esm({
|
|
|
15584
15769
|
init_integration_sim_coverage();
|
|
15585
15770
|
init_type_realization();
|
|
15586
15771
|
init_type_shape();
|
|
15772
|
+
init_param_conformance();
|
|
15587
15773
|
init_unclaimed_source();
|
|
15588
15774
|
init_export_conformance();
|
|
15589
15775
|
init_carried_debt();
|
|
@@ -15752,11 +15938,14 @@ var init_repository = __esm({
|
|
|
15752
15938
|
integrationSimWiringRule,
|
|
15753
15939
|
integrationSimCoverageRule,
|
|
15754
15940
|
// The data model's own claim on code — does the file hold the type, and is
|
|
15755
|
-
// it the SHAPE the spec claims —
|
|
15756
|
-
// the
|
|
15757
|
-
//
|
|
15941
|
+
// it the SHAPE the spec claims — then the SIGNATURE, the third reading:
|
|
15942
|
+
// does the code take the arguments the contract promises. And then the
|
|
15943
|
+
// question no spec can ask from the spec side: which files are named by
|
|
15944
|
+
// nothing at all. Last in the family because that one reads what all the
|
|
15945
|
+
// others named.
|
|
15758
15946
|
typeRealizationRule,
|
|
15759
15947
|
typeShapeRule,
|
|
15948
|
+
paramConformanceRule,
|
|
15760
15949
|
unclaimedSourceRule,
|
|
15761
15950
|
exportConformanceRule,
|
|
15762
15951
|
couplingRule,
|
|
@@ -15925,6 +16114,7 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
15925
16114
|
const fieldTypes = /* @__PURE__ */ new Map();
|
|
15926
16115
|
const localTypes = /* @__PURE__ */ new Map();
|
|
15927
16116
|
const typeShapes = /* @__PURE__ */ new Map();
|
|
16117
|
+
const functionParams = /* @__PURE__ */ new Map();
|
|
15928
16118
|
const mutableBindings = /* @__PURE__ */ new Set();
|
|
15929
16119
|
const schemaConstants = /* @__PURE__ */ new Map();
|
|
15930
16120
|
const derivedAliases = [];
|
|
@@ -16054,6 +16244,14 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
16054
16244
|
}
|
|
16055
16245
|
return void 0;
|
|
16056
16246
|
};
|
|
16247
|
+
const declaredParameters = (fn) => (fn.parameters ?? []).map((parameter) => {
|
|
16248
|
+
const fact = {
|
|
16249
|
+
optional: !!parameter.questionToken || !!parameter.initializer || !!parameter.dotDotDotToken
|
|
16250
|
+
};
|
|
16251
|
+
if (ts.isIdentifier(parameter.name)) fact.name = parameter.name.text;
|
|
16252
|
+
if (parameter.type) fact.type = parameter.type.getText(sf).replace(/\s+/g, " ").trim();
|
|
16253
|
+
return fact;
|
|
16254
|
+
});
|
|
16057
16255
|
const collectFunctionFacts = (fn) => {
|
|
16058
16256
|
let score = 1;
|
|
16059
16257
|
const callees = /* @__PURE__ */ new Map();
|
|
@@ -16096,6 +16294,9 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
16096
16294
|
const sites = calls.get(fnName) ?? /* @__PURE__ */ new Map();
|
|
16097
16295
|
for (const [key, site] of facts.callees) sites.set(key, site);
|
|
16098
16296
|
calls.set(fnName, sites);
|
|
16297
|
+
const signatures = functionParams.get(fnName) ?? [];
|
|
16298
|
+
signatures.push(declaredParameters(node));
|
|
16299
|
+
functionParams.set(fnName, signatures);
|
|
16099
16300
|
}
|
|
16100
16301
|
if (ts.isPropertyDeclaration(node)) recordFieldType(node.name, node.type);
|
|
16101
16302
|
else if (ts.isParameter(node) && node.parent && ts.isConstructorDeclaration(node.parent) && isParameterProperty(node)) {
|
|
@@ -16203,7 +16404,7 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
16203
16404
|
typeShapes.set(alias.name, { origin: "derived", fields: schemaMembers(literal), methods: [] });
|
|
16204
16405
|
}
|
|
16205
16406
|
const reexportOnly = sf.statements.length > 0 && sf.statements.every((st) => ts.isExportDeclaration(st) && !!st.moduleSpecifier);
|
|
16206
|
-
return { declared, anchors, exported, imports, reexports, starExports, namedReexports, complexity, calls, importBindings, typeOnlyBindings, fieldTypes, localTypes, typeShapes, mutableBindings, reexportOnly };
|
|
16407
|
+
return { declared, anchors, exported, imports, reexports, starExports, namedReexports, complexity, calls, importBindings, typeOnlyBindings, fieldTypes, localTypes, typeShapes, functionParams, mutableBindings, reexportOnly };
|
|
16207
16408
|
}
|
|
16208
16409
|
function resolveRelativeModule(fromFile, specifier) {
|
|
16209
16410
|
if (!specifier.startsWith(".")) return null;
|
|
@@ -16386,6 +16587,7 @@ function buildCodeModel(implementations, types, projectRoot2, sourceRoots = [],
|
|
|
16386
16587
|
fieldTypes: Object.fromEntries([...facts.fieldTypes].map(([k, v]) => [k, [...v]])),
|
|
16387
16588
|
localTypes: Object.fromEntries([...facts.localTypes].map(([k, v]) => [k, [...v]])),
|
|
16388
16589
|
typeShapes: Object.fromEntries(facts.typeShapes),
|
|
16590
|
+
functionParams: Object.fromEntries(facts.functionParams),
|
|
16389
16591
|
topLevelMutableBindings: [...facts.mutableBindings],
|
|
16390
16592
|
reexportOnly: facts.reexportOnly
|
|
16391
16593
|
};
|
|
@@ -30005,6 +30207,7 @@ function createMcpServer(options = {}) {
|
|
|
30005
30207
|
sourcePath: import_zod11.z.string().optional().describe("Optional: target source code file path relative to project root \u2014 for a chained subproject's implementation (qualified id), relative to that subproject's root; a path given relative to this root that lands inside the subproject is re-expressed for you"),
|
|
30006
30208
|
simPath: import_zod11.z.string().optional().describe("Optional: the committed integration-sim harness file (project-relative; N:1 sharing allowed). The validator proves it exists and its import graph wires the REAL modules (this component + each direct dependency; technology adapters may stay faked) \u2014 running it is CI's job. Declaring the first simPath in a subsystem activates MISSING_INTEGRATION_SIM for its other complete non-leaf implementations"),
|
|
30007
30209
|
technologies: import_zod11.z.array(import_zod11.z.string()).optional().describe(`External technologies this implementation binds to (e.g. ["mysql"]) \u2014 declares this component's ownership tree as the technology's home; references outside it are flagged (TECH_LEAKAGE) and contract identifiers must stay intent-language. Only for Adapter/Store/Registry/Index components.`),
|
|
30210
|
+
injectedParams: import_zod11.z.array(import_zod11.z.string()).optional().describe("The parameter names this realization takes BEFORE the ones its contract declares \u2014 a config object, a data root, the transport handles a portal is handed. Supplied by whatever wires the component up, never by the caller the contract describes, which is why they belong here and not to the contract: another realization may hold them as fields instead. Declared rather than guessed, because a leading parameter the contract does not name cannot be told from one it named under a different name (`seed(config)` realized as `bootstrapInstance(cfg)`); a leading parameter this list does not name is reported (UNDECLARED_PARAM). Only a LEADING run is dropped \u2014 one of these names appearing after the contract's own parameters is an argument in the middle of the caller's list, not wiring"),
|
|
30008
30211
|
detail: detailEnum.optional().describe("Spec-level narrative detail default for all methods"),
|
|
30009
30212
|
conformance: conformanceEnum.optional().describe("Spec-level conformance tier default: declared | anchored | off (omitted = stereotype default: Portal \u2192 anchored, else declared)"),
|
|
30010
30213
|
methods: import_zod11.z.array(import_zod11.z.object(implMethodShape).strict()).optional().describe("Method implementations containing L5 narratives"),
|
|
@@ -30015,11 +30218,11 @@ function createMcpServer(options = {}) {
|
|
|
30015
30218
|
server,
|
|
30016
30219
|
"sdd_write_narrative",
|
|
30017
30220
|
{
|
|
30018
|
-
description: "Write L4 Concrete Implementation spec containing L5 method narratives. Narratives are a FLAT ordered step list; flow steps (branch/switch/loop/try/parallel/jump/return/throw) jump by step number \u2014 blocks are just skipped regions. Steps may declare a `label` anchor, and every jump field has a *Label twin (toLabel, onTrueLabel, endLabel, \u2026) resolved to step numbers at write time \u2014 prefer labels over hand-counted numbers; an unresolvable label rejects the write. Detail dial per method: full (narrative required) | calls-only (call choreography suffices) | intent (prose instead of steps); omitted = stereotype default (Portal/Observer/Adapter: calls-only, Store/Index/Registry: intent, else full). A method whose narrative shows no steps declares the calls it makes in `calls` (one \"<component>.<method>\" each): the reachability walk takes exactly those edges and no others, so an intent-level method that reaches a collaborator must name it or that collaborator is reported unused. Conformance dial per method or spec: declared | anchored | off \u2014 how strictly structural conformance requires contract methods to be realized in their source file (omitted = Portal: anchored, else declared). A method whose body lives in its own file names it in the method's sourcePath; the implementation's sourcePath is the default for every method that names none. Re-authoring an existing id REPLACES the method list: a method left out of the input is REMOVED together with its narrative (and reported); spec-level lint/ext are carried forward, and the stored status is kept unless this input states a higher one. The answer carries a write receipt as structured content beside the sentence \u2014 the status written, whether a spec already held the id, and the notices a restatement raised, each as its own entry.",
|
|
30221
|
+
description: "Write L4 Concrete Implementation spec containing L5 method narratives. Narratives are a FLAT ordered step list; flow steps (branch/switch/loop/try/parallel/jump/return/throw) jump by step number \u2014 blocks are just skipped regions. Steps may declare a `label` anchor, and every jump field has a *Label twin (toLabel, onTrueLabel, endLabel, \u2026) resolved to step numbers at write time \u2014 prefer labels over hand-counted numbers; an unresolvable label rejects the write. Detail dial per method: full (narrative required) | calls-only (call choreography suffices) | intent (prose instead of steps); omitted = stereotype default (Portal/Observer/Adapter: calls-only, Store/Index/Registry: intent, else full). A method whose narrative shows no steps declares the calls it makes in `calls` (one \"<component>.<method>\" each): the reachability walk takes exactly those edges and no others, so an intent-level method that reaches a collaborator must name it or that collaborator is reported unused. Conformance dial per method or spec: declared | anchored | off \u2014 how strictly structural conformance requires contract methods to be realized in their source file (omitted = Portal: anchored, else declared). A method whose body lives in its own file names it in the method's sourcePath; the implementation's sourcePath is the default for every method that names none. Parameters the realization takes BEFORE its contract's own \u2014 a config object, a data root, a portal's transport handles \u2014 are wiring, and are declared once for the spec in injectedParams; a leading parameter it does not name is reported against the contract (UNDECLARED_PARAM). Re-authoring an existing id REPLACES the method list: a method left out of the input is REMOVED together with its narrative (and reported); spec-level lint/ext are carried forward, and the stored status is kept unless this input states a higher one. The answer carries a write receipt as structured content beside the sentence \u2014 the status written, whether a spec already held the id, and the notices a restatement raised, each as its own entry.",
|
|
30019
30222
|
inputSchema: implInput,
|
|
30020
30223
|
outputSchema: specWriteReceiptOutput
|
|
30021
30224
|
},
|
|
30022
|
-
({ id, name, description, contract, sourcePath, simPath, technologies, detail, conformance, methods, status: status2 }) => {
|
|
30225
|
+
({ id, name, description, contract, sourcePath, simPath, technologies, injectedParams, detail, conformance, methods, status: status2 }) => {
|
|
30023
30226
|
try {
|
|
30024
30227
|
const { loadInterfaceSpec: loadInterfaceSpec2, loadImplementationSpec: loadImplementationSpec2, saveImplementationSpec: saveImplementationSpec2 } = requireSpecs();
|
|
30025
30228
|
const intf = loadInterfaceSpec2(contract);
|
|
@@ -30051,6 +30254,7 @@ function createMcpServer(options = {}) {
|
|
|
30051
30254
|
sourcePath,
|
|
30052
30255
|
simPath,
|
|
30053
30256
|
technologies,
|
|
30257
|
+
injectedParams,
|
|
30054
30258
|
detail,
|
|
30055
30259
|
conformance,
|
|
30056
30260
|
// Post-resolution every cases/catches entry has its numeric step —
|