@wairon/cli 5.1.1-dev.34 → 5.1.1-dev.36
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 +325 -55
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +303 -52
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1113,7 +1113,7 @@ var init_defaults = __esm({
|
|
|
1113
1113
|
copilot: ".github/prompts",
|
|
1114
1114
|
codex: ".codex/agents"
|
|
1115
1115
|
};
|
|
1116
|
-
WAIRON_VERSION = "5.1.1-dev.
|
|
1116
|
+
WAIRON_VERSION = "5.1.1-dev.36";
|
|
1117
1117
|
GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
1118
1118
|
ARCHITECT_AGENT_ID = "agent-architect";
|
|
1119
1119
|
ARCHITECT_TEMPLATE_ID = "architect";
|
|
@@ -2530,13 +2530,34 @@ var init_step_graph = __esm({
|
|
|
2530
2530
|
});
|
|
2531
2531
|
|
|
2532
2532
|
// src/models/step-config.ts
|
|
2533
|
+
function stepFieldsFor(type) {
|
|
2534
|
+
const own = STEP_TYPE_FIELDS[type] ?? [];
|
|
2535
|
+
const allowed = /* @__PURE__ */ new Set([...STEP_COMMON_FIELDS, ...own]);
|
|
2536
|
+
for (const field of own) {
|
|
2537
|
+
const twin = STEP_LABEL_TWINS[field];
|
|
2538
|
+
if (twin) allowed.add(twin);
|
|
2539
|
+
}
|
|
2540
|
+
return allowed;
|
|
2541
|
+
}
|
|
2542
|
+
function isSet(step, field) {
|
|
2543
|
+
const v = step[field];
|
|
2544
|
+
if (v === void 0 || v === null) return false;
|
|
2545
|
+
if (Array.isArray(v) && v.length === 0) return false;
|
|
2546
|
+
return true;
|
|
2547
|
+
}
|
|
2533
2548
|
function flowConfigOn(step) {
|
|
2534
|
-
return FLOW_FIELDS.filter((f) =>
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2549
|
+
return FLOW_FIELDS.filter((f) => isSet(step, f));
|
|
2550
|
+
}
|
|
2551
|
+
function narrativeStepForeignFields(step) {
|
|
2552
|
+
const type = step.type;
|
|
2553
|
+
if (!Object.prototype.hasOwnProperty.call(STEP_TYPE_FIELDS, type)) return [];
|
|
2554
|
+
const allowed = stepFieldsFor(type);
|
|
2555
|
+
return Object.keys(step).filter((f) => !allowed.has(f) && isSet(step, f));
|
|
2556
|
+
}
|
|
2557
|
+
function listFields(fields) {
|
|
2558
|
+
const quoted = fields.map((f) => `"${f}"`);
|
|
2559
|
+
if (quoted.length === 1) return quoted[0];
|
|
2560
|
+
return `${quoted.slice(0, -1).join(", ")} and ${quoted[quoted.length - 1]}`;
|
|
2540
2561
|
}
|
|
2541
2562
|
function stepConfigVerdict(method) {
|
|
2542
2563
|
const steps = method.narrative ?? [];
|
|
@@ -2573,8 +2594,10 @@ function stepConfigVerdict(method) {
|
|
|
2573
2594
|
return i !== void 0 && i + 1 < nums.length ? nums[i + 1] : void 0;
|
|
2574
2595
|
};
|
|
2575
2596
|
for (const s of steps) {
|
|
2597
|
+
const alreadyNamed = /* @__PURE__ */ new Set();
|
|
2576
2598
|
if (s.detach && s.type !== "call" && s.type !== "dispatch") {
|
|
2577
2599
|
malformed(s.stepNumber, `step ${s.stepNumber} (${s.type}) carries "detach" \u2014 fire-and-forget applies to call/dispatch steps only.`);
|
|
2600
|
+
alreadyNamed.add("detach");
|
|
2578
2601
|
}
|
|
2579
2602
|
switch (s.type) {
|
|
2580
2603
|
case "local":
|
|
@@ -2582,7 +2605,10 @@ function stepConfigVerdict(method) {
|
|
|
2582
2605
|
case "register":
|
|
2583
2606
|
case "dispatch": {
|
|
2584
2607
|
const extra = flowConfigOn(s);
|
|
2585
|
-
if (extra.length)
|
|
2608
|
+
if (extra.length) {
|
|
2609
|
+
malformed(s.stepNumber, `step ${s.stepNumber} (${s.type}) carries flow config (${extra.join(", ")}) \u2014 use a flow step type instead.`);
|
|
2610
|
+
for (const f of extra) alreadyNamed.add(f);
|
|
2611
|
+
}
|
|
2586
2612
|
break;
|
|
2587
2613
|
}
|
|
2588
2614
|
case "branch":
|
|
@@ -2625,6 +2651,14 @@ function stepConfigVerdict(method) {
|
|
|
2625
2651
|
if (s.toStep === void 0) malformed(s.stepNumber, `jump step ${s.stepNumber} requires "toStep".`);
|
|
2626
2652
|
break;
|
|
2627
2653
|
}
|
|
2654
|
+
const foreign = narrativeStepForeignFields(s).filter((f) => !alreadyNamed.has(f));
|
|
2655
|
+
if (foreign.length) {
|
|
2656
|
+
problems.push({
|
|
2657
|
+
stepNumber: s.stepNumber,
|
|
2658
|
+
code: "FOREIGN_STEP_FIELD",
|
|
2659
|
+
detail: `step ${s.stepNumber} (${s.type}) carries ${listFields(foreign)}, which a ${s.type} step cannot \u2014 left over from an edit that changed the step's type, configuring nothing. \`wairon doctor --fix\` drops them; give the step the type that carries them instead if that is what it does.`
|
|
2660
|
+
});
|
|
2661
|
+
}
|
|
2628
2662
|
for (const [field, target] of jumpFieldsOf(s)) {
|
|
2629
2663
|
if (byNum.has(target)) continue;
|
|
2630
2664
|
sound = false;
|
|
@@ -2650,24 +2684,43 @@ function jumpFieldsOf(s) {
|
|
|
2650
2684
|
(s.branches ?? []).forEach((b, i) => fields.push([`branches[${i}].step`, b.step]));
|
|
2651
2685
|
return fields;
|
|
2652
2686
|
}
|
|
2653
|
-
var FLOW_FIELDS;
|
|
2687
|
+
var STEP_TYPE_FIELDS, STEP_COMMON_FIELDS, STEP_LABEL_TWINS, FLOW_STEP_TYPES, FLOW_FIELDS;
|
|
2654
2688
|
var init_step_config = __esm({
|
|
2655
2689
|
"src/models/step-config.ts"() {
|
|
2656
2690
|
"use strict";
|
|
2691
|
+
STEP_TYPE_FIELDS = {
|
|
2692
|
+
local: [],
|
|
2693
|
+
call: ["targetComponent", "targetMethod", "auth", "detach"],
|
|
2694
|
+
register: ["targetComponent", "targetMethod"],
|
|
2695
|
+
dispatch: ["targetComponent", "capability", "auth", "detach"],
|
|
2696
|
+
branch: ["condition", "onTrueStep", "onFalseStep"],
|
|
2697
|
+
switch: ["on", "cases", "defaultStep"],
|
|
2698
|
+
loop: ["loopKind", "over", "condition", "endStep"],
|
|
2699
|
+
try: ["endStep", "catches", "finallyStep"],
|
|
2700
|
+
parallel: ["endStep", "branches"],
|
|
2701
|
+
jump: ["toStep"],
|
|
2702
|
+
return: ["outcome"],
|
|
2703
|
+
throw: ["error"]
|
|
2704
|
+
};
|
|
2705
|
+
STEP_COMMON_FIELDS = [
|
|
2706
|
+
"stepNumber",
|
|
2707
|
+
"label",
|
|
2708
|
+
"description",
|
|
2709
|
+
"type",
|
|
2710
|
+
"assertsGuarantees",
|
|
2711
|
+
"assertsInvariants"
|
|
2712
|
+
];
|
|
2713
|
+
STEP_LABEL_TWINS = {
|
|
2714
|
+
onTrueStep: "onTrueLabel",
|
|
2715
|
+
onFalseStep: "onFalseLabel",
|
|
2716
|
+
defaultStep: "defaultLabel",
|
|
2717
|
+
endStep: "endLabel",
|
|
2718
|
+
finallyStep: "finallyLabel",
|
|
2719
|
+
toStep: "toLabel"
|
|
2720
|
+
};
|
|
2721
|
+
FLOW_STEP_TYPES = ["branch", "switch", "loop", "try", "parallel", "jump"];
|
|
2657
2722
|
FLOW_FIELDS = [
|
|
2658
|
-
|
|
2659
|
-
"onTrueStep",
|
|
2660
|
-
"onFalseStep",
|
|
2661
|
-
"on",
|
|
2662
|
-
"cases",
|
|
2663
|
-
"defaultStep",
|
|
2664
|
-
"loopKind",
|
|
2665
|
-
"over",
|
|
2666
|
-
"endStep",
|
|
2667
|
-
"catches",
|
|
2668
|
-
"finallyStep",
|
|
2669
|
-
"branches",
|
|
2670
|
-
"toStep"
|
|
2723
|
+
...new Set(FLOW_STEP_TYPES.flatMap((t) => [...STEP_TYPE_FIELDS[t]]))
|
|
2671
2724
|
];
|
|
2672
2725
|
}
|
|
2673
2726
|
});
|
|
@@ -9744,20 +9797,22 @@ var init_narrative_step_config = __esm({
|
|
|
9744
9797
|
init_models();
|
|
9745
9798
|
narrativeStepConfigRule = {
|
|
9746
9799
|
name: "narrative-step-config",
|
|
9747
|
-
description: 'The step configuration of L5 narratives: every flow step (branch, switch, loop, try, parallel, jump) carries the config its type requires and no simple step carries flow config, "detach" (fire-and-forget) is legal on call/dispatch steps only, a parallel body is covered by contiguous, ordered arms (>= 2), no two steps share a step number or a label, and every jump field targets an existing step number in the same narrative.',
|
|
9800
|
+
description: 'The step configuration of L5 narratives: every flow step (branch, switch, loop, try, parallel, jump) carries the config its type requires and no simple step carries flow config, "detach" (fire-and-forget) is legal on call/dispatch steps only, no step carries a field foreign to its type, a parallel body is covered by contiguous, ordered arms (>= 2), no two steps share a step number or a label, and every jump field targets an existing step number in the same narrative.',
|
|
9748
9801
|
codes: [
|
|
9749
9802
|
{ code: "MALFORMED_FLOW_STEP", defaultSeverity: "error", summary: "Flow step missing required config (or flow config on a local/call step)" },
|
|
9750
9803
|
{ code: "INVALID_STEP_JUMP", defaultSeverity: "error", summary: "Jump field targets a step number that does not exist in the narrative" },
|
|
9751
|
-
{ code: "DUPLICATE_STEP_LABEL", defaultSeverity: "error", summary: "Two steps in one narrative share a label \u2014 the symbolic anchor later deltas address by" }
|
|
9804
|
+
{ code: "DUPLICATE_STEP_LABEL", defaultSeverity: "error", summary: "Two steps in one narrative share a label \u2014 the symbolic anchor later deltas address by" },
|
|
9805
|
+
{ code: "FOREIGN_STEP_FIELD", defaultSeverity: "warning", summary: "Step carries a field its own type cannot have \u2014 a leftover of an edit, meaning nothing" }
|
|
9752
9806
|
],
|
|
9753
9807
|
check(ctx) {
|
|
9808
|
+
const severityOf = new Map(narrativeStepConfigRule.codes.map((c) => [c.code, c.defaultSeverity]));
|
|
9754
9809
|
for (const impl of ctx.implementations) {
|
|
9755
9810
|
const isDraftCtx = ctx.isImplementationDraft(impl);
|
|
9756
9811
|
for (const implMethod of impl.methods) {
|
|
9757
9812
|
if (!implMethod.narrative.length) continue;
|
|
9758
9813
|
const where = `Method "${implMethod.name}" in implementation "${impl.id}": `;
|
|
9759
9814
|
for (const problem of stepConfigVerdict(implMethod).problems) {
|
|
9760
|
-
ctx.addIssue("error", problem.code, where + problem.detail, impl.id, isDraftCtx);
|
|
9815
|
+
ctx.addIssue(severityOf.get(problem.code) ?? "error", problem.code, where + problem.detail, impl.id, isDraftCtx);
|
|
9761
9816
|
}
|
|
9762
9817
|
}
|
|
9763
9818
|
}
|
|
@@ -12348,15 +12403,16 @@ var init_unused_types = __esm({
|
|
|
12348
12403
|
init_models();
|
|
12349
12404
|
unusedTypesRule = {
|
|
12350
12405
|
name: "unused-types",
|
|
12351
|
-
description: "Flags types no field of any type and no
|
|
12406
|
+
description: "Flags types no field of any type, no interface method signature and no other type's method signature references. References are matched through the type-reference grammar (generic arguments, collections, qualified ids), and the declaring type's own generic parameters are left out \u2014 a type parameter is not a reference to a type. A type named only by its OWN methods stays unused, the way a function that only calls itself is.",
|
|
12352
12407
|
codes: [
|
|
12353
|
-
{ code: "UNUSED_TYPE", defaultSeverity: "warning", summary: "Type never referenced by fields or
|
|
12408
|
+
{ code: "UNUSED_TYPE", defaultSeverity: "warning", summary: "Type never referenced by fields, signatures or type methods" }
|
|
12354
12409
|
],
|
|
12355
12410
|
check(ctx) {
|
|
12356
12411
|
const referencedTypes = /* @__PURE__ */ new Set();
|
|
12357
|
-
const markTypeReferenced = (ref) => {
|
|
12412
|
+
const markTypeReferenced = (ref, exceptId) => {
|
|
12358
12413
|
if (ctx.isBuiltinType(ref)) return;
|
|
12359
12414
|
for (const spec of ctx.types) {
|
|
12415
|
+
if (spec.id === exceptId) continue;
|
|
12360
12416
|
if (typeMatchesRef(spec, ref)) {
|
|
12361
12417
|
referencedTypes.add(spec.id);
|
|
12362
12418
|
}
|
|
@@ -12378,6 +12434,14 @@ var init_unused_types = __esm({
|
|
|
12378
12434
|
}
|
|
12379
12435
|
}
|
|
12380
12436
|
}
|
|
12437
|
+
for (const t of ctx.types) {
|
|
12438
|
+
for (const m of t.methods) {
|
|
12439
|
+
const refs = methodTypeRefs(m);
|
|
12440
|
+
for (const ref of refs) {
|
|
12441
|
+
markTypeReferenced(ref, t.id);
|
|
12442
|
+
}
|
|
12443
|
+
}
|
|
12444
|
+
}
|
|
12381
12445
|
for (const t of ctx.types) {
|
|
12382
12446
|
if (!ctx.isSpecInScope(t.id)) continue;
|
|
12383
12447
|
if (!referencedTypes.has(t.id)) {
|
|
@@ -12386,7 +12450,7 @@ var init_unused_types = __esm({
|
|
|
12386
12450
|
ctx.addIssue(
|
|
12387
12451
|
"warning",
|
|
12388
12452
|
"UNUSED_TYPE",
|
|
12389
|
-
`Type "${t.id}" is defined but never referenced by any type
|
|
12453
|
+
`Type "${t.id}" is defined but never referenced by any type field, interface method or other type's method.`,
|
|
12390
12454
|
t.id,
|
|
12391
12455
|
isDraftCtx
|
|
12392
12456
|
);
|
|
@@ -18345,6 +18409,17 @@ function identityKeyOf(field, item) {
|
|
|
18345
18409
|
return str(o.description);
|
|
18346
18410
|
case "databases":
|
|
18347
18411
|
return str(o.id) ?? str(o.name);
|
|
18412
|
+
// A flow step's own arrays, addressed by the thing the author named them
|
|
18413
|
+
// for. Their `step` is a RELOCATABLE number, never an identity — a switch
|
|
18414
|
+
// case is the value it matches and a catch clause is the error it catches,
|
|
18415
|
+
// and both survive the renumbering that moves their target. (A parallel
|
|
18416
|
+
// arm falls to the default: named, it merges by name; unnamed, it carries
|
|
18417
|
+
// no identity at all and the list replaces wholesale, which is the same
|
|
18418
|
+
// rule everywhere else.)
|
|
18419
|
+
case "cases":
|
|
18420
|
+
return str(o.value);
|
|
18421
|
+
case "catches":
|
|
18422
|
+
return str(o.error);
|
|
18348
18423
|
default:
|
|
18349
18424
|
return str(o.name) ?? str(o.id);
|
|
18350
18425
|
}
|
|
@@ -19879,9 +19954,39 @@ var init_specs2 = __esm({
|
|
|
19879
19954
|
// Granular delta updates (sdd_update_spec)
|
|
19880
19955
|
// -------------------------------------------------------------------------
|
|
19881
19956
|
/**
|
|
19882
|
-
*
|
|
19883
|
-
*
|
|
19884
|
-
*
|
|
19957
|
+
* Apply a delta to one stored spec, in this ORDER — the order is the contract,
|
|
19958
|
+
* because every stage below can see what the stage above left:
|
|
19959
|
+
*
|
|
19960
|
+
* 1. LOAD the stored spec for the addressed kind and id; a spec that does
|
|
19961
|
+
* not exist refuses, and a mis-selected `system` kind refuses by name.
|
|
19962
|
+
* 2. REFUSE unknown delta keys, whole. A key the level's schema does not
|
|
19963
|
+
* know is dropped on write, so the edit would report a success it never
|
|
19964
|
+
* performed.
|
|
19965
|
+
* 3. QUALIFY the delta's id-bearing references against the spec's namespace,
|
|
19966
|
+
* BEFORE the merge — post-merge a bare id is ambiguous.
|
|
19967
|
+
* 4. MERGE. Identity-keyed arrays upsert element by element and honour their
|
|
19968
|
+
* delete markers, at every depth. Narrative step deltas apply in ASCENDING
|
|
19969
|
+
* stepNumber order, each against the numbering the earlier entries of the
|
|
19970
|
+
* same delta left behind — delete step 3 and step 7 becomes step 6, so a
|
|
19971
|
+
* second delete written as 7 addresses what used to be step 8. That is why
|
|
19972
|
+
* a delete may restate the step's `label` or `description` as a guard, and
|
|
19973
|
+
* why labels are the reliable way to name a jump target. Inserts and
|
|
19974
|
+
* deletes relocate every jump field in the same narrative around them; a
|
|
19975
|
+
* step whose `type` changes is REBUILT for its new type, keeping its
|
|
19976
|
+
* description and label.
|
|
19977
|
+
* 5. UNSET the fields the delta names, at the level each `unset` sits in.
|
|
19978
|
+
* 6. RESOLVE symbolic `*Label` references against the MERGED numbering — after
|
|
19979
|
+
* the merge, so a delta may anchor on a label that only pre-existing steps
|
|
19980
|
+
* carry, and a label in the delta retargets the stored numeric jump it
|
|
19981
|
+
* twins. An unresolved reference aborts the whole update.
|
|
19982
|
+
* 7. COMPARE with what is stored, both read through the level's canonical
|
|
19983
|
+
* schema. Equal means nothing is written and `written` is false.
|
|
19984
|
+
* 8. GATE the merged spec through the caller's hook, then SAVE.
|
|
19985
|
+
*
|
|
19986
|
+
* Returns the change report, whose `notices` carry the non-fatal effects (an
|
|
19987
|
+
* insert whose position was a jump target, so the relocated jumps now bypass
|
|
19988
|
+
* the inserted step; the fields a retype dropped) — empty when the merge had
|
|
19989
|
+
* nothing to say.
|
|
19885
19990
|
*/
|
|
19886
19991
|
updateSpec(kind, id, delta, hooks) {
|
|
19887
19992
|
const notices = [];
|
|
@@ -19995,14 +20100,113 @@ var init_specs2 = __esm({
|
|
|
19995
20100
|
);
|
|
19996
20101
|
}
|
|
19997
20102
|
};
|
|
19998
|
-
const
|
|
20103
|
+
const NO_NESTED_MERGE = /* @__PURE__ */ new Set(["ext", "narrative", "unset"]);
|
|
20104
|
+
const mergeElement = (existing, deltaItem) => {
|
|
20105
|
+
const out = { ...existing, ...deltaItem };
|
|
20106
|
+
if (!existing || typeof existing !== "object" || !deltaItem || typeof deltaItem !== "object") return out;
|
|
20107
|
+
for (const [key, value] of Object.entries(deltaItem)) {
|
|
20108
|
+
if (NO_NESTED_MERGE.has(key) || !Array.isArray(value) || value.length === 0) continue;
|
|
20109
|
+
const before = existing[key];
|
|
20110
|
+
if (before !== void 0 && !Array.isArray(before)) continue;
|
|
20111
|
+
const stored = Array.isArray(before) ? before : [];
|
|
20112
|
+
if (!isIdentifiedArray(key, stored, value)) continue;
|
|
20113
|
+
out[key] = mergeIdentifiedArray(key, stored, value);
|
|
20114
|
+
}
|
|
20115
|
+
return out;
|
|
20116
|
+
};
|
|
20117
|
+
const retargetByLabel = (merged, deltaStep) => {
|
|
20118
|
+
const out = { ...merged };
|
|
20119
|
+
for (const [stepField, labelField] of Object.entries(STEP_LABEL_TWINS)) {
|
|
20120
|
+
if (deltaStep?.[labelField] !== void 0 && deltaStep?.[stepField] === void 0) delete out[stepField];
|
|
20121
|
+
}
|
|
20122
|
+
for (const key of ["cases", "catches"]) {
|
|
20123
|
+
const deltaEntries = deltaStep?.[key];
|
|
20124
|
+
if (!Array.isArray(deltaEntries) || !Array.isArray(out[key])) continue;
|
|
20125
|
+
const retargeted = new Set(
|
|
20126
|
+
deltaEntries.filter((e) => e?.label !== void 0 && e?.step === void 0).map((e) => identityKeyOf(key, e)).filter((k) => k !== null)
|
|
20127
|
+
);
|
|
20128
|
+
if (!retargeted.size) continue;
|
|
20129
|
+
out[key] = out[key].map((e) => {
|
|
20130
|
+
const k = identityKeyOf(key, e);
|
|
20131
|
+
if (k === null || !retargeted.has(k)) return e;
|
|
20132
|
+
const { step, ...rest } = e;
|
|
20133
|
+
return rest;
|
|
20134
|
+
});
|
|
20135
|
+
}
|
|
20136
|
+
return out;
|
|
20137
|
+
};
|
|
20138
|
+
const rebuildOnRetype = (stored, deltaStep, merged, methodName) => {
|
|
20139
|
+
const newType = merged?.type;
|
|
20140
|
+
if (typeof newType !== "string" || stored?.type === newType) return merged;
|
|
20141
|
+
if (!Object.prototype.hasOwnProperty.call(STEP_TYPE_FIELDS, newType)) return merged;
|
|
20142
|
+
const allowed = stepFieldsFor(newType);
|
|
20143
|
+
const stated = Object.keys(deltaStep).filter(
|
|
20144
|
+
(k) => k !== "type" && deltaStep[k] !== void 0 && !allowed.has(k)
|
|
20145
|
+
);
|
|
20146
|
+
if (stated.length) {
|
|
20147
|
+
throw new Error(
|
|
20148
|
+
`Refusing to retype narrative step ${stored.stepNumber} of "${methodName}" from "${stored.type}" to "${newType}": the same delta sets ${stated.map((f) => `"${f}"`).join(", ")}, which a ${newType} step cannot carry. Drop those keys, or retype to a step type that carries them.`
|
|
20149
|
+
);
|
|
20150
|
+
}
|
|
20151
|
+
const out = {};
|
|
20152
|
+
const dropped = [];
|
|
20153
|
+
for (const [key, value] of Object.entries(merged)) {
|
|
20154
|
+
if (allowed.has(key)) out[key] = value;
|
|
20155
|
+
else dropped.push(key);
|
|
20156
|
+
}
|
|
20157
|
+
if (dropped.length) {
|
|
20158
|
+
notices.push(
|
|
20159
|
+
`Narrative step ${stored.stepNumber} of "${methodName}" was retyped ${stored.type} -> ${newType}: ${dropped.join(", ")} dropped \u2014 a ${newType} step cannot carry ${dropped.length === 1 ? "it" : "them"}. Its description and label are kept.`
|
|
20160
|
+
);
|
|
20161
|
+
}
|
|
20162
|
+
return out;
|
|
20163
|
+
};
|
|
20164
|
+
const mergeNarrative = (methodName, existingSteps, deltaSteps) => {
|
|
19999
20165
|
let steps = [...existingSteps];
|
|
20000
20166
|
const sortedDeltas = [...deltaSteps].sort((a, b) => a.stepNumber - b.stepNumber);
|
|
20001
20167
|
for (const deltaStep of sortedDeltas) {
|
|
20002
20168
|
const stepNum = deltaStep.stepNumber;
|
|
20169
|
+
if (typeof stepNum !== "number") {
|
|
20170
|
+
throw new Error(
|
|
20171
|
+
`Refusing to update the narrative of "${methodName}": a step delta must carry the "stepNumber" it addresses, got ${JSON.stringify(stepNum ?? null)}.`
|
|
20172
|
+
);
|
|
20173
|
+
}
|
|
20174
|
+
if ("remove" in deltaStep && typeof deltaStep.remove !== "boolean") {
|
|
20175
|
+
throw new Error(
|
|
20176
|
+
`Refusing to update narrative step ${stepNum} of "${methodName}": "remove" must be the boolean true, got ${JSON.stringify(deltaStep.remove)}. A non-boolean is ignored, which would leave the step in place while reporting success.`
|
|
20177
|
+
);
|
|
20178
|
+
}
|
|
20179
|
+
if ("action" in deltaStep && deltaStep.action !== "insert" && deltaStep.action !== "delete") {
|
|
20180
|
+
throw new Error(
|
|
20181
|
+
`Refusing to update narrative step ${stepNum} of "${methodName}": unknown action ${JSON.stringify(deltaStep.action)} \u2014 expected "insert" or "delete", or no action at all to edit the step in place. An unknown verb is ignored, which would report success for an edit never made.`
|
|
20182
|
+
);
|
|
20183
|
+
}
|
|
20184
|
+
if ("captureJumps" in deltaStep && deltaStep.action !== "insert") {
|
|
20185
|
+
throw new Error(
|
|
20186
|
+
`Refusing to update narrative step ${stepNum} of "${methodName}": "captureJumps" only means anything on an inserted step \u2014 it decides whether jumps aimed at that number follow the shifted original or land on the new step. On any other delta it is ignored.`
|
|
20187
|
+
);
|
|
20188
|
+
}
|
|
20003
20189
|
if (deltaStep.action === "delete" || deltaStep.remove === true) {
|
|
20004
20190
|
const idx = steps.findIndex((s) => s.stepNumber === stepNum);
|
|
20005
20191
|
if (idx !== -1) {
|
|
20192
|
+
const victim = steps[idx];
|
|
20193
|
+
for (const field of ["label", "description"]) {
|
|
20194
|
+
if (deltaStep[field] === void 0) continue;
|
|
20195
|
+
if (victim[field] !== deltaStep[field]) {
|
|
20196
|
+
throw new Error(
|
|
20197
|
+
`Refusing to delete narrative step ${stepNum}: the delta states ${field} ${JSON.stringify(deltaStep[field])}, but step ${stepNum} holds ${JSON.stringify(victim[field] ?? null)}. Step deltas apply in ascending order against the numbering earlier entries of the same delta left behind, so a later delete can address a step that has already moved.`
|
|
20198
|
+
);
|
|
20199
|
+
}
|
|
20200
|
+
}
|
|
20201
|
+
if (typeof victim.endStep === "number") {
|
|
20202
|
+
const body = steps.filter((s) => s.stepNumber > stepNum && s.stepNumber <= victim.endStep);
|
|
20203
|
+
if (body.length) {
|
|
20204
|
+
const span = body.length === 1 ? `step ${body[0].stepNumber}` : `steps ${body[0].stepNumber}-${body[body.length - 1].stepNumber}`;
|
|
20205
|
+
throw new Error(
|
|
20206
|
+
`Cannot delete narrative step ${stepNum}: it is a ${victim.type} header and ${span} ${body.length === 1 ? "is" : "are"} still its body. Deleting it would leave them in place with no ${victim.type} around them \u2014 a change of meaning nothing later reports. Dissolve the region first: retype step ${stepNum} to a type that carries no region (the region fields are dropped and reported), then delete it.`
|
|
20207
|
+
);
|
|
20208
|
+
}
|
|
20209
|
+
}
|
|
20006
20210
|
const referrers = steps.filter((s) => s.stepNumber !== stepNum).map((s) => ({ n: s.stepNumber, refs: jumpRefsTo(s, stepNum) })).filter((r) => r.refs.length > 0);
|
|
20007
20211
|
if (referrers.length) {
|
|
20008
20212
|
throw new Error(
|
|
@@ -20015,6 +20219,11 @@ var init_specs2 = __esm({
|
|
|
20015
20219
|
stepNum,
|
|
20016
20220
|
-1
|
|
20017
20221
|
));
|
|
20222
|
+
} else {
|
|
20223
|
+
const present = steps.length ? ` \u2014 it has steps ${steps[0].stepNumber}-${steps[steps.length - 1].stepNumber}` : " \u2014 it has no steps";
|
|
20224
|
+
throw new Error(
|
|
20225
|
+
`Refusing to delete narrative step ${stepNum}: this narrative has no step ${stepNum}${present}. Step deltas apply in ascending order against the numbering earlier entries of the same delta left behind, so a later delete can address a step that has already moved.`
|
|
20226
|
+
);
|
|
20018
20227
|
}
|
|
20019
20228
|
} else if (deltaStep.action === "insert") {
|
|
20020
20229
|
const capture = deltaStep.captureJumps === true;
|
|
@@ -20038,10 +20247,9 @@ var init_specs2 = __esm({
|
|
|
20038
20247
|
const idx = steps.findIndex((s) => s.stepNumber === stepNum);
|
|
20039
20248
|
if (idx !== -1) {
|
|
20040
20249
|
const { action, remove, ...cleanStep } = deltaStep;
|
|
20041
|
-
steps[idx]
|
|
20042
|
-
|
|
20043
|
-
|
|
20044
|
-
}, deltaStep);
|
|
20250
|
+
const stored = steps[idx];
|
|
20251
|
+
const merged = withUnset(retargetByLabel(mergeElement(stored, cleanStep), cleanStep), deltaStep);
|
|
20252
|
+
steps[idx] = rebuildOnRetype(stored, cleanStep, merged, methodName);
|
|
20045
20253
|
} else {
|
|
20046
20254
|
const { action, remove, ...cleanStep } = deltaStep;
|
|
20047
20255
|
steps.push(withUnset(cleanStep, deltaStep));
|
|
@@ -20072,12 +20280,11 @@ var init_specs2 = __esm({
|
|
|
20072
20280
|
const existingMethod = merged[idx];
|
|
20073
20281
|
let narrative = existingMethod.narrative ? [...existingMethod.narrative] : [];
|
|
20074
20282
|
if (Array.isArray(deltaMethod.narrative)) {
|
|
20075
|
-
narrative = deltaMethod.narrative.length === 0 ? [] : mergeNarrative(narrative, deltaMethod.narrative);
|
|
20283
|
+
narrative = deltaMethod.narrative.length === 0 ? [] : mergeNarrative(String(deltaMethod.name), narrative, deltaMethod.narrative);
|
|
20076
20284
|
}
|
|
20077
20285
|
const { narrative: _, ...cleanMethod } = deltaMethod;
|
|
20078
20286
|
merged[idx] = withUnset({
|
|
20079
|
-
...existingMethod,
|
|
20080
|
-
...cleanMethod,
|
|
20287
|
+
...mergeElement(existingMethod, cleanMethod),
|
|
20081
20288
|
...deltaMethod.ext !== void 0 ? { ext: mergeExt(existingMethod.ext, deltaMethod.ext) } : {},
|
|
20082
20289
|
narrative
|
|
20083
20290
|
}, deltaMethod);
|
|
@@ -20099,12 +20306,8 @@ var init_specs2 = __esm({
|
|
|
20099
20306
|
merged.splice(idx, 1);
|
|
20100
20307
|
} else {
|
|
20101
20308
|
merged[idx] = withUnset({
|
|
20102
|
-
...merged[idx],
|
|
20103
|
-
...deltaItem,
|
|
20104
|
-
...deltaItem.ext !== void 0 ? { ext: mergeExt(merged[idx].ext, deltaItem.ext) } : {},
|
|
20105
|
-
// An interface method's findings upsert and delete by code, like
|
|
20106
|
-
// lint.allow; an empty list still clears them outright.
|
|
20107
|
-
...Array.isArray(deltaItem.findings) && deltaItem.findings.length > 0 ? { findings: mergeIdentifiedArray("findings", merged[idx].findings ?? [], deltaItem.findings) } : {}
|
|
20309
|
+
...mergeElement(merged[idx], deltaItem),
|
|
20310
|
+
...deltaItem.ext !== void 0 ? { ext: mergeExt(merged[idx].ext, deltaItem.ext) } : {}
|
|
20108
20311
|
}, deltaItem);
|
|
20109
20312
|
}
|
|
20110
20313
|
} else {
|
|
@@ -20123,7 +20326,7 @@ var init_specs2 = __esm({
|
|
|
20123
20326
|
if (deltaItem.remove === true || deltaItem.action === "delete") {
|
|
20124
20327
|
merged.splice(idx, 1);
|
|
20125
20328
|
} else {
|
|
20126
|
-
merged[idx] = withUnset(
|
|
20329
|
+
merged[idx] = withUnset(mergeElement(merged[idx], deltaItem), deltaItem);
|
|
20127
20330
|
}
|
|
20128
20331
|
} else {
|
|
20129
20332
|
assertUnmatchedIsAnAddition(deltaItem, keyOf(deltaItem), merged.map(keyOf), "entry");
|
|
@@ -20142,10 +20345,7 @@ var init_specs2 = __esm({
|
|
|
20142
20345
|
if (deltaItem.remove === true || deltaItem.action === "delete") {
|
|
20143
20346
|
merged.splice(idx, 1);
|
|
20144
20347
|
} else {
|
|
20145
|
-
merged[idx] = withUnset(
|
|
20146
|
-
...merged[idx],
|
|
20147
|
-
...deltaItem
|
|
20148
|
-
}, deltaItem);
|
|
20348
|
+
merged[idx] = withUnset(mergeElement(merged[idx], deltaItem), deltaItem);
|
|
20149
20349
|
}
|
|
20150
20350
|
} else {
|
|
20151
20351
|
assertUnmatchedIsAnAddition(deltaItem, piKey(deltaItem), merged.map(piKey), "publicInterface");
|
|
@@ -20163,7 +20363,7 @@ var init_specs2 = __esm({
|
|
|
20163
20363
|
const isDelete = deltaItem?.remove === true || deltaItem?.action === "delete";
|
|
20164
20364
|
if (idx !== -1) {
|
|
20165
20365
|
if (isDelete) merged.splice(idx, 1);
|
|
20166
|
-
else merged[idx] = withUnset(
|
|
20366
|
+
else merged[idx] = withUnset(mergeElement(merged[idx], deltaItem), deltaItem);
|
|
20167
20367
|
} else {
|
|
20168
20368
|
if (key !== null) {
|
|
20169
20369
|
assertUnmatchedIsAnAddition(
|
|
@@ -25697,6 +25897,44 @@ var init_stereotype_migration = __esm({
|
|
|
25697
25897
|
}
|
|
25698
25898
|
});
|
|
25699
25899
|
|
|
25900
|
+
// src/core/narrative-repair.ts
|
|
25901
|
+
function repairForeignStepFields(apply) {
|
|
25902
|
+
const implementations = loadImplementationSpecs();
|
|
25903
|
+
const repairs = [];
|
|
25904
|
+
const changed = [];
|
|
25905
|
+
for (const impl of implementations) {
|
|
25906
|
+
let touched = false;
|
|
25907
|
+
for (const method of impl.methods) {
|
|
25908
|
+
for (const step of method.narrative) {
|
|
25909
|
+
const fields = narrativeStepForeignFields(step);
|
|
25910
|
+
if (!fields.length) continue;
|
|
25911
|
+
repairs.push({
|
|
25912
|
+
implementation: impl.id,
|
|
25913
|
+
method: method.name,
|
|
25914
|
+
stepNumber: step.stepNumber,
|
|
25915
|
+
stepType: step.type,
|
|
25916
|
+
fields
|
|
25917
|
+
});
|
|
25918
|
+
for (const field of fields) delete step[field];
|
|
25919
|
+
touched = true;
|
|
25920
|
+
}
|
|
25921
|
+
}
|
|
25922
|
+
if (touched) changed.push(impl);
|
|
25923
|
+
}
|
|
25924
|
+
if (apply && changed.length) {
|
|
25925
|
+
for (const impl of changed) saveImplementationSpec(impl);
|
|
25926
|
+
invalidateSpecCache();
|
|
25927
|
+
}
|
|
25928
|
+
return repairs;
|
|
25929
|
+
}
|
|
25930
|
+
var init_narrative_repair = __esm({
|
|
25931
|
+
"src/core/narrative-repair.ts"() {
|
|
25932
|
+
"use strict";
|
|
25933
|
+
init_specs2();
|
|
25934
|
+
init_models();
|
|
25935
|
+
}
|
|
25936
|
+
});
|
|
25937
|
+
|
|
25700
25938
|
// src/core/approver.ts
|
|
25701
25939
|
function gitConfig(key) {
|
|
25702
25940
|
try {
|
|
@@ -25777,6 +26015,7 @@ var init_core = __esm({
|
|
|
25777
26015
|
init_treetransfer();
|
|
25778
26016
|
init_provision();
|
|
25779
26017
|
init_stereotype_migration();
|
|
26018
|
+
init_narrative_repair();
|
|
25780
26019
|
init_approval();
|
|
25781
26020
|
init_approver();
|
|
25782
26021
|
init_specs2();
|
|
@@ -25881,6 +26120,9 @@ __export(src_exports, {
|
|
|
25881
26120
|
SCAN_EXCLUDE_DIRS: () => SCAN_EXCLUDE_DIRS,
|
|
25882
26121
|
SDD_RULES: () => SDD_RULES,
|
|
25883
26122
|
SEMANTIC_GUARANTEES: () => SEMANTIC_GUARANTEES,
|
|
26123
|
+
STEP_COMMON_FIELDS: () => STEP_COMMON_FIELDS,
|
|
26124
|
+
STEP_LABEL_TWINS: () => STEP_LABEL_TWINS,
|
|
26125
|
+
STEP_TYPE_FIELDS: () => STEP_TYPE_FIELDS,
|
|
25884
26126
|
SUPPORTED_ALIASES: () => SUPPORTED_ALIASES,
|
|
25885
26127
|
SURFACE_AUDIENCES: () => SURFACE_AUDIENCES,
|
|
25886
26128
|
SkillResourceNotFoundError: () => SkillResourceNotFoundError,
|
|
@@ -26094,6 +26336,7 @@ __export(src_exports, {
|
|
|
26094
26336
|
methodSourceFile: () => methodSourceFile,
|
|
26095
26337
|
methodTypeRefs: () => methodTypeRefs,
|
|
26096
26338
|
moveSubsystemProject: () => moveSubsystemProject,
|
|
26339
|
+
narrativeStepForeignFields: () => narrativeStepForeignFields,
|
|
26097
26340
|
normalizeApprover: () => normalizeApprover,
|
|
26098
26341
|
normalizeComponentLayout: () => normalizeComponentLayout,
|
|
26099
26342
|
packDirEntry: () => packDirEntry,
|
|
@@ -26138,6 +26381,7 @@ __export(src_exports, {
|
|
|
26138
26381
|
renderDomainsDoc: () => renderDomainsDoc,
|
|
26139
26382
|
renderTemplateInstructions: () => renderTemplateInstructions,
|
|
26140
26383
|
renderWaironGuide: () => renderWaironGuide,
|
|
26384
|
+
repairForeignStepFields: () => repairForeignStepFields,
|
|
26141
26385
|
resolveAgentTopology: () => resolveAgentTopology,
|
|
26142
26386
|
resolveChainingParent: () => resolveChainingParent,
|
|
26143
26387
|
resolveDomains: () => resolveDomains,
|
|
@@ -26176,6 +26420,7 @@ __export(src_exports, {
|
|
|
26176
26420
|
stateIdEquals: () => stateIdEquals,
|
|
26177
26421
|
stateIdString: () => stateIdString,
|
|
26178
26422
|
stepConfigVerdict: () => stepConfigVerdict,
|
|
26423
|
+
stepFieldsFor: () => stepFieldsFor,
|
|
26179
26424
|
stepGraph: () => stepGraph,
|
|
26180
26425
|
syncContextFiles: () => syncContextFiles,
|
|
26181
26426
|
toMarkdown: () => toMarkdown,
|
|
@@ -26602,6 +26847,9 @@ function loadProjectConfig4() {
|
|
|
26602
26847
|
SCAN_EXCLUDE_DIRS,
|
|
26603
26848
|
SDD_RULES,
|
|
26604
26849
|
SEMANTIC_GUARANTEES,
|
|
26850
|
+
STEP_COMMON_FIELDS,
|
|
26851
|
+
STEP_LABEL_TWINS,
|
|
26852
|
+
STEP_TYPE_FIELDS,
|
|
26605
26853
|
SUPPORTED_ALIASES,
|
|
26606
26854
|
SURFACE_AUDIENCES,
|
|
26607
26855
|
SkillResourceNotFoundError,
|
|
@@ -26815,6 +27063,7 @@ function loadProjectConfig4() {
|
|
|
26815
27063
|
methodSourceFile,
|
|
26816
27064
|
methodTypeRefs,
|
|
26817
27065
|
moveSubsystemProject,
|
|
27066
|
+
narrativeStepForeignFields,
|
|
26818
27067
|
normalizeApprover,
|
|
26819
27068
|
normalizeComponentLayout,
|
|
26820
27069
|
packDirEntry,
|
|
@@ -26859,6 +27108,7 @@ function loadProjectConfig4() {
|
|
|
26859
27108
|
renderDomainsDoc,
|
|
26860
27109
|
renderTemplateInstructions,
|
|
26861
27110
|
renderWaironGuide,
|
|
27111
|
+
repairForeignStepFields,
|
|
26862
27112
|
resolveAgentTopology,
|
|
26863
27113
|
resolveChainingParent,
|
|
26864
27114
|
resolveDomains,
|
|
@@ -26897,6 +27147,7 @@ function loadProjectConfig4() {
|
|
|
26897
27147
|
stateIdEquals,
|
|
26898
27148
|
stateIdString,
|
|
26899
27149
|
stepConfigVerdict,
|
|
27150
|
+
stepFieldsFor,
|
|
26900
27151
|
stepGraph,
|
|
26901
27152
|
syncContextFiles,
|
|
26902
27153
|
toMarkdown,
|