@wairon/cli 5.1.1-dev.96 → 5.1.1-dev.98
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 +2136 -901
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +1921 -703
- package/dist/index.js.map +1 -1
- package/dist/templates/skills/sdd-architect.md +5 -4
- package/dist/templates/skills/sdd-implement.md +1 -1
- package/package.json +6 -3
- package/schemas/design-export-1.json +1168 -0
package/dist/index.js
CHANGED
|
@@ -1672,15 +1672,15 @@ var require_node = __commonJS({
|
|
|
1672
1672
|
var slzh = function(d, b) {
|
|
1673
1673
|
return b + 30 + b2(d, b + 26) + b2(d, b + 28);
|
|
1674
1674
|
};
|
|
1675
|
-
var zh = function(d, b,
|
|
1675
|
+
var zh = function(d, b, z13) {
|
|
1676
1676
|
var fnl = b2(d, b + 28), efl = b2(d, b + 30), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl;
|
|
1677
|
-
var _a2 = z64hs(d, es, efl,
|
|
1677
|
+
var _a2 = z64hs(d, es, efl, z13, b4(d, b + 20), b4(d, b + 24), b4(d, b + 42)), sc = _a2[0], su = _a2[1], off = _a2[2];
|
|
1678
1678
|
return [b2(d, b + 10), sc, su, fn, es + efl + b2(d, b + 32), off];
|
|
1679
1679
|
};
|
|
1680
|
-
var z64hs = function(d, b, l,
|
|
1680
|
+
var z64hs = function(d, b, l, z13, sc, su, off) {
|
|
1681
1681
|
var nsc = sc == 4294967295, nsu = su == 4294967295, noff = off == 4294967295, e = b + l;
|
|
1682
1682
|
var nf = nsc + nsu + noff;
|
|
1683
|
-
if (
|
|
1683
|
+
if (z13 && nf) {
|
|
1684
1684
|
for (; b + 4 < e; b += 4 + b2(d, b + 2)) {
|
|
1685
1685
|
if (b2(d, b) == 1) {
|
|
1686
1686
|
return [
|
|
@@ -1691,7 +1691,7 @@ var require_node = __commonJS({
|
|
|
1691
1691
|
];
|
|
1692
1692
|
}
|
|
1693
1693
|
}
|
|
1694
|
-
if (
|
|
1694
|
+
if (z13 < 2)
|
|
1695
1695
|
err(13);
|
|
1696
1696
|
}
|
|
1697
1697
|
return [sc, su, off, 0];
|
|
@@ -2300,18 +2300,18 @@ var require_node = __commonJS({
|
|
|
2300
2300
|
if (lft) {
|
|
2301
2301
|
var c = lft;
|
|
2302
2302
|
var o = b4(data, e + 16);
|
|
2303
|
-
var
|
|
2304
|
-
if (
|
|
2303
|
+
var z13 = b4(data, e - 20) == 117853008;
|
|
2304
|
+
if (z13) {
|
|
2305
2305
|
var ze = b4(data, e - 12);
|
|
2306
|
-
|
|
2307
|
-
if (
|
|
2306
|
+
z13 = b4(data, ze) == 101075792;
|
|
2307
|
+
if (z13) {
|
|
2308
2308
|
c = lft = b4(data, ze + 32);
|
|
2309
2309
|
o = b4(data, ze + 48);
|
|
2310
2310
|
}
|
|
2311
2311
|
}
|
|
2312
2312
|
var fltr = opts && opts.filter;
|
|
2313
2313
|
var _loop_3 = function(i3) {
|
|
2314
|
-
var _a2 = zh(data, o,
|
|
2314
|
+
var _a2 = zh(data, o, z13), c_1 = _a2[0], sc = _a2[1], su = _a2[2], fn = _a2[3], no = _a2[4], off = _a2[5], b = slzh(data, off);
|
|
2315
2315
|
o = no;
|
|
2316
2316
|
var cbl = function(e2, d) {
|
|
2317
2317
|
if (e2) {
|
|
@@ -2366,18 +2366,18 @@ var require_node = __commonJS({
|
|
|
2366
2366
|
if (!c)
|
|
2367
2367
|
return {};
|
|
2368
2368
|
var o = b4(data, e + 16);
|
|
2369
|
-
var
|
|
2370
|
-
if (
|
|
2369
|
+
var z13 = b4(data, e - 20) == 117853008;
|
|
2370
|
+
if (z13) {
|
|
2371
2371
|
var ze = b4(data, e - 12);
|
|
2372
|
-
|
|
2373
|
-
if (
|
|
2372
|
+
z13 = b4(data, ze) == 101075792;
|
|
2373
|
+
if (z13) {
|
|
2374
2374
|
c = b4(data, ze + 32);
|
|
2375
2375
|
o = b4(data, ze + 48);
|
|
2376
2376
|
}
|
|
2377
2377
|
}
|
|
2378
2378
|
var fltr = opts && opts.filter;
|
|
2379
2379
|
for (var i2 = 0; i2 < c; ++i2) {
|
|
2380
|
-
var _a2 = zh(data, o,
|
|
2380
|
+
var _a2 = zh(data, o, z13), c_2 = _a2[0], sc = _a2[1], su = _a2[2], fn = _a2[3], no = _a2[4], off = _a2[5], b = slzh(data, off);
|
|
2381
2381
|
o = no;
|
|
2382
2382
|
if (!fltr || fltr({
|
|
2383
2383
|
name: fn,
|
|
@@ -3414,9 +3414,30 @@ __export(src_exports, {
|
|
|
3414
3414
|
CustomTargetConfigSchema: () => CustomTargetConfigSchema,
|
|
3415
3415
|
CustomTargetSchema: () => CustomTargetSchema,
|
|
3416
3416
|
DEFAULT_TARGET_DIRS: () => DEFAULT_TARGET_DIRS,
|
|
3417
|
+
DESIGN_APPROVALS: () => DESIGN_APPROVALS,
|
|
3418
|
+
DESIGN_DEPENDENCY_ROLES: () => DESIGN_DEPENDENCY_ROLES,
|
|
3419
|
+
DESIGN_FORMAT: () => DESIGN_FORMAT,
|
|
3420
|
+
DESIGN_FORMAT_VERSION: () => DESIGN_FORMAT_VERSION,
|
|
3417
3421
|
DatabaseSpecSchema: () => DatabaseSpecSchema,
|
|
3418
3422
|
DependencyClassSchema: () => DependencyClassSchema,
|
|
3423
|
+
DesignApprovalSchema: () => DesignApprovalSchema,
|
|
3424
|
+
DesignComponentSchema: () => DesignComponentSchema,
|
|
3425
|
+
DesignDependencyRoleSchema: () => DesignDependencyRoleSchema,
|
|
3426
|
+
DesignDependencySchema: () => DesignDependencySchema,
|
|
3419
3427
|
DesignDepthSchema: () => DesignDepthSchema,
|
|
3428
|
+
DesignExportEntrySchema: () => DesignExportEntrySchema,
|
|
3429
|
+
DesignExportSchema: () => DesignExportSchema,
|
|
3430
|
+
DesignFieldSchema: () => DesignFieldSchema,
|
|
3431
|
+
DesignImplementationSchema: () => DesignImplementationSchema,
|
|
3432
|
+
DesignInterfaceSchema: () => DesignInterfaceSchema,
|
|
3433
|
+
DesignMethodBodySchema: () => DesignMethodBodySchema,
|
|
3434
|
+
DesignMethodSchema: () => DesignMethodSchema,
|
|
3435
|
+
DesignParamSchema: () => DesignParamSchema,
|
|
3436
|
+
DesignProjectSchema: () => DesignProjectSchema,
|
|
3437
|
+
DesignSourceSchema: () => DesignSourceSchema,
|
|
3438
|
+
DesignSubsystemSchema: () => DesignSubsystemSchema,
|
|
3439
|
+
DesignTypeRefSchema: () => DesignTypeRefSchema,
|
|
3440
|
+
DesignTypeSchema: () => DesignTypeSchema,
|
|
3420
3441
|
DiagramConfigSchema: () => DiagramConfigSchema,
|
|
3421
3442
|
DispatchBindingSchema: () => DispatchBindingSchema,
|
|
3422
3443
|
DoctorOptionsError: () => DoctorOptionsError,
|
|
@@ -3476,6 +3497,8 @@ __export(src_exports, {
|
|
|
3476
3497
|
PortalAuthSchemeSchema: () => PortalAuthSchemeSchema,
|
|
3477
3498
|
PortalMountSchema: () => PortalMountSchema,
|
|
3478
3499
|
PortalTypeSchema: () => PortalTypeSchema,
|
|
3500
|
+
PreviousIdsSchema: () => PreviousIdsSchema,
|
|
3501
|
+
PreviousNamesSchema: () => PreviousNamesSchema,
|
|
3479
3502
|
ProfileSelectionSubjectSchema: () => ProfileSelectionSubjectSchema,
|
|
3480
3503
|
ProjectConfigSchema: () => ProjectConfigSchema,
|
|
3481
3504
|
ProjectNotInitializedError: () => ProjectNotInitializedError,
|
|
@@ -3519,6 +3542,7 @@ __export(src_exports, {
|
|
|
3519
3542
|
TopologyConfigSchema: () => TopologyConfigSchema,
|
|
3520
3543
|
TransportSchema: () => TransportSchema,
|
|
3521
3544
|
TrustedLinkSchema: () => TrustedLinkSchema,
|
|
3545
|
+
TypeExpressionSchema: () => TypeExpressionSchema,
|
|
3522
3546
|
TypeFieldSchema: () => TypeFieldSchema,
|
|
3523
3547
|
TypeKindSchema: () => TypeKindSchema,
|
|
3524
3548
|
TypeMethodSchema: () => TypeMethodSchema,
|
|
@@ -3606,6 +3630,7 @@ __export(src_exports, {
|
|
|
3606
3630
|
ensureDir: () => ensureDir,
|
|
3607
3631
|
ensureProjectInitialized: () => ensureProjectInitialized,
|
|
3608
3632
|
excerptParent: () => excerpt,
|
|
3633
|
+
exportDesign: () => exportDesign3,
|
|
3609
3634
|
exportSpecTree: () => exportSpecTree,
|
|
3610
3635
|
exportTargetKey: () => exportTargetKey,
|
|
3611
3636
|
exportUsage: () => exportUsage,
|
|
@@ -3755,6 +3780,7 @@ __export(src_exports, {
|
|
|
3755
3780
|
renameComponent: () => renameComponent,
|
|
3756
3781
|
renameId: () => renameProjectId,
|
|
3757
3782
|
renameMethod: () => renameMethod,
|
|
3783
|
+
renameType: () => renameType,
|
|
3758
3784
|
renderDiagram: () => renderDiagram,
|
|
3759
3785
|
repairForeignStepFields: () => repairForeignStepFields,
|
|
3760
3786
|
repairSignatures: () => repairSignatures,
|
|
@@ -3794,6 +3820,7 @@ __export(src_exports, {
|
|
|
3794
3820
|
settledSpecPaths: () => settledSpecPaths,
|
|
3795
3821
|
signatureFacts: () => signatureFacts,
|
|
3796
3822
|
signatureTypeRefs: () => signatureTypeRefs,
|
|
3823
|
+
specIndexRetiredBy: () => specIndexRetiredBy,
|
|
3797
3824
|
specPathsInScope: () => specPathsInScope,
|
|
3798
3825
|
splitNamespace: () => splitNamespace,
|
|
3799
3826
|
stepConfigVerdict: () => stepConfigVerdict,
|
|
@@ -6996,6 +7023,22 @@ var PortalMountSchema = import_zod8.z.object({
|
|
|
6996
7023
|
*/
|
|
6997
7024
|
via: import_zod8.z.string().optional()
|
|
6998
7025
|
});
|
|
7026
|
+
var PreviousIdsSchema = import_zod8.z.array(import_zod8.z.string().min(1));
|
|
7027
|
+
var PreviousNamesSchema = import_zod8.z.array(import_zod8.z.string().min(1));
|
|
7028
|
+
function specIndexRetiredBy(index, kind, id) {
|
|
7029
|
+
const holders = kind === "component" ? index.components : kind === "interface" ? index.interfaces : kind === "implementation" ? index.implementations : kind === "type" ? index.types : [];
|
|
7030
|
+
for (const holder of holders) {
|
|
7031
|
+
if (!holder.previousIds?.length) continue;
|
|
7032
|
+
const key = kind === "type" && holder.subsystem && !holder.id.startsWith(`${holder.subsystem}::`) ? `${holder.subsystem}::${holder.id}` : holder.id;
|
|
7033
|
+
const cut = key.lastIndexOf("::");
|
|
7034
|
+
const namespace = cut >= 0 ? key.slice(0, cut + 2) : "";
|
|
7035
|
+
for (const previous of holder.previousIds) {
|
|
7036
|
+
const previousKey = previous.includes("::") ? previous : namespace + previous;
|
|
7037
|
+
if (previousKey === id) return key;
|
|
7038
|
+
}
|
|
7039
|
+
}
|
|
7040
|
+
return void 0;
|
|
7041
|
+
}
|
|
6999
7042
|
var ComponentSpecSchema = import_zod8.z.object({
|
|
7000
7043
|
id: SpecIdSchema,
|
|
7001
7044
|
name: import_zod8.z.string(),
|
|
@@ -7039,6 +7082,8 @@ var ComponentSpecSchema = import_zod8.z.object({
|
|
|
7039
7082
|
* satisfies the source requirement for a source-less implementation (suppresses
|
|
7040
7083
|
* MISSING_SOURCE_PATH); `informative` links are context only. */
|
|
7041
7084
|
externalLinks: import_zod8.z.array(ExternalLinkSchema).optional(),
|
|
7085
|
+
/** The rename trace (see PreviousIdsSchema). */
|
|
7086
|
+
previousIds: PreviousIdsSchema.optional(),
|
|
7042
7087
|
/** Per-spec lint suppressions (see LintConfigSchema). */
|
|
7043
7088
|
lint: LintConfigSchema.optional(),
|
|
7044
7089
|
/** Opaque pack/tool extension data (see ExtDataSchema) — preserved verbatim. */
|
|
@@ -7162,11 +7207,16 @@ var MethodSignatureSchema = import_zod8.z.object({
|
|
|
7162
7207
|
*/
|
|
7163
7208
|
guarantees: import_zod8.z.array(GuaranteeSchema).optional(),
|
|
7164
7209
|
/**
|
|
7165
|
-
*
|
|
7166
|
-
*
|
|
7167
|
-
*
|
|
7210
|
+
* What this method does to its component's held state: `read` observes it, `write`
|
|
7211
|
+
* modifies an entity's domain fields, and `lifecycle` creates, destroys, or
|
|
7212
|
+
* (un)registers an entity's existence or membership without modifying its fields —
|
|
7213
|
+
* closed under composition (a lifecycle method calls only read and lifecycle methods,
|
|
7214
|
+
* LIFECYCLE_CALLS_WRITE). Required on a durable Store's contract methods so the
|
|
7215
|
+
* durability round-trip rule can pair mutations with hydration read-backs
|
|
7216
|
+
* (MISSING_HYDRATION); a Supervisor may call a data component it does not own only
|
|
7217
|
+
* through read and lifecycle methods (SUPERVISOR_WRITE_SHORTCUT). Optional elsewhere.
|
|
7168
7218
|
*/
|
|
7169
|
-
effect: import_zod8.z.enum(["read", "write"]).optional(),
|
|
7219
|
+
effect: import_zod8.z.enum(["read", "write", "lifecycle"]).optional(),
|
|
7170
7220
|
/**
|
|
7171
7221
|
* Typed acknowledgment of a real caller OUTSIDE the modeled narrative graph
|
|
7172
7222
|
* (runtime timer/hook, external system, sibling subsystem). Unused-detection
|
|
@@ -7201,6 +7251,8 @@ var MethodSignatureSchema = import_zod8.z.object({
|
|
|
7201
7251
|
seen.add(finding2.code);
|
|
7202
7252
|
});
|
|
7203
7253
|
}).optional(),
|
|
7254
|
+
/** The method's rename trace (see PreviousNamesSchema). */
|
|
7255
|
+
previousNames: PreviousNamesSchema.optional(),
|
|
7204
7256
|
/** Opaque pack/tool extension data (see ExtDataSchema) — preserved verbatim. */
|
|
7205
7257
|
ext: ExtDataSchema.optional()
|
|
7206
7258
|
});
|
|
@@ -7268,6 +7320,8 @@ var InterfaceSpecSchema = import_zod8.z.object({
|
|
|
7268
7320
|
component: import_zod8.z.string(),
|
|
7269
7321
|
// References L2 Component id
|
|
7270
7322
|
methods: import_zod8.z.array(StoredMethodSignatureSchema).default([]),
|
|
7323
|
+
/** The rename trace (see PreviousIdsSchema). */
|
|
7324
|
+
previousIds: PreviousIdsSchema.optional(),
|
|
7271
7325
|
/** Per-spec lint suppressions (see LintConfigSchema). */
|
|
7272
7326
|
lint: LintConfigSchema.optional(),
|
|
7273
7327
|
/** Opaque pack/tool extension data (see ExtDataSchema) — preserved verbatim. */
|
|
@@ -7558,6 +7612,8 @@ var ImplementationSpecSchema = import_zod8.z.object({
|
|
|
7558
7612
|
detail: NarrativeDetailSchema.optional(),
|
|
7559
7613
|
/** Spec-level conformance tier default (each method may override). */
|
|
7560
7614
|
conformance: ConformanceTierSchema.optional(),
|
|
7615
|
+
/** The rename trace (see PreviousIdsSchema). */
|
|
7616
|
+
previousIds: PreviousIdsSchema.optional(),
|
|
7561
7617
|
/** Per-spec lint suppressions (see LintConfigSchema). */
|
|
7562
7618
|
lint: LintConfigSchema.optional(),
|
|
7563
7619
|
/** Opaque pack/tool extension data (see ExtDataSchema) — preserved verbatim. */
|
|
@@ -7733,6 +7789,8 @@ var TypeSpecSchema = import_zod8.z.object({
|
|
|
7733
7789
|
* as `InvoiceLine`.
|
|
7734
7790
|
*/
|
|
7735
7791
|
symbol: import_zod8.z.string().optional(),
|
|
7792
|
+
/** The rename trace (see PreviousIdsSchema): ids this type held within its owner. */
|
|
7793
|
+
previousIds: PreviousIdsSchema.optional(),
|
|
7736
7794
|
/** Per-spec lint suppressions (see LintConfigSchema). */
|
|
7737
7795
|
lint: LintConfigSchema.optional(),
|
|
7738
7796
|
/** Opaque pack/tool extension data (see ExtDataSchema) — preserved verbatim. */
|
|
@@ -9382,12 +9440,12 @@ function exportTargetKey(e) {
|
|
|
9382
9440
|
|
|
9383
9441
|
// src/models/project-family.ts
|
|
9384
9442
|
var path10 = __toESM(require("path"));
|
|
9385
|
-
function walkMemberPath(
|
|
9443
|
+
function walkMemberPath(byKey3, start, segments) {
|
|
9386
9444
|
let node = start;
|
|
9387
9445
|
for (const segment of segments.slice(0, -1)) {
|
|
9388
9446
|
const next = node.aliases.get(segment);
|
|
9389
9447
|
if (next !== void 0) {
|
|
9390
|
-
const found =
|
|
9448
|
+
const found = byKey3.get(next);
|
|
9391
9449
|
if (!found) return null;
|
|
9392
9450
|
node = found;
|
|
9393
9451
|
continue;
|
|
@@ -9399,13 +9457,13 @@ function walkMemberPath(byKey2, start, segments) {
|
|
|
9399
9457
|
return { project: node, name: segments[segments.length - 1] };
|
|
9400
9458
|
}
|
|
9401
9459
|
function landReference(projects, reference, from) {
|
|
9402
|
-
const
|
|
9403
|
-
const origin =
|
|
9404
|
-
const root =
|
|
9460
|
+
const byKey3 = new Map(projects.map((p) => [p.namespace, p]));
|
|
9461
|
+
const origin = byKey3.get(from);
|
|
9462
|
+
const root = byKey3.get("");
|
|
9405
9463
|
if (!reference.includes("::")) return { kind: "project", project: from, name: reference };
|
|
9406
9464
|
const land = (form, start, segments2) => {
|
|
9407
9465
|
if (!start) return { kind: "unresolved", form };
|
|
9408
|
-
const walked = walkMemberPath(
|
|
9466
|
+
const walked = walkMemberPath(byKey3, start, segments2);
|
|
9409
9467
|
if (walked === "outside") return { kind: "outside", form };
|
|
9410
9468
|
if (walked) return { kind: "project", form, project: walked.project.namespace, name: walked.name };
|
|
9411
9469
|
return { kind: "unresolved", form };
|
|
@@ -9417,7 +9475,7 @@ function landReference(projects, reference, from) {
|
|
|
9417
9475
|
while (segments[0] === "super") {
|
|
9418
9476
|
segments.shift();
|
|
9419
9477
|
if (!node || node.parent === void 0) return { kind: "outside", form: "super" };
|
|
9420
|
-
node =
|
|
9478
|
+
node = byKey3.get(node.parent);
|
|
9421
9479
|
}
|
|
9422
9480
|
if (segments.length === 0 || !node) return { kind: "unresolved", form: "super" };
|
|
9423
9481
|
return land("super", node, segments);
|
|
@@ -9429,11 +9487,11 @@ function landReference(projects, reference, from) {
|
|
|
9429
9487
|
return land(segments.length === 2 ? "alias" : "path", origin, segments);
|
|
9430
9488
|
}
|
|
9431
9489
|
if (origin.subsystems.has(first)) return { kind: "project", project: from, name: segments[segments.length - 1] };
|
|
9432
|
-
const fromRoot = root ? walkMemberPath(
|
|
9490
|
+
const fromRoot = root ? walkMemberPath(byKey3, root, segments) : null;
|
|
9433
9491
|
if (fromRoot && fromRoot !== "outside") return { kind: "project", form: "path", project: fromRoot.project.namespace, name: fromRoot.name };
|
|
9434
9492
|
const byId = projects.filter((p) => p.id === first || p.namespace !== "" && p.namespace === first);
|
|
9435
9493
|
if (byId.length === 1) {
|
|
9436
|
-
const walked = walkMemberPath(
|
|
9494
|
+
const walked = walkMemberPath(byKey3, byId[0], segments.slice(1));
|
|
9437
9495
|
if (walked === "outside") return { kind: "outside", form: "path" };
|
|
9438
9496
|
if (walked) return { kind: "project", form: "path", project: walked.project.namespace, name: walked.name };
|
|
9439
9497
|
}
|
|
@@ -9573,6 +9631,188 @@ function selectsFamily(options, declaresMembers) {
|
|
|
9573
9631
|
return declaresMembers && options?.memberDepth !== 0;
|
|
9574
9632
|
}
|
|
9575
9633
|
|
|
9634
|
+
// src/models/design-export.ts
|
|
9635
|
+
var import_zod9 = require("zod");
|
|
9636
|
+
var DESIGN_FORMAT = "wairon-design";
|
|
9637
|
+
var DESIGN_FORMAT_VERSION = "1.0";
|
|
9638
|
+
var DESIGN_APPROVALS = ["locked", "stale", "unlocked", "unjudged"];
|
|
9639
|
+
var DesignApprovalSchema = import_zod9.z.enum(DESIGN_APPROVALS);
|
|
9640
|
+
var DESIGN_DEPENDENCY_ROLES = ["member", "external"];
|
|
9641
|
+
var DesignDependencyRoleSchema = import_zod9.z.enum(DESIGN_DEPENDENCY_ROLES);
|
|
9642
|
+
var ExtSchema = import_zod9.z.record(import_zod9.z.unknown());
|
|
9643
|
+
var TypeExpressionSchema = import_zod9.z.lazy(
|
|
9644
|
+
() => import_zod9.z.object({
|
|
9645
|
+
form: import_zod9.z.enum(["primitive", "named", "list", "set", "map", "optional", "union", "async", "applied"]),
|
|
9646
|
+
name: import_zod9.z.string().optional(),
|
|
9647
|
+
args: import_zod9.z.array(TypeExpressionSchema)
|
|
9648
|
+
}).passthrough()
|
|
9649
|
+
);
|
|
9650
|
+
var DesignTypeRefSchema = import_zod9.z.object({
|
|
9651
|
+
text: import_zod9.z.string(),
|
|
9652
|
+
expression: TypeExpressionSchema.optional()
|
|
9653
|
+
}).passthrough();
|
|
9654
|
+
var DesignParamSchema = import_zod9.z.object({
|
|
9655
|
+
name: import_zod9.z.string(),
|
|
9656
|
+
type: DesignTypeRefSchema,
|
|
9657
|
+
optional: import_zod9.z.boolean(),
|
|
9658
|
+
description: import_zod9.z.string().optional()
|
|
9659
|
+
}).passthrough();
|
|
9660
|
+
var DesignFieldSchema = import_zod9.z.object({
|
|
9661
|
+
name: import_zod9.z.string(),
|
|
9662
|
+
type: DesignTypeRefSchema,
|
|
9663
|
+
optional: import_zod9.z.boolean(),
|
|
9664
|
+
description: import_zod9.z.string().optional(),
|
|
9665
|
+
key: import_zod9.z.string().optional(),
|
|
9666
|
+
references: import_zod9.z.string().optional()
|
|
9667
|
+
}).passthrough();
|
|
9668
|
+
var DeclaredInvocationSchema = MethodSignatureSchema.shape.invokedBy.unwrap().passthrough();
|
|
9669
|
+
var DesignMethodSchema = import_zod9.z.object({
|
|
9670
|
+
key: import_zod9.z.string(),
|
|
9671
|
+
name: import_zod9.z.string(),
|
|
9672
|
+
description: import_zod9.z.string().optional(),
|
|
9673
|
+
params: import_zod9.z.array(DesignParamSchema),
|
|
9674
|
+
returns: DesignTypeRefSchema,
|
|
9675
|
+
signature: import_zod9.z.string(),
|
|
9676
|
+
signatureType: import_zod9.z.string().optional(),
|
|
9677
|
+
effect: import_zod9.z.string().optional(),
|
|
9678
|
+
guarantees: import_zod9.z.array(import_zod9.z.string()),
|
|
9679
|
+
invokedBy: DeclaredInvocationSchema.optional(),
|
|
9680
|
+
endpoint: import_zod9.z.record(import_zod9.z.string()).optional(),
|
|
9681
|
+
formerly: import_zod9.z.array(import_zod9.z.string()),
|
|
9682
|
+
ext: ExtSchema.optional()
|
|
9683
|
+
}).passthrough();
|
|
9684
|
+
var DesignExportEntrySchema = import_zod9.z.object({
|
|
9685
|
+
publicName: import_zod9.z.string(),
|
|
9686
|
+
targetKind: import_zod9.z.string(),
|
|
9687
|
+
target: import_zod9.z.string(),
|
|
9688
|
+
audience: import_zod9.z.string().optional(),
|
|
9689
|
+
version: import_zod9.z.string().optional(),
|
|
9690
|
+
stability: import_zod9.z.string().optional()
|
|
9691
|
+
}).passthrough();
|
|
9692
|
+
var DesignDependencySchema = import_zod9.z.object({
|
|
9693
|
+
alias: import_zod9.z.string(),
|
|
9694
|
+
projectId: import_zod9.z.string(),
|
|
9695
|
+
role: DesignDependencyRoleSchema,
|
|
9696
|
+
digest: import_zod9.z.string().optional(),
|
|
9697
|
+
uses: import_zod9.z.array(import_zod9.z.string())
|
|
9698
|
+
}).passthrough();
|
|
9699
|
+
var DesignSourceSchema = import_zod9.z.object({
|
|
9700
|
+
projectId: import_zod9.z.string(),
|
|
9701
|
+
stateId: import_zod9.z.string(),
|
|
9702
|
+
approved: import_zod9.z.boolean(),
|
|
9703
|
+
approval: DesignApprovalSchema
|
|
9704
|
+
}).passthrough();
|
|
9705
|
+
var DesignProjectSchema = import_zod9.z.object({
|
|
9706
|
+
name: import_zod9.z.string(),
|
|
9707
|
+
vision: import_zod9.z.string(),
|
|
9708
|
+
boundaries: import_zod9.z.array(import_zod9.z.string()),
|
|
9709
|
+
requirements: import_zod9.z.array(import_zod9.z.string()),
|
|
9710
|
+
targetLanguage: import_zod9.z.string().optional(),
|
|
9711
|
+
exports: import_zod9.z.array(DesignExportEntrySchema)
|
|
9712
|
+
}).passthrough();
|
|
9713
|
+
var DesignSubsystemSchema = import_zod9.z.object({
|
|
9714
|
+
key: import_zod9.z.string(),
|
|
9715
|
+
name: import_zod9.z.string(),
|
|
9716
|
+
description: import_zod9.z.string(),
|
|
9717
|
+
status: import_zod9.z.string(),
|
|
9718
|
+
profile: import_zod9.z.string().optional(),
|
|
9719
|
+
targetLanguage: import_zod9.z.string().optional(),
|
|
9720
|
+
lifecycle: import_zod9.z.array(LifecycleEntrypointSchema.passthrough()),
|
|
9721
|
+
exports: import_zod9.z.array(DesignExportEntrySchema),
|
|
9722
|
+
trustedLinks: import_zod9.z.array(import_zod9.z.string()),
|
|
9723
|
+
ext: ExtSchema.optional()
|
|
9724
|
+
}).passthrough();
|
|
9725
|
+
var DesignComponentSchema = import_zod9.z.object({
|
|
9726
|
+
key: import_zod9.z.string(),
|
|
9727
|
+
name: import_zod9.z.string(),
|
|
9728
|
+
description: import_zod9.z.string(),
|
|
9729
|
+
status: import_zod9.z.string(),
|
|
9730
|
+
subsystem: import_zod9.z.string(),
|
|
9731
|
+
stereotype: import_zod9.z.string(),
|
|
9732
|
+
variant: import_zod9.z.string().optional(),
|
|
9733
|
+
dependencyClass: import_zod9.z.string().optional(),
|
|
9734
|
+
durability: import_zod9.z.string().optional(),
|
|
9735
|
+
portalType: import_zod9.z.string().optional(),
|
|
9736
|
+
owns: import_zod9.z.array(import_zod9.z.string()),
|
|
9737
|
+
dependsOn: import_zod9.z.array(import_zod9.z.string()),
|
|
9738
|
+
emits: import_zod9.z.array(EventBindingSchema.passthrough()),
|
|
9739
|
+
subscribesTo: import_zod9.z.array(EventBindingSchema.passthrough()),
|
|
9740
|
+
auth: PortalAuthSchema.passthrough().optional(),
|
|
9741
|
+
basePath: import_zod9.z.string().optional(),
|
|
9742
|
+
dispatch: import_zod9.z.array(DispatchBindingSchema.passthrough()),
|
|
9743
|
+
/** A listener's mounts as declared, each portal as a key: entrypoint facts. */
|
|
9744
|
+
mounts: import_zod9.z.array(PortalMountSchema.passthrough()),
|
|
9745
|
+
/** The pack-declared patterns the component realizes, as declared. */
|
|
9746
|
+
patterns: import_zod9.z.array(PatternRefSchema.passthrough()),
|
|
9747
|
+
/** The opaque external references the component documents, as declared. */
|
|
9748
|
+
externalLinks: import_zod9.z.array(ExternalLinkSchema.passthrough()),
|
|
9749
|
+
formerly: import_zod9.z.array(import_zod9.z.string()),
|
|
9750
|
+
ext: ExtSchema.optional()
|
|
9751
|
+
}).passthrough();
|
|
9752
|
+
var DesignInterfaceSchema = import_zod9.z.object({
|
|
9753
|
+
key: import_zod9.z.string(),
|
|
9754
|
+
component: import_zod9.z.string(),
|
|
9755
|
+
name: import_zod9.z.string(),
|
|
9756
|
+
description: import_zod9.z.string(),
|
|
9757
|
+
status: import_zod9.z.string(),
|
|
9758
|
+
methods: import_zod9.z.array(DesignMethodSchema),
|
|
9759
|
+
formerly: import_zod9.z.array(import_zod9.z.string()),
|
|
9760
|
+
ext: ExtSchema.optional()
|
|
9761
|
+
}).passthrough();
|
|
9762
|
+
var DesignMethodBodySchema = import_zod9.z.object({
|
|
9763
|
+
method: import_zod9.z.string(),
|
|
9764
|
+
detail: import_zod9.z.string(),
|
|
9765
|
+
intent: import_zod9.z.string().optional(),
|
|
9766
|
+
calls: import_zod9.z.array(import_zod9.z.string()),
|
|
9767
|
+
narrative: import_zod9.z.array(NarrativeStepSchema.passthrough())
|
|
9768
|
+
}).passthrough();
|
|
9769
|
+
var DesignImplementationSchema = import_zod9.z.object({
|
|
9770
|
+
key: import_zod9.z.string(),
|
|
9771
|
+
contract: import_zod9.z.string(),
|
|
9772
|
+
component: import_zod9.z.string(),
|
|
9773
|
+
name: import_zod9.z.string(),
|
|
9774
|
+
description: import_zod9.z.string(),
|
|
9775
|
+
status: import_zod9.z.string(),
|
|
9776
|
+
technologies: import_zod9.z.array(import_zod9.z.string()),
|
|
9777
|
+
sourcePath: import_zod9.z.string().optional(),
|
|
9778
|
+
methods: import_zod9.z.array(DesignMethodBodySchema),
|
|
9779
|
+
formerly: import_zod9.z.array(import_zod9.z.string()),
|
|
9780
|
+
ext: ExtSchema.optional()
|
|
9781
|
+
}).passthrough();
|
|
9782
|
+
var DesignTypeSchema = import_zod9.z.object({
|
|
9783
|
+
key: import_zod9.z.string(),
|
|
9784
|
+
kind: import_zod9.z.string(),
|
|
9785
|
+
name: import_zod9.z.string(),
|
|
9786
|
+
description: import_zod9.z.string().optional(),
|
|
9787
|
+
status: import_zod9.z.string().optional(),
|
|
9788
|
+
fields: import_zod9.z.array(DesignFieldSchema),
|
|
9789
|
+
methods: import_zod9.z.array(DesignMethodSchema),
|
|
9790
|
+
params: import_zod9.z.array(DesignParamSchema),
|
|
9791
|
+
returns: DesignTypeRefSchema.optional(),
|
|
9792
|
+
values: import_zod9.z.array(EnumValueSchema.passthrough()),
|
|
9793
|
+
holds: import_zod9.z.string().optional(),
|
|
9794
|
+
invariants: import_zod9.z.array(InvariantSchema.passthrough()),
|
|
9795
|
+
componentClass: import_zod9.z.string().optional(),
|
|
9796
|
+
database: import_zod9.z.string().optional(),
|
|
9797
|
+
table: import_zod9.z.string().optional(),
|
|
9798
|
+
linkedEntity: import_zod9.z.string().optional(),
|
|
9799
|
+
formerly: import_zod9.z.array(import_zod9.z.string()),
|
|
9800
|
+
ext: ExtSchema.optional()
|
|
9801
|
+
}).passthrough();
|
|
9802
|
+
var DesignExportSchema = import_zod9.z.object({
|
|
9803
|
+
format: import_zod9.z.literal(DESIGN_FORMAT),
|
|
9804
|
+
formatVersion: import_zod9.z.string().regex(/^\d+\.\d+$/),
|
|
9805
|
+
generator: import_zod9.z.string(),
|
|
9806
|
+
source: DesignSourceSchema,
|
|
9807
|
+
project: DesignProjectSchema,
|
|
9808
|
+
dependencies: import_zod9.z.array(DesignDependencySchema),
|
|
9809
|
+
subsystems: import_zod9.z.array(DesignSubsystemSchema),
|
|
9810
|
+
components: import_zod9.z.array(DesignComponentSchema),
|
|
9811
|
+
interfaces: import_zod9.z.array(DesignInterfaceSchema),
|
|
9812
|
+
implementations: import_zod9.z.array(DesignImplementationSchema),
|
|
9813
|
+
types: import_zod9.z.array(DesignTypeSchema)
|
|
9814
|
+
}).passthrough();
|
|
9815
|
+
|
|
9576
9816
|
// src/core/narrative-labels.ts
|
|
9577
9817
|
var SCALAR_REFS = [
|
|
9578
9818
|
["onTrueLabel", "onTrueStep"],
|
|
@@ -14786,7 +15026,7 @@ var MODEL = __MODEL_JSON__;
|
|
|
14786
15026
|
|
|
14787
15027
|
// src/core/surfaces.ts
|
|
14788
15028
|
var fs9 = __toESM(require("fs"));
|
|
14789
|
-
var
|
|
15029
|
+
var path14 = __toESM(require("path"));
|
|
14790
15030
|
|
|
14791
15031
|
// src/utils/filenames.ts
|
|
14792
15032
|
function safeFilenamePart(value) {
|
|
@@ -14934,10 +15174,477 @@ function unpin(alias) {
|
|
|
14934
15174
|
// src/core/openapi.ts
|
|
14935
15175
|
var yaml2 = __toESM(require("js-yaml"));
|
|
14936
15176
|
|
|
15177
|
+
// src/config/defaults.ts
|
|
15178
|
+
var os2 = __toESM(require("os"));
|
|
15179
|
+
var path13 = __toESM(require("path"));
|
|
15180
|
+
var DEFAULT_TARGET_DIRS = {
|
|
15181
|
+
claude: ".claude/agents",
|
|
15182
|
+
gemini: ".gemini/agents",
|
|
15183
|
+
agy: ".gemini/agents",
|
|
15184
|
+
cursor: ".cursor/rules",
|
|
15185
|
+
copilot: ".github/prompts",
|
|
15186
|
+
codex: ".codex/agents"
|
|
15187
|
+
};
|
|
15188
|
+
function defaultTargetConfig(type) {
|
|
15189
|
+
return {
|
|
15190
|
+
type,
|
|
15191
|
+
outputDir: DEFAULT_TARGET_DIRS[type],
|
|
15192
|
+
enabled: true
|
|
15193
|
+
};
|
|
15194
|
+
}
|
|
15195
|
+
var WAIRON_VERSION = "5.1.1-dev.98";
|
|
15196
|
+
var GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
15197
|
+
var ARCHITECT_AGENT_ID = "agent-architect";
|
|
15198
|
+
var ARCHITECT_TEMPLATE_ID = "architect";
|
|
15199
|
+
function globalTemplatesDir(projectOverride) {
|
|
15200
|
+
if (process.env.WAIRON_TEMPLATES_DIR) {
|
|
15201
|
+
return process.env.WAIRON_TEMPLATES_DIR;
|
|
15202
|
+
}
|
|
15203
|
+
if (projectOverride) {
|
|
15204
|
+
return projectOverride;
|
|
15205
|
+
}
|
|
15206
|
+
return path13.join(os2.homedir(), ".wairon", "templates");
|
|
15207
|
+
}
|
|
15208
|
+
var BACKEND_COMMANDS = {
|
|
15209
|
+
claude: "claude",
|
|
15210
|
+
gemini: "gemini"
|
|
15211
|
+
};
|
|
15212
|
+
function backendCommand(backend) {
|
|
15213
|
+
return BACKEND_COMMANDS[backend] ?? backend;
|
|
15214
|
+
}
|
|
15215
|
+
var SUPPORTED_ALIASES = ["wai"];
|
|
15216
|
+
var SCAN_EXCLUDE_DIRS = /* @__PURE__ */ new Set([
|
|
15217
|
+
"node_modules",
|
|
15218
|
+
"dist",
|
|
15219
|
+
"build",
|
|
15220
|
+
"out",
|
|
15221
|
+
".git",
|
|
15222
|
+
".cache",
|
|
15223
|
+
"coverage",
|
|
15224
|
+
"__pycache__",
|
|
15225
|
+
".venv",
|
|
15226
|
+
"venv",
|
|
15227
|
+
"target",
|
|
15228
|
+
// Rust
|
|
15229
|
+
"vendor"
|
|
15230
|
+
]);
|
|
15231
|
+
|
|
15232
|
+
// src/core/design-export.ts
|
|
15233
|
+
var NoSystemSpecError = class extends Error {
|
|
15234
|
+
constructor() {
|
|
15235
|
+
super("no-system: the tree has no L0 system spec to export (.wai/specs holds no system spec).");
|
|
15236
|
+
this.code = "no-system";
|
|
15237
|
+
this.name = "NoSystemSpecError";
|
|
15238
|
+
}
|
|
15239
|
+
};
|
|
15240
|
+
var isOwn = (spec) => !spec.id.includes("::");
|
|
15241
|
+
var byKey = (a, b) => compareOrdinal(a.key, b.key);
|
|
15242
|
+
var KeyTable = class {
|
|
15243
|
+
constructor(components, interfaces, types, members = []) {
|
|
15244
|
+
this.components = /* @__PURE__ */ new Set();
|
|
15245
|
+
/** component key → the interfaces it declares. */
|
|
15246
|
+
this.interfacesOf = /* @__PURE__ */ new Map();
|
|
15247
|
+
this.typeRefCache = /* @__PURE__ */ new Map();
|
|
15248
|
+
/** bound key → `alias::publicName`, over every direct member. */
|
|
15249
|
+
this.publicNames = /* @__PURE__ */ new Map();
|
|
15250
|
+
/** alias → the public names this projection wrote a reference to. */
|
|
15251
|
+
this.used = /* @__PURE__ */ new Map();
|
|
15252
|
+
for (const m of members) for (const [bound2, name] of m.names) if (!this.publicNames.has(bound2)) this.publicNames.set(bound2, name);
|
|
15253
|
+
for (const c of components) this.components.add(c.id);
|
|
15254
|
+
for (const i of [...interfaces].sort((a, b) => compareOrdinal(a.id, b.id))) {
|
|
15255
|
+
const list = this.interfacesOf.get(i.component) ?? [];
|
|
15256
|
+
list.push(i);
|
|
15257
|
+
this.interfacesOf.set(i.component, list);
|
|
15258
|
+
}
|
|
15259
|
+
this.types = [...types].sort((a, b) => compareOrdinal(qualifiedTypeId(a), qualifiedTypeId(b)));
|
|
15260
|
+
}
|
|
15261
|
+
/** A contract method's key: `<interface key>.<name>` on the first of the component's interfaces declaring it, else the name as written. */
|
|
15262
|
+
methodKey(component, method) {
|
|
15263
|
+
if (!component) return method;
|
|
15264
|
+
const intf = (this.interfacesOf.get(component) ?? []).find((i) => i.methods.some((m) => m.name === method));
|
|
15265
|
+
return intf ? `${intf.id}.${method}` : method;
|
|
15266
|
+
}
|
|
15267
|
+
/** Whether `component.method` names a contract method of an own component — a method signature source. */
|
|
15268
|
+
isMethodSource(value) {
|
|
15269
|
+
const dot = value.lastIndexOf(".");
|
|
15270
|
+
if (dot <= 0 || dot === value.length - 1) return false;
|
|
15271
|
+
const head2 = value.slice(0, dot);
|
|
15272
|
+
const tail = value.slice(dot + 1);
|
|
15273
|
+
return this.components.has(head2) && (this.interfacesOf.get(head2) ?? []).some((i) => i.methods.some((m) => m.name === tail));
|
|
15274
|
+
}
|
|
15275
|
+
/**
|
|
15276
|
+
* The key of the own type a written name resolves to — same subsystem first,
|
|
15277
|
+
* then system-level, then any, ordinal by key within a rank — or null when
|
|
15278
|
+
* no own type answers to it (a generic parameter, or a name in another project).
|
|
15279
|
+
*/
|
|
15280
|
+
typeKey(name, owner, kind) {
|
|
15281
|
+
const cacheKey = `${owner ?? ""}|${kind ?? ""}|${name}`;
|
|
15282
|
+
if (this.typeRefCache.has(cacheKey)) return this.typeRefCache.get(cacheKey);
|
|
15283
|
+
const rank = (t) => t.subsystem === owner ? 0 : t.subsystem === void 0 ? 1 : 2;
|
|
15284
|
+
const hit = this.types.filter((t) => (kind === void 0 || t.kind === kind) && (t.id === name || qualifiedTypeId(t) === name || typeMatchesRef(t, name))).sort((a, b) => rank(a) - rank(b))[0];
|
|
15285
|
+
const key = hit ? qualifiedTypeId(hit) : null;
|
|
15286
|
+
this.typeRefCache.set(cacheKey, key);
|
|
15287
|
+
return key;
|
|
15288
|
+
}
|
|
15289
|
+
/** A reference to a type field (`Type.field`) or a type, resolved to its key; as written when it resolves to nothing. */
|
|
15290
|
+
typeFieldRef(ref, owner) {
|
|
15291
|
+
const whole = this.typeKey(ref, owner);
|
|
15292
|
+
if (whole) return whole;
|
|
15293
|
+
const dot = ref.lastIndexOf(".");
|
|
15294
|
+
if (dot > 0) {
|
|
15295
|
+
const head2 = this.typeKey(ref.slice(0, dot), owner);
|
|
15296
|
+
if (head2) return `${head2}.${ref.slice(dot + 1)}`;
|
|
15297
|
+
const outside = this.external(ref.slice(0, dot));
|
|
15298
|
+
if (outside !== ref.slice(0, dot)) return `${outside}.${ref.slice(dot + 1)}`;
|
|
15299
|
+
}
|
|
15300
|
+
return this.external(ref);
|
|
15301
|
+
}
|
|
15302
|
+
/**
|
|
15303
|
+
* A reference as a consumer resolves it: a bound key of an item a direct
|
|
15304
|
+
* member exports as `alias::publicName` (recorded as used), anything else as
|
|
15305
|
+
* written — an own key, an external's reference (already `alias::name`), or
|
|
15306
|
+
* one binding no exported name, which the gate reports.
|
|
15307
|
+
*/
|
|
15308
|
+
external(ref) {
|
|
15309
|
+
const name = this.publicNames.get(ref);
|
|
15310
|
+
if (name === void 0) return ref;
|
|
15311
|
+
const cut = name.indexOf("::");
|
|
15312
|
+
const alias = name.slice(0, cut);
|
|
15313
|
+
const set = this.used.get(alias) ?? /* @__PURE__ */ new Set();
|
|
15314
|
+
set.add(name.slice(cut + 2));
|
|
15315
|
+
this.used.set(alias, set);
|
|
15316
|
+
return name;
|
|
15317
|
+
}
|
|
15318
|
+
/** A component reference: an own component's key, or another project's item by its public name. */
|
|
15319
|
+
componentRef(ref) {
|
|
15320
|
+
return this.components.has(ref) ? ref : this.external(ref);
|
|
15321
|
+
}
|
|
15322
|
+
};
|
|
15323
|
+
function resolveExpression(expr, keys, owner) {
|
|
15324
|
+
const args = expr.args.map((a) => resolveExpression(a, keys, owner));
|
|
15325
|
+
if ((expr.form === "named" || expr.form === "applied") && expr.name !== void 0) {
|
|
15326
|
+
return { form: expr.form, name: keys.typeKey(expr.name, owner) ?? keys.external(expr.name), args };
|
|
15327
|
+
}
|
|
15328
|
+
return expr.name !== void 0 ? { form: expr.form, name: expr.name, args } : { form: expr.form, args };
|
|
15329
|
+
}
|
|
15330
|
+
function typeRef(text3, position, keys, owner) {
|
|
15331
|
+
const parse = parseTypeExpression(text3, position);
|
|
15332
|
+
if (!parse.expression) return { text: text3 };
|
|
15333
|
+
const expression = resolveExpression(parse.expression, keys, owner);
|
|
15334
|
+
return { text: canonicalTypeText(expression), expression };
|
|
15335
|
+
}
|
|
15336
|
+
function projectParams(params, position, keys, owner) {
|
|
15337
|
+
return (params ?? []).map((p) => ({
|
|
15338
|
+
name: p.name,
|
|
15339
|
+
type: typeRef(p.type, position, keys, owner),
|
|
15340
|
+
optional: p.optional === true,
|
|
15341
|
+
...p.description !== void 0 ? { description: p.description } : {}
|
|
15342
|
+
}));
|
|
15343
|
+
}
|
|
15344
|
+
function exportEntry(e, keys) {
|
|
15345
|
+
const target = e.kind === "type" ? { targetKind: "type", target: keys.typeKey(String(e.typeDef), e.source) ?? keys.external(String(e.typeDef)) } : e.interface ? { targetKind: "interface", target: keys.external(e.interface) } : { targetKind: "component", target: keys.componentRef(String(e.component)) };
|
|
15346
|
+
return {
|
|
15347
|
+
publicName: e.publicName,
|
|
15348
|
+
...target,
|
|
15349
|
+
...e.audience !== void 0 ? { audience: e.audience } : {},
|
|
15350
|
+
...e.version !== void 0 ? { version: e.version } : {},
|
|
15351
|
+
...e.stability !== void 0 ? { stability: e.stability } : {}
|
|
15352
|
+
};
|
|
15353
|
+
}
|
|
15354
|
+
function exportRows(entries, keys) {
|
|
15355
|
+
return entries.map((e) => exportEntry(e, keys)).sort((a, b) => compareOrdinal(a.publicName, b.publicName) || compareOrdinal(`${a.targetKind}:${a.target}`, `${b.targetKind}:${b.target}`));
|
|
15356
|
+
}
|
|
15357
|
+
var boundaryText = (b) => typeof b === "string" ? b : b.description ? `${b.name}: ${b.description}` : b.name;
|
|
15358
|
+
var requirementText = (r) => typeof r === "string" ? r : r.description;
|
|
15359
|
+
function projectSection(system, table, keys) {
|
|
15360
|
+
return {
|
|
15361
|
+
name: system.name,
|
|
15362
|
+
vision: system.vision,
|
|
15363
|
+
boundaries: system.boundaries.map(boundaryText),
|
|
15364
|
+
requirements: system.globalRequirements.map(requirementText),
|
|
15365
|
+
...system.targetLanguage !== void 0 ? { targetLanguage: system.targetLanguage } : {},
|
|
15366
|
+
exports: exportRows(table, keys)
|
|
15367
|
+
};
|
|
15368
|
+
}
|
|
15369
|
+
function dependency(binding, lock, keys) {
|
|
15370
|
+
const alias = binding.external.alias;
|
|
15371
|
+
const digest3 = lock?.externals[alias]?.digest;
|
|
15372
|
+
return {
|
|
15373
|
+
alias,
|
|
15374
|
+
projectId: binding.external.project,
|
|
15375
|
+
role: binding.external.role,
|
|
15376
|
+
...digest3 !== void 0 ? { digest: digest3 } : {},
|
|
15377
|
+
uses: [.../* @__PURE__ */ new Set([...(binding.usage?.used ?? []).map((u) => u.publicName), ...keys.used.get(alias) ?? []])].sort(compareOrdinal)
|
|
15378
|
+
};
|
|
15379
|
+
}
|
|
15380
|
+
function memberDependency(member, lock, keys) {
|
|
15381
|
+
const digest3 = lock?.externals[member.alias]?.digest;
|
|
15382
|
+
return {
|
|
15383
|
+
alias: member.alias,
|
|
15384
|
+
projectId: member.projectId,
|
|
15385
|
+
role: "member",
|
|
15386
|
+
...digest3 !== void 0 ? { digest: digest3 } : {},
|
|
15387
|
+
uses: [...keys.used.get(member.alias) ?? []].sort(compareOrdinal)
|
|
15388
|
+
};
|
|
15389
|
+
}
|
|
15390
|
+
function directMembers(family) {
|
|
15391
|
+
return family.nodes.filter((n) => n.parent === "" && n.namespace !== "").map((n) => {
|
|
15392
|
+
const alias = n.mountAlias ?? n.namespace;
|
|
15393
|
+
const names = /* @__PURE__ */ new Map();
|
|
15394
|
+
const bound2 = (key) => {
|
|
15395
|
+
const local = key.startsWith(`${n.namespace}::`) ? key : `${n.namespace}::${key}`;
|
|
15396
|
+
const last = `${n.namespace}::${key.split("::").pop() ?? key}`;
|
|
15397
|
+
return [.../* @__PURE__ */ new Set([local, last])];
|
|
15398
|
+
};
|
|
15399
|
+
const rows = [...resolveProjectExports(n.namespace).entries].sort((a, b) => compareOrdinal(a.publicName, b.publicName));
|
|
15400
|
+
for (const e of rows) {
|
|
15401
|
+
const name = `${alias}::${e.publicName}`;
|
|
15402
|
+
const targets = e.kind === "type" ? [e.typeDef] : e.interface !== void 0 ? [e.interface, e.component] : [e.component];
|
|
15403
|
+
for (const target of targets) {
|
|
15404
|
+
if (target === void 0) continue;
|
|
15405
|
+
for (const key of bound2(target)) if (!names.has(key)) names.set(key, name);
|
|
15406
|
+
}
|
|
15407
|
+
}
|
|
15408
|
+
return { alias, projectId: n.id ?? alias, names };
|
|
15409
|
+
}).sort((a, b) => compareOrdinal(a.alias, b.alias));
|
|
15410
|
+
}
|
|
15411
|
+
function subsystemSection(s, table, keys) {
|
|
15412
|
+
return {
|
|
15413
|
+
key: s.id,
|
|
15414
|
+
name: s.name,
|
|
15415
|
+
description: s.description,
|
|
15416
|
+
status: s.status,
|
|
15417
|
+
...s.profile !== void 0 ? { profile: s.profile } : {},
|
|
15418
|
+
...s.targetLanguage !== void 0 ? { targetLanguage: s.targetLanguage } : {},
|
|
15419
|
+
lifecycle: (s.lifecycle ?? []).map((l) => ({ ...l, component: keys.componentRef(l.component) })),
|
|
15420
|
+
exports: exportRows(table, keys),
|
|
15421
|
+
trustedLinks: s.trustedLinks.map((t) => t.subsystem),
|
|
15422
|
+
...s.ext !== void 0 ? { ext: s.ext } : {}
|
|
15423
|
+
};
|
|
15424
|
+
}
|
|
15425
|
+
function componentSection(c, keys) {
|
|
15426
|
+
return {
|
|
15427
|
+
key: c.id,
|
|
15428
|
+
name: c.name,
|
|
15429
|
+
description: c.description,
|
|
15430
|
+
status: c.status,
|
|
15431
|
+
subsystem: c.subsystem,
|
|
15432
|
+
stereotype: c.componentType,
|
|
15433
|
+
...c.variant !== void 0 ? { variant: c.variant } : {},
|
|
15434
|
+
...c.dependencyClass !== void 0 ? { dependencyClass: c.dependencyClass } : {},
|
|
15435
|
+
...c.durability !== void 0 ? { durability: c.durability } : {},
|
|
15436
|
+
...c.portalType !== void 0 ? { portalType: c.portalType } : {},
|
|
15437
|
+
owns: c.owns.map((o) => keys.componentRef(o)),
|
|
15438
|
+
dependsOn: c.dependsOn.map((d) => keys.componentRef(d)),
|
|
15439
|
+
emits: (c.emits ?? []).map((e) => ({ ...e })),
|
|
15440
|
+
subscribesTo: (c.subscribesTo ?? []).map((e) => ({ ...e })),
|
|
15441
|
+
...c.auth !== void 0 ? { auth: c.auth } : {},
|
|
15442
|
+
...c.basePath !== void 0 ? { basePath: c.basePath } : {},
|
|
15443
|
+
dispatch: (c.dispatch ?? []).map((d) => ({ ...d, component: keys.componentRef(d.component) })),
|
|
15444
|
+
mounts: (c.mounts ?? []).map((m) => ({ ...m, portal: keys.componentRef(m.portal) })),
|
|
15445
|
+
patterns: (c.patterns ?? []).map((p) => ({ ...p })),
|
|
15446
|
+
externalLinks: (c.externalLinks ?? []).map((l) => ({ ...l })),
|
|
15447
|
+
formerly: [...c.previousIds ?? []],
|
|
15448
|
+
...c.ext !== void 0 ? { ext: c.ext } : {}
|
|
15449
|
+
};
|
|
15450
|
+
}
|
|
15451
|
+
function contractMethod(intf, m, keys, owner) {
|
|
15452
|
+
const signatureType = m.signatureFrom !== void 0 && !keys.isMethodSource(m.signatureFrom) ? keys.typeKey(m.signatureFrom, owner, "signature") ?? void 0 : void 0;
|
|
15453
|
+
return {
|
|
15454
|
+
key: `${intf.id}.${m.name}`,
|
|
15455
|
+
name: m.name,
|
|
15456
|
+
description: m.description,
|
|
15457
|
+
params: projectParams(m.params, "param", keys, owner),
|
|
15458
|
+
returns: typeRef(m.returns, "returns", keys, owner),
|
|
15459
|
+
signature: m.signature,
|
|
15460
|
+
...signatureType !== void 0 ? { signatureType } : {},
|
|
15461
|
+
...m.effect !== void 0 ? { effect: m.effect } : {},
|
|
15462
|
+
guarantees: [...m.guarantees ?? []],
|
|
15463
|
+
...m.invokedBy !== void 0 ? { invokedBy: { ...m.invokedBy } } : {},
|
|
15464
|
+
...m.endpoint !== void 0 ? { endpoint: endpointFields(m.endpoint) } : {},
|
|
15465
|
+
formerly: [...m.previousNames ?? []],
|
|
15466
|
+
...m.ext !== void 0 ? { ext: m.ext } : {}
|
|
15467
|
+
};
|
|
15468
|
+
}
|
|
15469
|
+
function endpointFields(endpoint) {
|
|
15470
|
+
const out = {};
|
|
15471
|
+
for (const [k, v] of Object.entries(endpoint)) if (v !== void 0) out[k] = String(v);
|
|
15472
|
+
return out;
|
|
15473
|
+
}
|
|
15474
|
+
function interfaceSection(intf, keys, owner) {
|
|
15475
|
+
return {
|
|
15476
|
+
key: intf.id,
|
|
15477
|
+
component: intf.component,
|
|
15478
|
+
name: intf.name,
|
|
15479
|
+
description: intf.description,
|
|
15480
|
+
status: intf.status,
|
|
15481
|
+
methods: intf.methods.map((m) => contractMethod(intf, m, keys, owner)),
|
|
15482
|
+
formerly: [...intf.previousIds ?? []],
|
|
15483
|
+
...intf.ext !== void 0 ? { ext: intf.ext } : {}
|
|
15484
|
+
};
|
|
15485
|
+
}
|
|
15486
|
+
function stepWithKeys(step, keys) {
|
|
15487
|
+
const out = { ...step };
|
|
15488
|
+
if (step.targetMethod !== void 0) out.targetMethod = keys.methodKey(step.targetComponent, step.targetMethod);
|
|
15489
|
+
if (step.targetComponent !== void 0) out.targetComponent = keys.componentRef(step.targetComponent);
|
|
15490
|
+
const from = step.auth?.from;
|
|
15491
|
+
if (from !== void 0 && from.startsWith("component:")) {
|
|
15492
|
+
out.auth = { ...step.auth, from: `component:${keys.componentRef(from.slice("component:".length))}` };
|
|
15493
|
+
}
|
|
15494
|
+
return out;
|
|
15495
|
+
}
|
|
15496
|
+
function callKey(ref, keys) {
|
|
15497
|
+
const dot = ref.lastIndexOf(".");
|
|
15498
|
+
if (dot <= 0) return ref;
|
|
15499
|
+
const key = keys.methodKey(ref.slice(0, dot), ref.slice(dot + 1));
|
|
15500
|
+
return key.includes(".") ? key : `${keys.componentRef(ref.slice(0, dot))}.${ref.slice(dot + 1)}`;
|
|
15501
|
+
}
|
|
15502
|
+
function implementationSection(impl, contract, component, keys) {
|
|
15503
|
+
const methods = impl.methods.map((m) => ({
|
|
15504
|
+
method: `${impl.contract}.${m.name}`,
|
|
15505
|
+
detail: effectiveDetail(m, impl, component).level,
|
|
15506
|
+
...m.intent !== void 0 ? { intent: m.intent } : {},
|
|
15507
|
+
calls: (m.calls ?? []).map((c) => callKey(c, keys)),
|
|
15508
|
+
narrative: m.narrative.map((s) => stepWithKeys(s, keys))
|
|
15509
|
+
}));
|
|
15510
|
+
return {
|
|
15511
|
+
key: impl.id,
|
|
15512
|
+
contract: impl.contract,
|
|
15513
|
+
component: contract?.component ?? component?.id ?? "",
|
|
15514
|
+
name: impl.name,
|
|
15515
|
+
description: impl.description,
|
|
15516
|
+
status: impl.status,
|
|
15517
|
+
technologies: (impl.technologies ?? []).map(technologyName),
|
|
15518
|
+
...impl.sourcePath !== void 0 ? { sourcePath: impl.sourcePath } : {},
|
|
15519
|
+
methods,
|
|
15520
|
+
formerly: [...impl.previousIds ?? []],
|
|
15521
|
+
...impl.ext !== void 0 ? { ext: impl.ext } : {}
|
|
15522
|
+
};
|
|
15523
|
+
}
|
|
15524
|
+
function typeSection(t, keys) {
|
|
15525
|
+
const key = qualifiedTypeId(t);
|
|
15526
|
+
const owner = t.subsystem;
|
|
15527
|
+
return {
|
|
15528
|
+
key,
|
|
15529
|
+
kind: t.kind,
|
|
15530
|
+
name: t.name,
|
|
15531
|
+
...t.description !== void 0 ? { description: t.description } : {},
|
|
15532
|
+
fields: t.fields.map((f) => ({
|
|
15533
|
+
name: f.name,
|
|
15534
|
+
type: typeRef(f.type, "field", keys, owner),
|
|
15535
|
+
optional: f.optional === true,
|
|
15536
|
+
...f.description !== void 0 ? { description: f.description } : {},
|
|
15537
|
+
...f.key !== void 0 ? { key: f.key } : {},
|
|
15538
|
+
...f.references !== void 0 ? { references: keys.typeFieldRef(f.references, owner) } : {}
|
|
15539
|
+
})),
|
|
15540
|
+
methods: t.methods.map((m) => ({
|
|
15541
|
+
key: `${key}.${m.name}`,
|
|
15542
|
+
name: m.name,
|
|
15543
|
+
...m.description !== void 0 ? { description: m.description } : {},
|
|
15544
|
+
params: projectParams(m.params, "type-method-param", keys, owner),
|
|
15545
|
+
returns: typeRef(m.returns, "type-method-returns", keys, owner),
|
|
15546
|
+
signature: m.signature,
|
|
15547
|
+
guarantees: [],
|
|
15548
|
+
formerly: []
|
|
15549
|
+
})),
|
|
15550
|
+
params: t.kind === "signature" ? projectParams(t.params, "signature-param", keys, owner) : [],
|
|
15551
|
+
...t.kind === "signature" && t.returns !== void 0 ? { returns: typeRef(t.returns, "signature-returns", keys, owner) } : {},
|
|
15552
|
+
values: (t.values ?? []).map((v) => ({ ...v })),
|
|
15553
|
+
...t.holds !== void 0 ? { holds: t.holds } : {},
|
|
15554
|
+
invariants: (t.invariants ?? []).map((i) => ({ ...i })),
|
|
15555
|
+
...t.componentClass !== void 0 ? { componentClass: keys.componentRef(t.componentClass) } : {},
|
|
15556
|
+
...t.database !== void 0 ? { database: t.database } : {},
|
|
15557
|
+
...t.table !== void 0 ? { table: t.table } : {},
|
|
15558
|
+
...t.linkedEntity !== void 0 ? { linkedEntity: keys.typeKey(t.linkedEntity, owner) ?? keys.external(t.linkedEntity) } : {},
|
|
15559
|
+
formerly: [...t.previousIds ?? []],
|
|
15560
|
+
...t.ext !== void 0 ? { ext: t.ext } : {}
|
|
15561
|
+
};
|
|
15562
|
+
}
|
|
15563
|
+
function sortedKeys(value) {
|
|
15564
|
+
if (Array.isArray(value)) return value.map(sortedKeys);
|
|
15565
|
+
if (value && typeof value === "object") {
|
|
15566
|
+
const src = value;
|
|
15567
|
+
const out = {};
|
|
15568
|
+
for (const k of Object.keys(src).sort(compareOrdinal)) {
|
|
15569
|
+
if (src[k] !== void 0) out[k] = sortedKeys(src[k]);
|
|
15570
|
+
}
|
|
15571
|
+
return out;
|
|
15572
|
+
}
|
|
15573
|
+
return value;
|
|
15574
|
+
}
|
|
15575
|
+
function projectIdOf(system) {
|
|
15576
|
+
try {
|
|
15577
|
+
const config = loadProjectConfig();
|
|
15578
|
+
return (config ? effectiveProjectId(config) : null) ?? system.name;
|
|
15579
|
+
} catch {
|
|
15580
|
+
return system.name;
|
|
15581
|
+
}
|
|
15582
|
+
}
|
|
15583
|
+
function exportDesign(approval) {
|
|
15584
|
+
const system = loadSystemSpec();
|
|
15585
|
+
if (!system) throw new NoSystemSpecError();
|
|
15586
|
+
const subsystems = loadSubsystemSpecs().filter(isOwn);
|
|
15587
|
+
const components = loadComponentSpecs().filter(isOwn);
|
|
15588
|
+
const interfaces = loadInterfaceSpecs().filter(isOwn);
|
|
15589
|
+
const implementations = loadImplementationSpecs().filter(isOwn);
|
|
15590
|
+
const types = loadTypeSpecs().filter(isOwn);
|
|
15591
|
+
const projectTable = resolveProjectExports();
|
|
15592
|
+
const subsystemTables = new Map(subsystems.map((s) => [s.id, resolveSubsystemExports(s.id).entries]));
|
|
15593
|
+
const projectId = projectIdOf(system);
|
|
15594
|
+
const bindings = resolveDeclared();
|
|
15595
|
+
const members = directMembers(graph());
|
|
15596
|
+
let lock = null;
|
|
15597
|
+
try {
|
|
15598
|
+
lock = externalsRepository.readLock();
|
|
15599
|
+
} catch {
|
|
15600
|
+
lock = null;
|
|
15601
|
+
}
|
|
15602
|
+
const stateId = computeStateId();
|
|
15603
|
+
const state = approval ?? "unjudged";
|
|
15604
|
+
const source = {
|
|
15605
|
+
projectId,
|
|
15606
|
+
stateId: `${stateId.algorithm}:${stateId.digest}`,
|
|
15607
|
+
approval: state,
|
|
15608
|
+
approved: state === "locked"
|
|
15609
|
+
};
|
|
15610
|
+
const keys = new KeyTable(components, interfaces, types, members);
|
|
15611
|
+
const componentById = new Map(components.map((c) => [c.id, c]));
|
|
15612
|
+
const interfaceById = new Map(interfaces.map((i) => [i.id, i]));
|
|
15613
|
+
const ownerOf4 = (componentId) => componentId !== void 0 ? componentById.get(componentId)?.subsystem : void 0;
|
|
15614
|
+
const project = projectSection(system, projectTable.entries, keys);
|
|
15615
|
+
const subsystemSections = subsystems.map((s) => subsystemSection(s, subsystemTables.get(s.id) ?? [], keys)).sort(byKey);
|
|
15616
|
+
const componentSections = components.map((c) => componentSection(c, keys)).sort(byKey);
|
|
15617
|
+
const interfaceSections = interfaces.map((i) => interfaceSection(i, keys, ownerOf4(i.component))).sort(byKey);
|
|
15618
|
+
const implementationSections = implementations.map((impl) => {
|
|
15619
|
+
const contract = interfaceById.get(impl.contract);
|
|
15620
|
+
return implementationSection(impl, contract, contract ? componentById.get(contract.component) : void 0, keys);
|
|
15621
|
+
}).sort(byKey);
|
|
15622
|
+
const typeSections = types.map((t) => typeSection(t, keys)).sort(byKey);
|
|
15623
|
+
const externalAliases = new Set(bindings.map((b) => b.external.alias));
|
|
15624
|
+
const dependencies = [
|
|
15625
|
+
...bindings.map((b) => dependency(b, lock, keys)),
|
|
15626
|
+
...members.filter((m) => !externalAliases.has(m.alias)).map((m) => memberDependency(m, lock, keys))
|
|
15627
|
+
].sort((a, b) => compareOrdinal(a.alias, b.alias));
|
|
15628
|
+
const design = {
|
|
15629
|
+
format: DESIGN_FORMAT,
|
|
15630
|
+
formatVersion: DESIGN_FORMAT_VERSION,
|
|
15631
|
+
generator: WAIRON_VERSION,
|
|
15632
|
+
source,
|
|
15633
|
+
project,
|
|
15634
|
+
dependencies,
|
|
15635
|
+
subsystems: subsystemSections,
|
|
15636
|
+
components: componentSections,
|
|
15637
|
+
interfaces: interfaceSections,
|
|
15638
|
+
implementations: implementationSections,
|
|
15639
|
+
types: typeSections
|
|
15640
|
+
};
|
|
15641
|
+
return sortedKeys(design);
|
|
15642
|
+
}
|
|
15643
|
+
|
|
14937
15644
|
// src/core/surfaces.ts
|
|
14938
15645
|
var SURFACES_DIRNAME = "surfaces";
|
|
14939
15646
|
function surfacesDir(rootDir) {
|
|
14940
|
-
return
|
|
15647
|
+
return path14.join(rootDir, ".wai", SURFACES_DIRNAME);
|
|
14941
15648
|
}
|
|
14942
15649
|
function audienceRank(audience) {
|
|
14943
15650
|
const idx = SURFACE_AUDIENCES.indexOf(audience ?? "instance");
|
|
@@ -15016,7 +15723,7 @@ function boundProjectId() {
|
|
|
15016
15723
|
}
|
|
15017
15724
|
}
|
|
15018
15725
|
function contractEntry(entry, comp, interfaces) {
|
|
15019
|
-
const methods = interfaces.filter((i) => i.component === comp.id && (!entry.interface || i.id === entry.interface)).flatMap((i) => i.methods).map(({ signatureFrom: _source, ...method }) => method);
|
|
15726
|
+
const methods = interfaces.filter((i) => i.component === comp.id && (!entry.interface || i.id === entry.interface)).flatMap((i) => i.methods).map(({ signatureFrom: _source, previousNames: _trace, ...method }) => method);
|
|
15020
15727
|
return {
|
|
15021
15728
|
id: entry.publicName,
|
|
15022
15729
|
name: entry.name ?? comp.name,
|
|
@@ -15101,7 +15808,7 @@ function listSnapshots() {
|
|
|
15101
15808
|
for (const file of fs9.readdirSync(dir)) {
|
|
15102
15809
|
if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
|
|
15103
15810
|
try {
|
|
15104
|
-
out.push(SurfaceSnapshotSchema.parse(readYamlFile(
|
|
15811
|
+
out.push(SurfaceSnapshotSchema.parse(readYamlFile(path14.join(dir, file))));
|
|
15105
15812
|
} catch {
|
|
15106
15813
|
}
|
|
15107
15814
|
}
|
|
@@ -15112,7 +15819,7 @@ function snapshotFilename(projectName) {
|
|
|
15112
15819
|
}
|
|
15113
15820
|
function removeSnapshot(projectName) {
|
|
15114
15821
|
const dir = surfacesDir(getProjectRoot());
|
|
15115
|
-
const direct =
|
|
15822
|
+
const direct = path14.join(dir, snapshotFilename(projectName));
|
|
15116
15823
|
if (fs9.existsSync(direct)) {
|
|
15117
15824
|
fs9.unlinkSync(direct);
|
|
15118
15825
|
return true;
|
|
@@ -15120,7 +15827,7 @@ function removeSnapshot(projectName) {
|
|
|
15120
15827
|
if (!fs9.existsSync(dir)) return false;
|
|
15121
15828
|
for (const file of fs9.readdirSync(dir)) {
|
|
15122
15829
|
if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
|
|
15123
|
-
const p =
|
|
15830
|
+
const p = path14.join(dir, file);
|
|
15124
15831
|
try {
|
|
15125
15832
|
const snap = SurfaceSnapshotSchema.parse(readYamlFile(p));
|
|
15126
15833
|
if (snap.projectName === projectName) {
|
|
@@ -15159,6 +15866,32 @@ function listPinnedExternals() {
|
|
|
15159
15866
|
return { alias, project: entry.project, entry, snapshot };
|
|
15160
15867
|
});
|
|
15161
15868
|
}
|
|
15869
|
+
function withSortedKeys(value) {
|
|
15870
|
+
if (Array.isArray(value)) return value.map(withSortedKeys);
|
|
15871
|
+
if (value && typeof value === "object") {
|
|
15872
|
+
const src = value;
|
|
15873
|
+
const out = {};
|
|
15874
|
+
for (const k of Object.keys(src).sort(compareOrdinal)) if (src[k] !== void 0) out[k] = withSortedKeys(src[k]);
|
|
15875
|
+
return out;
|
|
15876
|
+
}
|
|
15877
|
+
return value;
|
|
15878
|
+
}
|
|
15879
|
+
function writeDesignTo(targetPath, design) {
|
|
15880
|
+
const resolved = path14.resolve(targetPath);
|
|
15881
|
+
try {
|
|
15882
|
+
fs9.mkdirSync(path14.dirname(resolved), { recursive: true });
|
|
15883
|
+
fs9.writeFileSync(resolved, `${JSON.stringify(withSortedKeys(design), null, 2)}
|
|
15884
|
+
`, "utf8");
|
|
15885
|
+
} catch (e) {
|
|
15886
|
+
throw new Error(`Cannot write the design export to ${resolved}: ${e.message}`);
|
|
15887
|
+
}
|
|
15888
|
+
return resolved;
|
|
15889
|
+
}
|
|
15890
|
+
function exportDesign2(outPath, approval) {
|
|
15891
|
+
const design = exportDesign(approval);
|
|
15892
|
+
if (outPath) writeDesignTo(outPath, design);
|
|
15893
|
+
return design;
|
|
15894
|
+
}
|
|
15162
15895
|
function listFamilyPins() {
|
|
15163
15896
|
const snapshots = listSnapshots();
|
|
15164
15897
|
const pins = snapshots.filter((snapshot) => snapshot.origin === "generated").map((snapshot) => ({
|
|
@@ -15177,8 +15910,8 @@ var UnknownExternalAliasError = class extends Error {
|
|
|
15177
15910
|
};
|
|
15178
15911
|
var OUT_OF_REACH = "its root is outside the request's reach";
|
|
15179
15912
|
function isWithinDir(dir, target) {
|
|
15180
|
-
const rel2 =
|
|
15181
|
-
return rel2 === "" || !rel2.startsWith("..") && !
|
|
15913
|
+
const rel2 = path14.relative(path14.resolve(dir), path14.resolve(target));
|
|
15914
|
+
return rel2 === "" || !rel2.startsWith("..") && !path14.isAbsolute(rel2);
|
|
15182
15915
|
}
|
|
15183
15916
|
function producerUnreadable(external) {
|
|
15184
15917
|
const directory = external.directory;
|
|
@@ -15431,6 +16164,9 @@ function listExternals() {
|
|
|
15431
16164
|
}
|
|
15432
16165
|
|
|
15433
16166
|
// src/core/surface-portal.ts
|
|
16167
|
+
function exportDesign3(outPath, approval) {
|
|
16168
|
+
return exportDesign2(outPath, approval);
|
|
16169
|
+
}
|
|
15434
16170
|
function listSnapshots2() {
|
|
15435
16171
|
return listSnapshots();
|
|
15436
16172
|
}
|
|
@@ -15464,7 +16200,7 @@ function pinnedParent2() {
|
|
|
15464
16200
|
|
|
15465
16201
|
// src/core/family-validation.ts
|
|
15466
16202
|
var fs10 = __toESM(require("fs"));
|
|
15467
|
-
var
|
|
16203
|
+
var path15 = __toESM(require("path"));
|
|
15468
16204
|
|
|
15469
16205
|
// src/models/pack-impact.ts
|
|
15470
16206
|
function packSettings(manifest, profile) {
|
|
@@ -15641,7 +16377,7 @@ function referencedOf(nodes) {
|
|
|
15641
16377
|
if (e.sourceKind === "hosted") {
|
|
15642
16378
|
const lookup2 = getHostedLookup();
|
|
15643
16379
|
const root = lookup2 && e.hosted !== void 0 ? lookup2(e.hosted) : null;
|
|
15644
|
-
if (root) directory =
|
|
16380
|
+
if (root) directory = path15.resolve(root);
|
|
15645
16381
|
else problem = lookup2 ? `the hosted member \`${e.hosted}\` is unknown or outside this request's reach` : `hosted-only member \`${e.hosted}\`: available only through the hosted server`;
|
|
15646
16382
|
}
|
|
15647
16383
|
if (directory !== void 0 && !fs10.existsSync(directory)) {
|
|
@@ -15705,7 +16441,7 @@ function notSelectedHint(left) {
|
|
|
15705
16441
|
}
|
|
15706
16442
|
function run(options) {
|
|
15707
16443
|
const family = graph();
|
|
15708
|
-
const root =
|
|
16444
|
+
const root = path15.resolve(getProjectRoot());
|
|
15709
16445
|
const ceiling = reachCeiling(root, options.family);
|
|
15710
16446
|
const selected = selectProjects(family, options);
|
|
15711
16447
|
const issues = [];
|
|
@@ -15925,7 +16661,7 @@ function pinOf(parent, alias, subject) {
|
|
|
15925
16661
|
}
|
|
15926
16662
|
function projectApprovals(depth) {
|
|
15927
16663
|
const family = graph();
|
|
15928
|
-
const root =
|
|
16664
|
+
const root = path15.resolve(getProjectRoot());
|
|
15929
16665
|
const limit = depth ?? Infinity;
|
|
15930
16666
|
const selected = family.nodes.filter((n) => depthOf(family, n) <= limit);
|
|
15931
16667
|
const directoryOf = new Map(family.nodes.map((n) => [n.namespace, n.directory]));
|
|
@@ -15978,7 +16714,7 @@ function projectApprovals(depth) {
|
|
|
15978
16714
|
function requiredBy(key) {
|
|
15979
16715
|
return key === "" ? "the family root" : `"${key}"`;
|
|
15980
16716
|
}
|
|
15981
|
-
function
|
|
16717
|
+
function requirementText2(requirement) {
|
|
15982
16718
|
return `"${requirement.pack}" ${requirement.version}${requirement.profile ? ` (profile "${requirement.profile}")` : ""}`;
|
|
15983
16719
|
}
|
|
15984
16720
|
function isBelow(family, node, ancestor) {
|
|
@@ -16033,7 +16769,7 @@ function judgeAdoption(requiring, member, requirements) {
|
|
|
16033
16769
|
const out = [];
|
|
16034
16770
|
const who = `The member ${named(member)}`;
|
|
16035
16771
|
for (const requirement of requirements) {
|
|
16036
|
-
const wanted = `${
|
|
16772
|
+
const wanted = `${requirementText2(requirement)}, required by ${requiredBy(requiring)}`;
|
|
16037
16773
|
const adopted = entryFor(config, loaded, requirement.pack);
|
|
16038
16774
|
if (!adopted) {
|
|
16039
16775
|
out.push(policyIssue("POLICY_NOT_ADOPTED", `${who} does not select the pack ${wanted}. Select it in the member's own configuration (\`wairon pack use ${requirement.pack}@<version> --pin\` at its root).`, member));
|
|
@@ -16125,69 +16861,12 @@ var fs12 = __toESM(require("fs"));
|
|
|
16125
16861
|
var os3 = __toESM(require("os"));
|
|
16126
16862
|
var path17 = __toESM(require("path"));
|
|
16127
16863
|
var import_module = require("module");
|
|
16128
|
-
var
|
|
16864
|
+
var import_zod10 = require("zod");
|
|
16129
16865
|
|
|
16130
16866
|
// src/core/packstore.ts
|
|
16131
16867
|
var crypto3 = __toESM(require("crypto"));
|
|
16132
16868
|
var fs11 = __toESM(require("fs"));
|
|
16133
16869
|
var path16 = __toESM(require("path"));
|
|
16134
|
-
|
|
16135
|
-
// src/config/defaults.ts
|
|
16136
|
-
var os2 = __toESM(require("os"));
|
|
16137
|
-
var path15 = __toESM(require("path"));
|
|
16138
|
-
var DEFAULT_TARGET_DIRS = {
|
|
16139
|
-
claude: ".claude/agents",
|
|
16140
|
-
gemini: ".gemini/agents",
|
|
16141
|
-
agy: ".gemini/agents",
|
|
16142
|
-
cursor: ".cursor/rules",
|
|
16143
|
-
copilot: ".github/prompts",
|
|
16144
|
-
codex: ".codex/agents"
|
|
16145
|
-
};
|
|
16146
|
-
function defaultTargetConfig(type) {
|
|
16147
|
-
return {
|
|
16148
|
-
type,
|
|
16149
|
-
outputDir: DEFAULT_TARGET_DIRS[type],
|
|
16150
|
-
enabled: true
|
|
16151
|
-
};
|
|
16152
|
-
}
|
|
16153
|
-
var WAIRON_VERSION = "5.1.1-dev.96";
|
|
16154
|
-
var GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
16155
|
-
var ARCHITECT_AGENT_ID = "agent-architect";
|
|
16156
|
-
var ARCHITECT_TEMPLATE_ID = "architect";
|
|
16157
|
-
function globalTemplatesDir(projectOverride) {
|
|
16158
|
-
if (process.env.WAIRON_TEMPLATES_DIR) {
|
|
16159
|
-
return process.env.WAIRON_TEMPLATES_DIR;
|
|
16160
|
-
}
|
|
16161
|
-
if (projectOverride) {
|
|
16162
|
-
return projectOverride;
|
|
16163
|
-
}
|
|
16164
|
-
return path15.join(os2.homedir(), ".wairon", "templates");
|
|
16165
|
-
}
|
|
16166
|
-
var BACKEND_COMMANDS = {
|
|
16167
|
-
claude: "claude",
|
|
16168
|
-
gemini: "gemini"
|
|
16169
|
-
};
|
|
16170
|
-
function backendCommand(backend) {
|
|
16171
|
-
return BACKEND_COMMANDS[backend] ?? backend;
|
|
16172
|
-
}
|
|
16173
|
-
var SUPPORTED_ALIASES = ["wai"];
|
|
16174
|
-
var SCAN_EXCLUDE_DIRS = /* @__PURE__ */ new Set([
|
|
16175
|
-
"node_modules",
|
|
16176
|
-
"dist",
|
|
16177
|
-
"build",
|
|
16178
|
-
"out",
|
|
16179
|
-
".git",
|
|
16180
|
-
".cache",
|
|
16181
|
-
"coverage",
|
|
16182
|
-
"__pycache__",
|
|
16183
|
-
".venv",
|
|
16184
|
-
"venv",
|
|
16185
|
-
"target",
|
|
16186
|
-
// Rust
|
|
16187
|
-
"vendor"
|
|
16188
|
-
]);
|
|
16189
|
-
|
|
16190
|
-
// src/core/packstore.ts
|
|
16191
16870
|
var UNVERSIONED = "0.0.0-unversioned";
|
|
16192
16871
|
var INSTALL_RECORD = ".install.yaml";
|
|
16193
16872
|
var DIGEST_EXCLUDED = /* @__PURE__ */ new Set([INSTALL_RECORD, ".git", "node_modules", ".DS_Store"]);
|
|
@@ -16355,10 +17034,10 @@ function uninstallPack(name, version) {
|
|
|
16355
17034
|
}
|
|
16356
17035
|
|
|
16357
17036
|
// src/core/extensions.ts
|
|
16358
|
-
var ProfileDefSchema =
|
|
16359
|
-
family:
|
|
16360
|
-
forbiddenStereotypes:
|
|
16361
|
-
discouragedStereotypes:
|
|
17037
|
+
var ProfileDefSchema = import_zod10.z.object({
|
|
17038
|
+
family: import_zod10.z.enum(["backend-like", "frontend-like", "neutral"]).default("neutral"),
|
|
17039
|
+
forbiddenStereotypes: import_zod10.z.array(import_zod10.z.object({ types: import_zod10.z.array(import_zod10.z.string()).min(1), reason: import_zod10.z.string().min(1) })).default([]),
|
|
17040
|
+
discouragedStereotypes: import_zod10.z.array(import_zod10.z.object({ types: import_zod10.z.array(import_zod10.z.string()).min(1), reason: import_zod10.z.string().min(1) })).default([]),
|
|
16362
17041
|
/**
|
|
16363
17042
|
* Edge deltas — the ALLOW half of the profile-scoped dependency matrix. An
|
|
16364
17043
|
* entry LICENSES intra-subsystem dependsOn edges the builtin stereotype
|
|
@@ -16368,20 +17047,20 @@ var ProfileDefSchema = import_zod9.z.object({
|
|
|
16368
17047
|
* boundary rules and pattern containment are never relaxable. The DENY
|
|
16369
17048
|
* half is a `forbid-edge` declarative assertion.
|
|
16370
17049
|
*/
|
|
16371
|
-
allowedEdges:
|
|
16372
|
-
from:
|
|
16373
|
-
to:
|
|
16374
|
-
reason:
|
|
17050
|
+
allowedEdges: import_zod10.z.array(import_zod10.z.object({
|
|
17051
|
+
from: import_zod10.z.array(import_zod10.z.string().min(1)).min(1),
|
|
17052
|
+
to: import_zod10.z.array(import_zod10.z.string().min(1)).min(1),
|
|
17053
|
+
reason: import_zod10.z.string().min(1)
|
|
16375
17054
|
})).default([]),
|
|
16376
17055
|
rules: RulesConfigSchema.partial().optional()
|
|
16377
17056
|
});
|
|
16378
|
-
var LanguagePackDefSchema =
|
|
16379
|
-
unsupportedFlow:
|
|
16380
|
-
foreignBuiltins:
|
|
17057
|
+
var LanguagePackDefSchema = import_zod10.z.object({
|
|
17058
|
+
unsupportedFlow: import_zod10.z.record(import_zod10.z.string()).default({}),
|
|
17059
|
+
foreignBuiltins: import_zod10.z.array(import_zod10.z.string()).optional()
|
|
16381
17060
|
});
|
|
16382
|
-
var PackSkillSchema =
|
|
17061
|
+
var PackSkillSchema = import_zod10.z.object({
|
|
16383
17062
|
/** A NEW skill, installed namespaced as `<pack-id>-<id>`. Mutually exclusive with `extends`. */
|
|
16384
|
-
id:
|
|
17063
|
+
id: import_zod10.z.string().min(1).optional(),
|
|
16385
17064
|
/**
|
|
16386
17065
|
* EXTEND a builtin skill (`sdd-architect` | `sdd-narrative` | `sdd-auditor` |
|
|
16387
17066
|
* `sdd-implement`) instead of standing beside it.
|
|
@@ -16393,90 +17072,90 @@ var PackSkillSchema = import_zod9.z.object({
|
|
|
16393
17072
|
* appended under `## Platform: <pack>`; the builtin stays wairon's, so an
|
|
16394
17073
|
* upgrade still updates it.
|
|
16395
17074
|
*/
|
|
16396
|
-
extends:
|
|
16397
|
-
source:
|
|
16398
|
-
targets:
|
|
17075
|
+
extends: import_zod10.z.string().min(1).optional(),
|
|
17076
|
+
source: import_zod10.z.string().min(1),
|
|
17077
|
+
targets: import_zod10.z.array(import_zod10.z.string()).default([])
|
|
16399
17078
|
}).refine((s) => s.id === void 0 !== (s.extends === void 0), {
|
|
16400
17079
|
message: "a pack skill declares either `id` (a new skill) or `extends` (a section appended to a builtin), not both and not neither"
|
|
16401
17080
|
});
|
|
16402
|
-
var PackInstructionBlockSchema =
|
|
17081
|
+
var PackInstructionBlockSchema = import_zod10.z.union([
|
|
16403
17082
|
// Scalar shorthand: `instructions: >- …` — the common case, unscoped.
|
|
16404
|
-
|
|
16405
|
-
|
|
16406
|
-
text:
|
|
16407
|
-
profile:
|
|
17083
|
+
import_zod10.z.string().min(1).transform((text3) => ({ text: text3 })),
|
|
17084
|
+
import_zod10.z.object({
|
|
17085
|
+
text: import_zod10.z.string().min(1),
|
|
17086
|
+
profile: import_zod10.z.array(import_zod10.z.string().min(1)).min(1).optional()
|
|
16408
17087
|
})
|
|
16409
17088
|
]);
|
|
16410
|
-
var PackInstructionsSchema =
|
|
17089
|
+
var PackInstructionsSchema = import_zod10.z.preprocess(
|
|
16411
17090
|
(raw) => raw === void 0 || raw === null ? [] : Array.isArray(raw) ? raw : [raw],
|
|
16412
|
-
|
|
17091
|
+
import_zod10.z.array(PackInstructionBlockSchema)
|
|
16413
17092
|
);
|
|
16414
|
-
var PatternDefSchema =
|
|
16415
|
-
id:
|
|
16416
|
-
version:
|
|
16417
|
-
description:
|
|
16418
|
-
metadata:
|
|
17093
|
+
var PatternDefSchema = import_zod10.z.object({
|
|
17094
|
+
id: import_zod10.z.string().min(1),
|
|
17095
|
+
version: import_zod10.z.string().min(1),
|
|
17096
|
+
description: import_zod10.z.string().optional(),
|
|
17097
|
+
metadata: import_zod10.z.record(import_zod10.z.unknown()).optional()
|
|
16419
17098
|
});
|
|
16420
|
-
var AssertionSelectorSchema =
|
|
16421
|
-
componentType:
|
|
16422
|
-
profile:
|
|
16423
|
-
id:
|
|
17099
|
+
var AssertionSelectorSchema = import_zod10.z.object({
|
|
17100
|
+
componentType: import_zod10.z.array(import_zod10.z.string().min(1)).optional(),
|
|
17101
|
+
profile: import_zod10.z.array(import_zod10.z.string().min(1)).optional(),
|
|
17102
|
+
id: import_zod10.z.string().min(1).optional()
|
|
16424
17103
|
});
|
|
16425
17104
|
var assertionBase = {
|
|
16426
17105
|
/** Pack-local code; surfaced namespaced as <PACK_NAME>_<CODE>. */
|
|
16427
|
-
code:
|
|
16428
|
-
severity:
|
|
17106
|
+
code: import_zod10.z.string().min(1),
|
|
17107
|
+
severity: import_zod10.z.enum(["warning", "error"]).default("warning"),
|
|
16429
17108
|
/** The doctrine, stated for the finding message. */
|
|
16430
|
-
reason:
|
|
17109
|
+
reason: import_zod10.z.string().min(1)
|
|
16431
17110
|
};
|
|
16432
|
-
var PackAssertionSchema =
|
|
16433
|
-
|
|
16434
|
-
kind:
|
|
17111
|
+
var PackAssertionSchema = import_zod10.z.discriminatedUnion("kind", [
|
|
17112
|
+
import_zod10.z.object({
|
|
17113
|
+
kind: import_zod10.z.literal("forbid-edge"),
|
|
16435
17114
|
...assertionBase,
|
|
16436
17115
|
from: AssertionSelectorSchema,
|
|
16437
17116
|
to: AssertionSelectorSchema,
|
|
16438
|
-
relation:
|
|
17117
|
+
relation: import_zod10.z.array(import_zod10.z.enum(["dependsOn", "owns"])).default(["dependsOn", "owns"])
|
|
16439
17118
|
}),
|
|
16440
|
-
|
|
16441
|
-
kind:
|
|
17119
|
+
import_zod10.z.object({
|
|
17120
|
+
kind: import_zod10.z.literal("require-field"),
|
|
16442
17121
|
...assertionBase,
|
|
16443
17122
|
on: AssertionSelectorSchema,
|
|
16444
|
-
level:
|
|
17123
|
+
level: import_zod10.z.enum(["component", "interface", "implementation"]).default("component"),
|
|
16445
17124
|
/** A top-level spec field name, or one `ext.*` path — nothing else is addressable. */
|
|
16446
|
-
field:
|
|
17125
|
+
field: import_zod10.z.string().min(1),
|
|
16447
17126
|
/** Optional closed value set (string equality). */
|
|
16448
|
-
values:
|
|
17127
|
+
values: import_zod10.z.array(import_zod10.z.string()).optional()
|
|
16449
17128
|
}),
|
|
16450
|
-
|
|
16451
|
-
kind:
|
|
17129
|
+
import_zod10.z.object({
|
|
17130
|
+
kind: import_zod10.z.literal("endpoint-shape"),
|
|
16452
17131
|
...assertionBase,
|
|
16453
17132
|
on: AssertionSelectorSchema,
|
|
16454
17133
|
/** Optional transport allowlist. */
|
|
16455
|
-
transport:
|
|
17134
|
+
transport: import_zod10.z.array(import_zod10.z.string().min(1)).optional(),
|
|
16456
17135
|
/** Optional anchored regex over the transport's address field (path/topic/command/…). */
|
|
16457
|
-
pathPattern:
|
|
17136
|
+
pathPattern: import_zod10.z.string().min(1).optional()
|
|
16458
17137
|
})
|
|
16459
17138
|
]);
|
|
16460
17139
|
function assertionFullCode(packName, code) {
|
|
16461
17140
|
const norm = (s) => s.toUpperCase().replace(/[^A-Z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
16462
17141
|
return `${norm(packName)}_${norm(code)}`;
|
|
16463
17142
|
}
|
|
16464
|
-
var DeclarativePackSchema =
|
|
16465
|
-
name:
|
|
16466
|
-
version:
|
|
16467
|
-
profiles:
|
|
16468
|
-
languages:
|
|
16469
|
-
skills:
|
|
16470
|
-
patterns:
|
|
17143
|
+
var DeclarativePackSchema = import_zod10.z.object({
|
|
17144
|
+
name: import_zod10.z.string().min(1),
|
|
17145
|
+
version: import_zod10.z.string().optional(),
|
|
17146
|
+
profiles: import_zod10.z.record(ProfileDefSchema).default({}),
|
|
17147
|
+
languages: import_zod10.z.record(LanguagePackDefSchema).default({}),
|
|
17148
|
+
skills: import_zod10.z.array(PackSkillSchema).default([]),
|
|
17149
|
+
patterns: import_zod10.z.array(PatternDefSchema).default([]),
|
|
16471
17150
|
/** Declarative rule assertions — instances of closed kinds, hosted-safe. */
|
|
16472
|
-
assertions:
|
|
17151
|
+
assertions: import_zod10.z.array(PackAssertionSchema).default([]),
|
|
16473
17152
|
/**
|
|
16474
17153
|
* Semantic guarantee tokens this pack adds to the builtin vocabulary
|
|
16475
17154
|
* (SEMANTIC_GUARANTEES). Declaring a token makes it legal on L3 method
|
|
16476
17155
|
* `guarantees` and narrative `assertsGuarantees`; referenced tokens outside
|
|
16477
17156
|
* builtin + declared are flagged UNKNOWN_GUARANTEE by the validator.
|
|
16478
17157
|
*/
|
|
16479
|
-
guarantees:
|
|
17158
|
+
guarantees: import_zod10.z.array(import_zod10.z.string().min(1)).default([]),
|
|
16480
17159
|
/**
|
|
16481
17160
|
* Connecting-agent guidance appended to wairon's own MCP `initialize`
|
|
16482
17161
|
* instructions, attributed to this pack, in pack load order.
|
|
@@ -16491,7 +17170,7 @@ var DeclarativePackSchema = import_zod9.z.object({
|
|
|
16491
17170
|
* explicit in the new project's `project.yaml` where it is visible in review
|
|
16492
17171
|
* and removable — never silent authority over projects that never mentioned it.
|
|
16493
17172
|
*/
|
|
16494
|
-
applyByDefault:
|
|
17173
|
+
applyByDefault: import_zod10.z.boolean().default(false)
|
|
16495
17174
|
});
|
|
16496
17175
|
var EXTENDABLE_BUILTIN_SKILLS = ["sdd-architect", "sdd-narrative", "sdd-auditor", "sdd-implement", "sdd-delegate"];
|
|
16497
17176
|
function skillExtendErrors(skills) {
|
|
@@ -17126,7 +17805,7 @@ function buildImportGraph(index, universe) {
|
|
|
17126
17805
|
function buildOwnershipIndex(ctx) {
|
|
17127
17806
|
const ownedBy2 = /* @__PURE__ */ new Map();
|
|
17128
17807
|
for (const comp of ctx.components) {
|
|
17129
|
-
if (isRetired(comp) || !isPattern(comp)) continue;
|
|
17808
|
+
if (isRetired(comp) || !(isPattern(comp) || comp.componentType === "Supervisor")) continue;
|
|
17130
17809
|
for (const memberId of comp.owns) {
|
|
17131
17810
|
const member = ctx.componentMap.get(memberId);
|
|
17132
17811
|
if (!member || isPattern(member)) continue;
|
|
@@ -17911,6 +18590,66 @@ var namedScalarTypesRule = {
|
|
|
17911
18590
|
}
|
|
17912
18591
|
};
|
|
17913
18592
|
|
|
18593
|
+
// src/core/rules/integrity/rename-traces.ts
|
|
18594
|
+
var CODE = "RENAME_TRACE_CONFLICT";
|
|
18595
|
+
function namespaceOf(key) {
|
|
18596
|
+
const cut = key.lastIndexOf("::");
|
|
18597
|
+
return cut >= 0 ? key.slice(0, cut + 2) : "";
|
|
18598
|
+
}
|
|
18599
|
+
function judgeKind(ctx, noun, live, holders, qualify) {
|
|
18600
|
+
const claimed = /* @__PURE__ */ new Map();
|
|
18601
|
+
for (const holder of holders) {
|
|
18602
|
+
for (const entry of holder.trace) {
|
|
18603
|
+
const key = qualify(entry, holder);
|
|
18604
|
+
const other = claimed.get(key);
|
|
18605
|
+
if (live.has(key) && key !== holder.key) {
|
|
18606
|
+
report(ctx, holder, `${holder.label} lists "${entry}" in its rename trace, but a live ${noun} has that key \u2014 a consumer of the design export would read the live ${noun} as this one renamed. Rename the newcomer, or unset the trace entry and accept that a consumer reads a delete plus an add.`);
|
|
18607
|
+
} else if (live.has(key)) {
|
|
18608
|
+
report(ctx, holder, `${holder.label} lists its own key "${entry}" in its rename trace \u2014 a rename never records the name it keeps. Unset the entry.`);
|
|
18609
|
+
} else if (other && other !== holder) {
|
|
18610
|
+
report(ctx, holder, `${holder.label} and ${other.label} both list "${entry}" in their rename traces \u2014 a consumer holding the old key cannot tell which one it became. Unset the entry on the one that was not renamed from it.`);
|
|
18611
|
+
}
|
|
18612
|
+
if (!other) claimed.set(key, holder);
|
|
18613
|
+
}
|
|
18614
|
+
}
|
|
18615
|
+
}
|
|
18616
|
+
function report(ctx, holder, message) {
|
|
18617
|
+
if (!ctx.isSpecInScope(holder.specId)) return;
|
|
18618
|
+
ctx.addIssue("warning", CODE, message, holder.specId);
|
|
18619
|
+
}
|
|
18620
|
+
var inNamespace = (entry, holder) => entry.includes("::") ? entry : namespaceOf(holder.key) + entry;
|
|
18621
|
+
var renameTracesRule = {
|
|
18622
|
+
name: "rename-traces",
|
|
18623
|
+
judges: "design",
|
|
18624
|
+
description: "A rename trace (a spec's previousIds, a contract method's previousNames) names keys that no longer exist, and is what lets a consumer of the design export tell a rename from a delete plus an add; it must therefore be unambiguous. Reported: a trace entry equal to a live key of the same kind (a component, interface or implementation id; a type id within the same owner; `<interface>.<method>` of a declared method), and one former key claimed by two elements of the same kind. The rename tools and the gated write refuse both (id-retired, name-retired), so a finding means a hand edit; the message names both holders and the way out \u2014 rename the newcomer, or unset the trace entry and accept the delete plus an add a consumer will read.",
|
|
18625
|
+
codes: [
|
|
18626
|
+
{ code: CODE, defaultSeverity: "warning", summary: "A rename-trace entry equals a live key of the same kind, or two elements claim one former key" }
|
|
18627
|
+
],
|
|
18628
|
+
check(ctx) {
|
|
18629
|
+
const specHolders = (specs, noun) => specs.filter((s) => s.previousIds?.length).map((s) => ({ key: s.id, specId: s.id, label: `${noun} "${s.id}"`, trace: s.previousIds }));
|
|
18630
|
+
judgeKind(ctx, "component", new Set(ctx.components.map((c) => c.id)), specHolders(ctx.components, "Component"), inNamespace);
|
|
18631
|
+
judgeKind(ctx, "interface", new Set(ctx.interfaces.map((i) => i.id)), specHolders(ctx.interfaces, "Interface"), inNamespace);
|
|
18632
|
+
judgeKind(ctx, "implementation", new Set(ctx.implementations.map((i) => i.id)), specHolders(ctx.implementations, "Implementation"), inNamespace);
|
|
18633
|
+
judgeKind(
|
|
18634
|
+
ctx,
|
|
18635
|
+
"type",
|
|
18636
|
+
new Set(ctx.types.map((t) => qualifiedTypeId(t))),
|
|
18637
|
+
ctx.types.filter((t) => t.previousIds?.length).map((t) => ({ key: qualifiedTypeId(t), specId: t.id, label: `Type "${qualifiedTypeId(t)}"`, trace: t.previousIds })),
|
|
18638
|
+
inNamespace
|
|
18639
|
+
);
|
|
18640
|
+
const methodHolders = [];
|
|
18641
|
+
const liveMethods = /* @__PURE__ */ new Set();
|
|
18642
|
+
for (const intf of ctx.interfaces) {
|
|
18643
|
+
for (const m of intf.methods) {
|
|
18644
|
+
const key = `${intf.id}.${m.name}`;
|
|
18645
|
+
liveMethods.add(key);
|
|
18646
|
+
if (m.previousNames?.length) methodHolders.push({ key, specId: intf.id, label: `Method "${key}"`, trace: m.previousNames });
|
|
18647
|
+
}
|
|
18648
|
+
}
|
|
18649
|
+
judgeKind(ctx, "contract method", liveMethods, methodHolders, inNamespace);
|
|
18650
|
+
}
|
|
18651
|
+
};
|
|
18652
|
+
|
|
17914
18653
|
// src/core/rules/integrity/public-surface-binding.ts
|
|
17915
18654
|
var publicSurfaceBindingRule = {
|
|
17916
18655
|
name: "public-surface-binding",
|
|
@@ -18423,10 +19162,10 @@ var projectBoundariesRule = {
|
|
|
18423
19162
|
var lintAllowsRule = {
|
|
18424
19163
|
name: "lint-allows",
|
|
18425
19164
|
judges: "design",
|
|
18426
|
-
description: "Per-spec lint suppressions (lint.allow) must name real issue codes and actually suppress a finding \u2014 unknown codes and stale allows are flagged. An allow covers exactly the occurrence it names: a finding that reports a site is silenced only by an allow whose `at` is that site, a finding that reports none only by an allow that names none, and an aggregating finding only by an allow whose `covers` lists every unit it reports \u2014 a unit nobody listed is named back as new instead of inheriting a decision taken about its neighbours. So a coarse allow left on a rule that names sites, and an allow whose site the run no longer reports, are both UNUSED_LINT_ALLOW, and the finding names the sites that did fire. Allows silence warnings and notices; errors always surface.",
|
|
19165
|
+
description: "Per-spec lint suppressions (lint.allow) must name real issue codes and actually suppress a finding \u2014 unknown codes and stale allows are flagged. An allow covers exactly the occurrence it names: a finding that reports a site is silenced only by an allow whose `at` is that site, a finding that reports none only by an allow that names none, and an aggregating finding only by an allow whose `covers` lists every unit it reports \u2014 a unit nobody listed is named back as new instead of inheriting a decision taken about its neighbours. So a coarse allow left on a rule that names sites, and an allow whose site the run no longer reports, are both UNUSED_LINT_ALLOW, and the finding names the sites that did fire. Allows silence warnings and notices; errors always surface \u2014 so an allow naming a code that is an error on its spec (it fired there as one, or its resolved severity is error) covers nothing, and the finding says plainly that an error cannot be allowed rather than that the code never fired.",
|
|
18427
19166
|
codes: [
|
|
18428
19167
|
{ code: "UNKNOWN_LINT_ALLOW_CODE", defaultSeverity: "warning", summary: "lint.allow names an issue code no registered rule emits" },
|
|
18429
|
-
{ code: "UNUSED_LINT_ALLOW", defaultSeverity: "warning", summary: "lint.allow entry
|
|
19168
|
+
{ code: "UNUSED_LINT_ALLOW", defaultSeverity: "warning", summary: "lint.allow entry covers nothing this run \u2014 the code never fired, it fired at sites this allow does not name, or it is an error, which no allow can cover" }
|
|
18430
19169
|
],
|
|
18431
19170
|
check(ctx) {
|
|
18432
19171
|
for (const a of ctx.lintAllows) {
|
|
@@ -18439,9 +19178,20 @@ var lintAllowsRule = {
|
|
|
18439
19178
|
);
|
|
18440
19179
|
continue;
|
|
18441
19180
|
}
|
|
18442
|
-
if (a.used) continue;
|
|
18443
19181
|
const reported = ctx.sitesReported(a.specId, a.code);
|
|
18444
19182
|
const at = a.at ? ` at "${a.at}"` : "";
|
|
19183
|
+
const fired = reported.unsited || reported.sites.length > 0;
|
|
19184
|
+
const isError = reported.errored || !fired && ctx.severityOf(a.code, a.specId) === "error";
|
|
19185
|
+
if (isError) {
|
|
19186
|
+
ctx.addIssue(
|
|
19187
|
+
"warning",
|
|
19188
|
+
"UNUSED_LINT_ALLOW",
|
|
19189
|
+
`Spec "${a.specId}" allows "${a.code}"${at} (reason: ${a.reason}), but "${a.code}" is an error${fired ? " and fired here as one" : ""}, and an error cannot be allowed \u2014 lint.allow silences warnings and notices only. Fix what the finding names, or remove the allow (a project may re-tune the code's severity in rules.sddRuleSeverity).`,
|
|
19190
|
+
a.specId
|
|
19191
|
+
);
|
|
19192
|
+
continue;
|
|
19193
|
+
}
|
|
19194
|
+
if (a.used) continue;
|
|
18445
19195
|
let why;
|
|
18446
19196
|
if (a.at && reported.unsited && reported.sites.length === 0) {
|
|
18447
19197
|
why = `findings of "${a.code}" on this spec name no site at all, so this allow must not name one \u2014 drop the \`at\``;
|
|
@@ -18488,12 +19238,12 @@ var contractSymmetryRule = {
|
|
|
18488
19238
|
);
|
|
18489
19239
|
}
|
|
18490
19240
|
}
|
|
18491
|
-
for (const
|
|
18492
|
-
if (!implMethodNames.has(
|
|
19241
|
+
for (const contractMethod2 of contract.methods) {
|
|
19242
|
+
if (!implMethodNames.has(contractMethod2.name)) {
|
|
18493
19243
|
ctx.addIssue(
|
|
18494
19244
|
"error",
|
|
18495
19245
|
"MISSING_IMPLEMENTATION_METHOD",
|
|
18496
|
-
`Implementation "${impl.id}" is missing implementation for contract method "${
|
|
19246
|
+
`Implementation "${impl.id}" is missing implementation for contract method "${contractMethod2.name}" from interface "${contract.id}".`,
|
|
18497
19247
|
impl.id,
|
|
18498
19248
|
isDraftCtx
|
|
18499
19249
|
);
|
|
@@ -19293,8 +20043,8 @@ var narrativeDetailRule = {
|
|
|
19293
20043
|
const component = ctx.componentMap.get(contract.component);
|
|
19294
20044
|
const isDraftCtx = ctx.isImplementationDraft(impl);
|
|
19295
20045
|
for (const implMethod of impl.methods) {
|
|
19296
|
-
const
|
|
19297
|
-
if (!
|
|
20046
|
+
const contractMethod2 = contract.methods.find((m) => m.name === implMethod.name);
|
|
20047
|
+
if (!contractMethod2) continue;
|
|
19298
20048
|
if (implMethod.narrative.length > 0) continue;
|
|
19299
20049
|
const eff = effectiveDetail(implMethod, impl, component);
|
|
19300
20050
|
if (eff.level === "full") {
|
|
@@ -19307,7 +20057,7 @@ var narrativeDetailRule = {
|
|
|
19307
20057
|
);
|
|
19308
20058
|
continue;
|
|
19309
20059
|
}
|
|
19310
|
-
const prose = implMethod.intent ??
|
|
20060
|
+
const prose = implMethod.intent ?? contractMethod2.description;
|
|
19311
20061
|
if (!passesIntentFloor(prose, implMethod.name)) {
|
|
19312
20062
|
ctx.addIssue(
|
|
19313
20063
|
eff.explicit ? "error" : "warning",
|
|
@@ -19964,18 +20714,47 @@ var dataBlockDepsRule = {
|
|
|
19964
20714
|
};
|
|
19965
20715
|
|
|
19966
20716
|
// src/core/rules/doctrine/entrypoint-dependencies.ts
|
|
20717
|
+
function maintainedRegistries(ctx) {
|
|
20718
|
+
const maintained = /* @__PURE__ */ new Map();
|
|
20719
|
+
const add2 = (supervisorId, registryId) => {
|
|
20720
|
+
let set = maintained.get(supervisorId);
|
|
20721
|
+
if (!set) maintained.set(supervisorId, set = /* @__PURE__ */ new Set());
|
|
20722
|
+
set.add(registryId);
|
|
20723
|
+
};
|
|
20724
|
+
for (const comp of ctx.components) {
|
|
20725
|
+
if (comp.componentType !== "Supervisor" || isRetired(comp)) continue;
|
|
20726
|
+
for (const memberId of comp.owns) {
|
|
20727
|
+
if (ctx.componentMap.get(memberId)?.componentType === "Registry") add2(comp.id, memberId);
|
|
20728
|
+
}
|
|
20729
|
+
}
|
|
20730
|
+
for (const impl of ctx.implementations) {
|
|
20731
|
+
const contract = ctx.interfaceMap.get(impl.contract);
|
|
20732
|
+
const supervisor = contract ? ctx.componentMap.get(contract.component) : void 0;
|
|
20733
|
+
if (!supervisor || supervisor.componentType !== "Supervisor" || isRetired(supervisor)) continue;
|
|
20734
|
+
for (const implMethod of impl.methods) {
|
|
20735
|
+
for (const step of implMethod.narrative) {
|
|
20736
|
+
if (step.type !== "call" || !step.targetComponent || !step.targetMethod) continue;
|
|
20737
|
+
if (ctx.componentMap.get(step.targetComponent)?.componentType !== "Registry") continue;
|
|
20738
|
+
const called = ctx.interfaceMethodsOf(step.targetComponent).find((m) => m.name === step.targetMethod);
|
|
20739
|
+
if (called?.effect === "lifecycle") add2(supervisor.id, step.targetComponent);
|
|
20740
|
+
}
|
|
20741
|
+
}
|
|
20742
|
+
}
|
|
20743
|
+
return new Map([...maintained].map(([id, set]) => [id, [...set]]));
|
|
20744
|
+
}
|
|
19967
20745
|
var entrypointDepsRule = {
|
|
19968
20746
|
name: "entrypoint-dependencies",
|
|
19969
20747
|
judges: "design",
|
|
19970
|
-
description: "Judges the edges at the system's entry points and its process layer. Portals and Observers are top-level entry points and subscribers, so nothing may depend on them \u2014 and that is the edge's one finding, which is why no other matrix rule judges it. Downward, a Portal dispatches to Orchestrators and may READ through Indexes and Repository facades but never reaches Store/Registry/Query or an Adapter, while an Observer forwards to one Orchestrator or Supervisor over a message-bus Adapter. A View stays a passive presenter. A Supervisor
|
|
20748
|
+
description: "Judges the edges at the system's entry points and its process layer. Portals and Observers are top-level entry points and subscribers, so nothing may depend on them \u2014 and that is the edge's one finding, which is why no other matrix rule judges it. Downward, a Portal dispatches to Orchestrators and may READ through Indexes and Repository facades but never reaches Store/Registry/Query or an Adapter, while an Observer forwards to one Orchestrator or Supervisor over a message-bus Adapter. A View stays a passive presenter. A Supervisor stays out of presentation; what it may do to the data it reaches is judged per call (supervisor-shared-data), and what it owns as its supervision state by the ownership rules. A component depending on a live Actor reaches it through the Actor's supervision: by depending on a Supervisor that supervises it, or on a Registry such a Supervisor maintains (owns, or calls with lifecycle-effect methods) \u2014 the lookup hop callers really take.",
|
|
19971
20749
|
codes: [
|
|
19972
20750
|
{ code: "ARCHITECTURE_VIOLATION_PORTAL_DEP", defaultSeverity: "error", summary: "Component depending on a Portal/Observer" },
|
|
19973
20751
|
{ code: "ARCHITECTURE_VIOLATION_PORTAL_FORBIDDEN_DEP", defaultSeverity: "error", summary: "Portal/Observer reaching the data layer directly" },
|
|
19974
20752
|
{ code: "ARCHITECTURE_VIOLATION_VIEW_DEP", defaultSeverity: "error", summary: "View depending on persistence layers or on logic that is not pure" },
|
|
19975
|
-
{ code: "ARCHITECTURE_VIOLATION_SUPERVISOR_DEP", defaultSeverity: "error", summary: "Supervisor depending on
|
|
19976
|
-
{ code: "ACTOR_REACHED_WITHOUT_SUPERVISOR", defaultSeverity: "error", summary: "Component depending on a live Actor it does not supervise,
|
|
20753
|
+
{ code: "ARCHITECTURE_VIOLATION_SUPERVISOR_DEP", defaultSeverity: "error", summary: "Supervisor depending on a presentation block (View, FeatureComponent, RouterComponent) \u2014 a Supervisor manages live processes; the data it reaches is judged per call by supervisor-shared-data" },
|
|
20754
|
+
{ code: "ACTOR_REACHED_WITHOUT_SUPERVISOR", defaultSeverity: "error", summary: "Component depending on a live Actor it does not supervise, reaching it neither through a Supervisor that supervises it nor through a Registry such a Supervisor maintains \u2014 model the real lookup hop" }
|
|
19977
20755
|
],
|
|
19978
20756
|
check(ctx) {
|
|
20757
|
+
const lookups = maintainedRegistries(ctx);
|
|
19979
20758
|
for (const edge of ctx.dependencyEdges().matrix) {
|
|
19980
20759
|
const comp = edge.from;
|
|
19981
20760
|
const depComp = edge.to;
|
|
@@ -20011,27 +20790,32 @@ var entrypointDepsRule = {
|
|
|
20011
20790
|
edge.draftContext
|
|
20012
20791
|
);
|
|
20013
20792
|
}
|
|
20014
|
-
if (comp.componentType === "Supervisor" && ["
|
|
20793
|
+
if (comp.componentType === "Supervisor" && ["View", "FeatureComponent", "RouterComponent"].includes(depComp.componentType)) {
|
|
20015
20794
|
ctx.addIssue(
|
|
20016
20795
|
"error",
|
|
20017
20796
|
"ARCHITECTURE_VIOLATION_SUPERVISOR_DEP",
|
|
20018
|
-
`Architectural violation: Supervisor "${comp.id}" cannot depend on ${stereotypeOf(depComp)} "${depComp.id}". A Supervisor
|
|
20797
|
+
`Architectural violation: Supervisor "${comp.id}" cannot depend on ${stereotypeOf(depComp)} "${depComp.id}". A Supervisor manages live processes and stays out of presentation \u2014 the UI reaches the system through its Portals and workflows, never through a Supervisor's dependencies.`,
|
|
20019
20798
|
comp.id,
|
|
20020
20799
|
edge.draftContext
|
|
20021
20800
|
);
|
|
20022
20801
|
}
|
|
20023
20802
|
if (depComp.componentType === "Actor" && comp.componentType !== "Supervisor") {
|
|
20024
|
-
const
|
|
20025
|
-
|
|
20026
|
-
|
|
20027
|
-
|
|
20028
|
-
|
|
20029
|
-
|
|
20030
|
-
|
|
20803
|
+
const supervisors = ctx.components.filter((c) => c.componentType === "Supervisor" && c.dependsOn.includes(depComp.id));
|
|
20804
|
+
const registries = supervisors.flatMap((s) => (lookups.get(s.id) ?? []).map((registry) => ({ registry, supervisor: s.id })));
|
|
20805
|
+
const reached = supervisors.some((s) => comp.dependsOn.includes(s.id)) || registries.some((r) => comp.dependsOn.includes(r.registry));
|
|
20806
|
+
if (!reached) {
|
|
20807
|
+
let remedy;
|
|
20808
|
+
if (registries.length > 0) {
|
|
20809
|
+
remedy = `depend on ${registries.length === 1 ? "the Registry" : "one of the Registries"} its Supervisor maintains (${registries.map((r) => `"${r.registry}", kept by "${r.supervisor}"`).join("; ")}) and look the Actor up by id there`;
|
|
20810
|
+
} else if (supervisors.length > 0) {
|
|
20811
|
+
remedy = `${supervisors.length === 1 ? "its Supervisor" : "its Supervisors"} (${supervisors.map((s) => `"${s.id}"`).join(", ")}) maintain no Registry of its live handles yet: model that lookup as a Registry the Supervisor keeps through lifecycle-effect methods (registering and unregistering a live handle), and depend on that Registry`;
|
|
20812
|
+
} else {
|
|
20813
|
+
remedy = `no Supervisor depends on "${depComp.id}" yet: give it a Supervisor that depends on it and maintains a Registry of its live handles through lifecycle-effect methods, and depend on that Registry`;
|
|
20814
|
+
}
|
|
20031
20815
|
ctx.addIssue(
|
|
20032
20816
|
"error",
|
|
20033
20817
|
"ACTOR_REACHED_WITHOUT_SUPERVISOR",
|
|
20034
|
-
`Architectural violation: ${stereotypeOf(comp)} "${comp.id}" depends on the live Actor "${depComp.id}" without
|
|
20818
|
+
`Architectural violation: ${stereotypeOf(comp)} "${comp.id}" depends on the live Actor "${depComp.id}" without reaching it through its supervision. A live Actor is found by id through a Registry its Supervisor maintains, or messaged through that Supervisor \u2014 ${remedy}.`,
|
|
20035
20819
|
comp.id,
|
|
20036
20820
|
edge.draftContext
|
|
20037
20821
|
);
|
|
@@ -20045,9 +20829,9 @@ var entrypointDepsRule = {
|
|
|
20045
20829
|
var portalWriteShortcutRule = {
|
|
20046
20830
|
name: "portal-write-shortcut",
|
|
20047
20831
|
judges: "design",
|
|
20048
|
-
description: "A Portal narrative call step or dispatch-table binding that reaches a write-effect method on a Repository or Index directly is the write shortcut: the Portal\u2192data-facade edge is licensed for reads only, and a write routes through an Orchestrator that owns the workflow. A dispatch step reaches its server only through a table binding, so judging every binding judges each dispatch step that takes it, once, where the route is declared. Methods that carry no effect tag are not judged.",
|
|
20832
|
+
description: "A Portal narrative call step or dispatch-table binding that reaches a write- or lifecycle-effect method on a Repository or Index directly is the write shortcut: the Portal\u2192data-facade edge is licensed for reads only, and a mutation \u2014 a write, or a lifecycle change to what exists \u2014 routes through an Orchestrator that owns the workflow. A dispatch step reaches its server only through a table binding, so judging every binding judges each dispatch step that takes it, once, where the route is declared. Methods that carry no effect tag are not judged.",
|
|
20049
20833
|
codes: [
|
|
20050
|
-
{ code: "PORTAL_WRITE_SHORTCUT", defaultSeverity: "error", summary: "Portal narrative call or dispatch-table binding reaches a write-effect method on a Repository/Index directly \u2014 reads may shortcut,
|
|
20834
|
+
{ code: "PORTAL_WRITE_SHORTCUT", defaultSeverity: "error", summary: "Portal narrative call or dispatch-table binding reaches a write- or lifecycle-effect method on a Repository/Index directly \u2014 reads may shortcut, mutations route through an Orchestrator (judged on effect-tagged facade methods; untagged methods are not yet judged)" }
|
|
20051
20835
|
],
|
|
20052
20836
|
check(ctx) {
|
|
20053
20837
|
for (const impl of ctx.implementations) {
|
|
@@ -20061,11 +20845,11 @@ var portalWriteShortcutRule = {
|
|
|
20061
20845
|
const target = ctx.componentMap.get(step.targetComponent);
|
|
20062
20846
|
if (!target || target.componentType !== "Repository" && target.componentType !== "Index") continue;
|
|
20063
20847
|
const targetMethod = ctx.interfaceMethodsOf(target.id).find((m) => m.name === step.targetMethod);
|
|
20064
|
-
if (targetMethod?.effect !== "write") continue;
|
|
20848
|
+
if (targetMethod?.effect !== "write" && targetMethod?.effect !== "lifecycle") continue;
|
|
20065
20849
|
ctx.addIssue(
|
|
20066
20850
|
"error",
|
|
20067
20851
|
"PORTAL_WRITE_SHORTCUT",
|
|
20068
|
-
`Portal "${component.id}": step ${step.stepNumber} of "${implMethod.name}" calls
|
|
20852
|
+
`Portal "${component.id}": step ${step.stepNumber} of "${implMethod.name}" calls ${targetMethod.effect}-effect method ${target.id}.${step.targetMethod} directly. The Portal\u2192${target.componentType} shortcut is licensed for READS only \u2014 route the ${targetMethod.effect === "write" ? "write" : "lifecycle change"} through an Orchestrator that owns the workflow.`,
|
|
20069
20853
|
impl.id,
|
|
20070
20854
|
isDraftCtx || ctx.isComponentDraft(target.id)
|
|
20071
20855
|
);
|
|
@@ -20079,11 +20863,11 @@ var portalWriteShortcutRule = {
|
|
|
20079
20863
|
const target = ctx.componentMap.get(binding.component);
|
|
20080
20864
|
if (!target || target.componentType !== "Repository" && target.componentType !== "Index") continue;
|
|
20081
20865
|
const targetMethod = ctx.interfaceMethodsOf(target.id).find((m) => m.name === binding.method);
|
|
20082
|
-
if (targetMethod?.effect !== "write") continue;
|
|
20866
|
+
if (targetMethod?.effect !== "write" && targetMethod?.effect !== "lifecycle") continue;
|
|
20083
20867
|
ctx.addIssue(
|
|
20084
20868
|
"error",
|
|
20085
20869
|
"PORTAL_WRITE_SHORTCUT",
|
|
20086
|
-
`Portal "${comp.id}": dispatch binding "${binding.capability}" routes to
|
|
20870
|
+
`Portal "${comp.id}": dispatch binding "${binding.capability}" routes to ${targetMethod.effect}-effect method ${target.id}.${binding.method} directly. The Portal\u2192${target.componentType} shortcut is licensed for READS only \u2014 route the ${targetMethod.effect === "write" ? "write" : "lifecycle change"} through an Orchestrator that owns the workflow.`,
|
|
20087
20871
|
comp.id,
|
|
20088
20872
|
isDraftCtx || ctx.isComponentDraft(target.id)
|
|
20089
20873
|
);
|
|
@@ -20092,28 +20876,101 @@ var portalWriteShortcutRule = {
|
|
|
20092
20876
|
}
|
|
20093
20877
|
};
|
|
20094
20878
|
|
|
20879
|
+
// src/core/rules/doctrine/supervisor-shared-data.ts
|
|
20880
|
+
var DATA_COMPONENTS = /* @__PURE__ */ new Set(["Store", "Registry", "Repository", "Index", "Query"]);
|
|
20881
|
+
var supervisorSharedDataRule = {
|
|
20882
|
+
name: "supervisor-shared-data",
|
|
20883
|
+
judges: "design",
|
|
20884
|
+
description: "A Supervisor keeps its own supervision state (the Stores and Registries it owns) with full read and write, but data it does not own is shared: a Supervisor narrative call step that reaches a method of a Store, Registry, Repository, Index or Query the Supervisor does not own is legal only when that method declares effect read or lifecycle. A write \u2014 or a method that declares no effect \u2014 goes through a workflow: the Supervisor depends on the Orchestrator that does it. A read on behalf of a request still passes; in practice the paired write is what forces the workflow out, and the read moves with it.",
|
|
20885
|
+
codes: [
|
|
20886
|
+
{ code: "SUPERVISOR_WRITE_SHORTCUT", defaultSeverity: "error", summary: "Supervisor narrative call reaches a method of a data component it does not own whose declared effect is neither read nor lifecycle \u2014 writes to shared data route through an Orchestrator" }
|
|
20887
|
+
],
|
|
20888
|
+
check(ctx) {
|
|
20889
|
+
const ownership = ctx.ownershipIndex();
|
|
20890
|
+
for (const impl of ctx.implementations) {
|
|
20891
|
+
const contract = ctx.interfaceMap.get(impl.contract);
|
|
20892
|
+
const supervisor = contract ? ctx.componentMap.get(contract.component) : void 0;
|
|
20893
|
+
if (!supervisor || supervisor.componentType !== "Supervisor" || isRetired(supervisor)) continue;
|
|
20894
|
+
const isDraftCtx = ctx.isImplementationDraft(impl);
|
|
20895
|
+
for (const implMethod of impl.methods) {
|
|
20896
|
+
for (const step of implMethod.narrative) {
|
|
20897
|
+
if (step.type !== "call" || !step.targetComponent || !step.targetMethod) continue;
|
|
20898
|
+
const target = ctx.componentMap.get(step.targetComponent);
|
|
20899
|
+
if (!target || !DATA_COMPONENTS.has(target.componentType)) continue;
|
|
20900
|
+
if (ownership.ownerOf(target.id) === supervisor.id) continue;
|
|
20901
|
+
const called = ctx.interfaceMethodsOf(target.id).find((m) => m.name === step.targetMethod);
|
|
20902
|
+
if (!called || called.effect === "read" || called.effect === "lifecycle") continue;
|
|
20903
|
+
const what = called.effect === "write" ? "a write-effect method" : "a method that declares no effect";
|
|
20904
|
+
const untaggedHint = called.effect === "write" ? "" : ` If ${target.id}.${called.name} only reads, or only changes what exists, declare its effect (read or lifecycle).`;
|
|
20905
|
+
ctx.addIssue(
|
|
20906
|
+
"error",
|
|
20907
|
+
"SUPERVISOR_WRITE_SHORTCUT",
|
|
20908
|
+
`Supervisor "${supervisor.id}": step ${step.stepNumber} of "${implMethod.name}" calls ${target.id}.${called.name}, ${what} on ${target.componentType} "${target.id}", which the Supervisor does not own. A Supervisor reads shared data and changes what exists in it (read and lifecycle effects); a write to its fields goes through a workflow \u2014 depend on the Orchestrator that does it and call that instead.${untaggedHint}`,
|
|
20909
|
+
impl.id,
|
|
20910
|
+
isDraftCtx || ctx.isComponentDraft(target.id)
|
|
20911
|
+
);
|
|
20912
|
+
}
|
|
20913
|
+
}
|
|
20914
|
+
}
|
|
20915
|
+
}
|
|
20916
|
+
};
|
|
20917
|
+
|
|
20918
|
+
// src/core/rules/doctrine/lifecycle-effect-closure.ts
|
|
20919
|
+
var lifecycleEffectClosureRule = {
|
|
20920
|
+
name: "lifecycle-effect-closure",
|
|
20921
|
+
judges: "design",
|
|
20922
|
+
description: "A lifecycle-effect method may create, destroy, or (un)register an entity's existence or membership, never modify its domain fields \u2014 and the effect is closed under composition: its narrative may call only read- and lifecycle-effect methods besides its construction and local steps. A call step to a write-effect method from a lifecycle-effect method is a declaration error: the method is a write, or the write belongs to a workflow beside it. Called methods that declare no effect are not judged.",
|
|
20923
|
+
codes: [
|
|
20924
|
+
{ code: "LIFECYCLE_CALLS_WRITE", defaultSeverity: "error", summary: "Lifecycle-effect method whose narrative calls a write-effect method \u2014 the lifecycle effect is closed under composition" }
|
|
20925
|
+
],
|
|
20926
|
+
check(ctx) {
|
|
20927
|
+
for (const impl of ctx.implementations) {
|
|
20928
|
+
const contract = ctx.interfaceMap.get(impl.contract);
|
|
20929
|
+
if (!contract) continue;
|
|
20930
|
+
const declared = ctx.interfaceMethodsOf(contract.component);
|
|
20931
|
+
const isDraftCtx = ctx.isImplementationDraft(impl);
|
|
20932
|
+
for (const implMethod of impl.methods) {
|
|
20933
|
+
if (declared.find((m) => m.name === implMethod.name)?.effect !== "lifecycle") continue;
|
|
20934
|
+
for (const step of implMethod.narrative) {
|
|
20935
|
+
if (step.type !== "call" || !step.targetComponent || !step.targetMethod) continue;
|
|
20936
|
+
const called = ctx.interfaceMethodsOf(step.targetComponent).find((m) => m.name === step.targetMethod);
|
|
20937
|
+
if (called?.effect !== "write") continue;
|
|
20938
|
+
ctx.addIssue(
|
|
20939
|
+
"error",
|
|
20940
|
+
"LIFECYCLE_CALLS_WRITE",
|
|
20941
|
+
`"${contract.component}.${implMethod.name}" declares effect lifecycle, but step ${step.stepNumber} calls write-effect method ${step.targetComponent}.${step.targetMethod}. A lifecycle method creates, destroys or (un)registers what exists and never modifies domain fields, and the effect is closed under composition \u2014 it may call only read and lifecycle methods. Declare the method a write, or move the write to a workflow beside it.`,
|
|
20942
|
+
impl.id,
|
|
20943
|
+
isDraftCtx
|
|
20944
|
+
);
|
|
20945
|
+
}
|
|
20946
|
+
}
|
|
20947
|
+
}
|
|
20948
|
+
}
|
|
20949
|
+
};
|
|
20950
|
+
|
|
20095
20951
|
// src/core/rules/doctrine/pattern-membership.ts
|
|
20096
20952
|
var patternMembershipRule = {
|
|
20097
20953
|
name: "pattern-membership",
|
|
20098
20954
|
judges: "design",
|
|
20099
|
-
description: "Only patterns (Repository/FeatureComponent/RouterComponent) own member blocks, and every pattern owns at least one. Each claim must name a component that exists and is itself a building block \u2014 patterns compose at the subsystem (L1) level, never by owning one another \u2014 and a block has exactly one owner, the first pattern to claim it.",
|
|
20955
|
+
description: "Only patterns (Repository/FeatureComponent/RouterComponent) own member blocks, and every pattern owns at least one. The one building block that may own is a Supervisor, which owns its supervision state and may own nothing at all; what it may own is pattern-containment's question. Each claim must name a component that exists and is itself a building block \u2014 patterns compose at the subsystem (L1) level, never by owning one another \u2014 and a block has exactly one owner, the first pattern or Supervisor to claim it.",
|
|
20100
20956
|
codes: [
|
|
20101
20957
|
{ code: "EMPTY_PATTERN", defaultSeverity: "error", summary: "Pattern with no owned member blocks" },
|
|
20102
|
-
{ code: "BLOCK_OWNS_MEMBERS", defaultSeverity: "error", summary: "Building block using owns" },
|
|
20958
|
+
{ code: "BLOCK_OWNS_MEMBERS", defaultSeverity: "error", summary: "Building block other than a Supervisor using owns" },
|
|
20103
20959
|
{ code: "INVALID_OWNED_MEMBER", defaultSeverity: "error", summary: "owns names a non-existent component" },
|
|
20104
20960
|
{ code: "PATTERN_OWNS_PATTERN", defaultSeverity: "error", summary: "Pattern owning another pattern" },
|
|
20105
|
-
{ code: "SHARED_OWNED_MEMBER", defaultSeverity: "error", summary: "Block owned by two patterns" }
|
|
20961
|
+
{ code: "SHARED_OWNED_MEMBER", defaultSeverity: "error", summary: "Block owned by two owners (patterns or Supervisors)" }
|
|
20106
20962
|
],
|
|
20107
20963
|
check(ctx) {
|
|
20108
20964
|
for (const comp of ctx.components) {
|
|
20109
20965
|
if (isRetired(comp)) continue;
|
|
20110
20966
|
const isDraftCtx = ctx.isComponentDraft(comp.id);
|
|
20111
20967
|
const pattern = isPattern(comp);
|
|
20968
|
+
const supervisor = comp.componentType === "Supervisor";
|
|
20112
20969
|
if (pattern && comp.owns.length === 0) {
|
|
20113
20970
|
ctx.addIssue("error", "EMPTY_PATTERN", `Pattern "${comp.id}" (${comp.componentType}) must own member blocks via "owns".`, comp.id, isDraftCtx);
|
|
20114
20971
|
}
|
|
20115
|
-
if (!pattern && comp.owns.length > 0) {
|
|
20116
|
-
ctx.addIssue("error", "BLOCK_OWNS_MEMBERS", `Building block "${comp.id}" (${comp.componentType}) cannot own members; only patterns (${Array.from(PATTERN_TYPES).join("/")}) use "owns".`, comp.id, isDraftCtx);
|
|
20972
|
+
if (!pattern && !supervisor && comp.owns.length > 0) {
|
|
20973
|
+
ctx.addIssue("error", "BLOCK_OWNS_MEMBERS", `Building block "${comp.id}" (${comp.componentType}) cannot own members; only patterns (${Array.from(PATTERN_TYPES).join("/")}) use "owns", and a Supervisor for its supervision state.`, comp.id, isDraftCtx);
|
|
20117
20974
|
}
|
|
20118
20975
|
}
|
|
20119
20976
|
const ownership = ctx.ownershipIndex();
|
|
@@ -20121,15 +20978,18 @@ var patternMembershipRule = {
|
|
|
20121
20978
|
if (isRetired(comp)) continue;
|
|
20122
20979
|
const isDraftCtx = ctx.isComponentDraft(comp.id);
|
|
20123
20980
|
const pattern = isPattern(comp);
|
|
20981
|
+
const supervisor = comp.componentType === "Supervisor";
|
|
20124
20982
|
for (const memberId of comp.owns) {
|
|
20125
20983
|
const member = ctx.componentMap.get(memberId);
|
|
20126
20984
|
if (!member) {
|
|
20127
20985
|
ctx.addIssue("error", "INVALID_OWNED_MEMBER", `Component "${comp.id}" owns "${memberId}" which does not exist.`, comp.id, isDraftCtx);
|
|
20128
20986
|
continue;
|
|
20129
20987
|
}
|
|
20130
|
-
if (!pattern) continue;
|
|
20988
|
+
if (!pattern && !supervisor) continue;
|
|
20131
20989
|
if (isPattern(member)) {
|
|
20132
|
-
|
|
20990
|
+
if (pattern) {
|
|
20991
|
+
ctx.addIssue("error", "PATTERN_OWNS_PATTERN", `Pattern "${comp.id}" owns "${memberId}", which is itself a pattern. Patterns own only building blocks \u2014 compose patterns at the subsystem (L1) level.`, comp.id, isDraftCtx);
|
|
20992
|
+
}
|
|
20133
20993
|
continue;
|
|
20134
20994
|
}
|
|
20135
20995
|
const firstOwner = ownership.ownerOf(memberId);
|
|
@@ -20143,13 +21003,15 @@ var patternMembershipRule = {
|
|
|
20143
21003
|
|
|
20144
21004
|
// src/core/rules/doctrine/pattern-containment.ts
|
|
20145
21005
|
var REPOSITORY_MEMBERS = /* @__PURE__ */ new Set(["Store", "Registry", "Index", "Query", "Adapter"]);
|
|
21006
|
+
var SUPERVISION_STATE = /* @__PURE__ */ new Set(["Store", "Registry"]);
|
|
20146
21007
|
var patternContainmentRule = {
|
|
20147
21008
|
name: "pattern-containment",
|
|
20148
21009
|
judges: "design",
|
|
20149
|
-
description: "Holds each
|
|
21010
|
+
description: "Holds each owner to the containment its definition prescribes. A Repository may own only Store, Registry, Index, Query and (optionally) Adapter, judged member by member. A Supervisor may own only its supervision state \u2014 Stores and Registries that are its own, one hop \u2014 judged member by member too. A FeatureComponent owns exactly one Orchestrator (the logic side) and one or more Views (its faces \u2014 list, detail, form \u2014 sharing the one logic component), and nothing else. A RouterComponent owns exactly one Portal as its facade and at least one other child to route to. A counting pattern that still owns a retired member is not judged until that member is migrated: its counts change with the migration, and STEREOTYPE_RETIRED is the one finding.",
|
|
20150
21011
|
codes: [
|
|
20151
21012
|
{ code: "REPOSITORY_CONTAINMENT", defaultSeverity: "error", summary: "Repository owning a non Store/Registry/Index/Query/Adapter member" },
|
|
20152
21013
|
{ code: "FEATURE_COMPONENT_CONTAINMENT", defaultSeverity: "error", summary: "FeatureComponent not owning exactly one Orchestrator + one or more Views" },
|
|
21014
|
+
{ code: "SUPERVISOR_CONTAINMENT", defaultSeverity: "error", summary: "Supervisor owning anything but a Store or Registry \u2014 a Supervisor owns only its supervision state" },
|
|
20153
21015
|
{ code: "ROUTER_COMPONENT_CONTAINMENT", defaultSeverity: "error", summary: "RouterComponent not owning exactly one Portal facade, or owning no children to route to" }
|
|
20154
21016
|
],
|
|
20155
21017
|
check(ctx) {
|
|
@@ -20200,6 +21062,15 @@ var patternContainmentRule = {
|
|
|
20200
21062
|
}
|
|
20201
21063
|
}
|
|
20202
21064
|
}
|
|
21065
|
+
for (const comp of ctx.components) {
|
|
21066
|
+
if (comp.componentType !== "Supervisor" || isRetired(comp)) continue;
|
|
21067
|
+
const isDraftCtx = ctx.isComponentDraft(comp.id);
|
|
21068
|
+
for (const memberId of comp.owns) {
|
|
21069
|
+
const member = ctx.componentMap.get(memberId);
|
|
21070
|
+
if (!member || isRetired(member) || SUPERVISION_STATE.has(member.componentType)) continue;
|
|
21071
|
+
ctx.addIssue("error", "SUPERVISOR_CONTAINMENT", `Supervisor "${comp.id}" owns "${memberId}" of type ${member.componentType}; a Supervisor owns only its supervision state \u2014 Stores and Registries that are its own. Depend on "${memberId}" as a collaborator instead.`, comp.id, isDraftCtx);
|
|
21072
|
+
}
|
|
21073
|
+
}
|
|
20203
21074
|
}
|
|
20204
21075
|
};
|
|
20205
21076
|
|
|
@@ -20207,7 +21078,7 @@ var patternContainmentRule = {
|
|
|
20207
21078
|
var unownedBlocksRule = {
|
|
20208
21079
|
name: "unowned-blocks",
|
|
20209
21080
|
judges: "design",
|
|
20210
|
-
description: `Judges the data blocks no pattern owns. A Store may stand alone deliberately \u2014 the sanctioned lightweight form for genuinely simple state, acknowledged with a lint.allow \u2014 while the recommended shape stays a Repository; what must never happen is folding the state into a consuming component, where no spec, diagram or conformance check can see it again. A Registry standing alone with no Store to write to is either mistyped (the "file-backed Registry" idiom, a fused persistent store that belongs typed Store) or orphaned. A Query has no standalone form at all: it computes reads over its own Repository's Store.`,
|
|
21081
|
+
description: `Judges the data blocks no owner (a pattern, or a Supervisor keeping its supervision state) owns. A Store may stand alone deliberately \u2014 the sanctioned lightweight form for genuinely simple state, acknowledged with a lint.allow \u2014 while the recommended shape stays a Repository; what must never happen is folding the state into a consuming component, where no spec, diagram or conformance check can see it again. A Registry standing alone with no Store to write to is either mistyped (the "file-backed Registry" idiom, a fused persistent store that belongs typed Store) or orphaned. A Query has no standalone form at all: it computes reads over its own Repository's Store.`,
|
|
20211
21082
|
codes: [
|
|
20212
21083
|
{ code: "UNOWNED_STORE", defaultSeverity: "warning", summary: "Store not owned by any pattern \u2014 recommended shape is a Repository; a deliberate standalone Store needs a lint.allow" },
|
|
20213
21084
|
{ code: "REGISTRY_WITHOUT_STORE", defaultSeverity: "warning", summary: "Standalone Registry with no Store to write to \u2014 either mistyped (a fused file-backed store belongs typed Store) or orphaned" },
|
|
@@ -20253,9 +21124,10 @@ var unownedBlocksRule = {
|
|
|
20253
21124
|
var memberVisibilityRule = {
|
|
20254
21125
|
name: "member-visibility",
|
|
20255
21126
|
judges: "design",
|
|
20256
|
-
description: "A component may depend on a block within its own group (it is the
|
|
21127
|
+
description: "A component may depend on a block within its own group (it is the owner, or a sibling member of the same owner), on any pattern facade, or on a standalone block \u2014 never on a block privately owned by ANOTHER pattern, which must be reached through that pattern's facade. A Store or Registry a Supervisor owns is that Supervisor's supervision state and nobody else depends on it: a component that does is the intruder, and the finding is reported on it, naming the Supervisor and the state. A retired depending component is skipped, as everywhere in this family.",
|
|
20257
21128
|
codes: [
|
|
20258
|
-
{ code: "VISIBILITY_VIOLATION", defaultSeverity: "error", summary: "Dependency on a block privately owned by another pattern" }
|
|
21129
|
+
{ code: "VISIBILITY_VIOLATION", defaultSeverity: "error", summary: "Dependency on a block privately owned by another pattern" },
|
|
21130
|
+
{ code: "SUPERVISION_STATE_INTRUSION", defaultSeverity: "error", summary: "Dependency on a Store or Registry a Supervisor owns as its supervision state \u2014 reported on the intruder, naming the Supervisor and the state" }
|
|
20259
21131
|
],
|
|
20260
21132
|
check(ctx) {
|
|
20261
21133
|
const ownership = ctx.ownershipIndex();
|
|
@@ -20266,7 +21138,12 @@ var memberVisibilityRule = {
|
|
|
20266
21138
|
if (!owner) continue;
|
|
20267
21139
|
if (owner === comp.id) continue;
|
|
20268
21140
|
if (ownership.ownerOf(comp.id) === owner) continue;
|
|
20269
|
-
|
|
21141
|
+
const isDraftCtx = ctx.isComponentDraft(comp.id) || ctx.isComponentDraft(depId);
|
|
21142
|
+
if (ctx.componentMap.get(owner)?.componentType === "Supervisor") {
|
|
21143
|
+
ctx.addIssue("error", "SUPERVISION_STATE_INTRUSION", `"${comp.id}" depends on "${depId}", which Supervisor "${owner}" owns as its supervision state. Supervision state is private to its Supervisor \u2014 nobody else depends on it. If "${comp.id}" needs this data it is shared data: move "${depId}" out of "${owner}"'s owns into a data component both depend on (the Supervisor keeping it through read and lifecycle calls), or reach what "${comp.id}" needs through "${owner}".`, comp.id, isDraftCtx);
|
|
21144
|
+
continue;
|
|
21145
|
+
}
|
|
21146
|
+
ctx.addIssue("error", "VISIBILITY_VIOLATION", `Component "${comp.id}" depends on "${depId}", which is privately owned by pattern "${owner}". Depend on the facade "${owner}" instead.`, comp.id, isDraftCtx);
|
|
20270
21147
|
}
|
|
20271
21148
|
}
|
|
20272
21149
|
}
|
|
@@ -21399,9 +22276,9 @@ var durabilityRule = {
|
|
|
21399
22276
|
// Stage 8: its verdict needs the whole system's specs, so a part judged alone skips it.
|
|
21400
22277
|
needsWholeTree: true,
|
|
21401
22278
|
judges: "design",
|
|
21402
|
-
description: "A durable Store (persisted RAM projection) must carry effect-tagged contract methods, and its
|
|
22279
|
+
description: "A durable Store (persisted RAM projection) must carry effect-tagged contract methods, and its mutations \u2014 write-effect methods, and lifecycle-effect methods, which change what exists \u2014 require a hydration read-back reachable from a lifecycle init entrypoint. read-through is exempt (every read IS the read-back), as are ram-projection (rebuilt not restored) and cache (evictable, loss-safe). The flagship semantic check is opt-out by declaration, never silently absent \u2014 the declaration itself is enforced by durability-declaration.",
|
|
21403
22280
|
codes: [
|
|
21404
|
-
{ code: "MISSING_EFFECT_TAG", defaultSeverity: "warning", summary: "Durable Store contract method lacks an effect: read | write tag" },
|
|
22281
|
+
{ code: "MISSING_EFFECT_TAG", defaultSeverity: "warning", summary: "Durable Store contract method lacks an effect: read | write | lifecycle tag" },
|
|
21405
22282
|
{ code: "MISSING_HYDRATION", defaultSeverity: "error", summary: "Durable Store is written but no read-back is reachable from any lifecycle init entrypoint" }
|
|
21406
22283
|
],
|
|
21407
22284
|
check(ctx) {
|
|
@@ -21429,7 +22306,7 @@ var durabilityRule = {
|
|
|
21429
22306
|
isDraftCtx
|
|
21430
22307
|
);
|
|
21431
22308
|
}
|
|
21432
|
-
const writes = methods.filter((method) => method.effect === "write");
|
|
22309
|
+
const writes = methods.filter((method) => method.effect === "write" || method.effect === "lifecycle");
|
|
21433
22310
|
const reads = methods.filter((method) => method.effect === "read");
|
|
21434
22311
|
if (writes.length === 0) continue;
|
|
21435
22312
|
const hydrated = initReach !== null && reads.some((method) => initReach.reachesMethod(comp.id, method.name));
|
|
@@ -21622,10 +22499,10 @@ function familyAliases(family) {
|
|
|
21622
22499
|
}
|
|
21623
22500
|
return out;
|
|
21624
22501
|
}
|
|
21625
|
-
function typeRefReadings(
|
|
21626
|
-
const [first, ...rest] =
|
|
21627
|
-
if (!rest.length) return [
|
|
21628
|
-
return [
|
|
22502
|
+
function typeRefReadings(typeRef2, aliases) {
|
|
22503
|
+
const [first, ...rest] = typeRef2.split(/::|\./);
|
|
22504
|
+
if (!rest.length) return [typeRef2];
|
|
22505
|
+
return [typeRef2, ...(aliases.get(first) ?? []).map((key) => `${key}::${rest.join("::")}`)];
|
|
21629
22506
|
}
|
|
21630
22507
|
function resolveInvariantRef(ref, types, aliases = /* @__PURE__ */ new Map()) {
|
|
21631
22508
|
const parts = splitInvariantRef(ref);
|
|
@@ -23095,8 +23972,8 @@ var asyncConformanceRule = {
|
|
|
23095
23972
|
check(ctx) {
|
|
23096
23973
|
const code = ctx.codeIndex();
|
|
23097
23974
|
for (const { implementation, method, sourceFile, draftContext: draftContext4 } of ctx.implementationMethods()) {
|
|
23098
|
-
const
|
|
23099
|
-
if (!
|
|
23975
|
+
const contractMethod2 = ctx.interfaceMap.get(implementation.contract)?.methods.find((m) => m.name === method.name);
|
|
23976
|
+
if (!contractMethod2 || typeof contractMethod2.returns !== "string" || !sourceFile) continue;
|
|
23100
23977
|
const file = pathKey(sourceFile);
|
|
23101
23978
|
const facts = code.factsAt(file);
|
|
23102
23979
|
if (!facts || facts.status !== "analyzed" || facts.analysisGrade !== "exact") continue;
|
|
@@ -23105,7 +23982,7 @@ var asyncConformanceRule = {
|
|
|
23105
23982
|
if (!signatures || !Object.prototype.hasOwnProperty.call(signatures, symbol)) continue;
|
|
23106
23983
|
const bodies = signatures[symbol].length;
|
|
23107
23984
|
if (bodies === 0) continue;
|
|
23108
|
-
const returns = parseTypeExpression(
|
|
23985
|
+
const returns = parseTypeExpression(contractMethod2.returns, "returns");
|
|
23109
23986
|
if (!returns.expression) continue;
|
|
23110
23987
|
const contractAsync = returns.expression.form === "async";
|
|
23111
23988
|
const asyncBodies = (facts.asyncFunctions ?? []).filter((name) => name === symbol).length;
|
|
@@ -23114,7 +23991,7 @@ var asyncConformanceRule = {
|
|
|
23114
23991
|
ctx.addIssue(
|
|
23115
23992
|
"warning",
|
|
23116
23993
|
"ASYNC_MISMATCH",
|
|
23117
|
-
`Method "${method.name}" of contract "${implementation.contract}" returns "${
|
|
23994
|
+
`Method "${method.name}" of contract "${implementation.contract}" returns "${contractMethod2.returns}", which completes later, but ${subject} completes now \u2014 it is neither declared async nor annotated to return a Promise. Every caller is told to await a call that answers at once. Make the code async, or drop \`async\` from the returns.`,
|
|
23118
23995
|
implementation.id,
|
|
23119
23996
|
draftContext4,
|
|
23120
23997
|
void 0,
|
|
@@ -23124,7 +24001,7 @@ var asyncConformanceRule = {
|
|
|
23124
24001
|
ctx.addIssue(
|
|
23125
24002
|
"warning",
|
|
23126
24003
|
"ASYNC_MISMATCH",
|
|
23127
|
-
`Method "${method.name}" of contract "${implementation.contract}" returns "${
|
|
24004
|
+
`Method "${method.name}" of contract "${implementation.contract}" returns "${contractMethod2.returns}", which completes now, but ${subject} completes later (declared async, or annotated to return a Promise). Every caller built from the contract forgets to await it. Write the returns as "async ${contractMethod2.returns}" \u2014 or, if the code is async by accident, make it complete now.`,
|
|
23128
24005
|
implementation.id,
|
|
23129
24006
|
draftContext4,
|
|
23130
24007
|
void 0,
|
|
@@ -24669,6 +25546,8 @@ var SDD_RULES = [
|
|
|
24669
25546
|
typeExpressionsRule,
|
|
24670
25547
|
enumTypesRule,
|
|
24671
25548
|
namedScalarTypesRule,
|
|
25549
|
+
// The rename traces: a former key a consumer resolves must name one element.
|
|
25550
|
+
renameTracesRule,
|
|
24672
25551
|
// Contracts and the targets narratives name, in four questions with one
|
|
24673
25552
|
// owner each: does the implementation mirror its contract, does a target
|
|
24674
25553
|
// inside this tree resolve, does a target that leaves it pin to exactly one
|
|
@@ -24722,6 +25601,10 @@ var SDD_RULES = [
|
|
|
24722
25601
|
dataBlockDepsRule,
|
|
24723
25602
|
entrypointDepsRule,
|
|
24724
25603
|
portalWriteShortcutRule,
|
|
25604
|
+
// The process layer's data reach and the lifecycle effect's closure, both
|
|
25605
|
+
// read from narratives against the callee's declared effect.
|
|
25606
|
+
supervisorSharedDataRule,
|
|
25607
|
+
lifecycleEffectClosureRule,
|
|
24725
25608
|
// Patterns in four questions: who may own and what a claim must name,
|
|
24726
25609
|
// what each pattern must contain, which data blocks are left standing
|
|
24727
25610
|
// alone, and who may see a private member.
|
|
@@ -26445,7 +27328,16 @@ function buildRuleContext(opts) {
|
|
|
26445
27328
|
const sitesSeen = /* @__PURE__ */ new Map();
|
|
26446
27329
|
const sitesReported = (specId, code) => {
|
|
26447
27330
|
const seen = sitesSeen.get(`${specId}\0${code}`);
|
|
26448
|
-
return { sites: [...seen?.sites ?? []], unsited: seen?.unsited ?? false };
|
|
27331
|
+
return { sites: [...seen?.sites ?? []], unsited: seen?.unsited ?? false, errored: seen?.errored ?? false };
|
|
27332
|
+
};
|
|
27333
|
+
const codeDefaults = new Map(opts.issueCodeSeverities ?? []);
|
|
27334
|
+
for (const a of opts.extensions?.assertions ?? []) {
|
|
27335
|
+
if (!codeDefaults.has(a.fullCode)) codeDefaults.set(a.fullCode, a.severity);
|
|
27336
|
+
}
|
|
27337
|
+
const severityOf = (code, specId) => {
|
|
27338
|
+
const defaultSeverity = codeDefaults.get(code);
|
|
27339
|
+
if (!defaultSeverity) return void 0;
|
|
27340
|
+
return getRuleSeverity(code, defaultSeverity, false, subsystemOfSpec.get(specId));
|
|
26449
27341
|
};
|
|
26450
27342
|
for (const s of subsystems) collectAllows(s.id, s.lint);
|
|
26451
27343
|
for (const c of components) collectAllows(c.id, c.lint);
|
|
@@ -26488,9 +27380,10 @@ function buildRuleContext(opts) {
|
|
|
26488
27380
|
if (specId) {
|
|
26489
27381
|
const key = `${specId}\0${code}`;
|
|
26490
27382
|
let seen = sitesSeen.get(key);
|
|
26491
|
-
if (!seen) sitesSeen.set(key, seen = { sites: /* @__PURE__ */ new Set(), unsited: false });
|
|
27383
|
+
if (!seen) sitesSeen.set(key, seen = { sites: /* @__PURE__ */ new Set(), unsited: false, errored: false });
|
|
26492
27384
|
if (parts) seen.sites.add(parts.at);
|
|
26493
27385
|
else seen.unsited = true;
|
|
27386
|
+
if (severity === "error") seen.errored = true;
|
|
26494
27387
|
}
|
|
26495
27388
|
let allowClaimed = false;
|
|
26496
27389
|
if (specId) {
|
|
@@ -26607,6 +27500,7 @@ function buildRuleContext(opts) {
|
|
|
26607
27500
|
roundTripIssues: opts.roundTripIssues,
|
|
26608
27501
|
lintAllows: lintAllows2,
|
|
26609
27502
|
sitesReported,
|
|
27503
|
+
severityOf,
|
|
26610
27504
|
knownIssueCodes: opts.knownIssueCodes,
|
|
26611
27505
|
carriedFindings,
|
|
26612
27506
|
carryableIssueCodes: opts.carryableIssueCodes ?? /* @__PURE__ */ new Set(),
|
|
@@ -26760,12 +27654,12 @@ function measure(candidate) {
|
|
|
26760
27654
|
// src/core/rules/gate-identity.ts
|
|
26761
27655
|
var crypto4 = __toESM(require("crypto"));
|
|
26762
27656
|
var GATE_ALGORITHM = "sha256+content+doctrine+inputs+members";
|
|
26763
|
-
var
|
|
27657
|
+
var byKey2 = (items, key) => [...items].sort((a, b) => compareOrdinal(key(a), key(b)));
|
|
26764
27658
|
function ruleIdentities(rules) {
|
|
26765
|
-
return
|
|
27659
|
+
return byKey2(
|
|
26766
27660
|
rules.map((r) => ({
|
|
26767
27661
|
name: r.name,
|
|
26768
|
-
codes:
|
|
27662
|
+
codes: byKey2(r.codes.map((c) => ({ code: c.code, severity: c.defaultSeverity })), (c) => c.code)
|
|
26769
27663
|
})),
|
|
26770
27664
|
(r) => r.name
|
|
26771
27665
|
);
|
|
@@ -26813,7 +27707,7 @@ function doctrineIdentity(doctrine2, builtinRules, gate) {
|
|
|
26813
27707
|
* changed requirement stales the requiring project's lock.
|
|
26814
27708
|
*/
|
|
26815
27709
|
composition: gate.composition ?? null,
|
|
26816
|
-
packs:
|
|
27710
|
+
packs: byKey2(
|
|
26817
27711
|
doctrine2.packs.map((p) => ({ name: p.name, version: p.version ?? null, scope: p.scope })),
|
|
26818
27712
|
(p) => `${p.name}@${p.version ?? ""}#${p.scope}`
|
|
26819
27713
|
),
|
|
@@ -26821,13 +27715,13 @@ function doctrineIdentity(doctrine2, builtinRules, gate) {
|
|
|
26821
27715
|
// the identity — a load-order change that flips a collision winner shows up here.
|
|
26822
27716
|
profiles: doctrine2.profiles,
|
|
26823
27717
|
languages: doctrine2.languages,
|
|
26824
|
-
patterns:
|
|
27718
|
+
patterns: byKey2(
|
|
26825
27719
|
doctrine2.patterns.map((p) => ({ id: p.id, version: p.version, pack: p.pack })),
|
|
26826
27720
|
(p) => `${p.pack}/${p.id}@${p.version}`
|
|
26827
27721
|
),
|
|
26828
27722
|
guarantees: [...doctrine2.guarantees].sort(),
|
|
26829
|
-
assertions:
|
|
26830
|
-
rules:
|
|
27723
|
+
assertions: byKey2(doctrine2.assertions.map((a) => ({ ...a })), (a) => a.fullCode),
|
|
27724
|
+
rules: byKey2(
|
|
26831
27725
|
doctrine2.rules.map((r) => ({ name: r.name, codes: r.codes.map((c) => c.code).sort() })),
|
|
26832
27726
|
(r) => r.name
|
|
26833
27727
|
)
|
|
@@ -26838,7 +27732,7 @@ function computeGateIdentity(content, doctrine2, builtinRules, inputs, gate, mem
|
|
|
26838
27732
|
content: content.digest,
|
|
26839
27733
|
doctrine: doctrineIdentity(doctrine2, builtinRules, gate),
|
|
26840
27734
|
inputs: [...inputs].sort(compareOrdinal),
|
|
26841
|
-
members:
|
|
27735
|
+
members: byKey2(Object.entries(members), ([alias]) => alias).map(([alias, subject]) => ({ alias, subject }))
|
|
26842
27736
|
};
|
|
26843
27737
|
const digest3 = crypto4.createHash("sha256").update(canonicalize(payload)).digest("hex");
|
|
26844
27738
|
return { algorithm: GATE_ALGORITHM, digest: digest3 };
|
|
@@ -27039,6 +27933,7 @@ function runOwnersGate(rulesOrOptions, projectType = "backend") {
|
|
|
27039
27933
|
const carryableCodes = new Set(
|
|
27040
27934
|
knownIssueCodes().filter((rc) => rc.carryable).map((rc) => rc.code)
|
|
27041
27935
|
);
|
|
27936
|
+
const codeSeverities = new Map(knownIssueCodes().map((rc) => [rc.code, rc.defaultSeverity]));
|
|
27042
27937
|
const family = graph();
|
|
27043
27938
|
const memberTables = family.nodes.filter((n) => n.namespace !== "").map((n) => resolveProjectExports(n.namespace));
|
|
27044
27939
|
const producers = new Set(family.references.filter((r) => r.consumer === "").map((r) => r.producer));
|
|
@@ -27081,6 +27976,7 @@ function runOwnersGate(rulesOrOptions, projectType = "backend") {
|
|
|
27081
27976
|
codeModel,
|
|
27082
27977
|
roundTripIssues,
|
|
27083
27978
|
knownIssueCodes: knownCodes,
|
|
27979
|
+
issueCodeSeverities: codeSeverities,
|
|
27084
27980
|
carryableIssueCodes: carryableCodes,
|
|
27085
27981
|
issues
|
|
27086
27982
|
});
|
|
@@ -27181,8 +28077,8 @@ function judgePartAlone(config, scopeSubsystem) {
|
|
|
27181
28077
|
issues.push(issue("warning", "EXTERNAL_CHECK_UNAVAILABLE", `The parent "${parentId}" governs its parts with a pack this machine cannot load at its pinned version, so its rules were not run here: ${failure}`));
|
|
27182
28078
|
}
|
|
27183
28079
|
const ownIds = new Set([...own.subsystems, ...own.components, ...own.interfaces, ...own.implementations, ...own.types].map((s) => s.id));
|
|
27184
|
-
const
|
|
27185
|
-
issues.push(...getLoaderIssues().filter((e) => !e.specId ||
|
|
28080
|
+
const isOwn2 = (id) => ownIds.has(id);
|
|
28081
|
+
issues.push(...getLoaderIssues().filter((e) => !e.specId || isOwn2(e.specId)));
|
|
27186
28082
|
for (const [key, by] of namedKeys(own)) {
|
|
27187
28083
|
if (ownIds.has(key) || context.ids.has(key)) continue;
|
|
27188
28084
|
issues.push(issue("warning", "EXTERNAL_CHECK_UNAVAILABLE", `"${by}" names "${key}", which neither this part nor its pinned excerpt of "${parentId}" holds \u2014 used since the pin: re-pin with \`wairon externals pin\` while the parent is on disk.`, by));
|
|
@@ -27190,8 +28086,8 @@ function judgePartAlone(config, scopeSubsystem) {
|
|
|
27190
28086
|
const ownSignatures = signatureFacts();
|
|
27191
28087
|
const ownTypeSpellings = typeSpellingFacts();
|
|
27192
28088
|
const partTypeSpellings = {
|
|
27193
|
-
respellings: ownTypeSpellings.respellings.filter((r) =>
|
|
27194
|
-
problems: ownTypeSpellings.problems.filter((p) => p.specId === void 0 ||
|
|
28089
|
+
respellings: ownTypeSpellings.respellings.filter((r) => isOwn2(r.specId)),
|
|
28090
|
+
problems: ownTypeSpellings.problems.filter((p) => p.specId === void 0 || isOwn2(p.specId))
|
|
27195
28091
|
};
|
|
27196
28092
|
const resolved = resolveSignatures(
|
|
27197
28093
|
[...own.interfaces, ...context.interfaces],
|
|
@@ -27238,7 +28134,7 @@ function judgePartAlone(config, scopeSubsystem) {
|
|
|
27238
28134
|
packRequirements: [],
|
|
27239
28135
|
surfaceSnapshots: [],
|
|
27240
28136
|
codeModel,
|
|
27241
|
-
roundTripIssues: dryRunSerializeSpecs(
|
|
28137
|
+
roundTripIssues: dryRunSerializeSpecs(isOwn2),
|
|
27242
28138
|
knownIssueCodes: knownCodes,
|
|
27243
28139
|
carryableIssueCodes: new Set(knownIssueCodes().filter((rc) => rc.carryable).map((rc) => rc.code)),
|
|
27244
28140
|
issues
|
|
@@ -28271,10 +29167,10 @@ function settle(owner, level, candidates, problems) {
|
|
|
28271
29167
|
detail: `"${name}" is bound to ${targets.length} different targets (${targets.join(", ")}) by ${explicit.length ? "explicit entries" : "wildcard re-exports"}; it is left out of the table`
|
|
28272
29168
|
});
|
|
28273
29169
|
}
|
|
28274
|
-
const
|
|
28275
|
-
for (const e of entries)
|
|
29170
|
+
const byKey3 = /* @__PURE__ */ new Map();
|
|
29171
|
+
for (const e of entries) byKey3.set(nameKey(e.publicName), [...byKey3.get(nameKey(e.publicName)) ?? [], e]);
|
|
28276
29172
|
const clashing = /* @__PURE__ */ new Set();
|
|
28277
|
-
for (const group of
|
|
29173
|
+
for (const group of byKey3.values()) {
|
|
28278
29174
|
const targets = [...new Set(group.map((e) => exportTargetKey(e)))];
|
|
28279
29175
|
if (group.length < 2 || targets.length < 2) continue;
|
|
28280
29176
|
group.forEach((e) => clashing.add(e));
|
|
@@ -28592,7 +29488,7 @@ function pinnedUsageOf(consumer, alias) {
|
|
|
28592
29488
|
function emptySignatureFacts() {
|
|
28593
29489
|
return { sources: [], staleTexts: [] };
|
|
28594
29490
|
}
|
|
28595
|
-
function
|
|
29491
|
+
function namespaceOf2(key) {
|
|
28596
29492
|
const at = key.lastIndexOf("::");
|
|
28597
29493
|
return at === -1 ? "" : key.slice(0, at);
|
|
28598
29494
|
}
|
|
@@ -28620,7 +29516,7 @@ function methodReading(tables, intf, value) {
|
|
|
28620
29516
|
if (dot <= 0 || dot === value.length - 1) return null;
|
|
28621
29517
|
const head2 = value.slice(0, dot);
|
|
28622
29518
|
const tail = value.slice(dot + 1);
|
|
28623
|
-
const ns =
|
|
29519
|
+
const ns = namespaceOf2(intf.id);
|
|
28624
29520
|
const keys = [head2, ...ns && !head2.startsWith(`${ns}::`) ? [`${ns}::${head2}`] : []];
|
|
28625
29521
|
for (const key of keys) {
|
|
28626
29522
|
if (!tables.componentKeys.has(key)) continue;
|
|
@@ -28632,8 +29528,8 @@ function methodReading(tables, intf, value) {
|
|
|
28632
29528
|
function typeReading(tables, intf, value) {
|
|
28633
29529
|
const bound2 = value.includes("::") ? tables.boundTypes.get(`${intf.id}|${value}`) : void 0;
|
|
28634
29530
|
const named2 = bound2 !== void 0 ? tables.types.filter((t) => t.id === bound2) : tables.types.filter((t) => t.id === value || typeMatchesRef(t, value));
|
|
28635
|
-
const ns =
|
|
28636
|
-
const local = (t) =>
|
|
29531
|
+
const ns = namespaceOf2(intf.id);
|
|
29532
|
+
const local = (t) => namespaceOf2(t.id) === ns ? 0 : 1;
|
|
28637
29533
|
const ranked = [...named2].sort((a, b) => local(a) - local(b));
|
|
28638
29534
|
return { signature: ranked.find((t) => t.kind === "signature"), other: ranked.find((t) => t.kind !== "signature") };
|
|
28639
29535
|
}
|
|
@@ -29386,7 +30282,7 @@ function keyedSystem(system, key, subsystems) {
|
|
|
29386
30282
|
};
|
|
29387
30283
|
}
|
|
29388
30284
|
function resolveFamilyTables(raws) {
|
|
29389
|
-
const
|
|
30285
|
+
const byKey3 = new Map(raws.map((r) => [r.record.namespace, r]));
|
|
29390
30286
|
const done = /* @__PURE__ */ new Set();
|
|
29391
30287
|
const resolving = /* @__PURE__ */ new Set();
|
|
29392
30288
|
const resolve41 = (raw) => {
|
|
@@ -29403,7 +30299,7 @@ function resolveFamilyTables(raws) {
|
|
|
29403
30299
|
const source = e.from ?? e.subsystem;
|
|
29404
30300
|
const producerKey = source !== void 0 ? raw.record.aliases.get(source) : void 0;
|
|
29405
30301
|
if (producerKey === void 0 || producerTables.has(producerKey)) continue;
|
|
29406
|
-
const producer =
|
|
30302
|
+
const producer = byKey3.get(producerKey);
|
|
29407
30303
|
producerTables.set(producerKey, producer ? resolve41(producer) : null);
|
|
29408
30304
|
audienceOf.set(producerKey, "project");
|
|
29409
30305
|
}
|
|
@@ -33089,6 +33985,14 @@ var SpecWorkspace = class {
|
|
|
33089
33985
|
}
|
|
33090
33986
|
const receiving = this.moveTargetContract(to, ofTarget);
|
|
33091
33987
|
if (typeof receiving === "string") return receiving;
|
|
33988
|
+
if (receiving) {
|
|
33989
|
+
for (const name of methods) {
|
|
33990
|
+
const holder2 = receiving.methods.find((m) => (m.previousNames ?? []).includes(`${receiving.id}.${name}`));
|
|
33991
|
+
if (holder2) {
|
|
33992
|
+
return `name-retired: "${receiving.id}" retired the name "${name}" \u2014 its method "${holder2.name}" lists "${receiving.id}.${name}" in its previousNames. Unsetting that previousNames releases the name.`;
|
|
33993
|
+
}
|
|
33994
|
+
}
|
|
33995
|
+
}
|
|
33092
33996
|
const contractId = receiving?.id ?? `i${to}`;
|
|
33093
33997
|
const holder = contracts.find((i) => i.id === contractId);
|
|
33094
33998
|
if (!receiving && holder) {
|
|
@@ -33142,7 +34046,7 @@ var SpecWorkspace = class {
|
|
|
33142
34046
|
for (const contract of contracts.filter((i) => i.component === source.id)) {
|
|
33143
34047
|
const leaving = contract.methods.filter((m) => methods.includes(m.name));
|
|
33144
34048
|
if (leaving.length === 0) continue;
|
|
33145
|
-
arriving.push(...cloneSpec(leaving));
|
|
34049
|
+
arriving.push(...cloneSpec(leaving).map((m) => ({ ...m, previousNames: [...m.previousNames ?? [], `${contract.id}.${m.name}`] })));
|
|
33146
34050
|
const remaining = cloneSpec(contract);
|
|
33147
34051
|
remaining.methods = remaining.methods.filter((m) => !methods.includes(m.name));
|
|
33148
34052
|
this.stageMoveEdit(plan6, "interface", contract.id, contract, remaining);
|
|
@@ -33325,9 +34229,9 @@ var SpecWorkspace = class {
|
|
|
33325
34229
|
const reports = moveChangeReports(edits, false);
|
|
33326
34230
|
const written = [];
|
|
33327
34231
|
try {
|
|
33328
|
-
for (const
|
|
33329
|
-
const edit4 = edits.find((e) => e.kind ===
|
|
33330
|
-
|
|
34232
|
+
for (const report3 of reports) {
|
|
34233
|
+
const edit4 = edits.find((e) => e.kind === report3.kind && e.id === report3.id);
|
|
34234
|
+
report3.notices.push(...this.saveMovedSpec(edit4.kind, edit4.after));
|
|
33331
34235
|
written.push(edit4);
|
|
33332
34236
|
}
|
|
33333
34237
|
finish?.();
|
|
@@ -33568,6 +34472,9 @@ function getInterfacePath(id, componentId) {
|
|
|
33568
34472
|
function getImplementationPath(id, contractId) {
|
|
33569
34473
|
return current().getImplementationPath(id, contractId);
|
|
33570
34474
|
}
|
|
34475
|
+
function getTypePath(id, subsystemId, group) {
|
|
34476
|
+
return current().getTypePath(id, subsystemId, group);
|
|
34477
|
+
}
|
|
33571
34478
|
function loadSystemSpec() {
|
|
33572
34479
|
return current().loadSystemSpec();
|
|
33573
34480
|
}
|
|
@@ -35480,6 +36387,11 @@ function renameComponent(componentId, newId) {
|
|
|
35480
36387
|
if (taken.length > 0) {
|
|
35481
36388
|
throw new WaironError(`id-taken: the new id, or an id it implies, is already in use: ${taken.join(", ")}.`);
|
|
35482
36389
|
}
|
|
36390
|
+
refuseRetiredIds([
|
|
36391
|
+
{ kind: "component", id: newId },
|
|
36392
|
+
{ kind: "interface", id: interfaceId },
|
|
36393
|
+
{ kind: "implementation", id: implementationId }
|
|
36394
|
+
]);
|
|
35483
36395
|
const contracts = interfaces.filter((i) => i.component === componentId);
|
|
35484
36396
|
const movingInterface = contracts.find((i) => i.id === `i${componentId}`);
|
|
35485
36397
|
const movingImplementation = implementations.find((impl) => impl.id === `${componentId}_impl` && contracts.some((i) => i.id === impl.contract));
|
|
@@ -35501,18 +36413,21 @@ function renameComponent(componentId, newId) {
|
|
|
35501
36413
|
return ref;
|
|
35502
36414
|
};
|
|
35503
36415
|
const specsDir = aiPathsAt(getProjectRoot()).specsDir();
|
|
36416
|
+
const derivesName = (entry) => entry.interface !== void 0 ? movingInterface !== void 0 && entry.interface === movingInterface.id : entry.typeDef === void 0 && entry.component === componentId;
|
|
36417
|
+
const keptDry = keepPublicNames(specsDir, derivesName, true);
|
|
35504
36418
|
assertSpecsInReach(
|
|
35505
|
-
[...renamed.map(({ kind, from }) => ({ kind, id: from })), ...rewriteRefFields(specsDir, remap, void 0, true), ...rekeyLintAllows(specsDir, rename, true)],
|
|
36419
|
+
[...renamed.map(({ kind, from }) => ({ kind, id: from })), ...keptDry.specs, ...rewriteRefFields(specsDir, remap, void 0, true), ...rekeyLintAllows(specsDir, rename, true)],
|
|
35506
36420
|
`renaming component "${componentId}"`,
|
|
35507
36421
|
Array.isArray(registerEdits) && registerEdits.length > 0
|
|
35508
36422
|
);
|
|
35509
|
-
const
|
|
36423
|
+
const kept = keepPublicNames(specsDir, derivesName);
|
|
36424
|
+
const rewrittenRefs = [...kept.specs, ...rewriteRefFields(specsDir, remap)];
|
|
35510
36425
|
const allowsRekeyed = rekeyLintAllows(specsDir, rename);
|
|
35511
36426
|
const rewritten = [...new Set([...rewrittenRefs, ...allowsRekeyed].filter((spec) => !renamed.some((moved) => moved.kind === spec.kind && moved.from === spec.id)).map((spec) => spec.id))];
|
|
35512
36427
|
invalidateSpecCache();
|
|
35513
36428
|
moveRenamedSpecs(componentId, newId, component, movingInterface, movingImplementation);
|
|
35514
36429
|
const carried = projectConfigRepository.rekeyCarried(rename);
|
|
35515
|
-
return { renamed, rewritten, carried };
|
|
36430
|
+
return { renamed, rewritten, carried, keptPublicNames: kept.names };
|
|
35516
36431
|
}
|
|
35517
36432
|
function moveRenamedSpecs(componentId, newId, component, movingInterface, movingImplementation) {
|
|
35518
36433
|
const interfaceId = `i${newId}`;
|
|
@@ -35520,20 +36435,69 @@ function moveRenamedSpecs(componentId, newId, component, movingInterface, moving
|
|
|
35520
36435
|
const movedComponent2 = loadComponentSpec(componentId) ?? component;
|
|
35521
36436
|
const movedInterface = movingInterface ? loadInterfaceSpec(movingInterface.id) ?? movingInterface : null;
|
|
35522
36437
|
const movedImplementation = movingImplementation ? loadImplementationSpec(movingImplementation.id) ?? movingImplementation : null;
|
|
35523
|
-
saveComponentSpec({ ...movedComponent2, id: newId });
|
|
35524
|
-
if (movedInterface)
|
|
36438
|
+
saveComponentSpec({ ...movedComponent2, id: newId, previousIds: traced(movedComponent2.previousIds, componentId) });
|
|
36439
|
+
if (movedInterface) {
|
|
36440
|
+
saveInterfaceSpec({ ...movedInterface, id: interfaceId, component: newId, previousIds: traced(movedInterface.previousIds, movedInterface.id) });
|
|
36441
|
+
}
|
|
35525
36442
|
if (movedImplementation) {
|
|
35526
36443
|
const oldFile = getImplementationPath(movedImplementation.id);
|
|
35527
36444
|
if (path25.resolve(getImplementationPath(implementationId, movedImplementation.contract)) === path25.resolve(oldFile)) {
|
|
35528
36445
|
fs16.unlinkSync(oldFile);
|
|
35529
36446
|
}
|
|
35530
|
-
saveImplementationSpec({ ...movedImplementation, id: implementationId });
|
|
36447
|
+
saveImplementationSpec({ ...movedImplementation, id: implementationId, previousIds: traced(movedImplementation.previousIds, movedImplementation.id) });
|
|
35531
36448
|
}
|
|
35532
36449
|
removeSpecFile2(getComponentPath(componentId), componentId);
|
|
35533
36450
|
if (movingInterface) removeSpecFile2(getInterfacePath(movingInterface.id), movingInterface.id);
|
|
35534
36451
|
if (movingImplementation) removeSpecFile2(getImplementationPath(movingImplementation.id), movingImplementation.id);
|
|
35535
36452
|
invalidateSpecCache();
|
|
35536
36453
|
}
|
|
36454
|
+
function traced(trace, former) {
|
|
36455
|
+
const out = [...trace ?? []];
|
|
36456
|
+
if (!out.includes(former)) out.push(former);
|
|
36457
|
+
return out;
|
|
36458
|
+
}
|
|
36459
|
+
function refuseRetiredIds(wanted) {
|
|
36460
|
+
const index = scanAllSpecs({ memberDepth: 0 });
|
|
36461
|
+
const retired = wanted.flatMap(({ kind, id }) => {
|
|
36462
|
+
const holder = specIndexRetiredBy(index, kind, id);
|
|
36463
|
+
return holder ? [`${kind} "${id}" is listed in the previousIds of "${holder}"`] : [];
|
|
36464
|
+
});
|
|
36465
|
+
if (retired.length > 0) {
|
|
36466
|
+
throw new WaironError(
|
|
36467
|
+
`id-retired: ${retired.join("; ")}. A consumer holding the old key would read the new spec as the renamed one; unsetting the holder's previousIds (sdd_update_spec unset) releases the id.`
|
|
36468
|
+
);
|
|
36469
|
+
}
|
|
36470
|
+
}
|
|
36471
|
+
function keepPublicNames(specsDir, derives, dryRun = false) {
|
|
36472
|
+
const names = [];
|
|
36473
|
+
const specs = [];
|
|
36474
|
+
for (const file of listFilesRecursive(specsDir, ".yaml")) {
|
|
36475
|
+
let raw;
|
|
36476
|
+
try {
|
|
36477
|
+
raw = readYamlFile(file);
|
|
36478
|
+
} catch {
|
|
36479
|
+
continue;
|
|
36480
|
+
}
|
|
36481
|
+
if (!raw || typeof raw !== "object") continue;
|
|
36482
|
+
const kind = specKind(raw);
|
|
36483
|
+
if (kind !== "subsystem" && kind !== "system" || !Array.isArray(raw.publicInterfaces)) continue;
|
|
36484
|
+
let changed = false;
|
|
36485
|
+
for (const entry of raw.publicInterfaces) {
|
|
36486
|
+
if (!entry || typeof entry !== "object" || entry.as !== void 0 || entry.id !== void 0) continue;
|
|
36487
|
+
if (!derives(entry)) continue;
|
|
36488
|
+
const source = entry.interface ?? entry.component ?? entry.typeDef;
|
|
36489
|
+
if (typeof source !== "string") continue;
|
|
36490
|
+
const name = source.split("::").pop() ?? source;
|
|
36491
|
+
entry.as = name;
|
|
36492
|
+
names.push(name);
|
|
36493
|
+
changed = true;
|
|
36494
|
+
}
|
|
36495
|
+
if (!changed) continue;
|
|
36496
|
+
if (!dryRun) writeYamlFile(file, raw);
|
|
36497
|
+
specs.push({ kind, id: kind === "system" ? "system" : String(raw.id) });
|
|
36498
|
+
}
|
|
36499
|
+
return { names: [...new Set(names)], specs };
|
|
36500
|
+
}
|
|
35537
36501
|
function removeSpecFile2(file, id) {
|
|
35538
36502
|
if (!fs16.existsSync(file)) return;
|
|
35539
36503
|
try {
|
|
@@ -35582,6 +36546,12 @@ function renameMethod(componentId, methodName, newName, pinSymbol) {
|
|
|
35582
36546
|
if (taken.length > 0) {
|
|
35583
36547
|
throw new WaironError(`name-taken: ${taken.join(", ")} already declares a method under the name "${newName}".`);
|
|
35584
36548
|
}
|
|
36549
|
+
const retiredOn = moving.flatMap((i) => i.methods.filter((m) => (m.previousNames ?? []).includes(`${i.id}.${newName}`)).map((m) => `"${i.id}.${m.name}"`));
|
|
36550
|
+
if (retiredOn.length > 0) {
|
|
36551
|
+
throw new WaironError(
|
|
36552
|
+
`name-retired: ${retiredOn.join(", ")} lists "${newName}" in its previousNames \u2014 the name is retired on that contract. Unsetting that previousNames releases it.`
|
|
36553
|
+
);
|
|
36554
|
+
}
|
|
35585
36555
|
const implementations = loadImplementationSpecs();
|
|
35586
36556
|
const movingContracts = new Set(moving.map((i) => i.id));
|
|
35587
36557
|
const renamed = [];
|
|
@@ -35615,6 +36585,7 @@ function renameMethod(componentId, methodName, newName, pinSymbol) {
|
|
|
35615
36585
|
methods: contract.methods.map((m) => m.name === methodName ? {
|
|
35616
36586
|
...m,
|
|
35617
36587
|
name: newName,
|
|
36588
|
+
previousNames: traced(m.previousNames, `${contract.id}.${methodName}`),
|
|
35618
36589
|
...m.params === void 0 && m.signatureFrom === void 0 ? { signature: renameInSignature(m.signature, methodName, newName) } : {}
|
|
35619
36590
|
} : m)
|
|
35620
36591
|
});
|
|
@@ -35639,6 +36610,7 @@ function renameMethod(componentId, methodName, newName, pinSymbol) {
|
|
|
35639
36610
|
const allowsRekeyed = rekeyLintAllows(specsDir, rename);
|
|
35640
36611
|
const rewritten = [...new Set([...retargeted, ...allowsRekeyed].map((spec) => spec.id))];
|
|
35641
36612
|
const mentions = collectMentions(specsDir, methodName, moving);
|
|
36613
|
+
const publishedIn = exportsPublishing(componentId, new Set(moving.map((i) => i.id)));
|
|
35642
36614
|
const carried = projectConfigRepository.rekeyCarried(rename);
|
|
35643
36615
|
return {
|
|
35644
36616
|
component: componentId,
|
|
@@ -35648,9 +36620,25 @@ function renameMethod(componentId, methodName, newName, pinSymbol) {
|
|
|
35648
36620
|
rewritten,
|
|
35649
36621
|
mentions,
|
|
35650
36622
|
...pinnedSymbol ? { pinnedSymbol } : {},
|
|
35651
|
-
carried
|
|
36623
|
+
carried,
|
|
36624
|
+
publishedIn
|
|
35652
36625
|
};
|
|
35653
36626
|
}
|
|
36627
|
+
function exportsPublishing(componentId, contracts) {
|
|
36628
|
+
const names = /* @__PURE__ */ new Set();
|
|
36629
|
+
const tables = [
|
|
36630
|
+
...loadSubsystemSpecs().filter((s) => !s.id.includes("::")).map((s) => resolveSubsystemExports(s.id)),
|
|
36631
|
+
resolveProjectExports()
|
|
36632
|
+
];
|
|
36633
|
+
for (const table of tables) {
|
|
36634
|
+
for (const entry of table.entries) {
|
|
36635
|
+
if (entry.kind !== "component" || entry.component !== componentId) continue;
|
|
36636
|
+
if (entry.interface !== void 0 && !contracts.has(entry.interface)) continue;
|
|
36637
|
+
names.add(entry.publicName);
|
|
36638
|
+
}
|
|
36639
|
+
}
|
|
36640
|
+
return [...names].sort();
|
|
36641
|
+
}
|
|
35654
36642
|
function renameInSignature(signature, from, to) {
|
|
35655
36643
|
return signature.replace(identifierPattern(from), to);
|
|
35656
36644
|
}
|
|
@@ -35686,6 +36674,150 @@ function collectMentions(specsDir, methodName, moved) {
|
|
|
35686
36674
|
function identifierPattern(methodName) {
|
|
35687
36675
|
return new RegExp(`(?<![A-Za-z0-9_])${methodName}(?![A-Za-z0-9_])`);
|
|
35688
36676
|
}
|
|
36677
|
+
function respellLike(written, oldId, newId) {
|
|
36678
|
+
const words2 = (id) => id.split(/[_-]+/).filter(Boolean);
|
|
36679
|
+
const pascal = (id) => words2(id).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
|
|
36680
|
+
const camel = (id) => {
|
|
36681
|
+
const p = pascal(id);
|
|
36682
|
+
return p.charAt(0).toLowerCase() + p.slice(1);
|
|
36683
|
+
};
|
|
36684
|
+
const kebab = (id) => words2(id).join("-");
|
|
36685
|
+
if (written === oldId) return newId;
|
|
36686
|
+
if (written === pascal(oldId)) return pascal(newId);
|
|
36687
|
+
if (written === camel(oldId)) return camel(newId);
|
|
36688
|
+
if (written === kebab(oldId)) return kebab(newId);
|
|
36689
|
+
if (written.includes("-")) return kebab(newId);
|
|
36690
|
+
return /^[A-Z]/.test(written) ? pascal(newId) : newId;
|
|
36691
|
+
}
|
|
36692
|
+
function renameType(typeId, newId) {
|
|
36693
|
+
const all = loadTypeSpecs();
|
|
36694
|
+
const cut = typeId.lastIndexOf("::");
|
|
36695
|
+
const qualifier = cut >= 0 ? typeId.slice(0, cut) : void 0;
|
|
36696
|
+
const ownSubsystem = qualifier !== void 0 && loadSubsystemSpecs().some((s) => s.id === qualifier);
|
|
36697
|
+
if (qualifier !== void 0 && !ownSubsystem) {
|
|
36698
|
+
throw new WaironError(`chained-type: "${typeId}" lives in another project; rename it from that project's own root.`);
|
|
36699
|
+
}
|
|
36700
|
+
const type = qualifier !== void 0 ? all.find((t) => t.id === typeId.slice(cut + 2) && t.subsystem === qualifier) ?? null : loadTypeSpec(typeId);
|
|
36701
|
+
if (!type) throw new WaironError(`type-missing: no type has the id "${typeId}".`);
|
|
36702
|
+
if (type.id.includes("::")) {
|
|
36703
|
+
throw new WaironError(`chained-type: "${type.id}" lives in another project; rename it from that project's own root.`);
|
|
36704
|
+
}
|
|
36705
|
+
const oldId = type.id;
|
|
36706
|
+
if (!SpecIdSchema.safeParse(newId).success) {
|
|
36707
|
+
throw new WaironError(`invalid-id: "${newId}" is not a lowercase identifier with no namespace separator.`);
|
|
36708
|
+
}
|
|
36709
|
+
const sameOwner = (t) => (t.subsystem ?? "") === (type.subsystem ?? "");
|
|
36710
|
+
if (all.some((t) => t !== type && t.id === newId && sameOwner(t))) {
|
|
36711
|
+
throw new WaironError(`id-taken: another type of ${type.subsystem ? `"${type.subsystem}"` : "the system"} already has the id "${newId}".`);
|
|
36712
|
+
}
|
|
36713
|
+
refuseRetiredIds([{ kind: "type", id: qualifiedTypeId({ id: newId, subsystem: type.subsystem }) }]);
|
|
36714
|
+
const rename = { specs: [{ from: oldId, to: newId }] };
|
|
36715
|
+
const registerEdits = projectConfigRepository.rekeyCarried(rename, true);
|
|
36716
|
+
const components = new Map(loadComponentSpecs().map((c) => [c.id, c.subsystem]));
|
|
36717
|
+
const others = all.filter((t) => t !== type);
|
|
36718
|
+
const namesType = (token, owner) => {
|
|
36719
|
+
if (!typeMatchesRef(type, token)) return false;
|
|
36720
|
+
if (!others.some((t) => typeMatchesRef(t, token))) return true;
|
|
36721
|
+
return (owner ?? "") === (type.subsystem ?? "");
|
|
36722
|
+
};
|
|
36723
|
+
const respellText = (text3, owner) => {
|
|
36724
|
+
if (typeof text3 !== "string") return text3;
|
|
36725
|
+
return text3.replace(/[A-Za-z_][A-Za-z0-9_-]*(?:(?:::|\.)[A-Za-z_][A-Za-z0-9_-]*)*/g, (token) => {
|
|
36726
|
+
if (!namesType(token, owner)) return token;
|
|
36727
|
+
const parts = token.split(/(::|\.)/);
|
|
36728
|
+
parts[parts.length - 1] = respellLike(parts[parts.length - 1], oldId, newId);
|
|
36729
|
+
return parts.join("");
|
|
36730
|
+
});
|
|
36731
|
+
};
|
|
36732
|
+
const specsDir = aiPathsAt(getProjectRoot()).specsDir();
|
|
36733
|
+
const derivesName = (entry) => entry.interface === void 0 && entry.component === void 0 && typeof entry.typeDef === "string" && namesType(entry.typeDef, void 0);
|
|
36734
|
+
const respellSpec = (raw) => {
|
|
36735
|
+
const kind = specKind(raw);
|
|
36736
|
+
const before = JSON.stringify(raw);
|
|
36737
|
+
const at = (holder, key, owner) => {
|
|
36738
|
+
if (holder && typeof holder[key] === "string") holder[key] = respellText(holder[key], owner);
|
|
36739
|
+
};
|
|
36740
|
+
const methodPositions = (method, owner, sourced) => {
|
|
36741
|
+
if (!method || typeof method !== "object") return;
|
|
36742
|
+
for (const p of Array.isArray(method.params) ? method.params : []) at(p, "type", owner);
|
|
36743
|
+
at(method, "returns", owner);
|
|
36744
|
+
if (sourced && typeof method.signatureFrom === "string" && namesType(method.signatureFrom, owner)) at(method, "signatureFrom", owner);
|
|
36745
|
+
if (typeof method.signature === "string") {
|
|
36746
|
+
if (Array.isArray(method.params)) method.signature = deriveMethodSignature(method) ?? method.signature;
|
|
36747
|
+
else {
|
|
36748
|
+
const close2 = method.signature.lastIndexOf(")");
|
|
36749
|
+
if (close2 >= 0) method.signature = method.signature.slice(0, close2 + 1) + respellText(method.signature.slice(close2 + 1), owner);
|
|
36750
|
+
}
|
|
36751
|
+
}
|
|
36752
|
+
};
|
|
36753
|
+
if (kind === "interface") {
|
|
36754
|
+
const owner = components.get(String(raw.component));
|
|
36755
|
+
for (const m of Array.isArray(raw.methods) ? raw.methods : []) methodPositions(m, owner, true);
|
|
36756
|
+
} else if (kind === "type") {
|
|
36757
|
+
const owner = typeof raw.subsystem === "string" ? raw.subsystem : void 0;
|
|
36758
|
+
for (const f of Array.isArray(raw.fields) ? raw.fields : []) {
|
|
36759
|
+
at(f, "type", owner);
|
|
36760
|
+
if (typeof f?.references === "string") {
|
|
36761
|
+
const [head2, ...rest] = f.references.split(".");
|
|
36762
|
+
if (namesType(head2, owner)) f.references = [respellText(head2, owner), ...rest].join(".");
|
|
36763
|
+
}
|
|
36764
|
+
}
|
|
36765
|
+
for (const p of Array.isArray(raw.params) ? raw.params : []) at(p, "type", owner);
|
|
36766
|
+
at(raw, "returns", owner);
|
|
36767
|
+
if (typeof raw.linkedEntity === "string" && namesType(raw.linkedEntity, owner)) at(raw, "linkedEntity", owner);
|
|
36768
|
+
for (const m of Array.isArray(raw.methods) ? raw.methods : []) methodPositions(m, owner, false);
|
|
36769
|
+
} else if (kind === "subsystem" || kind === "system") {
|
|
36770
|
+
const owner = kind === "subsystem" ? String(raw.id) : void 0;
|
|
36771
|
+
for (const e of Array.isArray(raw.publicInterfaces) ? raw.publicInterfaces : []) {
|
|
36772
|
+
if (e && typeof e.typeDef === "string" && namesType(e.typeDef, owner)) at(e, "typeDef", owner);
|
|
36773
|
+
}
|
|
36774
|
+
}
|
|
36775
|
+
return JSON.stringify(raw) !== before;
|
|
36776
|
+
};
|
|
36777
|
+
const respellAll = (dryRun) => {
|
|
36778
|
+
const out = [];
|
|
36779
|
+
for (const file of listFilesRecursive(specsDir, ".yaml")) {
|
|
36780
|
+
let raw;
|
|
36781
|
+
try {
|
|
36782
|
+
raw = readYamlFile(file);
|
|
36783
|
+
} catch {
|
|
36784
|
+
continue;
|
|
36785
|
+
}
|
|
36786
|
+
const kind = raw && typeof raw === "object" ? specKind(raw) : void 0;
|
|
36787
|
+
if (!kind || !respellSpec(raw)) continue;
|
|
36788
|
+
if (!dryRun) writeYamlFile(file, raw);
|
|
36789
|
+
out.push({ kind, id: kind === "system" ? "system" : String(raw.id) });
|
|
36790
|
+
}
|
|
36791
|
+
return out;
|
|
36792
|
+
};
|
|
36793
|
+
assertSpecsInReach(
|
|
36794
|
+
[{ kind: "type", id: oldId }, ...keepPublicNames(specsDir, derivesName, true).specs, ...respellAll(true), ...rekeyLintAllows(specsDir, rename, true)],
|
|
36795
|
+
`renaming type "${typeId}"`,
|
|
36796
|
+
Array.isArray(registerEdits) && registerEdits.length > 0
|
|
36797
|
+
);
|
|
36798
|
+
const kept = keepPublicNames(specsDir, derivesName);
|
|
36799
|
+
const respelled = respellAll(false);
|
|
36800
|
+
const allowsRekeyed = rekeyLintAllows(specsDir, rename);
|
|
36801
|
+
const rewritten = [...new Set([...kept.specs, ...respelled, ...allowsRekeyed].filter((spec) => !(spec.kind === "type" && spec.id === oldId)).map((spec) => spec.id))];
|
|
36802
|
+
invalidateSpecCache();
|
|
36803
|
+
const moved = loadTypeSpecs().find((t) => t.id === oldId && (t.subsystem ?? "") === (type.subsystem ?? "")) ?? type;
|
|
36804
|
+
saveSpec("type", { ...moved, id: newId, previousIds: traced(moved.previousIds, oldId) });
|
|
36805
|
+
invalidateSpecCache();
|
|
36806
|
+
removeSpecFile2(typeFileOf(oldId, type), oldId);
|
|
36807
|
+
if (loadTypeSpecs().some((t) => t.id === oldId && (t.subsystem ?? "") === (type.subsystem ?? ""))) deleteSpec("type", oldId);
|
|
36808
|
+
invalidateSpecCache();
|
|
36809
|
+
const carried = projectConfigRepository.rekeyCarried(rename);
|
|
36810
|
+
return {
|
|
36811
|
+
from: qualifiedTypeId(type),
|
|
36812
|
+
to: qualifiedTypeId({ id: newId, subsystem: type.subsystem }),
|
|
36813
|
+
rewritten,
|
|
36814
|
+
keptPublicNames: kept.names,
|
|
36815
|
+
carried
|
|
36816
|
+
};
|
|
36817
|
+
}
|
|
36818
|
+
function typeFileOf(id, type) {
|
|
36819
|
+
return getTypePath(id, type.subsystem, type.group);
|
|
36820
|
+
}
|
|
35689
36821
|
function moveMountToMembers(alias) {
|
|
35690
36822
|
const family = graph();
|
|
35691
36823
|
const member = family.nodes.find((n) => n.parent === "" && n.mountAlias === alias);
|
|
@@ -35871,18 +37003,18 @@ function normalizePath(p) {
|
|
|
35871
37003
|
var fs18 = __toESM(require("fs"));
|
|
35872
37004
|
var os4 = __toESM(require("os"));
|
|
35873
37005
|
var path27 = __toESM(require("path"));
|
|
35874
|
-
var
|
|
35875
|
-
var VariantDefSchema =
|
|
37006
|
+
var import_zod11 = require("zod");
|
|
37007
|
+
var VariantDefSchema = import_zod11.z.object({
|
|
35876
37008
|
/** Variant id referenced by a component's `variant` (e.g. "publisher", "org/external-config-adapter"). */
|
|
35877
|
-
id:
|
|
37009
|
+
id: import_zod11.z.string().min(1),
|
|
35878
37010
|
/** The core stereotype this variant specializes — authoritative for generic semantics (Adapter, Orchestrator, …). */
|
|
35879
|
-
base:
|
|
37011
|
+
base: import_zod11.z.string().min(1),
|
|
35880
37012
|
/** How to implement a component of this variant — the recipe the implementer follows and reuses across same-variant components. */
|
|
35881
|
-
guidance:
|
|
37013
|
+
guidance: import_zod11.z.string().min(1),
|
|
35882
37014
|
/** Optional: this variant only applies for the given target language (else it applies everywhere). */
|
|
35883
|
-
target:
|
|
37015
|
+
target: import_zod11.z.string().optional(),
|
|
35884
37016
|
/** Optional: this variant only applies under the given architectural profile. */
|
|
35885
|
-
profile:
|
|
37017
|
+
profile: import_zod11.z.string().optional()
|
|
35886
37018
|
});
|
|
35887
37019
|
function globalVariantsDir() {
|
|
35888
37020
|
return process.env.WAIRON_VARIANTS_DIR ?? path27.join(os4.homedir(), ".wairon", "variants");
|
|
@@ -37045,19 +38177,19 @@ function retireSpecialists(apply3) {
|
|
|
37045
38177
|
if (decision === void 0) return "pending";
|
|
37046
38178
|
return decision === "unset" ? "neither" : decision;
|
|
37047
38179
|
}
|
|
37048
|
-
const
|
|
37049
|
-
if (
|
|
37050
|
-
if (
|
|
38180
|
+
const dependency2 = byId.get(id);
|
|
38181
|
+
if (dependency2?.componentType === "Orchestrator" && dependency2.dependencyClass) return dependency2.dependencyClass;
|
|
38182
|
+
if (dependency2 && DATA_FACADES.has(dependency2.componentType)) return "facade";
|
|
37051
38183
|
return "neither";
|
|
37052
38184
|
};
|
|
37053
38185
|
const described = (id) => {
|
|
37054
|
-
const
|
|
38186
|
+
const dependency2 = byId.get(id);
|
|
37055
38187
|
const fit = fitOf(id);
|
|
37056
38188
|
let what;
|
|
37057
|
-
if (!
|
|
38189
|
+
if (!dependency2) what = "missing";
|
|
37058
38190
|
else if (fit === "pure" || fit === "read") what = fit;
|
|
37059
|
-
else if (
|
|
37060
|
-
else what =
|
|
38191
|
+
else if (dependency2.componentType === "Orchestrator" || specialistIds.has(id)) what = "workflow";
|
|
38192
|
+
else what = dependency2.componentType;
|
|
37061
38193
|
return `${id} (${what})`;
|
|
37062
38194
|
};
|
|
37063
38195
|
const reasonFor = (specialist, decision, settled2) => {
|
|
@@ -38242,7 +39374,7 @@ function buildServerInstructions2() {
|
|
|
38242
39374
|
// src/mcp/server.ts
|
|
38243
39375
|
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
38244
39376
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
38245
|
-
var
|
|
39377
|
+
var import_zod12 = require("zod");
|
|
38246
39378
|
var import_types12 = require("@modelcontextprotocol/sdk/types.js");
|
|
38247
39379
|
var path48 = __toESM(require("path"));
|
|
38248
39380
|
var crypto10 = __toESM(require("crypto"));
|
|
@@ -38354,6 +39486,7 @@ function refuseUnknownOwner(kind, merged, storedOwner) {
|
|
|
38354
39486
|
}
|
|
38355
39487
|
var STORE_MANAGED_FIELDS = /* @__PURE__ */ new Set(["status", "updatedAt"]);
|
|
38356
39488
|
var ALWAYS_CARRIED_FIELDS = /* @__PURE__ */ new Set(["ext"]);
|
|
39489
|
+
var TRACED_KINDS = /* @__PURE__ */ new Set(["component", "interface", "implementation", "type"]);
|
|
38357
39490
|
var STATUS_ORDER = ["draft", "design", "complete"];
|
|
38358
39491
|
var STATUSED_KINDS = /* @__PURE__ */ new Set(["subsystem", "component", "interface", "implementation"]);
|
|
38359
39492
|
var MISSING_PARENT = {
|
|
@@ -38400,6 +39533,10 @@ function applyRestatement(restatement, loaded, parent) {
|
|
|
38400
39533
|
const carried = carryInto(restatement, existing, candidate);
|
|
38401
39534
|
const cleared = clearedByOmission(existing, candidate, restatement.fields);
|
|
38402
39535
|
stampLifecycle(candidate, existing, status.status);
|
|
39536
|
+
if (restatement.kind === "interface") {
|
|
39537
|
+
const retired = retiredMethodNames(existing, candidate);
|
|
39538
|
+
if (retired) return refused(restatement, replacedExisting, `${retired} Nothing was written.`);
|
|
39539
|
+
}
|
|
38403
39540
|
if (restatement.kind === "interface") {
|
|
38404
39541
|
const restated = restatedSources(candidate.methods);
|
|
38405
39542
|
if (restated.length) return refused(restatement, replacedExisting, `${restatedSourceRefusal(String(candidate.id), restated)} Nothing was written.`);
|
|
@@ -38494,9 +39631,32 @@ function carryInto(restatement, existing, candidate) {
|
|
|
38494
39631
|
for (const field of carryUnexpressed(prev, method, restatement.memberFields)) carried.push(`${field} (${String(method.name)})`);
|
|
38495
39632
|
}
|
|
38496
39633
|
}
|
|
39634
|
+
if (restatement.kind === "interface" && !restatement.memberFields && Array.isArray(candidate.methods)) {
|
|
39635
|
+
const stored = existing.methods ?? [];
|
|
39636
|
+
for (const method of candidate.methods) {
|
|
39637
|
+
const prev = stored.find((p) => p.name === method.name);
|
|
39638
|
+
if (prev?.previousNames === void 0 || method.previousNames !== void 0) continue;
|
|
39639
|
+
method.previousNames = prev.previousNames;
|
|
39640
|
+
carried.push(`previousNames (${String(method.name)})`);
|
|
39641
|
+
}
|
|
39642
|
+
}
|
|
38497
39643
|
carried.push(...carryUnexpressed(existing, candidate, [...restatement.fields, "createdAt"]));
|
|
38498
39644
|
return carried;
|
|
38499
39645
|
}
|
|
39646
|
+
function retiredMethodNames(existing, candidate) {
|
|
39647
|
+
const id = String(candidate.id);
|
|
39648
|
+
const storedNames = new Set((existing?.methods ?? []).map((m) => m.name));
|
|
39649
|
+
const methods = Array.isArray(candidate.methods) ? candidate.methods : [];
|
|
39650
|
+
const holders = [...methods, ...existing?.methods ?? []];
|
|
39651
|
+
for (const method of methods) {
|
|
39652
|
+
if (storedNames.has(method.name)) continue;
|
|
39653
|
+
const holder = holders.find((m) => m !== method && (m.previousNames ?? []).includes(`${id}.${method.name}`));
|
|
39654
|
+
if (holder) {
|
|
39655
|
+
return `Refusing to write interface "${id}": name-retired \u2014 the new method "${method.name}" takes a name this contract retired ("${holder.name}" lists "${id}.${method.name}" in its previousNames). Unsetting that previousNames releases the name.`;
|
|
39656
|
+
}
|
|
39657
|
+
}
|
|
39658
|
+
return void 0;
|
|
39659
|
+
}
|
|
38500
39660
|
function carryUnexpressed(existing, next, expressed) {
|
|
38501
39661
|
if (!existing) return [];
|
|
38502
39662
|
const carried = [];
|
|
@@ -38603,6 +39763,16 @@ function writeSpec(restatement) {
|
|
|
38603
39763
|
const parent = parentRef ? loadSpec(parentRef.kind, parentRef.id) : null;
|
|
38604
39764
|
const id = restatement.kind === "system" ? "system" : restatement.spec.id;
|
|
38605
39765
|
const existing = loadSpec(restatement.kind, id);
|
|
39766
|
+
if (!existing && TRACED_KINDS.has(restatement.kind)) {
|
|
39767
|
+
const spec = restatement.spec;
|
|
39768
|
+
const key = restatement.kind === "type" ? qualifiedTypeId(spec) : spec.id;
|
|
39769
|
+
const holder = specIndexRetiredBy(scanAllSpecs({ memberDepth: 0 }), restatement.kind, key);
|
|
39770
|
+
if (holder) {
|
|
39771
|
+
throw new Error(
|
|
39772
|
+
`id-retired: ${restatement.kind} "${spec.id}" is listed in the previousIds of "${holder}", which was renamed from it. Left alone, a consumer holding the old key would read the new spec as the renamed one. Unsetting the holder's previousIds (sdd_update_spec with {"unset": ["previousIds"]}) releases the id, at the cost that such a consumer reads a delete and an add. Nothing was written.`
|
|
39773
|
+
);
|
|
39774
|
+
}
|
|
39775
|
+
}
|
|
38606
39776
|
const application = applyRestatement(restatement, existing, parent);
|
|
38607
39777
|
if (application.refusal !== void 0) throw new Error(application.refusal);
|
|
38608
39778
|
const gateNotices = restatement.kind === "component" ? judgeComponent(application.spec, bound2) : [];
|
|
@@ -38672,17 +39842,17 @@ function updateSpecGated(kind, id, delta, dryRun) {
|
|
|
38672
39842
|
const testRoots = bound2.rules?.conformance?.testRoots ?? [];
|
|
38673
39843
|
const stored = loadSpec(kind, id);
|
|
38674
39844
|
const gate = componentCandidateGate(bound2, stored?.subsystem, stored);
|
|
38675
|
-
const
|
|
38676
|
-
const changed = changedMethods(
|
|
39845
|
+
const report3 = updateSpec(kind, id, delta, gate, dryRun);
|
|
39846
|
+
const changed = changedMethods(report3);
|
|
38677
39847
|
if (changed.length > 0 && testRoots.length > 0) {
|
|
38678
39848
|
const written = Array.isArray(delta?.methods) ? delta.methods : [];
|
|
38679
|
-
|
|
39849
|
+
report3.testsToRevisit = testsInvalidatedBy(kind, id, changed, [stored], bound2, written);
|
|
38680
39850
|
}
|
|
38681
|
-
return
|
|
39851
|
+
return report3;
|
|
38682
39852
|
}
|
|
38683
|
-
function changedMethods(
|
|
39853
|
+
function changedMethods(report3) {
|
|
38684
39854
|
const named2 = /* @__PURE__ */ new Set();
|
|
38685
|
-
for (const change of
|
|
39855
|
+
for (const change of report3.changes) {
|
|
38686
39856
|
const [field, name] = change.path.split(".");
|
|
38687
39857
|
if (field === "methods" && name) named2.add(name);
|
|
38688
39858
|
}
|
|
@@ -39473,10 +40643,10 @@ function addPin(ctx, consumer, alias) {
|
|
|
39473
40643
|
function planEntry(ctx, producer, ref, table, reason) {
|
|
39474
40644
|
const target = targetOf(ref);
|
|
39475
40645
|
if (!target) {
|
|
39476
|
-
return
|
|
40646
|
+
return report2(ctx, "target-missing", ref, `${ref.specId} names "${ref.target}", but ${label3(producer.namespace)} declares no component, subsystem-owned type or project-level type of that id \u2014 the reference is wrong`);
|
|
39477
40647
|
}
|
|
39478
40648
|
if (target.kind === "subsystem") {
|
|
39479
|
-
return
|
|
40649
|
+
return report2(ctx, "subsystem-reference", ref, `${ref.specId} re-exports ${label3(producer.namespace)}'s subsystem "${target.id}" wholesale \u2014 no L0 entry short of exporting it expresses that; rewrite the reference to name the items it uses`);
|
|
39480
40650
|
}
|
|
39481
40651
|
if (target.source === void 0) return decideOwnType(ctx, producer, ref, target, table, reason);
|
|
39482
40652
|
return decideEntry(ctx, producer, ref, target, table, resolveSubsystemExports(target.source), reason);
|
|
@@ -39498,7 +40668,7 @@ function decideOwnType(ctx, producer, ref, target, table, reason) {
|
|
|
39498
40668
|
const local = localIn3(producer.namespace, target.id);
|
|
39499
40669
|
const taken = table.entries.find((e) => e.publicName === local && exportTargetKey(e) !== key) ?? entryOf(ctx, producer).exports.find((e) => e.publicName === local && (e.component ?? e.typeDef) !== local);
|
|
39500
40670
|
if (taken) {
|
|
39501
|
-
return
|
|
40671
|
+
return report2(ctx, "name-taken", ref, `"${local}" already names another item in ${label3(producer.namespace)} \u2014 export the type "${target.id}" under a name a person chooses`);
|
|
39502
40672
|
}
|
|
39503
40673
|
mergeEntry(entryOf(ctx, producer), target, void 0, local, local, ref, reason);
|
|
39504
40674
|
return "planned";
|
|
@@ -39507,18 +40677,18 @@ function decideEntry(ctx, producer, ref, target, table, published, reason) {
|
|
|
39507
40677
|
const key = targetKey(target);
|
|
39508
40678
|
const at = published.entries.filter((e) => exportTargetKey({ ...e, interface: void 0 }) === key);
|
|
39509
40679
|
if (at.length === 0) {
|
|
39510
|
-
return
|
|
40680
|
+
return report2(ctx, "target-unpublished", ref, `"${target.id}" is not in its subsystem's L1 table, so no L0 re-export can follow it \u2014 publish it at L1 first, or the reference is wrong`);
|
|
39511
40681
|
}
|
|
39512
40682
|
const exported = table.entries.filter((e) => exportTargetKey({ ...e, interface: void 0 }) === key);
|
|
39513
40683
|
if (exported.length > 0 && reachableThrough(exported, ref)) return "present";
|
|
39514
40684
|
if (exported.length > 0 || !reachableThrough(at, ref)) {
|
|
39515
|
-
return
|
|
40685
|
+
return report2(ctx, "narrowed", ref, `"${target.id}" is exported under a narrowing that does not declare "${ref.member ?? "what the reference reaches"}" \u2014 widen the narrowing or reach another member`);
|
|
39516
40686
|
}
|
|
39517
40687
|
const local = localIn3(producer.namespace, target.id);
|
|
39518
40688
|
const publicName = local.split("::").pop();
|
|
39519
40689
|
const taken = table.entries.find((e) => e.publicName === publicName && exportTargetKey({ ...e, interface: void 0 }) !== key) ?? entryOf(ctx, producer).exports.find((e) => e.publicName === publicName && (e.component ?? e.typeDef) !== local);
|
|
39520
40690
|
if (taken) {
|
|
39521
|
-
return
|
|
40691
|
+
return report2(ctx, "name-taken", ref, `"${publicName}" already names another item in ${label3(producer.namespace)} \u2014 export "${target.id}" under a name a person chooses`);
|
|
39522
40692
|
}
|
|
39523
40693
|
mergeEntry(entryOf(ctx, producer), target, localIn3(producer.namespace, target.source), local, publicName, ref, reason);
|
|
39524
40694
|
return "planned";
|
|
@@ -39559,7 +40729,7 @@ function addSorted(list, value) {
|
|
|
39559
40729
|
list.sort();
|
|
39560
40730
|
}
|
|
39561
40731
|
}
|
|
39562
|
-
function
|
|
40732
|
+
function report2(ctx, kind, ref, detail) {
|
|
39563
40733
|
ctx.findings.push({ kind, project: ref.producer, detail, reference: ref, blocking: false });
|
|
39564
40734
|
return "refused";
|
|
39565
40735
|
}
|
|
@@ -42100,30 +43270,30 @@ function structured(content, data) {
|
|
|
42100
43270
|
return { content: [{ type: "text", text: content }], structuredContent: data };
|
|
42101
43271
|
}
|
|
42102
43272
|
function migrationTool(request, dryRun) {
|
|
42103
|
-
let
|
|
43273
|
+
let report3;
|
|
42104
43274
|
try {
|
|
42105
|
-
|
|
43275
|
+
report3 = run2(request, dryRun);
|
|
42106
43276
|
} catch (e) {
|
|
42107
43277
|
return errMessage(e);
|
|
42108
43278
|
}
|
|
42109
|
-
const view = migrationView(
|
|
43279
|
+
const view = migrationView(report3, dryRun === true);
|
|
42110
43280
|
const body = JSON.stringify(view, null, 2);
|
|
42111
|
-
if (
|
|
43281
|
+
if (report3.plan.refusals.length > 0) return errText(`the ${request.verb} migration is refused; nothing was written.
|
|
42112
43282
|
${body}`);
|
|
42113
|
-
if (!
|
|
42114
|
-
const how =
|
|
42115
|
-
return errText(`the ${request.verb} migration failed (${
|
|
43283
|
+
if (!report3.applied && report3.outcome) {
|
|
43284
|
+
const how = report3.outcome.restored ? "the family was restored exactly as before" : "some files could not be restored: a person must run `wairon doctor --fix` in the project";
|
|
43285
|
+
return errText(`the ${request.verb} migration failed (${report3.outcome.failure ?? "unknown failure"}) and ${how}.
|
|
42116
43286
|
${body}`);
|
|
42117
43287
|
}
|
|
42118
43288
|
return structured(body, view);
|
|
42119
43289
|
}
|
|
42120
|
-
function migrationView(
|
|
42121
|
-
const plan6 =
|
|
43290
|
+
function migrationView(report3, dryRun) {
|
|
43291
|
+
const plan6 = report3.plan;
|
|
42122
43292
|
return {
|
|
42123
43293
|
dryRun,
|
|
42124
|
-
applied:
|
|
42125
|
-
relock:
|
|
42126
|
-
...
|
|
43294
|
+
applied: report3.applied,
|
|
43295
|
+
relock: report3.applied ? report3.relock : plan6.relock,
|
|
43296
|
+
...report3.outcome ? { outcome: { committed: report3.outcome.committed, restored: report3.outcome.restored, unrestored: report3.outcome.unrestored, ...report3.outcome.failure ? { failure: report3.outcome.failure } : {} } } : {},
|
|
42127
43297
|
plan: {
|
|
42128
43298
|
verb: plan6.request.verb,
|
|
42129
43299
|
familyRoot: plan6.familyRoot,
|
|
@@ -42139,69 +43309,69 @@ function jsonStructured(value) {
|
|
|
42139
43309
|
return structured(JSON.stringify(value, null, 2), value);
|
|
42140
43310
|
}
|
|
42141
43311
|
var staleServerOutput = {
|
|
42142
|
-
staleServer:
|
|
43312
|
+
staleServer: import_zod12.z.boolean().optional().describe(
|
|
42143
43313
|
"True when the wairon build on disk changed after this server started \u2014 the structured twin of the text answer's STALE SERVER banner. When the rebuild left the spec and tool schemas alone, writes still go through; reconnect to run the new code."
|
|
42144
43314
|
),
|
|
42145
|
-
writesRefused:
|
|
43315
|
+
writesRefused: import_zod12.z.boolean().optional().describe(
|
|
42146
43316
|
"True when the rebuild changed a spec or tool schema (or its schemas could not be compared): every spec write through this server is refused and writes nothing, because it would silently drop the fields only the new build knows. The human has to reconnect the server (/mcp reconnect wairon)."
|
|
42147
43317
|
)
|
|
42148
43318
|
};
|
|
42149
43319
|
var externalPinsOutput = {
|
|
42150
|
-
pins:
|
|
42151
|
-
alias:
|
|
42152
|
-
outcome:
|
|
42153
|
-
project:
|
|
42154
|
-
snapshot:
|
|
42155
|
-
digest:
|
|
42156
|
-
usedNames:
|
|
42157
|
-
unexported:
|
|
42158
|
-
detail:
|
|
43320
|
+
pins: import_zod12.z.array(import_zod12.z.object({
|
|
43321
|
+
alias: import_zod12.z.string(),
|
|
43322
|
+
outcome: import_zod12.z.enum(["pinned", "unchanged", "unresolved", "unreachable"]),
|
|
43323
|
+
project: import_zod12.z.string().optional(),
|
|
43324
|
+
snapshot: import_zod12.z.string().optional(),
|
|
43325
|
+
digest: import_zod12.z.string().optional(),
|
|
43326
|
+
usedNames: import_zod12.z.number(),
|
|
43327
|
+
unexported: import_zod12.z.array(import_zod12.z.record(import_zod12.z.unknown())),
|
|
43328
|
+
detail: import_zod12.z.string().optional()
|
|
42159
43329
|
})).describe("One outcome per alias pinned, in declaration order, with its unexported references."),
|
|
42160
43330
|
...staleServerOutput
|
|
42161
43331
|
};
|
|
42162
43332
|
var externalStatusesOutput = {
|
|
42163
|
-
statuses:
|
|
42164
|
-
alias:
|
|
42165
|
-
project:
|
|
42166
|
-
sourceKind:
|
|
42167
|
-
pinned:
|
|
42168
|
-
reachable:
|
|
42169
|
-
stale:
|
|
42170
|
-
drifted:
|
|
42171
|
-
uses:
|
|
42172
|
-
detail:
|
|
42173
|
-
outOfReach:
|
|
42174
|
-
pinnedDigest:
|
|
42175
|
-
pinnedCommit:
|
|
43333
|
+
statuses: import_zod12.z.array(import_zod12.z.object({
|
|
43334
|
+
alias: import_zod12.z.string(),
|
|
43335
|
+
project: import_zod12.z.string(),
|
|
43336
|
+
sourceKind: import_zod12.z.string(),
|
|
43337
|
+
pinned: import_zod12.z.boolean(),
|
|
43338
|
+
reachable: import_zod12.z.boolean(),
|
|
43339
|
+
stale: import_zod12.z.boolean(),
|
|
43340
|
+
drifted: import_zod12.z.boolean().optional(),
|
|
43341
|
+
uses: import_zod12.z.array(import_zod12.z.record(import_zod12.z.unknown())),
|
|
43342
|
+
detail: import_zod12.z.string().optional(),
|
|
43343
|
+
outOfReach: import_zod12.z.boolean().optional(),
|
|
43344
|
+
pinnedDigest: import_zod12.z.string().optional().describe("The content digest the lock recorded; provenance, never compared here."),
|
|
43345
|
+
pinnedCommit: import_zod12.z.string().optional().describe("The producer commit the lock recorded, for one in another repository; provenance only.")
|
|
42176
43346
|
})).describe("One status per declared external, in declaration order; EXTERNAL_CHECK_UNAVAILABLE marks what could not be compared."),
|
|
42177
43347
|
...staleServerOutput
|
|
42178
43348
|
};
|
|
42179
|
-
function renderChangeReport(
|
|
42180
|
-
const lines = [
|
|
42181
|
-
for (const change of
|
|
43349
|
+
function renderChangeReport(report3) {
|
|
43350
|
+
const lines = [report3.dryRun ? `DRY RUN \u2014 nothing was written. ${report3.summary}` : report3.summary];
|
|
43351
|
+
for (const change of report3.changes) {
|
|
42182
43352
|
const to = change.after === void 0 ? "" : `: ${JSON.stringify(change.after)}`;
|
|
42183
43353
|
const from = change.before === void 0 ? "" : ` (was ${JSON.stringify(change.before)})`;
|
|
42184
|
-
lines.push(`- ${change.path} ${
|
|
43354
|
+
lines.push(`- ${change.path} ${report3.dryRun ? `would be ${change.change}` : change.change}${to}${from}`);
|
|
42185
43355
|
}
|
|
42186
|
-
if (
|
|
42187
|
-
lines.push("", "NO EFFECT:", ...
|
|
43356
|
+
if (report3.ineffective.length) {
|
|
43357
|
+
lines.push("", "NO EFFECT:", ...report3.ineffective.map((i) => `- ${i}`));
|
|
42188
43358
|
}
|
|
42189
|
-
if (
|
|
42190
|
-
if (
|
|
42191
|
-
lines.push("", `DROPPED FROM THE STORED FILE (${
|
|
43359
|
+
if (report3.notices.length) lines.push("", "NOTICE:", ...report3.notices.map((n) => `- ${n}`));
|
|
43360
|
+
if (report3.strippedKeys?.length) {
|
|
43361
|
+
lines.push("", `DROPPED FROM THE STORED FILE (${report3.dryRun ? "would be " : ""}removed \u2014 the schema does not know them):`, ...report3.strippedKeys.map((k) => `- ${k}`));
|
|
42192
43362
|
}
|
|
42193
|
-
lines.push(...renderRespellings(
|
|
42194
|
-
lines.push(...renderTestsToRevisit(
|
|
43363
|
+
lines.push(...renderRespellings(report3.respellings));
|
|
43364
|
+
lines.push(...renderTestsToRevisit(report3.testsToRevisit));
|
|
42195
43365
|
return lines.join("\n");
|
|
42196
43366
|
}
|
|
42197
43367
|
var SPEC_KINDS = ["system", "subsystem", "component", "interface", "implementation", "type"];
|
|
42198
43368
|
var STATUS_VALUES = ["draft", "design", "complete"];
|
|
42199
|
-
var testsToRevisitOutput =
|
|
42200
|
-
method:
|
|
42201
|
-
symbol:
|
|
42202
|
-
imported:
|
|
42203
|
-
mentioned:
|
|
42204
|
-
indiscriminate:
|
|
43369
|
+
var testsToRevisitOutput = import_zod12.z.array(import_zod12.z.object({
|
|
43370
|
+
method: import_zod12.z.string().describe("The contract method this write changed or deleted."),
|
|
43371
|
+
symbol: import_zod12.z.string().describe("The code-level name searched for: the method's `symbol` when it declares one, else its name."),
|
|
43372
|
+
imported: import_zod12.z.array(import_zod12.z.string()).describe("Test files that IMPORT that symbol \u2014 the high-confidence list, because an import is a binding and not a coincidence."),
|
|
43373
|
+
mentioned: import_zod12.z.array(import_zod12.z.string()).describe("Test files that name the symbol without importing it \u2014 usually a test driving it through a portal. Empty when `indiscriminate` is true."),
|
|
43374
|
+
indiscriminate: import_zod12.z.boolean().describe("True when the bare name matched more than a tenth of the test suite, so the mention list was withheld as noise.")
|
|
42205
43375
|
})).describe(
|
|
42206
43376
|
"The tests that encode a method this write changed or deleted, one entry per such method. Empty when the write touched no method, when the project declares no `rules.conformance.testRoots`, or when nothing references them. Read it before promising that existing tests still pass."
|
|
42207
43377
|
);
|
|
@@ -42218,31 +43388,31 @@ function renderTestsToRevisit(entries) {
|
|
|
42218
43388
|
}
|
|
42219
43389
|
return lines;
|
|
42220
43390
|
}
|
|
42221
|
-
var typeRespellingOutput =
|
|
42222
|
-
specId:
|
|
42223
|
-
kind:
|
|
42224
|
-
path:
|
|
42225
|
-
written:
|
|
42226
|
-
stored:
|
|
43391
|
+
var typeRespellingOutput = import_zod12.z.object({
|
|
43392
|
+
specId: import_zod12.z.string().describe("The interface or type holding the position."),
|
|
43393
|
+
kind: import_zod12.z.enum(["interface", "type"]).describe("interface | type."),
|
|
43394
|
+
path: import_zod12.z.string().describe("Where in the spec: methods.save.params.key, methods.save.returns, fields.createdAt, params.listener."),
|
|
43395
|
+
written: import_zod12.z.string().describe("The text the input (or the stored file) held."),
|
|
43396
|
+
stored: import_zod12.z.string().describe("The canonical spelling, which is what is stored and shown.")
|
|
42227
43397
|
});
|
|
42228
43398
|
function renderRespellings(entries) {
|
|
42229
43399
|
if (!entries.length) return [];
|
|
42230
43400
|
return ["", "RESPELLED (stored canonical):", ...entries.map((r) => `- ${r.path}: "${r.written}" \u2192 "${r.stored}"`)];
|
|
42231
43401
|
}
|
|
42232
43402
|
var specWriteReceiptOutput = {
|
|
42233
|
-
kind:
|
|
42234
|
-
id:
|
|
42235
|
-
name:
|
|
42236
|
-
replacedExisting:
|
|
43403
|
+
kind: import_zod12.z.enum(SPEC_KINDS).describe("The spec kind written."),
|
|
43404
|
+
id: import_zod12.z.string().describe('The id the spec is stored under; "system" for the L0 singleton.'),
|
|
43405
|
+
name: import_zod12.z.string().describe("The spec's display name as written."),
|
|
43406
|
+
replacedExisting: import_zod12.z.boolean().describe(
|
|
42237
43407
|
"True when a spec already held this id and the call re-authored it in place rather than adding one. The notices then say what was carried forward, removed or cleared by the restatement."
|
|
42238
43408
|
),
|
|
42239
|
-
status:
|
|
43409
|
+
status: import_zod12.z.enum(STATUS_VALUES).optional().describe(
|
|
42240
43410
|
"The lifecycle status written. Absent for the L0 and a type, which carry none."
|
|
42241
43411
|
),
|
|
42242
|
-
notices:
|
|
43412
|
+
notices: import_zod12.z.array(import_zod12.z.string()).describe(
|
|
42243
43413
|
"The notice lines the text answer lists, one per entry: what was carried forward, what a restatement removed, what an omission cleared, and every gate warning the write raised. Empty for a clean create."
|
|
42244
43414
|
),
|
|
42245
|
-
respellings:
|
|
43415
|
+
respellings: import_zod12.z.array(typeRespellingOutput).describe(
|
|
42246
43416
|
"Each type position the write normalised: what the input wrote against the canonical spelling stored. Aliases are accepted, never refused, and this list is how an author learns the canonical form. Empty when every position was already canonical."
|
|
42247
43417
|
),
|
|
42248
43418
|
testsToRevisit: testsToRevisitOutput,
|
|
@@ -42260,86 +43430,86 @@ ${respelledBlock}` : ""}${testsBlock ? `
|
|
|
42260
43430
|
${testsBlock}` : ""}`, receipt);
|
|
42261
43431
|
}
|
|
42262
43432
|
var specDeletionOutput = {
|
|
42263
|
-
kind:
|
|
42264
|
-
id:
|
|
42265
|
-
deleted:
|
|
43433
|
+
kind: import_zod12.z.enum(SPEC_KINDS).describe("The spec kind deleted."),
|
|
43434
|
+
id: import_zod12.z.string().describe("The id the spec was stored under."),
|
|
43435
|
+
deleted: import_zod12.z.boolean().describe("True when a spec document was removed."),
|
|
42266
43436
|
testsToRevisit: testsToRevisitOutput,
|
|
42267
43437
|
...staleServerOutput
|
|
42268
43438
|
};
|
|
42269
43439
|
var specChangeOutput = {
|
|
42270
|
-
path:
|
|
42271
|
-
change:
|
|
43440
|
+
path: import_zod12.z.string().describe("The dotted path the change addresses, with names and indexes."),
|
|
43441
|
+
change: import_zod12.z.enum(["set", "added", "removed", "cleared", "renumbered", "relocated"]).describe(
|
|
42272
43442
|
"What happened at that path. A narrative is compared by step identity: `renumbered` is a run of unchanged steps shifted by an insert or delete (before/after name the ranges), `relocated` a jump field that followed its target to the target's new number."
|
|
42273
43443
|
),
|
|
42274
|
-
before:
|
|
42275
|
-
after:
|
|
43444
|
+
before: import_zod12.z.string().optional().describe("The previous value, summarized; absent when there was none."),
|
|
43445
|
+
after: import_zod12.z.string().optional().describe("The new value, summarized; absent when there is none.")
|
|
42276
43446
|
};
|
|
42277
43447
|
var specChangeReportOutput = {
|
|
42278
|
-
kind:
|
|
42279
|
-
id:
|
|
42280
|
-
written:
|
|
42281
|
-
dryRun:
|
|
43448
|
+
kind: import_zod12.z.enum(SPEC_KINDS).describe("The spec kind written."),
|
|
43449
|
+
id: import_zod12.z.string().describe("The stored spec's id."),
|
|
43450
|
+
written: import_zod12.z.boolean().describe("False when the merged spec equals what is stored: nothing reached disk."),
|
|
43451
|
+
dryRun: import_zod12.z.boolean().describe(
|
|
42282
43452
|
"True when the caller asked what the delta WOULD do. `written` is false for a dry run exactly as it is for a delta that changed nothing, and only this field tells the two apart."
|
|
42283
43453
|
),
|
|
42284
|
-
changes:
|
|
43454
|
+
changes: import_zod12.z.array(import_zod12.z.object(specChangeOutput)).describe(
|
|
42285
43455
|
"Every change the write made; empty exactly when `written` is false."
|
|
42286
43456
|
),
|
|
42287
|
-
ineffective:
|
|
43457
|
+
ineffective: import_zod12.z.array(import_zod12.z.string()).describe(
|
|
42288
43458
|
"Every path the delta named that the write did not act on, each with why. Read it: a nested typo the permissive delta cannot refuse shows up here and nowhere else."
|
|
42289
43459
|
),
|
|
42290
|
-
notices:
|
|
42291
|
-
respellings:
|
|
43460
|
+
notices: import_zod12.z.array(import_zod12.z.string()).describe("Store placement notices, gate warnings and delta notices."),
|
|
43461
|
+
respellings: import_zod12.z.array(typeRespellingOutput).describe(
|
|
42292
43462
|
"Each type position the write normalised (or, on a dry run, would): what the delta or the stored file wrote against the canonical spelling stored. Aliases are accepted and respelled, never refused \u2014 this is how the canonical form is taught. Empty when every position was already canonical."
|
|
42293
43463
|
),
|
|
42294
|
-
summary:
|
|
43464
|
+
summary: import_zod12.z.string().describe("One line for people."),
|
|
42295
43465
|
testsToRevisit: testsToRevisitOutput,
|
|
42296
|
-
strippedKeys:
|
|
43466
|
+
strippedKeys: import_zod12.z.array(import_zod12.z.string()).optional().describe(
|
|
42297
43467
|
"Keys the stored file carries that the level's schema does not know, each as `path: value`, which this write drops (or, on a dry run, would drop). Absent when there are none."
|
|
42298
43468
|
),
|
|
42299
43469
|
...staleServerOutput
|
|
42300
43470
|
};
|
|
42301
43471
|
var validationIssueOutput = {
|
|
42302
|
-
severity:
|
|
42303
|
-
code:
|
|
42304
|
-
message:
|
|
42305
|
-
agentId:
|
|
42306
|
-
specId:
|
|
42307
|
-
draftContext:
|
|
43472
|
+
severity: import_zod12.z.enum(["error", "warning", "notice"]).describe("The finding's severity after project overrides."),
|
|
43473
|
+
code: import_zod12.z.string().describe("The rule code, UPPER_SNAKE \u2014 the stable handle to filter and suppress by."),
|
|
43474
|
+
message: import_zod12.z.string().describe("What is wrong, named."),
|
|
43475
|
+
agentId: import_zod12.z.string().optional().describe("The agent the finding concerns, when it concerns one."),
|
|
43476
|
+
specId: import_zod12.z.string().optional().describe("The spec the finding concerns, when it concerns one."),
|
|
43477
|
+
draftContext: import_zod12.z.boolean().optional().describe(
|
|
42308
43478
|
"True when the finding was raised against a draft/design spec \u2014 what the --ci gate waives."
|
|
42309
43479
|
),
|
|
42310
|
-
resolution:
|
|
42311
|
-
outcome:
|
|
42312
|
-
owner:
|
|
42313
|
-
callSite:
|
|
42314
|
-
canonicalTarget:
|
|
42315
|
-
inputDigest:
|
|
42316
|
-
reason:
|
|
42317
|
-
importedVia:
|
|
43480
|
+
resolution: import_zod12.z.object({
|
|
43481
|
+
outcome: import_zod12.z.enum(["resolved", "missing", "ambiguous", "unavailable", "forbidden"]).describe("How the owner's gate resolved the reference, decided before the severity."),
|
|
43482
|
+
owner: import_zod12.z.string().describe("The referring project's id: the one project whose gate judges the reference."),
|
|
43483
|
+
callSite: import_zod12.z.string().describe("Where the reference is written: the referring spec and the position in it."),
|
|
43484
|
+
canonicalTarget: import_zod12.z.string().optional().describe("The target in producer-id form, `<producer id>::<public name>`."),
|
|
43485
|
+
inputDigest: import_zod12.z.string().optional().describe("The digest of the input the reference was judged against (a pin, or a member's live table)."),
|
|
43486
|
+
reason: import_zod12.z.string().describe("One sentence saying why the outcome is what it is."),
|
|
43487
|
+
importedVia: import_zod12.z.string().optional().describe("For a bare name resolved through a `use` import: the alias that supplied it.")
|
|
42318
43488
|
}).optional().describe(
|
|
42319
43489
|
"On a finding about a cross-project reference: how the owner's gate resolved it, decided before the severity."
|
|
42320
43490
|
),
|
|
42321
|
-
project:
|
|
43491
|
+
project: import_zod12.z.string().optional().describe(
|
|
42322
43492
|
"In a family run: the key of the project whose gate the finding belongs to ('' for the family root)."
|
|
42323
43493
|
)
|
|
42324
43494
|
};
|
|
42325
43495
|
var memberCreationOutput = {
|
|
42326
|
-
configCreated:
|
|
42327
|
-
adopted:
|
|
42328
|
-
name:
|
|
42329
|
-
version:
|
|
42330
|
-
integrity:
|
|
42331
|
-
source:
|
|
42332
|
-
bundle:
|
|
43496
|
+
configCreated: import_zod12.z.boolean().describe("Whether this call created the member's configuration; only then were the declaring project's required packs scaffolded."),
|
|
43497
|
+
adopted: import_zod12.z.array(import_zod12.z.object({
|
|
43498
|
+
name: import_zod12.z.string(),
|
|
43499
|
+
version: import_zod12.z.string().optional(),
|
|
43500
|
+
integrity: import_zod12.z.string().optional(),
|
|
43501
|
+
source: import_zod12.z.string().optional(),
|
|
43502
|
+
bundle: import_zod12.z.boolean().optional()
|
|
42333
43503
|
})).describe("The selections written into the new member's extensions.packs, each pinned to the highest installed version its requirement admits."),
|
|
42334
|
-
unadopted:
|
|
42335
|
-
pack:
|
|
42336
|
-
version:
|
|
42337
|
-
profile:
|
|
43504
|
+
unadopted: import_zod12.z.array(import_zod12.z.object({
|
|
43505
|
+
pack: import_zod12.z.string(),
|
|
43506
|
+
version: import_zod12.z.string(),
|
|
43507
|
+
profile: import_zod12.z.string().optional()
|
|
42338
43508
|
})).describe("Requirements no installed version satisfies: nothing was written for them, and the next family run reports each as POLICY_NOT_ADOPTED."),
|
|
42339
|
-
projectType:
|
|
42340
|
-
as:
|
|
42341
|
-
storage:
|
|
42342
|
-
commit:
|
|
43509
|
+
projectType: import_zod12.z.string().optional().describe("The profile written as the new member's projectType, when exactly one adopted requirement names one."),
|
|
43510
|
+
as: import_zod12.z.string().describe("part | project: what was created (stage 8; a part by default)."),
|
|
43511
|
+
storage: import_zod12.z.string().describe("contained | path | git: where its files live."),
|
|
43512
|
+
commit: import_zod12.z.string().optional().describe("git: the commit the member was pinned at."),
|
|
42343
43513
|
...staleServerOutput
|
|
42344
43514
|
};
|
|
42345
43515
|
function describeMemberPacks(creation) {
|
|
@@ -42354,36 +43524,36 @@ function describeMemberPacks(creation) {
|
|
|
42354
43524
|
}
|
|
42355
43525
|
return parts.join("");
|
|
42356
43526
|
}
|
|
42357
|
-
var doctrineChangeOutput =
|
|
42358
|
-
axis:
|
|
42359
|
-
change:
|
|
42360
|
-
subject:
|
|
42361
|
-
profile:
|
|
42362
|
-
from:
|
|
42363
|
-
to:
|
|
42364
|
-
reason:
|
|
43527
|
+
var doctrineChangeOutput = import_zod12.z.object({
|
|
43528
|
+
axis: import_zod12.z.enum(["rule", "concept"]),
|
|
43529
|
+
change: import_zod12.z.string().describe("loosened | raised | off | added | depth | inert | redefined | removed | discouraged | licensed | gated \u2014 stated, never judged."),
|
|
43530
|
+
subject: import_zod12.z.string(),
|
|
43531
|
+
profile: import_zod12.z.string().optional(),
|
|
43532
|
+
from: import_zod12.z.string().optional(),
|
|
43533
|
+
to: import_zod12.z.string().optional(),
|
|
43534
|
+
reason: import_zod12.z.string().optional()
|
|
42365
43535
|
});
|
|
42366
|
-
var impactTotalsOutput =
|
|
42367
|
-
key:
|
|
42368
|
-
id:
|
|
42369
|
-
directory:
|
|
42370
|
-
valid:
|
|
42371
|
-
errors:
|
|
42372
|
-
warnings:
|
|
42373
|
-
notices:
|
|
43536
|
+
var impactTotalsOutput = import_zod12.z.object({
|
|
43537
|
+
key: import_zod12.z.string(),
|
|
43538
|
+
id: import_zod12.z.string().optional(),
|
|
43539
|
+
directory: import_zod12.z.string(),
|
|
43540
|
+
valid: import_zod12.z.boolean(),
|
|
43541
|
+
errors: import_zod12.z.number(),
|
|
43542
|
+
warnings: import_zod12.z.number(),
|
|
43543
|
+
notices: import_zod12.z.number()
|
|
42374
43544
|
});
|
|
42375
43545
|
var packImpactOutput = {
|
|
42376
|
-
pack:
|
|
42377
|
-
version:
|
|
42378
|
-
replaces:
|
|
42379
|
-
direction:
|
|
42380
|
-
doctrine:
|
|
42381
|
-
previousDoctrine:
|
|
42382
|
-
governing:
|
|
42383
|
-
findings:
|
|
42384
|
-
introduced:
|
|
42385
|
-
resolved:
|
|
42386
|
-
regraded:
|
|
43546
|
+
pack: import_zod12.z.string().describe("The pack measured."),
|
|
43547
|
+
version: import_zod12.z.string().optional().describe("The version the candidate resolves to; absent for an unversioned pack."),
|
|
43548
|
+
replaces: import_zod12.z.string().optional().describe("The version applied now under the same name, when the selection would replace it."),
|
|
43549
|
+
direction: import_zod12.z.enum(["apply", "remove"]).describe("remove when the pack is already applied exactly as asked: the findings then read as what the pack accounts for now."),
|
|
43550
|
+
doctrine: import_zod12.z.array(doctrineChangeOutput).describe("The pack's changes against wairon's defaults. Nothing in it is a finding."),
|
|
43551
|
+
previousDoctrine: import_zod12.z.array(doctrineChangeOutput).optional().describe("On an update: the replaced version's changes against the same defaults."),
|
|
43552
|
+
governing: import_zod12.z.array(import_zod12.z.string()).describe("The pack's profiles that would govern something in this project."),
|
|
43553
|
+
findings: import_zod12.z.object({
|
|
43554
|
+
introduced: import_zod12.z.array(import_zod12.z.object(validationIssueOutput)),
|
|
43555
|
+
resolved: import_zod12.z.array(import_zod12.z.object(validationIssueOutput)),
|
|
43556
|
+
regraded: import_zod12.z.array(import_zod12.z.object({ finding: import_zod12.z.object(validationIssueOutput), from: import_zod12.z.string() }))
|
|
42387
43557
|
}).describe("The owner's-gate findings that differ between the current and the candidate configuration."),
|
|
42388
43558
|
before: impactTotalsOutput.describe("The current configuration's totals."),
|
|
42389
43559
|
after: impactTotalsOutput.describe("The candidate configuration's totals."),
|
|
@@ -42417,57 +43587,57 @@ function pendingBanner() {
|
|
|
42417
43587
|
}
|
|
42418
43588
|
}
|
|
42419
43589
|
var validateTreeOutput = {
|
|
42420
|
-
valid:
|
|
42421
|
-
errors:
|
|
42422
|
-
warnings:
|
|
42423
|
-
notices:
|
|
43590
|
+
valid: import_zod12.z.boolean().describe("False when the tree holds at least one error; warnings and notices never make it false."),
|
|
43591
|
+
errors: import_zod12.z.array(import_zod12.z.object(validationIssueOutput)).describe("Every finding of severity error."),
|
|
43592
|
+
warnings: import_zod12.z.array(import_zod12.z.object(validationIssueOutput)).describe("Every finding of severity warning."),
|
|
43593
|
+
notices: import_zod12.z.array(import_zod12.z.object(validationIssueOutput)).describe(
|
|
42424
43594
|
"Every finding of severity notice: reported, never a failure \u2014 they never make the tree invalid and never fail `wairon validate --ci`."
|
|
42425
43595
|
),
|
|
42426
|
-
hint:
|
|
43596
|
+
hint: import_zod12.z.string().optional().describe(
|
|
42427
43597
|
"The owner's gate: present when the project declares externals \u2014 they were judged against their pins alone, and `wairon validate --family` composes them against their live producers. A family run: present when externals were left out because their producers lie outside the run's reach."
|
|
42428
43598
|
),
|
|
42429
|
-
projects:
|
|
42430
|
-
key:
|
|
42431
|
-
id:
|
|
42432
|
-
directory:
|
|
42433
|
-
valid:
|
|
42434
|
-
errors:
|
|
42435
|
-
warnings:
|
|
42436
|
-
notices:
|
|
43599
|
+
projects: import_zod12.z.array(import_zod12.z.object({
|
|
43600
|
+
key: import_zod12.z.string().describe("The project's key in the family root's scan ('' for the root itself)."),
|
|
43601
|
+
id: import_zod12.z.string().optional().describe("The project's effective id."),
|
|
43602
|
+
directory: import_zod12.z.string().describe("The project's root directory."),
|
|
43603
|
+
valid: import_zod12.z.boolean().describe("Whether its own gate found no error."),
|
|
43604
|
+
errors: import_zod12.z.number().describe("Its own gate's error count."),
|
|
43605
|
+
warnings: import_zod12.z.number().describe("Its own gate's warning count."),
|
|
43606
|
+
notices: import_zod12.z.number().describe("Its own gate's notice count.")
|
|
42437
43607
|
})).optional().describe(
|
|
42438
43608
|
"A family run only: one line per selected project (the root first) with its own gate's totals. Absent on the owner's gate."
|
|
42439
43609
|
),
|
|
42440
43610
|
...staleServerOutput
|
|
42441
43611
|
};
|
|
42442
43612
|
var getSpecOutput = {
|
|
42443
|
-
kind:
|
|
42444
|
-
id:
|
|
42445
|
-
spec:
|
|
43613
|
+
kind: import_zod12.z.enum(SPEC_KINDS).describe("The kind of spec read."),
|
|
43614
|
+
id: import_zod12.z.string().describe("The id it was read by."),
|
|
43615
|
+
spec: import_zod12.z.record(import_zod12.z.unknown()).describe(
|
|
42446
43616
|
"The stored spec, exactly as the text block renders it \u2014 minus the two derived markers below, which the text folds in and this answer keeps separate so nothing derived can be mistaken for stored."
|
|
42447
43617
|
),
|
|
42448
|
-
partialResult:
|
|
42449
|
-
shown:
|
|
42450
|
-
omitted:
|
|
42451
|
-
warning:
|
|
43618
|
+
partialResult: import_zod12.z.object({
|
|
43619
|
+
shown: import_zod12.z.array(import_zod12.z.string()).describe("The method names this answer carries."),
|
|
43620
|
+
omitted: import_zod12.z.number().describe("How many of the spec's methods are NOT in it."),
|
|
43621
|
+
warning: import_zod12.z.string().describe("Why it must never be re-authored from.")
|
|
42452
43622
|
}).optional().describe(
|
|
42453
43623
|
"Present only when `methods` filtered the read. A filtered spec is a partial one: sdd_define_interface and sdd_write_narrative REPLACE the method list, so re-authoring from it would delete every method left out."
|
|
42454
43624
|
),
|
|
42455
|
-
variantGuidance:
|
|
42456
|
-
variant:
|
|
42457
|
-
base:
|
|
42458
|
-
guidance:
|
|
42459
|
-
siblings:
|
|
42460
|
-
target:
|
|
42461
|
-
profile:
|
|
43625
|
+
variantGuidance: import_zod12.z.object({
|
|
43626
|
+
variant: import_zod12.z.string().describe("The variant id the component declares."),
|
|
43627
|
+
base: import_zod12.z.string().describe("The core stereotype it specializes."),
|
|
43628
|
+
guidance: import_zod12.z.string().describe("How to implement a component of this variant."),
|
|
43629
|
+
siblings: import_zod12.z.array(import_zod12.z.string()).describe("Other components of the same variant, to implement alike."),
|
|
43630
|
+
target: import_zod12.z.string().optional().describe("The target language the variant scopes itself to, if any."),
|
|
43631
|
+
profile: import_zod12.z.string().optional().describe("The architectural profile it scopes itself to, if any.")
|
|
42462
43632
|
}).optional().describe(
|
|
42463
43633
|
"Derived, read-only guidance for a variant-tagged component \u2014 resolved from the variant registry, not part of the spec. Never write it back."
|
|
42464
43634
|
),
|
|
42465
|
-
resolvedSignatures:
|
|
42466
|
-
method:
|
|
42467
|
-
signatureFrom:
|
|
42468
|
-
signature:
|
|
42469
|
-
params:
|
|
42470
|
-
returns:
|
|
43635
|
+
resolvedSignatures: import_zod12.z.array(import_zod12.z.object({
|
|
43636
|
+
method: import_zod12.z.string().describe("The contract method that takes its signature from a source."),
|
|
43637
|
+
signatureFrom: import_zod12.z.string().describe("The source it names, as the spec holds it."),
|
|
43638
|
+
signature: import_zod12.z.string().describe("The text it shows, derived from the resolved params and returns."),
|
|
43639
|
+
params: import_zod12.z.array(import_zod12.z.record(import_zod12.z.unknown())).optional().describe("The params the source supplies; absent when it supplies none (unresolved, ambiguous or chained)."),
|
|
43640
|
+
returns: import_zod12.z.string().describe("The returns the source supplies (`unknown` when it supplies none).")
|
|
42471
43641
|
})).optional().describe(
|
|
42472
43642
|
"Derived, read-only: for a contract whose methods take their signature from a source, each such method's RESOLVED params, returns and text. The spec carries those methods in stored form (the signatureFrom alone) so it can be re-authored from as it is; never write these back beside the source."
|
|
42473
43643
|
),
|
|
@@ -42630,6 +43800,7 @@ var SPEC_WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
|
42630
43800
|
"sdd_rename_member_alias",
|
|
42631
43801
|
"sdd_rename_component",
|
|
42632
43802
|
"sdd_rename_method",
|
|
43803
|
+
"sdd_rename_type",
|
|
42633
43804
|
"sdd_add_component",
|
|
42634
43805
|
"sdd_define_interface",
|
|
42635
43806
|
"sdd_set_endpoints",
|
|
@@ -42651,10 +43822,10 @@ function reg(server, name, config, cb) {
|
|
|
42651
43822
|
if (result.isError !== true && SPEC_WRITE_TOOLS.has(name)) listChangedEmitters.get(server)?.();
|
|
42652
43823
|
return result;
|
|
42653
43824
|
};
|
|
42654
|
-
const strictConfig = config.inputSchema ? { ...config, inputSchema:
|
|
43825
|
+
const strictConfig = config.inputSchema ? { ...config, inputSchema: import_zod12.z.object(config.inputSchema).strict() } : config;
|
|
42655
43826
|
server.registerTool(name, strictConfig, guarded2);
|
|
42656
43827
|
}
|
|
42657
|
-
var statusInput =
|
|
43828
|
+
var statusInput = import_zod12.z.enum(STATUS_VALUES).optional().describe(
|
|
42658
43829
|
"The spec's lifecycle status. Omitted means draft for a NEW spec and the status already stored for a re-authoring, so a restatement never reopens a frozen spec. State it to author straight at design or complete instead of promoting afterwards. A status that would LOWER the stored one is refused \u2014 reopening a spec for revision is sdd_update_spec's job, which sets the demotion deliberately."
|
|
42659
43830
|
);
|
|
42660
43831
|
function createBareMcpServer(options = {}) {
|
|
@@ -42681,7 +43852,7 @@ function createBareMcpServer(options = {}) {
|
|
|
42681
43852
|
"listAgents",
|
|
42682
43853
|
{
|
|
42683
43854
|
description: "List all AI agents registered in this project. Returns id, name, description, domainRoot, template, tags, and status for each agent. Filter by domainId to scope to one domain.",
|
|
42684
|
-
inputSchema: { domainId:
|
|
43855
|
+
inputSchema: { domainId: import_zod12.z.string().optional() }
|
|
42685
43856
|
},
|
|
42686
43857
|
({ domainId }) => {
|
|
42687
43858
|
try {
|
|
@@ -42706,7 +43877,7 @@ function createBareMcpServer(options = {}) {
|
|
|
42706
43877
|
"getAgent",
|
|
42707
43878
|
{
|
|
42708
43879
|
description: "Get full details of a specific agent by id, including ownership rules, context, and output targets.",
|
|
42709
|
-
inputSchema: { id:
|
|
43880
|
+
inputSchema: { id: import_zod12.z.string() }
|
|
42710
43881
|
},
|
|
42711
43882
|
({ id }) => {
|
|
42712
43883
|
try {
|
|
@@ -42739,7 +43910,7 @@ function createBareMcpServer(options = {}) {
|
|
|
42739
43910
|
{
|
|
42740
43911
|
description: "Validate the project's agent topology. Returns errors, warnings and notices (duplicate ids, overlapping ownership, missing paths, etc.). Supports optional subsystem scoping.",
|
|
42741
43912
|
inputSchema: {
|
|
42742
|
-
subsystem:
|
|
43913
|
+
subsystem: import_zod12.z.string().optional().describe("Only validate topology for agents under the specified subsystem")
|
|
42743
43914
|
}
|
|
42744
43915
|
},
|
|
42745
43916
|
({ subsystem }) => {
|
|
@@ -42782,11 +43953,11 @@ function createBareMcpServer(options = {}) {
|
|
|
42782
43953
|
}
|
|
42783
43954
|
);
|
|
42784
43955
|
const systemInput = {
|
|
42785
|
-
name:
|
|
42786
|
-
vision:
|
|
42787
|
-
boundaries:
|
|
42788
|
-
globalRequirements:
|
|
42789
|
-
targetLanguage:
|
|
43956
|
+
name: import_zod12.z.string().describe("Overarching name of the project/system"),
|
|
43957
|
+
vision: import_zod12.z.string().describe("Vision, mission, and core goals of the system"),
|
|
43958
|
+
boundaries: import_zod12.z.array(import_zod12.z.union([import_zod12.z.string(), import_zod12.z.object({ name: import_zod12.z.string(), description: import_zod12.z.string().optional() }).strict()])).optional().describe("System boundary rules or scope statements (strings or name/description objects)"),
|
|
43959
|
+
globalRequirements: import_zod12.z.array(import_zod12.z.union([import_zod12.z.string(), import_zod12.z.object({ description: import_zod12.z.string() }).strict()])).optional().describe("Global functional and non-functional requirements (strings or description objects)"),
|
|
43960
|
+
targetLanguage: import_zod12.z.string().optional().describe('Default implementation language for the system (e.g. "typescript", "rust", "python"). Subsystems may override. Enables language-aware validation.')
|
|
42790
43961
|
};
|
|
42791
43962
|
const systemInputFields = Object.keys(systemInput);
|
|
42792
43963
|
reg(
|
|
@@ -42820,34 +43991,34 @@ function createBareMcpServer(options = {}) {
|
|
|
42820
43991
|
}
|
|
42821
43992
|
}
|
|
42822
43993
|
);
|
|
42823
|
-
const publicInterfaceItemInput =
|
|
42824
|
-
type:
|
|
42825
|
-
details:
|
|
42826
|
-
component:
|
|
42827
|
-
interface:
|
|
42828
|
-
consumers:
|
|
42829
|
-
from:
|
|
42830
|
-
typeDef:
|
|
42831
|
-
as:
|
|
43994
|
+
const publicInterfaceItemInput = import_zod12.z.object({
|
|
43995
|
+
type: import_zod12.z.enum(["REST", "GraphQL", "MessageBus", "RPC", "Custom"]).optional().describe("Transport kind of an own item (required on an own component item); a re-export inherits its target's"),
|
|
43996
|
+
details: import_zod12.z.string().optional().describe("Consumer-facing description of an own item (required on an own component item); a re-export inherits its target's"),
|
|
43997
|
+
component: import_zod12.z.string().optional().describe("For an own item, the L2 component that realizes it (this subsystem's published surface); for a re-export, the component re-exported from `from`"),
|
|
43998
|
+
interface: import_zod12.z.string().optional().describe("Optional L3 interface id the entry narrows to"),
|
|
43999
|
+
consumers: import_zod12.z.array(import_zod12.z.string()).optional().describe("The subsystem ids this surface is published to. Absent, any subsystem may depend on the component; present, only these may \u2014 when every entry publishing the component names consumers, the union of the lists is the whole set, and a dependency from any other subsystem is CROSS_SUBSYSTEM_UNLISTED_CONSUMER. Every id must name a subsystem of the tree (PUBLIC_INTERFACE_UNKNOWN_CONSUMER)."),
|
|
44000
|
+
from: import_zod12.z.string().optional().describe("Re-export source: another subsystem of this project. With neither component nor typeDef, the entry re-exports everything that subsystem exports (a wildcard)"),
|
|
44001
|
+
typeDef: import_zod12.z.string().optional().describe("A type exported as is: owned by this subsystem, or re-exported from `from`"),
|
|
44002
|
+
as: import_zod12.z.string().optional().describe("The public name; defaults to the narrowed interface, then the component or type id. Must fit [a-z0-9-_]+ (EXPORT_INVALID otherwise)")
|
|
42832
44003
|
}).strict();
|
|
42833
44004
|
const subsystemInput = {
|
|
42834
|
-
id:
|
|
42835
|
-
name:
|
|
42836
|
-
description:
|
|
42837
|
-
publicInterfaces:
|
|
42838
|
-
projectPath:
|
|
42839
|
-
targetLanguage:
|
|
42840
|
-
profile:
|
|
42841
|
-
designDepth:
|
|
42842
|
-
trustedLinks:
|
|
42843
|
-
subsystem:
|
|
42844
|
-
reason:
|
|
44005
|
+
id: import_zod12.z.string().describe("Lowercase identifier for the subsystem"),
|
|
44006
|
+
name: import_zod12.z.string().describe("Human-readable display name"),
|
|
44007
|
+
description: import_zod12.z.string().describe("Purpose and details of the subsystem"),
|
|
44008
|
+
publicInterfaces: import_zod12.z.array(publicInterfaceItemInput).optional().describe("The subsystem's export table: its own entrypoints, each bound to a realizing component, and re-exports of what other subsystems of this project export"),
|
|
44009
|
+
projectPath: import_zod12.z.string().optional().describe("REFUSED: the legacy L1 mount form. A subsystem is never a mount \u2014 declare a member project with sdd_add_member instead"),
|
|
44010
|
+
targetLanguage: import_zod12.z.string().optional().describe("Override of the system-level targetLanguage for this subsystem"),
|
|
44011
|
+
profile: import_zod12.z.string().optional().describe("Architectural profile override for this subsystem (built-ins: backend, frontend-reactive, frontend-controller, lowlevel-os, game-ecs, realtime-embedded, plc-cyclic; extension packs may add more \u2014 unknown names get UNKNOWN_PROFILE)"),
|
|
44012
|
+
designDepth: import_zod12.z.enum(["components", "interfaces", "implementations", "narratives"]).optional().describe("How deep THIS subsystem commits to designing (overrides project rules.designDepth; default narratives = full depth). Expectation checks below the depth are gated \u2014 soundness of authored content always applies."),
|
|
44013
|
+
trustedLinks: import_zod12.z.array(import_zod12.z.object({
|
|
44014
|
+
subsystem: import_zod12.z.string().describe("Peer subsystem id"),
|
|
44015
|
+
reason: import_zod12.z.string().describe('Why the coupling is sanctioned (e.g. "dispatch latency fast lane")')
|
|
42845
44016
|
}).strict()).optional().describe("Sanctioned tight couplings with peers \u2014 required to acknowledge a mutual subsystem dependency; the Adapter \u2192 published Portal shape still applies."),
|
|
42846
|
-
lifecycle:
|
|
42847
|
-
phase:
|
|
42848
|
-
component:
|
|
42849
|
-
method:
|
|
42850
|
-
description:
|
|
44017
|
+
lifecycle: import_zod12.z.array(import_zod12.z.object({
|
|
44018
|
+
phase: import_zod12.z.enum(["init", "shutdown", "cyclic", "interrupt", "scheduled"]).describe("Which lifecycle/execution flow this roots (cyclic = every scan/tick, interrupt = hardware/OS interrupt, scheduled = timer/cron)"),
|
|
44019
|
+
component: import_zod12.z.string().describe("Component id whose method the runtime invokes at this phase"),
|
|
44020
|
+
method: import_zod12.z.string().describe("Method name on that component's interface"),
|
|
44021
|
+
description: import_zod12.z.string().optional()
|
|
42851
44022
|
}).strict()).optional().describe("Declared execution-flow roots \u2014 reachability entrypoints alongside Portals/Observers. Only init flows feed the durable-Store hydration check (MISSING_HYDRATION); cyclic/interrupt/scheduled root non-request/response execution models (PLC scan, ISR, cron)."),
|
|
42852
44023
|
status: statusInput
|
|
42853
44024
|
};
|
|
@@ -42892,8 +44063,8 @@ function createBareMcpServer(options = {}) {
|
|
|
42892
44063
|
{
|
|
42893
44064
|
description: "Set (replace) an existing subsystem's export table (its publicInterfaces). An OWN item binds type + details to the component (and optional interface) that realizes it, or exports a type the subsystem owns (typeDef). A RE-EXPORT names another subsystem of the project in `from` and one component (optionally narrowed with `interface`) or one typeDef from what it exports, optionally renamed with `as` \u2014 `from` alone re-exports everything it exports; type and details are optional on a re-export, which inherits its target's. Use this to backfill bindings once the subsystem's components exist \u2014 cross-subsystem dependencies may only target a component its owning subsystem publishes; a re-export is a name, not a licence. A replacement, not a merge: an entry left out is removed. An own entry's identity is its component and interface, a re-export's its source, item and name, so a list naming one identity twice is refused. Written through the authoring seam as one gated delta, and answered with the change report \u2014 every entry added, changed or removed, or that nothing changed \u2014 as structured content beside the sentence.",
|
|
42894
44065
|
inputSchema: {
|
|
42895
|
-
subsystem:
|
|
42896
|
-
publicInterfaces:
|
|
44066
|
+
subsystem: import_zod12.z.string().describe("The L1 subsystem id to update"),
|
|
44067
|
+
publicInterfaces: import_zod12.z.array(publicInterfaceItemInput).describe("The full replacement list of the subsystem's export table: own items and re-exports")
|
|
42897
44068
|
},
|
|
42898
44069
|
outputSchema: specChangeReportOutput
|
|
42899
44070
|
},
|
|
@@ -42903,11 +44074,11 @@ function createBareMcpServer(options = {}) {
|
|
|
42903
44074
|
if (!sub) return errText(`Subsystem "${subsystem}" does not exist.`);
|
|
42904
44075
|
const delta = publicInterfacesReplacement(subsystem, sub.publicInterfaces ?? [], publicInterfaces);
|
|
42905
44076
|
if (typeof delta === "string") return errText(delta);
|
|
42906
|
-
const
|
|
44077
|
+
const report3 = updateSpecGated("subsystem", subsystem, delta);
|
|
42907
44078
|
return structured(
|
|
42908
44079
|
`Updated public interfaces for subsystem "${subsystem}" (${publicInterfaces.length} ${publicInterfaces.length === 1 ? "entry" : "entries"}).
|
|
42909
|
-
${renderChangeReport(
|
|
42910
|
-
|
|
44080
|
+
${renderChangeReport(report3)}`,
|
|
44081
|
+
report3
|
|
42911
44082
|
);
|
|
42912
44083
|
} catch (e) {
|
|
42913
44084
|
return errMessage(e);
|
|
@@ -42920,10 +44091,10 @@ ${renderChangeReport(report2)}`,
|
|
|
42920
44091
|
{
|
|
42921
44092
|
description: "Create a member of the bound project at `source`, in the one members grammar: `services/scheduler` (contained), `../admin` (a sibling checkout), `git@host:acme/payments.git` (a git repository, pinned at its default branch head unless `#<commit>` is given). By default a PART (stage 8): a piece of this project stored in another folder or repository, whose subsystems are this project's own (local ids, the ordinary subsystem rules, this project's lock); it gets only a specs folder, plus a configuration naming this project when it is not contained. With `as: project` an independent PROJECT instead: its project content is created \u2014 a project.yaml declaring the alias as its id, its L0, and the bound project's required packs (composition.requirePolicies) once \u2014 and it is reached only as `alias::name` through its L0 exports. What a member is follows from that content. A git member is not scaffolded; the repository's content decides what it is. Boundaries are earned: create a part unless the piece needs its own team, release, approval or public surface; sdd_promote_member makes one later. Idempotent \u2014 the same call again writes nothing; a different member under the alias is refused.",
|
|
42922
44093
|
inputSchema: {
|
|
42923
|
-
alias:
|
|
42924
|
-
source:
|
|
42925
|
-
description:
|
|
42926
|
-
as:
|
|
44094
|
+
alias: import_zod12.z.string().describe("The member's alias ([a-z0-9-_]+); a project's new id"),
|
|
44095
|
+
source: import_zod12.z.string().describe("A contained path, a `../` sibling path, or a git URL (optionally `#<commit>`)"),
|
|
44096
|
+
description: import_zod12.z.string().optional().describe("What the member is to this project; also the vision of a bootstrapped project L0"),
|
|
44097
|
+
as: import_zod12.z.enum(["part", "project"]).optional().describe("project to create the project content; omitted creates a part")
|
|
42927
44098
|
},
|
|
42928
44099
|
outputSchema: memberCreationOutput
|
|
42929
44100
|
},
|
|
@@ -42944,8 +44115,8 @@ ${renderChangeReport(report2)}`,
|
|
|
42944
44115
|
{
|
|
42945
44116
|
description: "What selecting (or updating to) an installed pack would change on the bound project, writing nothing \u2014 the pack's doctrine against wairon's defaults (rules loosened, raised, turned off or added; profiles, stereotype fencing, edge licenses, patterns, guarantees and language tables added, redefined or removed), which of its profiles would govern, and the findings that change here. A pack the project already applies exactly as asked is measured as removed, so the findings read as what it accounts for now. Nothing in it is a finding: packs exist to adjust wairon's checks, and a loosening is stated like any other change. Apply a pack with `wairon pack use`.",
|
|
42946
44117
|
inputSchema: {
|
|
42947
|
-
pack:
|
|
42948
|
-
version:
|
|
44118
|
+
pack: import_zod12.z.string().describe("The pack name"),
|
|
44119
|
+
version: import_zod12.z.string().optional().describe("An exact version; omitted, the latest installed")
|
|
42949
44120
|
},
|
|
42950
44121
|
outputSchema: packImpactOutput
|
|
42951
44122
|
},
|
|
@@ -42970,8 +44141,8 @@ ${renderChangeReport(report2)}`,
|
|
|
42970
44141
|
{
|
|
42971
44142
|
description: "Relocate a member's directory on disk and point its `members` entry there in one step (a member still declared in the legacy L1 form is moved into `members` first). Errors if the alias declares no member, or the new path escapes the project or already exists.",
|
|
42972
44143
|
inputSchema: {
|
|
42973
|
-
alias:
|
|
42974
|
-
newPath:
|
|
44144
|
+
alias: import_zod12.z.string().describe("The member's alias"),
|
|
44145
|
+
newPath: import_zod12.z.string().describe("The member's new root, relative to the bound project")
|
|
42975
44146
|
}
|
|
42976
44147
|
},
|
|
42977
44148
|
({ alias, newPath }) => {
|
|
@@ -42983,16 +44154,16 @@ ${renderChangeReport(report2)}`,
|
|
|
42983
44154
|
}
|
|
42984
44155
|
}
|
|
42985
44156
|
);
|
|
42986
|
-
const dryRunArg =
|
|
44157
|
+
const dryRunArg = import_zod12.z.boolean().optional().describe("Answer the plan and write nothing \u2014 run this first and show the plan");
|
|
42987
44158
|
reg(
|
|
42988
44159
|
server,
|
|
42989
44160
|
"sdd_externalize_subsystem",
|
|
42990
44161
|
{
|
|
42991
44162
|
description: "Move an internal subsystem out to the path. By default (stage 8) into a PART \u2014 a storage move: the subsystem's specs move to that directory (a new part, or the existing part there), and nothing else changes: no reference, export, external or lock entry, the same verdict. With `as: project`, into a member PROJECT instead, family-wide and all-or-nothing \u2014 the move followed by a promote: what crosses the new boundary exported and imported, references respelled `alias::name`, the new member's external for this project pinned, and every other family project's references checked to still resolve (a reference that would need a component made public refuses the plan). Source code is not moved. dryRun answers the plan and writes nothing; run it first and show the plan. Never locks: the answer names the projects to re-lock.",
|
|
42992
44163
|
inputSchema: {
|
|
42993
|
-
subsystem:
|
|
42994
|
-
path:
|
|
42995
|
-
as:
|
|
44164
|
+
subsystem: import_zod12.z.string().describe("The subsystem to move out"),
|
|
44165
|
+
path: import_zod12.z.string().describe("The part's root, relative to the bound project (a new directory, or an existing part's)"),
|
|
44166
|
+
as: import_zod12.z.enum(["part", "project"]).optional().describe("part (default) or project"),
|
|
42996
44167
|
dryRun: dryRunArg
|
|
42997
44168
|
}
|
|
42998
44169
|
},
|
|
@@ -43004,8 +44175,8 @@ ${renderChangeReport(report2)}`,
|
|
|
43004
44175
|
{
|
|
43005
44176
|
description: "Promote a part of the bound project to an independent project in place (stage 8) \u2014 its files stay where they are; it gets an id, an L0 exporting exactly what the rest of the project uses of it, its references across the new boundary respelled `alias::name`, the parent declared as its external, and pins on both sides. Refused (each reason listed) for a part fetched from git, a trusted link that would cross the new boundary, a used component its subsystem does not publish, or an id already taken. All-or-nothing; dryRun answers the plan and writes nothing \u2014 run it first and show the plan. Never locks: the answer names the project to re-lock and the new one to lock.",
|
|
43006
44177
|
inputSchema: {
|
|
43007
|
-
alias:
|
|
43008
|
-
id:
|
|
44178
|
+
alias: import_zod12.z.string().describe("The part's alias"),
|
|
44179
|
+
id: import_zod12.z.string().optional().describe("The new project's id (default: the alias)"),
|
|
43009
44180
|
dryRun: dryRunArg
|
|
43010
44181
|
}
|
|
43011
44182
|
},
|
|
@@ -43017,11 +44188,11 @@ ${renderChangeReport(report2)}`,
|
|
|
43017
44188
|
{
|
|
43018
44189
|
description: "Demote a project member of the bound project to a part in place (stage 8) \u2014 sdd_promote_member's inverse: its files stay where they are; its own metadata goes to the homes the destination names (as sdd_internalize_member sends it), its L0, lock and pins end, its references across the old boundary become local ids, and its configuration is reduced to naming its parent. Refused while another family project consumes it (a part has no exports \u2014 each consumer listed), for a member fetched from git, or for internalize's reasons. All-or-nothing; dryRun answers the plan and writes nothing \u2014 run it first and show the plan. Never locks.",
|
|
43019
44190
|
inputSchema: {
|
|
43020
|
-
alias:
|
|
43021
|
-
destination:
|
|
43022
|
-
home:
|
|
43023
|
-
packs:
|
|
43024
|
-
exports:
|
|
44191
|
+
alias: import_zod12.z.string().describe("The project member's alias"),
|
|
44192
|
+
destination: import_zod12.z.object({
|
|
44193
|
+
home: import_zod12.z.string().optional().describe("The subsystem that receives the member's L0 vision"),
|
|
44194
|
+
packs: import_zod12.z.enum(["adopt", "drop"]).optional().describe("adopt | drop: packs only the member selects"),
|
|
44195
|
+
exports: import_zod12.z.array(import_zod12.z.string()).optional().describe("Public names of the member the bound project exports afterwards")
|
|
43025
44196
|
}).optional().describe("Where its own metadata goes (its home subsystem, packs to adopt or drop)"),
|
|
43026
44197
|
dryRun: dryRunArg
|
|
43027
44198
|
}
|
|
@@ -43038,10 +44209,10 @@ ${renderChangeReport(report2)}`,
|
|
|
43038
44209
|
{
|
|
43039
44210
|
description: "Fold a member \u2014 every subsystem of it \u2014 back into the bound project, sending its own metadata to the destination (its L0 vision to the `into` subsystem's description; its requirements, boundaries and databases to the bound L0; its language, profile and depth onto the moved subsystems; its members and externals to the bound project's; its packs adopted or dropped as `packs` says) and re-pointing every other family project that consumed it at the bound project. What has no home \u2014 its lock, pins, derived outputs \u2014 is listed as deleted. Refused for a member carrying conformance debt, a pack only it selects with no `packs` answer, or a name collision. All-or-nothing; dryRun answers the plan and writes nothing; run it first and show the plan. Never locks.",
|
|
43040
44211
|
inputSchema: {
|
|
43041
|
-
alias:
|
|
43042
|
-
into:
|
|
43043
|
-
packs:
|
|
43044
|
-
exports:
|
|
44212
|
+
alias: import_zod12.z.string().describe("The member's alias"),
|
|
44213
|
+
into: import_zod12.z.string().optional().describe("The home subsystem for the member's L0 vision; required when it holds several subsystems"),
|
|
44214
|
+
packs: import_zod12.z.enum(["adopt", "drop"]).optional().describe("adopt | drop: packs only the member selects"),
|
|
44215
|
+
exports: import_zod12.z.array(import_zod12.z.string()).optional().describe("Extra public names of the member the bound project exports afterwards"),
|
|
43045
44216
|
dryRun: dryRunArg
|
|
43046
44217
|
}
|
|
43047
44218
|
},
|
|
@@ -43057,9 +44228,9 @@ ${renderChangeReport(report2)}`,
|
|
|
43057
44228
|
{
|
|
43058
44229
|
description: "Make an existing project at the path a member of the bound project, keeping its L0, subsystems, packs and lock (sdd_add_member scaffolds a new one instead). Refused when its id collides with a family project's. All-or-nothing; dryRun answers the plan and writes nothing. Never locks.",
|
|
43059
44230
|
inputSchema: {
|
|
43060
|
-
alias:
|
|
43061
|
-
path:
|
|
43062
|
-
description:
|
|
44231
|
+
alias: import_zod12.z.string().describe("The alias to declare ([a-z0-9-_]+)"),
|
|
44232
|
+
path: import_zod12.z.string().describe("The project's root, relative to the bound project"),
|
|
44233
|
+
description: import_zod12.z.string().optional().describe("What the member is to this project"),
|
|
43063
44234
|
dryRun: dryRunArg
|
|
43064
44235
|
}
|
|
43065
44236
|
},
|
|
@@ -43071,8 +44242,8 @@ ${renderChangeReport(report2)}`,
|
|
|
43071
44242
|
{
|
|
43072
44243
|
description: "Move a project's id \u2014 the bound project's, or a member's named by its alias path \u2014 and every reference to the old id across the family (aliases that were the id, their references and re-exports, externals naming it, pins). The whole family must be in reach. Every project it writes must be re-locked; the answer names them. All-or-nothing; dryRun answers the plan and writes nothing; run it first and show the plan.",
|
|
43073
44244
|
inputSchema: {
|
|
43074
|
-
newId:
|
|
43075
|
-
project:
|
|
44245
|
+
newId: import_zod12.z.string().describe("The new project id"),
|
|
44246
|
+
project: import_zod12.z.string().optional().describe("The member's alias path from the bound project (e.g. billing/payments); the bound project when omitted"),
|
|
43076
44247
|
dryRun: dryRunArg
|
|
43077
44248
|
}
|
|
43078
44249
|
},
|
|
@@ -43084,8 +44255,8 @@ ${renderChangeReport(report2)}`,
|
|
|
43084
44255
|
{
|
|
43085
44256
|
description: "Rename one alias of the bound project (a member or an external) and respell the bound project's references through it; nothing in any member or sibling changes. All-or-nothing; dryRun answers the plan and writes nothing. Never locks.",
|
|
43086
44257
|
inputSchema: {
|
|
43087
|
-
alias:
|
|
43088
|
-
newAlias:
|
|
44258
|
+
alias: import_zod12.z.string().describe("The alias as declared now"),
|
|
44259
|
+
newAlias: import_zod12.z.string().describe("The new alias"),
|
|
43089
44260
|
dryRun: dryRunArg
|
|
43090
44261
|
}
|
|
43091
44262
|
},
|
|
@@ -43097,8 +44268,8 @@ ${renderChangeReport(report2)}`,
|
|
|
43097
44268
|
{
|
|
43098
44269
|
description: "Take a member out of the family; the bound project and every family consumer then reach it as an external by path, pinned. No reference text changes. Refused (audience-too-narrow, each export named with its users) while a family project uses an export the member gives the family alone, unless widen is set: then exactly those used exports are widened to the instance audience in the member's L0, each shown in the plan. All-or-nothing; dryRun answers the plan and writes nothing. Never locks.",
|
|
43099
44270
|
inputSchema: {
|
|
43100
|
-
alias:
|
|
43101
|
-
widen:
|
|
44271
|
+
alias: import_zod12.z.string().describe("The member's alias"),
|
|
44272
|
+
widen: import_zod12.z.boolean().optional().describe("Widen the used family-only exports to the instance audience instead of refusing"),
|
|
43102
44273
|
dryRun: dryRunArg
|
|
43103
44274
|
}
|
|
43104
44275
|
},
|
|
@@ -43110,8 +44281,8 @@ ${renderChangeReport(report2)}`,
|
|
|
43110
44281
|
{
|
|
43111
44282
|
description: "Make the bound project's external a member \u2014 sdd_detach_member's inverse. Locally the external is found by a path inside the bound project and adopted where it is; on a hosted instance it names a project by source.hosted and `path` says where to adopt it (the hosting server relocates it there). All-or-nothing; dryRun answers the plan and writes nothing. Never locks.",
|
|
43112
44283
|
inputSchema: {
|
|
43113
|
-
alias:
|
|
43114
|
-
path:
|
|
44284
|
+
alias: import_zod12.z.string().describe("The external's alias"),
|
|
44285
|
+
path: import_zod12.z.string().optional().describe("Hosted: the member path to adopt a source.hosted external at, relative to the bound project; a source.path external is adopted where it is"),
|
|
43115
44286
|
dryRun: dryRunArg
|
|
43116
44287
|
}
|
|
43117
44288
|
},
|
|
@@ -43123,8 +44294,8 @@ ${renderChangeReport(report2)}`,
|
|
|
43123
44294
|
{
|
|
43124
44295
|
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.",
|
|
43125
44296
|
inputSchema: {
|
|
43126
|
-
id:
|
|
43127
|
-
newId:
|
|
44297
|
+
id: import_zod12.z.string().describe("The component to rename (namespaced if needed)"),
|
|
44298
|
+
newId: import_zod12.z.string().describe("Its new id: a lowercase identifier with no namespace separator")
|
|
43128
44299
|
}
|
|
43129
44300
|
},
|
|
43130
44301
|
({ id, newId }) => {
|
|
@@ -43141,10 +44312,10 @@ ${renderChangeReport(report2)}`,
|
|
|
43141
44312
|
{
|
|
43142
44313
|
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.",
|
|
43143
44314
|
inputSchema: {
|
|
43144
|
-
id:
|
|
43145
|
-
method:
|
|
43146
|
-
newName:
|
|
43147
|
-
pinSymbol:
|
|
44315
|
+
id: import_zod12.z.string().describe("The component whose method is renamed (namespaced if needed)"),
|
|
44316
|
+
method: import_zod12.z.string().describe("The method name as it stands"),
|
|
44317
|
+
newName: import_zod12.z.string().describe("Its new name: a camel-case identifier"),
|
|
44318
|
+
pinSymbol: import_zod12.z.boolean().optional().describe("Whether an implementation that declares no symbol is pinned to the old name so its function still binds; true when omitted")
|
|
43148
44319
|
}
|
|
43149
44320
|
},
|
|
43150
44321
|
({ id, method, newName, pinSymbol }) => {
|
|
@@ -43155,16 +44326,36 @@ ${renderChangeReport(report2)}`,
|
|
|
43155
44326
|
}
|
|
43156
44327
|
}
|
|
43157
44328
|
);
|
|
44329
|
+
reg(
|
|
44330
|
+
server,
|
|
44331
|
+
"sdd_rename_type",
|
|
44332
|
+
{
|
|
44333
|
+
description: "Rename a type and rewrite every reference to it in the bound tree: every type position naming it (contract and type-method params and returns, fields, signature-type params and returns), a signatureFrom naming it as a signature type, and an L1 or L0 export entry's typeDef. Only the named members of a type expression that name this type are respelled, in the style they were written (`Invoice` \u2192 `Bill`, `invoice` \u2192 `bill`); the rest of the text stays as written. The type moves to the new id and file under the same owner, and its old id joins its rename trace (previousIds) so a consumer of the design export reads the rename as a rename; an export entry that derived its public name from the old id gets `as: <that name>` first, so the published name and every consumer's pin stay. Rename traces are never rewritten. Findings keyed on the type follow it: lint allows naming it, and every debt-register entry anchored on it, rewritten in place (a register that cannot be rewritten that precisely is refused before the first write). The display name is left as it is. Refuses, writing nothing: a type that does not exist (type-missing), one in another project (chained-type), a new id that is not a lowercase identifier (invalid-id), and a new id another type of the same owner holds (id-taken) or retired (id-retired \u2014 unsetting the holder's previousIds releases it). Returns from and to, the specs rewritten, keptPublicNames and `carried`: each register edit.",
|
|
44334
|
+
inputSchema: {
|
|
44335
|
+
id: import_zod12.z.string().describe("The type to rename (qualified by its owning subsystem if needed, `subsystem::id`)"),
|
|
44336
|
+
newId: import_zod12.z.string().describe("Its new id: a lowercase identifier with no namespace separator")
|
|
44337
|
+
}
|
|
44338
|
+
},
|
|
44339
|
+
({ id, newId }) => {
|
|
44340
|
+
try {
|
|
44341
|
+
const bare = id.startsWith("::") ? id.slice(2) : id;
|
|
44342
|
+
const resolved = loadTypeSpec(bare) ? bare : id;
|
|
44343
|
+
return json(renameType(resolved, newId));
|
|
44344
|
+
} catch (e) {
|
|
44345
|
+
return errText(String(e));
|
|
44346
|
+
}
|
|
44347
|
+
}
|
|
44348
|
+
);
|
|
43158
44349
|
reg(
|
|
43159
44350
|
server,
|
|
43160
44351
|
"sdd_move_methods",
|
|
43161
44352
|
{
|
|
43162
44353
|
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.",
|
|
43163
44354
|
inputSchema: {
|
|
43164
|
-
from:
|
|
43165
|
-
to:
|
|
43166
|
-
methods:
|
|
43167
|
-
dryRun:
|
|
44355
|
+
from: import_zod12.z.string().describe("The component the methods belong to (namespaced if needed)"),
|
|
44356
|
+
to: import_zod12.z.string().describe("The component that should receive them (namespaced if needed)"),
|
|
44357
|
+
methods: import_zod12.z.array(import_zod12.z.string()).describe("The method names to move; every one must exist on the source contract"),
|
|
44358
|
+
dryRun: import_zod12.z.boolean().optional().describe("Answer with what the move would do and write nothing")
|
|
43168
44359
|
}
|
|
43169
44360
|
},
|
|
43170
44361
|
({ from, to, methods, dryRun }) => {
|
|
@@ -43180,39 +44371,39 @@ ${renderChangeReport(report2)}`,
|
|
|
43180
44371
|
}
|
|
43181
44372
|
);
|
|
43182
44373
|
const componentInput = {
|
|
43183
|
-
id:
|
|
43184
|
-
name:
|
|
43185
|
-
description:
|
|
43186
|
-
subsystem:
|
|
43187
|
-
componentType:
|
|
43188
|
-
owns:
|
|
43189
|
-
dependsOn:
|
|
43190
|
-
portalType:
|
|
43191
|
-
basePath:
|
|
43192
|
-
dispatch:
|
|
43193
|
-
capability:
|
|
43194
|
-
component:
|
|
43195
|
-
method:
|
|
43196
|
-
description:
|
|
44374
|
+
id: import_zod12.z.string().describe("Lowercase identifier for the component"),
|
|
44375
|
+
name: import_zod12.z.string().describe("Human-readable display name"),
|
|
44376
|
+
description: import_zod12.z.string().describe("Responsibility / internal architecture details"),
|
|
44377
|
+
subsystem: import_zod12.z.string().describe("The L1 subsystem ID this component belongs to"),
|
|
44378
|
+
componentType: import_zod12.z.enum(["Portal", "Orchestrator", "Supervisor", "Actor", "Store", "Index", "Query", "Registry", "Adapter", "Observer", "Repository"]).describe("The building block, or the pattern Repository. Specialist and Gateway are retired and cannot be authored: logic is an Orchestrator with a dependencyClass, a gateway is a Portal with the gateway variant"),
|
|
44379
|
+
owns: import_zod12.z.array(import_zod12.z.string()).optional().describe("Member block ids privately owned by this component (patterns only)"),
|
|
44380
|
+
dependsOn: import_zod12.z.array(import_zod12.z.string()).optional().describe("IDs of other components this collaborates with (facades or standalone blocks)"),
|
|
44381
|
+
portalType: import_zod12.z.enum(["HTTP_API", "gRPC", "GraphQL", "MessageBus", "CLI", "NamedPipe", "IPC", "Custom"]).optional().describe("Portal-only, and expected on every Portal. OMIT IT on any other componentType \u2014 passing it there is refused at the write (UNEXPECTED_PORTAL_FIELD), nothing is saved."),
|
|
44382
|
+
basePath: import_zod12.z.string().optional().describe("Portal-only: base path/prefix all the portal's endpoints mount under. OMIT IT on any other componentType \u2014 passing it there is refused at the write (UNEXPECTED_PORTAL_FIELD), nothing is saved."),
|
|
44383
|
+
dispatch: import_zod12.z.array(import_zod12.z.object({
|
|
44384
|
+
capability: import_zod12.z.string().describe('Capability name exactly as dispatched at runtime (e.g. "shadow_module.get")'),
|
|
44385
|
+
component: import_zod12.z.string().describe("Component id serving this capability (must also appear under dependsOn/owns)"),
|
|
44386
|
+
method: import_zod12.z.string().describe("Method name on the serving component's interface"),
|
|
44387
|
+
description: import_zod12.z.string().optional()
|
|
43197
44388
|
}).strict()).optional().describe("Portal-only: capability \u2192 component.method dispatch table for generic-handle portals. Gives the reachability walker real edges and is validated against target interfaces (UNSERVED_CAPABILITY)."),
|
|
43198
|
-
mounts:
|
|
43199
|
-
portal:
|
|
43200
|
-
prefixes:
|
|
43201
|
-
via:
|
|
44389
|
+
mounts: import_zod12.z.array(import_zod12.z.object({
|
|
44390
|
+
portal: import_zod12.z.string().describe("The mounted Portal's component id"),
|
|
44391
|
+
prefixes: import_zod12.z.array(import_zod12.z.string()).describe('The path prefixes this listener routes to the portal. A path lies under a prefix when it equals it or continues it past a slash, so "/" covers only the root itself'),
|
|
44392
|
+
via: import_zod12.z.string().optional().describe("The router entry the listener calls to hand the portal its request, exported by the PORTAL's own file (held to it: UNREALIZED_EXPORT_HANDLE). Omit when the listener calls the portal's contract methods directly, route by route")
|
|
43202
44393
|
}).strict()).optional().describe("Portal-only: the portals this LISTENER serves, each under its path prefixes and through its router entry. Declaring the field \u2014 even as an empty array \u2014 marks this portal as a listener, the one kind of portal nothing else needs to mount. Checked by portal-mounts: a mount must name a Portal (MOUNT_TARGET_NOT_PORTAL), every HTTP endpoint of a mounted portal must lie under one of its prefixes (ENDPOINT_OUTSIDE_MOUNT), and a portal with HTTP endpoints that is neither a listener nor mounted by one is reported (UNMOUNTED_PORTAL)."),
|
|
43203
|
-
durability:
|
|
43204
|
-
dependencyClass:
|
|
43205
|
-
emits:
|
|
43206
|
-
topic:
|
|
43207
|
-
event:
|
|
43208
|
-
description:
|
|
44394
|
+
durability: import_zod12.z.enum(["ram-projection", "durable", "read-through", "cache"]).optional().describe("Store-only \u2014 OMIT IT on any other componentType, where it is refused at the write (DURABILITY_ON_NON_STORE) and nothing is saved. Every Store should declare one (MISSING_DURABILITY): durable = persisted RAM projection (hydration read-back from a lifecycle init entrypoint required \u2014 MISSING_HYDRATION); read-through = persisted with no RAM copy (every read is the read-back, hydration exempt); ram-projection = rebuilt not restored; cache = evictable loss-safe memo state."),
|
|
44395
|
+
dependencyClass: import_zod12.z.enum(["pure", "read"]).optional().describe("Orchestrator-only \u2014 OMIT IT on any other componentType, where it is refused at the write (DEPENDENCY_CLASS_ON_NON_ORCHESTRATOR) and nothing is saved. Declares what logic may depend on, enforced as a Store's durability is (DEPENDENCY_CLASS_VIOLATION): pure = depends only on pure Orchestrators (a computation over the values it is handed, e.g. an arbiter or codec); read = also on read Orchestrators, Repositories, Indexes and Adapters, never calling their write methods; unset = a workflow."),
|
|
44396
|
+
emits: import_zod12.z.array(import_zod12.z.object({
|
|
44397
|
+
topic: import_zod12.z.string().describe("Topic/channel name exactly as used on the bus"),
|
|
44398
|
+
event: import_zod12.z.string().optional().describe("Optional event name within the topic (informational; pairing is by topic)"),
|
|
44399
|
+
description: import_zod12.z.string().optional()
|
|
43209
44400
|
}).strict()).optional().describe("Topics this component publishes \u2014 every emitted topic needs a subscriber somewhere in the tree (UNCONSUMED_TOPIC)."),
|
|
43210
|
-
subscribesTo:
|
|
43211
|
-
topic:
|
|
43212
|
-
event:
|
|
43213
|
-
description:
|
|
44401
|
+
subscribesTo: import_zod12.z.array(import_zod12.z.object({
|
|
44402
|
+
topic: import_zod12.z.string().describe("Topic/channel name exactly as used on the bus"),
|
|
44403
|
+
event: import_zod12.z.string().optional(),
|
|
44404
|
+
description: import_zod12.z.string().optional()
|
|
43214
44405
|
}).strict()).optional().describe("Topics this component consumes (typical on Observers) \u2014 every subscription needs an emitter somewhere in the tree (UNSOURCED_SUBSCRIPTION)."),
|
|
43215
|
-
ext:
|
|
44406
|
+
ext: import_zod12.z.record(import_zod12.z.unknown()).optional().describe('Opaque pack/tool extension data (namespaced keys, e.g. "mypack:priority") \u2014 preserved verbatim, never validated or interpreted by the core'),
|
|
43216
44407
|
status: statusInput
|
|
43217
44408
|
};
|
|
43218
44409
|
const componentInputFields = Object.keys(componentInput);
|
|
@@ -43260,45 +44451,45 @@ ${renderChangeReport(report2)}`,
|
|
|
43260
44451
|
}
|
|
43261
44452
|
}
|
|
43262
44453
|
);
|
|
43263
|
-
const methodParamItem =
|
|
43264
|
-
name:
|
|
43265
|
-
type:
|
|
43266
|
-
description:
|
|
43267
|
-
optional:
|
|
44454
|
+
const methodParamItem = import_zod12.z.object({
|
|
44455
|
+
name: import_zod12.z.string(),
|
|
44456
|
+
type: import_zod12.z.string().describe(TYPE_REF_GRAMMAR("The parameter's type")),
|
|
44457
|
+
description: import_zod12.z.string().optional(),
|
|
44458
|
+
optional: import_zod12.z.boolean().optional().describe(
|
|
43268
44459
|
'Whether the parameter may be OMITTED by a caller. It is not nullability: a parameter that must be passed but may be passed as nothing is a required parameter whose type says so \u2014 "ProjectConfig?". Say whichever is true; they are different contracts (both together: may be left out, and may be none).'
|
|
43269
44460
|
)
|
|
43270
44461
|
}).strict();
|
|
43271
44462
|
const interfaceMethodShape = {
|
|
43272
|
-
name:
|
|
43273
|
-
description:
|
|
43274
|
-
signature:
|
|
44463
|
+
name: import_zod12.z.string(),
|
|
44464
|
+
description: import_zod12.z.string(),
|
|
44465
|
+
signature: import_zod12.z.string().optional().describe(
|
|
43275
44466
|
"Prose signature \u2014 only for a method WITHOUT params. With params the server derives and writes the text (`name(a: T, b?: U): R`) and ignores this one (a notice names one that differed); a method with a signatureFrom states none."
|
|
43276
44467
|
),
|
|
43277
|
-
returns:
|
|
43278
|
-
signatureFrom:
|
|
44468
|
+
returns: import_zod12.z.string().optional().describe(TYPE_REF_GRAMMAR("The type the method answers with. Required unless signatureFrom is set, whose source supplies it")),
|
|
44469
|
+
signatureFrom: import_zod12.z.string().min(1).optional().describe(
|
|
43279
44470
|
"Take this method's params and returns from ONE source instead of stating them: a signature type id (`billing.change_listener`, `alias::name`) or a contract method `component.method` whose component this one names in dependsOn or owns (no chains). State it ALONE \u2014 params or returns beside it are refused (SIGNATURE_SOURCE_RESTATED). A value that names both a method and a signature type is ambiguous: qualify it."
|
|
43280
44471
|
),
|
|
43281
|
-
params:
|
|
43282
|
-
guarantees:
|
|
43283
|
-
effect:
|
|
43284
|
-
invokedBy:
|
|
43285
|
-
kind:
|
|
43286
|
-
caller:
|
|
44472
|
+
params: import_zod12.z.array(methodParamItem).optional().describe("Structured parameters \u2014 authoritative for type checking, and the signature text is derived from them. Strongly preferred."),
|
|
44473
|
+
guarantees: import_zod12.z.array(import_zod12.z.string().min(1)).optional().describe("Semantic guarantees the method promises (combinable); any guarantee a narrative step asserts must be declared here. Builtin tokens: idempotent | atomic | transactional | exactly-once; extension packs may declare more (any other token is UNKNOWN_GUARANTEE)"),
|
|
44474
|
+
effect: import_zod12.z.enum(["read", "write", "lifecycle"]).optional().describe("What the method does to the component's held state: read observes it; write modifies an entity's domain fields; lifecycle creates, destroys, or (un)registers an entity's existence or membership without modifying its fields, and calls only read and lifecycle methods (LIFECYCLE_CALLS_WRITE). Required on a durable Store's contract methods so the durability round-trip rule can pair mutations with hydration read-backs; a Supervisor may call a data component it does not own only through read and lifecycle methods (SUPERVISOR_WRITE_SHORTCUT)"),
|
|
44475
|
+
invokedBy: import_zod12.z.object({
|
|
44476
|
+
kind: import_zod12.z.enum(["runtime", "external", "sibling-subsystem"]).describe("Who owns the out-of-graph invocation: runtime (timer/signal/shutdown hook), external (a system outside this project), sibling-subsystem (a modeled sibling whose edge is not narrated here)"),
|
|
44477
|
+
caller: import_zod12.z.string().optional().describe("WHO invokes it and when, as reviewable prose \u2014 missing or placeholder-thin prose is INVOKED_BY_UNDESCRIBED")
|
|
43287
44478
|
}).strict().optional().describe("Typed acknowledgment of a real caller OUTSIDE the modeled narrative graph. Unused-detection seeds the method as an entrypoint so reachability propagates through its narrative (unlike lint.allow); a method the internal walk already reaches is flagged stale (INVOKED_BY_REDUNDANT). Prefer a `register` narrative step when the wiring is internal."),
|
|
43288
|
-
findings:
|
|
43289
|
-
code:
|
|
43290
|
-
severity:
|
|
43291
|
-
summary:
|
|
44479
|
+
findings: import_zod12.z.array(import_zod12.z.object({
|
|
44480
|
+
code: import_zod12.z.string().describe("UPPER_SNAKE finding code, unique within the method; a pack's codes carry the pack prefix (<PACK>_<CODE>)"),
|
|
44481
|
+
severity: import_zod12.z.enum(["error", "warning", "notice"]).describe("Default severity, before project severity overrides and draft-context downgrades. A notice is reported but never fails the gate"),
|
|
44482
|
+
summary: import_zod12.z.string().describe("One line saying what the finding means")
|
|
43292
44483
|
}).strict()).optional().describe("The finding codes this method can report, each with its default severity and summary. Each declared code must be anchored in the method's source file, as a string literal or a property-access name (UNREALIZED_FINDING). A code is declared once per method; sdd_update_spec upserts and deletes findings by code."),
|
|
43293
|
-
ext:
|
|
44484
|
+
ext: import_zod12.z.record(import_zod12.z.unknown()).optional().describe("Opaque pack/tool extension data for this method (namespaced keys) \u2014 preserved verbatim")
|
|
43294
44485
|
};
|
|
43295
44486
|
const interfaceMethodInputFields = Object.keys(interfaceMethodShape);
|
|
43296
44487
|
const interfaceInput = {
|
|
43297
|
-
id:
|
|
43298
|
-
name:
|
|
43299
|
-
description:
|
|
43300
|
-
component:
|
|
43301
|
-
methods:
|
|
44488
|
+
id: import_zod12.z.string().describe('Lowercase identifier prefixed with "i", e.g. "istorage"'),
|
|
44489
|
+
name: import_zod12.z.string().describe("Human-readable contract name"),
|
|
44490
|
+
description: import_zod12.z.string().describe("Contract description and obligations"),
|
|
44491
|
+
component: import_zod12.z.string().describe("The L2 component ID this interface belongs to"),
|
|
44492
|
+
methods: import_zod12.z.array(import_zod12.z.object(interfaceMethodShape).strict()).optional().describe("List of method signature contracts"),
|
|
43302
44493
|
status: statusInput
|
|
43303
44494
|
};
|
|
43304
44495
|
const interfaceInputFields = Object.keys(interfaceInput);
|
|
@@ -43335,24 +44526,24 @@ ${renderChangeReport(report2)}`,
|
|
|
43335
44526
|
{
|
|
43336
44527
|
description: "Bind concrete wire endpoints to existing L3 interface methods (required for every Portal). Pick `transport` and fill that transport's address fields. Run after sdd_define_interface. Written through the authoring seam as one gated delta, and answered with the change report \u2014 every binding set or changed, or that nothing changed \u2014 as structured content beside the sentence.",
|
|
43337
44528
|
inputSchema: {
|
|
43338
|
-
interface:
|
|
43339
|
-
endpoints:
|
|
43340
|
-
method:
|
|
43341
|
-
transport:
|
|
43342
|
-
httpMethod:
|
|
43343
|
-
path:
|
|
43344
|
-
service:
|
|
43345
|
-
rpcMethod:
|
|
43346
|
-
operation:
|
|
43347
|
-
field:
|
|
43348
|
-
topic:
|
|
43349
|
-
event:
|
|
43350
|
-
queue:
|
|
43351
|
-
direction:
|
|
43352
|
-
pipe:
|
|
43353
|
-
channel:
|
|
43354
|
-
command:
|
|
43355
|
-
address:
|
|
44529
|
+
interface: import_zod12.z.string().describe('The L3 interface ID (e.g. "ibilling-gateway")'),
|
|
44530
|
+
endpoints: import_zod12.z.array(import_zod12.z.object({
|
|
44531
|
+
method: import_zod12.z.string().describe("The NAME of the interface method to bind (not the HTTP verb)"),
|
|
44532
|
+
transport: import_zod12.z.enum(["HTTP", "gRPC", "GraphQL", "MessageBus", "NamedPipe", "IPC", "CLI", "Custom"]).describe("Wire protocol; must match the Portal's portalType"),
|
|
44533
|
+
httpMethod: import_zod12.z.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"]).optional().describe("HTTP: verb"),
|
|
44534
|
+
path: import_zod12.z.string().optional().describe('HTTP: route path, e.g. "/v1/checkout"'),
|
|
44535
|
+
service: import_zod12.z.string().optional().describe("gRPC: service name"),
|
|
44536
|
+
rpcMethod: import_zod12.z.string().optional().describe("gRPC: rpc method name"),
|
|
44537
|
+
operation: import_zod12.z.enum(["query", "mutation", "subscription"]).optional().describe("GraphQL: operation kind"),
|
|
44538
|
+
field: import_zod12.z.string().optional().describe("GraphQL: root field name"),
|
|
44539
|
+
topic: import_zod12.z.string().optional().describe("MessageBus: topic"),
|
|
44540
|
+
event: import_zod12.z.string().optional().describe("MessageBus: event name"),
|
|
44541
|
+
queue: import_zod12.z.string().optional().describe("MessageBus: optional queue/consumer group"),
|
|
44542
|
+
direction: import_zod12.z.enum(["subscribe", "publish"]).optional().describe("MessageBus: subscribe (default) or publish"),
|
|
44543
|
+
pipe: import_zod12.z.string().optional().describe('NamedPipe: pipe name, e.g. "\\\\.\\pipe\\gk-events"'),
|
|
44544
|
+
channel: import_zod12.z.string().optional().describe("IPC: channel name"),
|
|
44545
|
+
command: import_zod12.z.string().optional().describe("CLI: command/subcommand"),
|
|
44546
|
+
address: import_zod12.z.string().optional().describe("Custom: free-form address")
|
|
43356
44547
|
}).strict()).describe("One binding per method")
|
|
43357
44548
|
},
|
|
43358
44549
|
outputSchema: specChangeReportOutput
|
|
@@ -43394,80 +44585,80 @@ ${renderChangeReport(report2)}`,
|
|
|
43394
44585
|
methods.push({ name: e.method, endpoint: parsed.data });
|
|
43395
44586
|
bound2.push(`${e.method}\u2192${e.transport}`);
|
|
43396
44587
|
}
|
|
43397
|
-
const
|
|
44588
|
+
const report3 = updateSpecGated("interface", interfaceId, { methods });
|
|
43398
44589
|
return structured(
|
|
43399
44590
|
`Bound ${bound2.length} endpoint(s) on "${interfaceId}": ${bound2.join(", ")}.
|
|
43400
|
-
${renderChangeReport(
|
|
43401
|
-
|
|
44591
|
+
${renderChangeReport(report3)}`,
|
|
44592
|
+
report3
|
|
43402
44593
|
);
|
|
43403
44594
|
} catch (e) {
|
|
43404
44595
|
return errMessage(e);
|
|
43405
44596
|
}
|
|
43406
44597
|
}
|
|
43407
44598
|
);
|
|
43408
|
-
const stepNo = () =>
|
|
43409
|
-
const labelRef = () =>
|
|
43410
|
-
const narrativeStepInput =
|
|
44599
|
+
const stepNo = () => import_zod12.z.number().int().positive();
|
|
44600
|
+
const labelRef = () => import_zod12.z.string().min(1);
|
|
44601
|
+
const narrativeStepInput = import_zod12.z.object({
|
|
43411
44602
|
stepNumber: stepNo().optional().describe("Defaults to the 1-based array position \u2014 jump fields reference these numbers"),
|
|
43412
44603
|
label: labelRef().optional().describe("Optional symbolic anchor for this step (unique per narrative). Every jump-by-number field has a *Label twin resolved against these anchors at write time \u2014 prefer labels over hand-counted step numbers"),
|
|
43413
|
-
description:
|
|
43414
|
-
type:
|
|
43415
|
-
targetComponent:
|
|
43416
|
-
targetMethod:
|
|
43417
|
-
auth:
|
|
43418
|
-
detach:
|
|
43419
|
-
capability:
|
|
43420
|
-
assertsGuarantees:
|
|
43421
|
-
assertsInvariants:
|
|
43422
|
-
condition:
|
|
44604
|
+
description: import_zod12.z.string(),
|
|
44605
|
+
type: import_zod12.z.enum(["local", "call", "dispatch", "register", "branch", "switch", "loop", "try", "parallel", "jump", "return", "throw"]),
|
|
44606
|
+
targetComponent: import_zod12.z.string().optional().describe("call/register/dispatch: L2 component id (for dispatch, the Portal routed through)"),
|
|
44607
|
+
targetMethod: import_zod12.z.string().optional().describe("call/register: method name on the target. A register step hands the target method to the runtime as a callback (timer, event listener, shutdown hook): reachability follows the edge, but it is never an invocation \u2014 exempt from call-graph conformance, call-cycle detection, and the durability boot walk"),
|
|
44608
|
+
auth: import_zod12.z.object({ from: import_zod12.z.string(), note: import_zod12.z.string().optional() }).strict().optional().describe("call/dispatch: the credential this step presents to an AUTHED callee Portal and WHERE it loads from (`from`). Opaque form (env:API_KEY, a config key, vault:path) = a design note wairon never resolves; modeled form `component:<id>` references the Adapter/Store that provides the secret and is validated (must resolve, be an Adapter/Store, and be wired to the presenter). Absence on a call into a Portal whose auth \u2260 none warns (PORTAL_AUTH_UNMET). The authenticated call itself should be made by an Adapter (AUTH_PRESENTER_NOT_ADAPTER)."),
|
|
44609
|
+
detach: import_zod12.z.boolean().optional().describe("call/dispatch: fire-and-forget \u2014 issue the call and continue without awaiting the result (no later step consumes it)"),
|
|
44610
|
+
capability: import_zod12.z.string().optional().describe("dispatch: the capability routed through the target Portal's dispatch table (validated against it \u2014 UNSERVED_CAPABILITY)"),
|
|
44611
|
+
assertsGuarantees: import_zod12.z.array(import_zod12.z.string().min(1)).optional().describe("Semantic guarantees this step relies on \u2014 each must be declared in the called method's L3 guarantees (NARRATIVE_SEMANTIC_UNBACKED otherwise). Builtin tokens: idempotent | atomic | transactional | exactly-once; extension packs may declare more (any other token is UNKNOWN_GUARANTEE)"),
|
|
44612
|
+
assertsInvariants: import_zod12.z.array(import_zod12.z.string()).optional().describe(`Declared entity invariants this step upholds, as "<type-id>.<invariant-id>" refs (UNKNOWN_INVARIANT_REF when unresolved); write-effect methods of the entity's componentClass must carry one per declared invariant (UNASSERTED_INVARIANT)`),
|
|
44613
|
+
condition: import_zod12.z.string().optional().describe("branch / while / doWhile"),
|
|
43423
44614
|
onTrueStep: stepNo().optional().describe("branch: default = next step"),
|
|
43424
44615
|
onTrueLabel: labelRef().optional().describe("branch: symbolic alternative to onTrueStep"),
|
|
43425
44616
|
onFalseStep: stepNo().optional().describe("branch: required (or onFalseLabel)"),
|
|
43426
44617
|
onFalseLabel: labelRef().optional().describe("branch: symbolic alternative to onFalseStep"),
|
|
43427
|
-
on:
|
|
43428
|
-
cases:
|
|
44618
|
+
on: import_zod12.z.string().optional().describe("switch: the dispatched value"),
|
|
44619
|
+
cases: import_zod12.z.array(import_zod12.z.object({ value: import_zod12.z.string(), step: stepNo().optional(), label: labelRef().optional() }).strict()).optional().describe("switch: required; each case targets its region by step number or label"),
|
|
43429
44620
|
defaultStep: stepNo().optional().describe("switch: default = next step"),
|
|
43430
44621
|
defaultLabel: labelRef().optional().describe("switch: symbolic alternative to defaultStep"),
|
|
43431
|
-
loopKind:
|
|
43432
|
-
over:
|
|
44622
|
+
loopKind: import_zod12.z.enum(["forEach", "for", "while", "doWhile"]).optional().describe('loop: default forEach when "over" is set, else while'),
|
|
44623
|
+
over: import_zod12.z.string().optional().describe("loop forEach/for: iteration source"),
|
|
43433
44624
|
endStep: stepNo().optional().describe("loop/try: last step of the body region (required, or endLabel)"),
|
|
43434
44625
|
endLabel: labelRef().optional().describe("loop/try: symbolic alternative to endStep"),
|
|
43435
|
-
catches:
|
|
44626
|
+
catches: import_zod12.z.array(import_zod12.z.object({ error: import_zod12.z.string(), step: stepNo().optional(), label: labelRef().optional() }).strict()).optional().describe("try: handler regions, each targeted by step number or label"),
|
|
43436
44627
|
finallyStep: stepNo().optional().describe("try: first step of the always-runs region"),
|
|
43437
44628
|
finallyLabel: labelRef().optional().describe("try: symbolic alternative to finallyStep"),
|
|
43438
|
-
branches:
|
|
44629
|
+
branches: import_zod12.z.array(import_zod12.z.object({ step: stepNo().optional(), label: labelRef().optional(), name: import_zod12.z.string().optional() }).strict()).optional().describe("parallel: >= 2 arm entries (step number or label), ascending, first = the step after the header; arms are contiguous sub-regions of body next..endStep, joining after endStep once ALL complete"),
|
|
43439
44630
|
toStep: stepNo().optional().describe("jump: required (break/continue/rejoin), or toLabel"),
|
|
43440
44631
|
toLabel: labelRef().optional().describe("jump: symbolic alternative to toStep \u2014 resolves to the labeled step at write time"),
|
|
43441
|
-
outcome:
|
|
43442
|
-
error:
|
|
44632
|
+
outcome: import_zod12.z.string().optional().describe('return: e.g. "success", "not found"'),
|
|
44633
|
+
error: import_zod12.z.string().optional().describe("throw: the raised error")
|
|
43443
44634
|
}).strict();
|
|
43444
|
-
const detailEnum =
|
|
43445
|
-
const conformanceEnum =
|
|
44635
|
+
const detailEnum = import_zod12.z.enum(["full", "calls-only", "intent"]);
|
|
44636
|
+
const conformanceEnum = import_zod12.z.enum(["declared", "anchored", "off"]);
|
|
43446
44637
|
const implMethodShape = {
|
|
43447
|
-
name:
|
|
43448
|
-
sourcePath:
|
|
44638
|
+
name: import_zod12.z.string(),
|
|
44639
|
+
sourcePath: import_zod12.z.string().optional().describe("Optional: the source file realizing THIS method when it is not the implementation's sourcePath (e.g. a command whose body lives in its own file); the implementation's sourcePath is the default. 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"),
|
|
43449
44640
|
detail: detailEnum.optional().describe("Detail level for this method (overrides the spec default)"),
|
|
43450
|
-
intent:
|
|
44641
|
+
intent: import_zod12.z.string().optional().describe("detail: intent \u2014 behavioral prose (what it does and how it fails); substitute for a narrative"),
|
|
43451
44642
|
conformance: conformanceEnum.optional().describe("Conformance tier for this method (overrides the spec default)"),
|
|
43452
|
-
symbol:
|
|
43453
|
-
exportedVia:
|
|
43454
|
-
ext:
|
|
43455
|
-
narrative:
|
|
43456
|
-
calls:
|
|
44643
|
+
symbol: import_zod12.z.string().optional().describe("Code-level name realizing this contract method in the sourcePath file, when it legitimately differs from the intent-language contract name (e.g. put realized by saveSnapshot)"),
|
|
44644
|
+
exportedVia: import_zod12.z.string().optional().describe("The exported binding a consumer imports to REACH this method, when the realization is published as a value that composes it rather than exported in its own right (a rule module publishes callConformanceRule, and the method is the check inside it). Not symbol, which names the function itself: this names the route to it, so the surface check reads that export as promised. A handle the method's own source file does not actually export is reported (UNREALIZED_EXPORT_HANDLE) and allows nothing"),
|
|
44645
|
+
ext: import_zod12.z.record(import_zod12.z.unknown()).optional().describe("Opaque pack/tool extension data for this method (namespaced keys) \u2014 preserved verbatim"),
|
|
44646
|
+
narrative: import_zod12.z.array(narrativeStepInput).optional(),
|
|
44647
|
+
calls: import_zod12.z.array(import_zod12.z.string().min(1)).optional().describe('The calls this method makes, when its narrative does not show them (detail: intent, or calls-only with no steps authored) \u2014 each as "<component>.<method>", the spelling the debt register and lint allows name a unit with. The narrative walk takes exactly these edges and no others, so an undeclared collaborator is NOT reached: this is what keeps unused-detection honest at a lower detail dial. Each entry is validated like a call step (the component resolves, this component declares it, the method is on its contract). Refused beside a non-empty narrative \u2014 add the call step there instead')
|
|
43457
44648
|
};
|
|
43458
44649
|
const implMethodInputFields = Object.keys(implMethodShape);
|
|
43459
44650
|
const implInput = {
|
|
43460
|
-
id:
|
|
43461
|
-
name:
|
|
43462
|
-
description:
|
|
43463
|
-
contract:
|
|
43464
|
-
sourcePath:
|
|
43465
|
-
simPath:
|
|
43466
|
-
technologies:
|
|
43467
|
-
injectedParams:
|
|
44651
|
+
id: import_zod12.z.string().describe('Lowercase identifier, e.g. "vfs_storage"'),
|
|
44652
|
+
name: import_zod12.z.string().describe("Human-readable implementation name"),
|
|
44653
|
+
description: import_zod12.z.string().describe("Implementation details"),
|
|
44654
|
+
contract: import_zod12.z.string().describe("The L3 Interface contract ID this implements"),
|
|
44655
|
+
sourcePath: import_zod12.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"),
|
|
44656
|
+
simPath: import_zod12.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"),
|
|
44657
|
+
technologies: import_zod12.z.array(import_zod12.z.union([import_zod12.z.string(), import_zod12.z.object({ name: import_zod12.z.string(), matches: import_zod12.z.array(import_zod12.z.string()).min(1).describe("The tokens the leakage and contract checks match INSTEAD of the name \u2014 for a technology whose name is also an ordinary word of the tree (the yaml package, the YAML format)") }).strict()])).optional().describe(`External technologies this implementation binds to (e.g. ["mysql"], or [{ "name": "yaml", "matches": ["yaml package", "parseDocument"] }] when the bare name would match a common word) \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.`),
|
|
44658
|
+
injectedParams: import_zod12.z.array(import_zod12.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"),
|
|
43468
44659
|
detail: detailEnum.optional().describe("Spec-level narrative detail default for all methods"),
|
|
43469
44660
|
conformance: conformanceEnum.optional().describe("Spec-level conformance tier default: declared | anchored | off (omitted = stereotype default: Portal \u2192 anchored, else declared)"),
|
|
43470
|
-
methods:
|
|
44661
|
+
methods: import_zod12.z.array(import_zod12.z.object(implMethodShape).strict()).optional().describe("Method implementations containing L5 narratives"),
|
|
43471
44662
|
status: statusInput
|
|
43472
44663
|
};
|
|
43473
44664
|
const implInputFields = Object.keys(implInput);
|
|
@@ -43514,46 +44705,46 @@ ${renderChangeReport(report2)}`,
|
|
|
43514
44705
|
}
|
|
43515
44706
|
);
|
|
43516
44707
|
const typeInput = {
|
|
43517
|
-
kind:
|
|
43518
|
-
id:
|
|
43519
|
-
name:
|
|
43520
|
-
description:
|
|
43521
|
-
subsystem:
|
|
43522
|
-
group:
|
|
43523
|
-
fields:
|
|
43524
|
-
name:
|
|
43525
|
-
type:
|
|
43526
|
-
description:
|
|
43527
|
-
optional:
|
|
43528
|
-
key:
|
|
43529
|
-
references:
|
|
44708
|
+
kind: import_zod12.z.enum(["entity", "value-object", "signature", "enum"]).describe("entity (owned by a subsystem), value-object (often system-level shared), signature \u2014 a named function type: params and returns, nothing else \u2014 or enum: a closed, ordered set of named values"),
|
|
44709
|
+
id: import_zod12.z.string().describe("Lowercase identifier"),
|
|
44710
|
+
name: import_zod12.z.string().describe("Human-readable name"),
|
|
44711
|
+
description: import_zod12.z.string().optional(),
|
|
44712
|
+
subsystem: import_zod12.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"),
|
|
44713
|
+
group: import_zod12.z.string().optional().describe("Optional logical group ID to organize this type in subfolders"),
|
|
44714
|
+
fields: import_zod12.z.array(import_zod12.z.object({
|
|
44715
|
+
name: import_zod12.z.string(),
|
|
44716
|
+
type: import_zod12.z.string().describe(TYPE_REF_GRAMMAR("The field's type")),
|
|
44717
|
+
description: import_zod12.z.string().optional(),
|
|
44718
|
+
optional: import_zod12.z.boolean().optional(),
|
|
44719
|
+
key: import_zod12.z.enum(["primary", "unique", "foreign"]).optional().describe("Identity marker (PK/unique/FK) for ERD and database schema derivation"),
|
|
44720
|
+
references: import_zod12.z.string().optional().describe('For foreign keys, the referenced type/table id and optional field, e.g. "invoice.id"')
|
|
43530
44721
|
}).strict()).optional().describe('Data fields (type is a primitive or a qualified type id, e.g. "billing.Invoice")'),
|
|
43531
|
-
methods:
|
|
43532
|
-
name:
|
|
43533
|
-
signature:
|
|
43534
|
-
params:
|
|
43535
|
-
returns:
|
|
43536
|
-
description:
|
|
43537
|
-
sourcePath:
|
|
43538
|
-
symbol:
|
|
44722
|
+
methods: import_zod12.z.array(import_zod12.z.object({
|
|
44723
|
+
name: import_zod12.z.string(),
|
|
44724
|
+
signature: import_zod12.z.string().optional().describe("Prose signature \u2014 only for a method WITHOUT params; with params the server derives and writes the text"),
|
|
44725
|
+
params: import_zod12.z.array(methodParamItem).optional().describe("Structured parameters \u2014 authoritative for type checking; the signature text is derived from them"),
|
|
44726
|
+
returns: import_zod12.z.string().describe(TYPE_REF_GRAMMAR("The type the method answers with")),
|
|
44727
|
+
description: import_zod12.z.string().optional(),
|
|
44728
|
+
sourcePath: import_zod12.z.string().optional().describe("Source file realizing this method when the type's own sourcePath does not hold it \u2014 a pure type method often lives apart from the declaration"),
|
|
44729
|
+
symbol: import_zod12.z.string().optional().describe("Code-level name realizing this method when it differs from the method name, e.g. narrative_step.foreignFields realized by narrativeStepForeignFields")
|
|
43539
44730
|
}).strict()).optional().describe("Pure intrinsic methods only"),
|
|
43540
|
-
componentClass:
|
|
43541
|
-
invariants:
|
|
43542
|
-
id:
|
|
43543
|
-
description:
|
|
44731
|
+
componentClass: import_zod12.z.string().optional().describe("Optional component id that implements or owns this logical entity"),
|
|
44732
|
+
invariants: import_zod12.z.array(import_zod12.z.object({
|
|
44733
|
+
id: import_zod12.z.string().describe("Stable invariant id, unique within the entity"),
|
|
44734
|
+
description: import_zod12.z.string().describe("The property that must hold, stated precisely")
|
|
43544
44735
|
}).strict()).optional().describe("Declared domain invariants (entities): every write-effect method of the componentClass must carry a narrative step asserting each (assertsInvariants) \u2014 declarations checked, enforcement never proven"),
|
|
43545
|
-
database:
|
|
43546
|
-
table:
|
|
43547
|
-
linkedEntity:
|
|
43548
|
-
sourcePath:
|
|
43549
|
-
symbol:
|
|
43550
|
-
params:
|
|
43551
|
-
returns:
|
|
43552
|
-
values:
|
|
43553
|
-
name:
|
|
43554
|
-
description:
|
|
44736
|
+
database: import_zod12.z.string().optional().describe("Optional database id for table-schema types"),
|
|
44737
|
+
table: import_zod12.z.string().optional().describe("Optional database table name for table-schema types"),
|
|
44738
|
+
linkedEntity: import_zod12.z.string().optional().describe("Optional logical entity id represented by this table-schema type"),
|
|
44739
|
+
sourcePath: import_zod12.z.string().optional().describe("Source file holding the declaration of this type (project-relative). Naming one turns the type into a claim on code: the file must resolve and the declaration must be anchored in it (UNREALIZED_TYPE)"),
|
|
44740
|
+
symbol: import_zod12.z.string().optional().describe('Code-level name realizing the declaration when it differs from name, e.g. a type named "Invoice Line" declared as InvoiceLine'),
|
|
44741
|
+
params: import_zod12.z.array(methodParamItem).optional().describe("kind signature only: the function type's parameters, in declared order (SIGNATURE_TYPE_MEMBERS on any other kind)"),
|
|
44742
|
+
returns: import_zod12.z.string().optional().describe(TYPE_REF_GRAMMAR("kind signature only, and required there: the function type's one output")),
|
|
44743
|
+
values: import_zod12.z.array(import_zod12.z.object({
|
|
44744
|
+
name: import_zod12.z.string().min(1).describe(`The value's name, exactly as data carries it ("stable", "local_only")`),
|
|
44745
|
+
description: import_zod12.z.string().optional().describe("What the value means")
|
|
43555
44746
|
}).strict()).optional().describe("kind enum only, and required there: the values in declared order \u2014 the order is part of the design (a narrowest-first track list means something). Unique by name ignoring case and separators; no ordinals and no separate wire value"),
|
|
43556
|
-
holds:
|
|
44747
|
+
holds: import_zod12.z.string().optional().describe('kind value-object only: makes it a NAMED SCALAR \u2014 one primitive under a name (string, int, float, bool, bytes, date, datetime or duration), a newtype or type alias in every language (`type PackPath = string`), declared in place of fields. Not a union, not a named type, not any; fields beside it, or holds on another kind, is NAMED_SCALAR_MEMBERS. Aliases are respelled (boolean \u2192 bool) and number is refused ("int or float?")')
|
|
43557
44748
|
};
|
|
43558
44749
|
const typeInputFields = Object.keys(typeInput);
|
|
43559
44750
|
reg(
|
|
@@ -43610,9 +44801,9 @@ ${renderChangeReport(report2)}`,
|
|
|
43610
44801
|
{
|
|
43611
44802
|
description: "Validate the SDD spec tree, checking parent references, contract compatibility, narratives, and component type boundaries. Supports scoping and recursion controls. Findings come back as structured content too, under the schema this tool declares \u2014 errors, warnings and notices already split into three lists (a notice never makes the tree invalid and never fails --ci), each with its code, severity, message and the spec it concerns \u2014 so a caller filters them as objects instead of parsing the JSON text block and hoping its shape holds.",
|
|
43612
44803
|
inputSchema: {
|
|
43613
|
-
subsystem:
|
|
43614
|
-
recursive:
|
|
43615
|
-
family:
|
|
44804
|
+
subsystem: import_zod12.z.string().optional().describe("Only validate the specified subsystem (granular)"),
|
|
44805
|
+
recursive: import_zod12.z.boolean().optional().describe("At a project that declares members: the family run (true, the default) or the owner's gate alone (false)"),
|
|
44806
|
+
family: import_zod12.z.boolean().optional().describe("Ask for the family run explicitly: every member's own gate, and this project's externals composed against their live producers within the request's reach (`wairon validate --family`)")
|
|
43616
44807
|
},
|
|
43617
44808
|
outputSchema: validateTreeOutput
|
|
43618
44809
|
},
|
|
@@ -43653,9 +44844,9 @@ ${renderChangeReport(report2)}`,
|
|
|
43653
44844
|
{
|
|
43654
44845
|
description: `Get/read the parsed JSON contents of a specific spec from the spec tree. Returns structural contents without file system path searching. Pass "methods" to read only the named methods of a contract, an implementation or a type \u2014 a 45-method spec fetched whole to look at one of them is the read side of the same waste a restatement is on the write side; the answer then carries a "partialResult" marker naming what was left out, and must never be re-authored from. For a variant-tagged COMPONENT the result also carries a derived, read-only "variantGuidance" (the variant's base, its implementation guidance, and the same-variant sibling components to implement alike) \u2014 it is resolved from the variant registry, not part of the spec, so never write it back. A contract's methods come back in their STORED form \u2014 a method that takes its signature from a source carries its signatureFrom, not the params the loader resolves into it \u2014 so the answer can be re-authored from as it is; the resolved params, returns and text of each such method come back as a derived, read-only "resolvedSignatures" marker. The structured content carries the same answer with the derived markers KEPT SEPARATE from the stored spec ({kind, id, spec, partialResult?, variantGuidance?, resolvedSignatures?}), so nothing derived can be mistaken for something stored; the text block folds them in as it always has.`,
|
|
43655
44846
|
inputSchema: {
|
|
43656
|
-
kind:
|
|
43657
|
-
id:
|
|
43658
|
-
methods:
|
|
44847
|
+
kind: import_zod12.z.enum(["system", "subsystem", "component", "interface", "implementation", "type"]).describe("The kind of specification"),
|
|
44848
|
+
id: import_zod12.z.string().describe('The identifier of the spec to fetch (the L0 system spec is a singleton \u2014 pass the system name or "system")'),
|
|
44849
|
+
methods: import_zod12.z.array(import_zod12.z.string().min(1)).optional().describe("Return only these methods by name; every other field of the spec comes back unchanged. Only an interface, an implementation or a type declares methods \u2014 asking for one elsewhere is refused, as is a name the spec does not declare (the answer names the ones it does). Omit it for the whole spec.")
|
|
43659
44850
|
},
|
|
43660
44851
|
outputSchema: getSpecOutput
|
|
43661
44852
|
},
|
|
@@ -43740,8 +44931,8 @@ ${renderChangeReport(report2)}`,
|
|
|
43740
44931
|
{
|
|
43741
44932
|
description: "Delete a specification file from the spec tree and clean up any empty parent directories. Answers with a structured deletion beside the sentence: whether a spec was removed, and the tests that encode a method the deletion took away (when the project declares test roots).",
|
|
43742
44933
|
inputSchema: {
|
|
43743
|
-
kind:
|
|
43744
|
-
id:
|
|
44934
|
+
kind: import_zod12.z.enum(["subsystem", "component", "interface", "implementation", "type"]).describe("The kind of spec to delete"),
|
|
44935
|
+
id: import_zod12.z.string().describe("The ID of the spec to delete")
|
|
43745
44936
|
},
|
|
43746
44937
|
outputSchema: specDeletionOutput
|
|
43747
44938
|
},
|
|
@@ -43763,17 +44954,17 @@ ${testsBlock}` : ""}`, deletion);
|
|
|
43763
44954
|
{
|
|
43764
44955
|
description: "Update/patch an existing SDD specification (subsystem, component, interface, implementation, or type) using a granular delta. Updates fields, appends/merges array elements, or inserts/deletes narrative steps. Answers with exactly what changed, and with every path the delta named that the write did not act on. Type positions (the type of a param, a returns, the type of a field, the params and returns of a signature) are written in the neutral type grammar: an alias the delta writes (string[], T | null, boolean, Promise<T>) is stored canonical and listed under `respellings`, and a stored alias at a position the write keeps is respelled with it; a position the delta writes that has no canonical spelling (number \u2014 int or float?, an inline object or function type, a literal union, a union mixing in a primitive) is refused, naming the replacement, while one the stored spec already held is left alone. Pass dryRun to be told what it would do without writing it.",
|
|
43765
44956
|
inputSchema: {
|
|
43766
|
-
kind:
|
|
43767
|
-
id:
|
|
43768
|
-
delta:
|
|
43769
|
-
dryRun:
|
|
44957
|
+
kind: import_zod12.z.enum(["system", "subsystem", "component", "interface", "implementation", "type"]).describe("The spec kind to update (system = the singleton L0 \u2014 vision, boundaries, globalRequirements, databases, and publicInterfaces: the project export table, each entry a re-export {from, component, interface, typeDef, as, name, type, details, audience: project|department|instance|partner|external} \u2014 from alone re-exports everything a subsystem exports, and a legacy {id, subsystem} reads as {as, from})"),
|
|
44958
|
+
id: import_zod12.z.string().describe("The ID of the spec to update (namespaced if needed)"),
|
|
44959
|
+
delta: import_zod12.z.record(import_zod12.z.any()).describe(`The partial fields to merge into the spec. ARRAYS UPSERT, they do not replace: an array whose elements carry an identity is merged element-by-element, so a delta naming ONE element leaves the others intact. Identity is "name" or "id" by default, and per field: dispatch by "capability", a listener's mounts by "portal", lifecycle by phase+component+method, emits/subscribesTo by topic+event, trustedLinks by "subsystem", a subsystem's publicInterfaces by component+interface (or type+details for an entry not yet bound to a component, and by from+item+interface+as for a re-export or a type export), invariants and patterns by "id", lint.allow by "code" AND "at" (an allow covers one occurrence, so several may share a code on one spec), an interface method's findings by "code", boundaries by "name", globalRequirements by "description", switch cases by "value", try catches by "error". Identity merging applies at EVERY depth, including an array INSIDE an element (a method's params, a step's catches). Add "action: 'delete'" (or "remove: true") alongside that identity to REMOVE an element \u2014 including a stale lint allow. Arrays of plain STRINGS (owns, dependsOn, guarantees) carry no per-element identity and are replaced wholesale; pass [] to clear any array outright. To REMOVE an optional field entirely, list it in "unset": e.g. {"unset": ["basePath", "variant"]} \u2014 passing null/undefined means "no change" (they are skipped), and writing "" would leave the field present but empty, which is a different and usually wrong spec. Unsetting a required field is refused by schema validation, which names it. For narrative steps, match by "stepNumber" and use "action: 'insert'" (shifts subsequent steps up) or "action: 'delete'" (shifts subsequent steps down and removes it). Step entries apply in ASCENDING stepNumber order, each against the numbering the earlier entries of the SAME delta left behind \u2014 delete step 3 and step 7 becomes step 6 \u2014 so prefer labels, and restate the step's "label" or "description" on a delete to have it checked against the step actually addressed. Renumbering RELOCATES every flow jump field (onTrueStep/onFalseStep/cases.step/defaultStep/endStep/catches.step/finallyStep/toStep) in the same narrative. Only STORED jumps relocate: a jump the delta itself writes (on an inserted, appended or edited step) names its target in the numbering the WHOLE delta leaves behind, after all of its inserts and deletes, and no later step of the same delta moves it. A method the delta ADDS without a narrative is an intent-level method with none ([]). An element the delta NAMES merges field by field: a field it leaves out, or passes as null, keeps its stored value at EVERY depth (a method named without "narrative" keeps its steps, a step named without "catches" keeps them), while "narrative": [] CLEARS that method's steps \u2014 so leave a method you are not editing out of the delta. A delete is REJECTED when the narrative has no such step, when a jump still targets it (retarget the referrers first), when a restated label/description does not match, or when it is a loop/try/parallel header whose body would be left standing (retype the header first to dissolve the region, then delete it). Changing a step's "type" REBUILDS it for the new type: its description and label are kept and every field the new type cannot carry is dropped (returned as a NOTICE); a delta that retypes AND sets such a field is refused. A step delta is also refused when it carries a marker the merge does not recognise: a non-boolean "remove", an "action" that is neither "insert" nor "delete", a "captureJumps" outside an insert, or no "stepNumber" to address. Inserting AT a jump target relocates those jumps past the inserted step by default (a NOTICE is returned) \u2014 add "captureJumps": true on the inserted step to retarget entry jumps onto it (loop/try endStep region tails always relocate with the body and are never captured). Every jump field has a "*Label" twin (toLabel, onFalseLabel, endLabel, \u2026, and "label" on a cases/catches entry) resolved against step labels AFTER the merge, so a delta may anchor on a label only pre-existing steps carry; a label the delta supplies REPLACES the stored number it twins, while setting the number and its label together in one delta is refused as a contradiction. Reference ids in deltas may use LOCAL names \u2014 they are qualified against the spec's namespace exactly as the loader would. Per-spec lint suppression: set "lint: { allow: [{ code, at, covers, reason }] }" to silence a WARNING or NOTICE code on this spec only (errors always surface; stale allows are flagged). An allow covers EXACTLY the occurrence it names: "at" is the site the finding names (a contract method, an import edge "from -> to", a declared edge "component -> target") and is REQUIRED for a code whose findings report one, while a finding that reports no site is covered only by an allow that names none; "covers" lists the units an aggregating finding reports, and the allow silences it only when every one is listed. This delta is deliberately OPEN below its top level \u2014 the shapes nest further than a schema here should restate \u2014 so a key that is not a field at its depth is not refused, it is NAMED BACK under NO EFFECT in the answer, together with any value the spec already held and any "unset" that removed nothing. Read that list: it is where a nested typo shows up.`),
|
|
44960
|
+
dryRun: import_zod12.z.boolean().optional().describe("Ask what this delta WOULD do instead of doing it. The whole write runs, the candidate gate included, and the answer is the change report it would have produced \u2014 marked DRY RUN, with nothing stamped and not one byte of the stored file moved. Use it before a delta that renumbers a long narrative.")
|
|
43770
44961
|
},
|
|
43771
44962
|
outputSchema: specChangeReportOutput
|
|
43772
44963
|
},
|
|
43773
44964
|
({ kind, id, delta, dryRun }) => {
|
|
43774
44965
|
try {
|
|
43775
|
-
const
|
|
43776
|
-
return structured(renderChangeReport(
|
|
44966
|
+
const report3 = updateSpecGated(kind, id, delta, dryRun);
|
|
44967
|
+
return structured(renderChangeReport(report3), report3);
|
|
43777
44968
|
} catch (e) {
|
|
43778
44969
|
return errText(String(e));
|
|
43779
44970
|
}
|
|
@@ -43785,8 +44976,8 @@ ${testsBlock}` : ""}`, deletion);
|
|
|
43785
44976
|
{
|
|
43786
44977
|
description: "Get the completeness status dashboard of the SDD spec tree. Supports scoping and recursion controls.",
|
|
43787
44978
|
inputSchema: {
|
|
43788
|
-
subsystem:
|
|
43789
|
-
recursive:
|
|
44979
|
+
subsystem: import_zod12.z.string().optional().describe("Only show status for the specified subsystem"),
|
|
44980
|
+
recursive: import_zod12.z.boolean().optional().describe("Whether to descend into the members this project declares (default: true)")
|
|
43790
44981
|
}
|
|
43791
44982
|
},
|
|
43792
44983
|
({ subsystem, recursive }) => {
|
|
@@ -43800,14 +44991,14 @@ ${testsBlock}` : ""}`, deletion);
|
|
|
43800
44991
|
} catch {
|
|
43801
44992
|
approvals = void 0;
|
|
43802
44993
|
}
|
|
43803
|
-
const
|
|
44994
|
+
const report3 = getStatusReport({
|
|
43804
44995
|
subsystem,
|
|
43805
44996
|
memberDepth,
|
|
43806
44997
|
approvals
|
|
43807
44998
|
});
|
|
43808
44999
|
const family = statusFamilyContext();
|
|
43809
45000
|
const verdict = approvalVerdict(approvals);
|
|
43810
|
-
return text2(`${banner}${family}${
|
|
45001
|
+
return text2(`${banner}${family}${report3.text}${verdict.text}`);
|
|
43811
45002
|
} catch (e) {
|
|
43812
45003
|
return errText(`${banner}${String(e)}`);
|
|
43813
45004
|
}
|
|
@@ -43819,7 +45010,7 @@ ${testsBlock}` : ""}`, deletion);
|
|
|
43819
45010
|
{
|
|
43820
45011
|
description: "Pin the bound project's declared externals (.wai/project.yaml `externals`) \u2014 the named aliases, else all \u2014 into .wai/externals/<alias>.yaml and .wai/externals.lock.yaml, recording the signature digest of every member the project's references use. Answers one outcome per alias (pinned, unchanged, unresolved, unreachable) with the references that land on no public name of the producer (export them from its L0 to pin them). A tree-scoped write: a producer the request may not read is reported unreachable, never read.",
|
|
43821
45012
|
inputSchema: {
|
|
43822
|
-
aliases:
|
|
45013
|
+
aliases: import_zod12.z.array(import_zod12.z.string()).optional().describe("The aliases to pin; all declared externals when omitted")
|
|
43823
45014
|
},
|
|
43824
45015
|
outputSchema: externalPinsOutput
|
|
43825
45016
|
},
|
|
@@ -43856,7 +45047,7 @@ ${testsBlock}` : ""}`, deletion);
|
|
|
43856
45047
|
{
|
|
43857
45048
|
description: "Compose the LIVE delegation brief for one resolved agent: the fully rendered instruction body plus the ownedPaths/readPaths scope fence \u2014 the dynamic replacement for generated per-component agent files. Fetch a brief and spawn a generic subagent with it: always fresh after a re-lock, no session restart needed. List agent ids via listAgents or resources/list (the wairon-agent:// entries).",
|
|
43858
45049
|
inputSchema: {
|
|
43859
|
-
agentId:
|
|
45050
|
+
agentId: import_zod12.z.string().describe("The resolved agent id (list via listAgents or resources/list)")
|
|
43860
45051
|
}
|
|
43861
45052
|
},
|
|
43862
45053
|
({ agentId }) => {
|
|
@@ -43918,9 +45109,30 @@ function loadProjectConfig3() {
|
|
|
43918
45109
|
CustomTargetConfigSchema,
|
|
43919
45110
|
CustomTargetSchema,
|
|
43920
45111
|
DEFAULT_TARGET_DIRS,
|
|
45112
|
+
DESIGN_APPROVALS,
|
|
45113
|
+
DESIGN_DEPENDENCY_ROLES,
|
|
45114
|
+
DESIGN_FORMAT,
|
|
45115
|
+
DESIGN_FORMAT_VERSION,
|
|
43921
45116
|
DatabaseSpecSchema,
|
|
43922
45117
|
DependencyClassSchema,
|
|
45118
|
+
DesignApprovalSchema,
|
|
45119
|
+
DesignComponentSchema,
|
|
45120
|
+
DesignDependencyRoleSchema,
|
|
45121
|
+
DesignDependencySchema,
|
|
43923
45122
|
DesignDepthSchema,
|
|
45123
|
+
DesignExportEntrySchema,
|
|
45124
|
+
DesignExportSchema,
|
|
45125
|
+
DesignFieldSchema,
|
|
45126
|
+
DesignImplementationSchema,
|
|
45127
|
+
DesignInterfaceSchema,
|
|
45128
|
+
DesignMethodBodySchema,
|
|
45129
|
+
DesignMethodSchema,
|
|
45130
|
+
DesignParamSchema,
|
|
45131
|
+
DesignProjectSchema,
|
|
45132
|
+
DesignSourceSchema,
|
|
45133
|
+
DesignSubsystemSchema,
|
|
45134
|
+
DesignTypeRefSchema,
|
|
45135
|
+
DesignTypeSchema,
|
|
43924
45136
|
DiagramConfigSchema,
|
|
43925
45137
|
DispatchBindingSchema,
|
|
43926
45138
|
DoctorOptionsError,
|
|
@@ -43980,6 +45192,8 @@ function loadProjectConfig3() {
|
|
|
43980
45192
|
PortalAuthSchemeSchema,
|
|
43981
45193
|
PortalMountSchema,
|
|
43982
45194
|
PortalTypeSchema,
|
|
45195
|
+
PreviousIdsSchema,
|
|
45196
|
+
PreviousNamesSchema,
|
|
43983
45197
|
ProfileSelectionSubjectSchema,
|
|
43984
45198
|
ProjectConfigSchema,
|
|
43985
45199
|
ProjectNotInitializedError,
|
|
@@ -44023,6 +45237,7 @@ function loadProjectConfig3() {
|
|
|
44023
45237
|
TopologyConfigSchema,
|
|
44024
45238
|
TransportSchema,
|
|
44025
45239
|
TrustedLinkSchema,
|
|
45240
|
+
TypeExpressionSchema,
|
|
44026
45241
|
TypeFieldSchema,
|
|
44027
45242
|
TypeKindSchema,
|
|
44028
45243
|
TypeMethodSchema,
|
|
@@ -44110,6 +45325,7 @@ function loadProjectConfig3() {
|
|
|
44110
45325
|
ensureDir,
|
|
44111
45326
|
ensureProjectInitialized,
|
|
44112
45327
|
excerptParent,
|
|
45328
|
+
exportDesign,
|
|
44113
45329
|
exportSpecTree,
|
|
44114
45330
|
exportTargetKey,
|
|
44115
45331
|
exportUsage,
|
|
@@ -44259,6 +45475,7 @@ function loadProjectConfig3() {
|
|
|
44259
45475
|
renameComponent,
|
|
44260
45476
|
renameId,
|
|
44261
45477
|
renameMethod,
|
|
45478
|
+
renameType,
|
|
44262
45479
|
renderDiagram,
|
|
44263
45480
|
repairForeignStepFields,
|
|
44264
45481
|
repairSignatures,
|
|
@@ -44298,6 +45515,7 @@ function loadProjectConfig3() {
|
|
|
44298
45515
|
settledSpecPaths,
|
|
44299
45516
|
signatureFacts,
|
|
44300
45517
|
signatureTypeRefs,
|
|
45518
|
+
specIndexRetiredBy,
|
|
44301
45519
|
specPathsInScope,
|
|
44302
45520
|
splitNamespace,
|
|
44303
45521
|
stepConfigVerdict,
|