@wairon/cli 5.1.1-dev.11 → 5.1.1-dev.13
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 +457 -141
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +336 -112
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1312,7 +1312,7 @@ var init_defaults = __esm({
|
|
|
1312
1312
|
copilot: ".github/prompts",
|
|
1313
1313
|
codex: ".codex/agents"
|
|
1314
1314
|
};
|
|
1315
|
-
WAIRON_VERSION = "5.1.1-dev.
|
|
1315
|
+
WAIRON_VERSION = "5.1.1-dev.13";
|
|
1316
1316
|
GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
1317
1317
|
ARCHITECT_AGENT_ID = "agent-architect";
|
|
1318
1318
|
ARCHITECT_TEMPLATE_ID = "architect";
|
|
@@ -2884,17 +2884,43 @@ function isExternalNamespaceRef(ctx, ref) {
|
|
|
2884
2884
|
if (sep6 === -1) return false;
|
|
2885
2885
|
return !ctx.subsystemIds.has(ref.slice(0, sep6));
|
|
2886
2886
|
}
|
|
2887
|
+
function isProvidedBy(snapshot, provider) {
|
|
2888
|
+
return snapshot.projectName === provider || snapshot.projectName.split("::").pop() === provider;
|
|
2889
|
+
}
|
|
2890
|
+
function sameContract(a, b) {
|
|
2891
|
+
return a.component.split("::").pop() === b.component.split("::").pop() && JSON.stringify(a.methods) === JSON.stringify(b.methods) && JSON.stringify(a.dispatch ?? []) === JSON.stringify(b.dispatch ?? []);
|
|
2892
|
+
}
|
|
2887
2893
|
function resolveSurfaceRef(ctx, ref, fromSubsystem) {
|
|
2888
|
-
const
|
|
2889
|
-
|
|
2894
|
+
const segments = ref.split("::").filter((seg) => seg && seg !== "super");
|
|
2895
|
+
const local = segments.pop();
|
|
2896
|
+
if (!local) return { kind: "unresolved" };
|
|
2897
|
+
const provider = segments.pop();
|
|
2890
2898
|
const mountPools = fromSubsystem ? enclosingMounts(ctx, fromSubsystem).reverse().map((ns) => ctx.mountSurfaceSnapshots.find((m) => m.namespace === ns)?.snapshots ?? []) : [];
|
|
2891
2899
|
for (const pool of [...mountPools, ctx.surfaceSnapshots]) {
|
|
2900
|
+
const candidates = [];
|
|
2892
2901
|
for (const snapshot of pool) {
|
|
2902
|
+
if (provider !== void 0 && !isProvidedBy(snapshot, provider)) continue;
|
|
2893
2903
|
const entry = snapshot.interfaces.find((e) => e.component === local || e.id === local);
|
|
2894
|
-
if (entry)
|
|
2904
|
+
if (entry) candidates.push({ snapshot, entry });
|
|
2905
|
+
}
|
|
2906
|
+
if (candidates.length === 0) continue;
|
|
2907
|
+
const [first] = candidates;
|
|
2908
|
+
if (candidates.every((c) => sameContract(c.entry, first.entry))) {
|
|
2909
|
+
return { kind: "resolved", ...first };
|
|
2895
2910
|
}
|
|
2911
|
+
return { kind: "ambiguous", providers: [...new Set(candidates.map((c) => c.snapshot.projectName))] };
|
|
2896
2912
|
}
|
|
2897
|
-
return
|
|
2913
|
+
return { kind: "unresolved" };
|
|
2914
|
+
}
|
|
2915
|
+
function reportAmbiguousSurfaceRef(ctx, subject, ref, providers, specId, isDraftContext) {
|
|
2916
|
+
const local = ref.split("::").filter((seg) => seg && seg !== "super").pop() ?? ref;
|
|
2917
|
+
ctx.addIssue(
|
|
2918
|
+
"error",
|
|
2919
|
+
"SURFACE_REF_AMBIGUOUS",
|
|
2920
|
+
`${subject} cross-tree component "${ref}", which the surface snapshots of ${providers.map((p) => `"${p}"`).join(", ")} expose with different contracts \u2014 the reference matches more than one declared contract, so none of them can judge it. Name the provider it means (super::<provider>::${local}), or remove the snapshot that no longer applies.`,
|
|
2921
|
+
specId,
|
|
2922
|
+
isDraftContext
|
|
2923
|
+
);
|
|
2898
2924
|
}
|
|
2899
2925
|
function enclosingMounts(ctx, subsystemId) {
|
|
2900
2926
|
const mounts = [];
|
|
@@ -2985,6 +3011,7 @@ var init_contracts = __esm({
|
|
|
2985
3011
|
{ code: "INVALID_TARGET_COMPONENT_REFERENCE", defaultSeverity: "error", summary: "Call/register step targets a non-existent component" },
|
|
2986
3012
|
{ code: "CROSS_TREE_REF_UNRESOLVED", defaultSeverity: "warning", summary: "Cross-tree reference (super::/:: form) with no surface snapshot covering it \u2014 only the parent project can verify it" },
|
|
2987
3013
|
{ code: "SURFACE_REF_NOT_EXPOSED", defaultSeverity: "error", summary: "Cross-tree reference resolves to a surface snapshot that does not expose the called method/capability" },
|
|
3014
|
+
{ code: "SURFACE_REF_AMBIGUOUS", defaultSeverity: "error", summary: "Cross-tree call/dispatch/register target matched by surface snapshots of several providers with different contracts" },
|
|
2988
3015
|
{ code: "UNDECLARED_DEPENDENCY_CALL", defaultSeverity: "error", summary: "Call step targets a component the caller does not depend on or own" },
|
|
2989
3016
|
{ code: "INVALID_TARGET_METHOD_REFERENCE", defaultSeverity: "error", summary: "Call step targets a method not on any target interface" },
|
|
2990
3017
|
{ code: "NARRATIVE_SEMANTIC_UNBACKED", defaultSeverity: "warning", summary: "Narrative asserts a guarantee the called contract does not declare" }
|
|
@@ -3039,7 +3066,18 @@ var init_contracts = __esm({
|
|
|
3039
3066
|
if (!dispatchTarget) {
|
|
3040
3067
|
if (isCrossTreeForm || isCollapsedForm) {
|
|
3041
3068
|
const resolved = resolveSurfaceRef(ctx, step.targetComponent, fromSubsystem);
|
|
3042
|
-
if (resolved) {
|
|
3069
|
+
if (resolved.kind === "ambiguous") {
|
|
3070
|
+
reportAmbiguousSurfaceRef(
|
|
3071
|
+
ctx,
|
|
3072
|
+
`Method "${implMethod.name}" in implementation "${impl.id}" dispatches (step ${step.stepNumber}) through`,
|
|
3073
|
+
step.targetComponent,
|
|
3074
|
+
resolved.providers,
|
|
3075
|
+
impl.id,
|
|
3076
|
+
isDraftCtx
|
|
3077
|
+
);
|
|
3078
|
+
continue;
|
|
3079
|
+
}
|
|
3080
|
+
if (resolved.kind === "resolved") {
|
|
3043
3081
|
if (step.capability && !(resolved.entry.dispatch ?? []).some((b) => b.capability === step.capability)) {
|
|
3044
3082
|
ctx.addIssue(
|
|
3045
3083
|
"error",
|
|
@@ -3099,7 +3137,18 @@ var init_contracts = __esm({
|
|
|
3099
3137
|
if (!targetComp) {
|
|
3100
3138
|
if (isCrossTreeForm || isCollapsedForm) {
|
|
3101
3139
|
const resolved = resolveSurfaceRef(ctx, step.targetComponent, fromSubsystem);
|
|
3102
|
-
if (resolved) {
|
|
3140
|
+
if (resolved.kind === "ambiguous") {
|
|
3141
|
+
reportAmbiguousSurfaceRef(
|
|
3142
|
+
ctx,
|
|
3143
|
+
`Method "${implMethod.name}" in implementation "${impl.id}" ${verb} "${step.targetMethod}" (step ${step.stepNumber}) on`,
|
|
3144
|
+
step.targetComponent,
|
|
3145
|
+
resolved.providers,
|
|
3146
|
+
impl.id,
|
|
3147
|
+
isDraftCtx
|
|
3148
|
+
);
|
|
3149
|
+
continue;
|
|
3150
|
+
}
|
|
3151
|
+
if (resolved.kind === "resolved") {
|
|
3103
3152
|
const surfaceMethod = resolved.entry.methods.find((m) => m.name === step.targetMethod);
|
|
3104
3153
|
if (!surfaceMethod) {
|
|
3105
3154
|
ctx.addIssue(
|
|
@@ -4614,6 +4663,7 @@ var init_stereotype_deps = __esm({
|
|
|
4614
4663
|
codes: [
|
|
4615
4664
|
{ code: "INVALID_DEPENDENCY_REFERENCE", defaultSeverity: "error", summary: "dependsOn names a non-existent component" },
|
|
4616
4665
|
{ code: "CROSS_TREE_REF_UNRESOLVED", defaultSeverity: "warning", summary: "Cross-tree dependsOn (super::/:: form) with no surface snapshot covering it" },
|
|
4666
|
+
{ code: "SURFACE_REF_AMBIGUOUS", defaultSeverity: "error", summary: "Cross-tree dependsOn matched by surface snapshots of several providers with different contracts" },
|
|
4617
4667
|
{ code: "CROSS_SUBSYSTEM_NON_ADAPTER", defaultSeverity: "error", summary: "Non-Adapter component crossing a subsystem boundary" },
|
|
4618
4668
|
{ code: "CROSS_SUBSYSTEM_PRIVATE_ACCESS", defaultSeverity: "error", summary: "Cross-subsystem dependency on an unpublished component" },
|
|
4619
4669
|
{ code: "CROSS_SUBSYSTEM_TARGET_NON_PORTAL", defaultSeverity: "error", summary: "Cross-subsystem hop entering through a non-Portal" },
|
|
@@ -4637,7 +4687,11 @@ var init_stereotype_deps = __esm({
|
|
|
4637
4687
|
const external = isExternalNamespaceRef(ctx, depId);
|
|
4638
4688
|
if (external || isCollapsedCrossTreeRef(ctx, depId, comp.subsystem)) {
|
|
4639
4689
|
const resolved = resolveSurfaceRef(ctx, depId, comp.subsystem);
|
|
4640
|
-
if (resolved) {
|
|
4690
|
+
if (resolved.kind === "ambiguous") {
|
|
4691
|
+
reportAmbiguousSurfaceRef(ctx, `Component "${comp.id}" depends on`, depId, resolved.providers, comp.id, isDraftCtx);
|
|
4692
|
+
continue;
|
|
4693
|
+
}
|
|
4694
|
+
if (resolved.kind === "resolved") {
|
|
4641
4695
|
if (comp.componentType !== "Adapter") {
|
|
4642
4696
|
ctx.addIssue(
|
|
4643
4697
|
"error",
|
|
@@ -4729,12 +4783,12 @@ var init_stereotype_deps = __esm({
|
|
|
4729
4783
|
}
|
|
4730
4784
|
}
|
|
4731
4785
|
if (comp.componentType === "Specialist") {
|
|
4732
|
-
const forbiddenTypes = ["Portal", "Observer", "Orchestrator", "Store", "Supervisor"];
|
|
4786
|
+
const forbiddenTypes = ["Portal", "Observer", "Orchestrator", "Store", "Registry", "Supervisor", "Actor"];
|
|
4733
4787
|
if (forbiddenTypes.includes(depComp.componentType)) {
|
|
4734
4788
|
ctx.addIssue(
|
|
4735
4789
|
"error",
|
|
4736
4790
|
"ARCHITECTURE_VIOLATION_SPECIALIST_DEP",
|
|
4737
|
-
`Architectural violation: Specialist component "${comp.id}" cannot depend on "${depComp.componentType}" component "${depComp.id}". Specialists are
|
|
4791
|
+
`Architectural violation: Specialist component "${comp.id}" cannot depend on "${depComp.componentType}" component "${depComp.id}". Specialists are pure capabilities \u2014 they may use Repository facades, Indexes, and Adapters, but never workflow/runtime blocks (Orchestrators, Supervisors, Actors) and never persistence directly (Stores, Registries \u2014 all storage, even in-memory, is reached through a Repository facade), nor Portals or Observers.` + (depComp.componentType === "Store" ? storeResolutionHint(comp.componentType, depComp.id) : ""),
|
|
4738
4792
|
comp.id,
|
|
4739
4793
|
isDraftCtx || ctx.isComponentDraft(depComp.id)
|
|
4740
4794
|
);
|
|
@@ -8010,7 +8064,7 @@ function buildRuleContext(opts) {
|
|
|
8010
8064
|
for (const i of interfaces) collectAllows(i.id, i.lint);
|
|
8011
8065
|
for (const im of implementations) collectAllows(im.id, im.lint);
|
|
8012
8066
|
for (const t of types) collectAllows(t.id, t.lint);
|
|
8013
|
-
const
|
|
8067
|
+
const knownIssueCodes2 = /* @__PURE__ */ new Set([
|
|
8014
8068
|
...[...SDD_RULES, ...extensions.rules].flatMap((r) => r.codes.map((c) => c.code)),
|
|
8015
8069
|
// Declarative assertions bring their own namespaced codes — lint.allow
|
|
8016
8070
|
// and severity overrides treat them exactly like builtins.
|
|
@@ -8073,7 +8127,7 @@ function buildRuleContext(opts) {
|
|
|
8073
8127
|
mountSurfaceSnapshots: opts.mountSurfaceSnapshots ?? [],
|
|
8074
8128
|
codeModel: opts.codeModel ?? emptyCodeModel(),
|
|
8075
8129
|
lintAllows,
|
|
8076
|
-
knownIssueCodes,
|
|
8130
|
+
knownIssueCodes: knownIssueCodes2,
|
|
8077
8131
|
addIssue
|
|
8078
8132
|
};
|
|
8079
8133
|
}
|
|
@@ -8343,8 +8397,8 @@ function doctrineIdentity(doctrine, gate) {
|
|
|
8343
8397
|
)
|
|
8344
8398
|
};
|
|
8345
8399
|
}
|
|
8346
|
-
function hashGateState(doctrine, gate = {}) {
|
|
8347
|
-
const payload = { tree: loadTree(), doctrine: doctrineIdentity(doctrine, gate) };
|
|
8400
|
+
function hashGateState(doctrine, inputs, gate = {}) {
|
|
8401
|
+
const payload = { tree: loadTree(), doctrine: doctrineIdentity(doctrine, gate), inputs: [...inputs].sort() };
|
|
8348
8402
|
const digest2 = crypto2.createHash("sha256").update(canonicalize(payload)).digest("hex");
|
|
8349
8403
|
return { algorithm: GATE_ALGORITHM, digest: digest2 };
|
|
8350
8404
|
}
|
|
@@ -8375,7 +8429,7 @@ var init_statehash = __esm({
|
|
|
8375
8429
|
init_specs2();
|
|
8376
8430
|
init_rules();
|
|
8377
8431
|
CONTENT_ALGORITHM = "sha256";
|
|
8378
|
-
GATE_ALGORITHM = "sha256+doctrine";
|
|
8432
|
+
GATE_ALGORITHM = "sha256+doctrine+inputs";
|
|
8379
8433
|
}
|
|
8380
8434
|
});
|
|
8381
8435
|
|
|
@@ -13349,6 +13403,9 @@ var MODEL = __MODEL_JSON__;
|
|
|
13349
13403
|
function addRule(rule) {
|
|
13350
13404
|
ruleSet.push(rule);
|
|
13351
13405
|
}
|
|
13406
|
+
function listRules() {
|
|
13407
|
+
return ruleSet;
|
|
13408
|
+
}
|
|
13352
13409
|
function registerBuiltinRules() {
|
|
13353
13410
|
ruleSet = [];
|
|
13354
13411
|
for (const rule of SDD_RULES) addRule(rule);
|
|
@@ -13360,6 +13417,9 @@ function ruleSequence() {
|
|
|
13360
13417
|
const base = ruleSet.filter((r) => r !== lintAllowsRule);
|
|
13361
13418
|
return ruleSet.includes(lintAllowsRule) ? [...base, lintAllowsRule] : base;
|
|
13362
13419
|
}
|
|
13420
|
+
function knownIssueCodes() {
|
|
13421
|
+
return listRules().flatMap((r) => r.codes);
|
|
13422
|
+
}
|
|
13363
13423
|
var ruleSet;
|
|
13364
13424
|
var init_repository = __esm({
|
|
13365
13425
|
"src/core/rules/repository.ts"() {
|
|
@@ -14132,15 +14192,18 @@ function importSurface(sourcePath, origin) {
|
|
|
14132
14192
|
saveSnapshot(snapshot);
|
|
14133
14193
|
return snapshot;
|
|
14134
14194
|
}
|
|
14135
|
-
function
|
|
14136
|
-
|
|
14137
|
-
if (!parent) return null;
|
|
14138
|
-
const childRoot = getProjectRoot();
|
|
14139
|
-
const projected = runWithProjectRoot(parent.parentRoot, () => {
|
|
14195
|
+
function projectFamilySurfaces(parent) {
|
|
14196
|
+
return runWithProjectRoot(parent.parentRoot, () => {
|
|
14140
14197
|
invalidateSpecCache();
|
|
14141
14198
|
const siblings = loadSubsystemSpecs().filter((s) => !s.id.includes("::") && s.id !== parent.subsystemId);
|
|
14142
14199
|
return [projectChildSurface(), ...siblings.map((s) => projectSubsystemSurface(s.id))];
|
|
14143
14200
|
});
|
|
14201
|
+
}
|
|
14202
|
+
function pinFamilySurfaces() {
|
|
14203
|
+
const parent = resolveChainingParent();
|
|
14204
|
+
if (!parent) return null;
|
|
14205
|
+
const childRoot = getProjectRoot();
|
|
14206
|
+
const projected = projectFamilySurfaces(parent);
|
|
14144
14207
|
const before = new Map(listSnapshots(childRoot).map((s) => [s.projectName, surfaceContentKey(s)]));
|
|
14145
14208
|
const changed = [];
|
|
14146
14209
|
for (const snapshot of projected) {
|
|
@@ -14151,17 +14214,21 @@ function pinFamilySurfaces() {
|
|
|
14151
14214
|
}
|
|
14152
14215
|
return changed;
|
|
14153
14216
|
}
|
|
14154
|
-
function
|
|
14155
|
-
|
|
14217
|
+
function projectedFamilyContent(parent) {
|
|
14218
|
+
try {
|
|
14219
|
+
return new Map(projectFamilySurfaces(parent).map((s) => [s.projectName, surfaceContentKey(s)]));
|
|
14220
|
+
} catch {
|
|
14221
|
+
return null;
|
|
14222
|
+
}
|
|
14156
14223
|
}
|
|
14157
14224
|
function listExternalInterfaces() {
|
|
14158
14225
|
const snapshots = listSnapshots();
|
|
14159
14226
|
const chainingParent = resolveChainingParent();
|
|
14160
|
-
const
|
|
14227
|
+
const projected = chainingParent ? projectedFamilyContent(chainingParent) : null;
|
|
14161
14228
|
return snapshots.map((snapshot) => {
|
|
14162
14229
|
const generated = snapshot.origin === "generated";
|
|
14163
14230
|
const sourceKind = !generated ? "foreign" : snapshot.projectName.includes("::") ? "sibling" : "parent";
|
|
14164
|
-
const freshness = generated &&
|
|
14231
|
+
const freshness = generated && projected ? projected.get(snapshot.projectName) === surfaceContentKey(snapshot) ? "fresh" : "stale" : "unverifiable";
|
|
14165
14232
|
return {
|
|
14166
14233
|
projectName: snapshot.projectName,
|
|
14167
14234
|
origin: snapshot.origin,
|
|
@@ -14291,6 +14358,32 @@ function projectPackSelections() {
|
|
|
14291
14358
|
return [];
|
|
14292
14359
|
}
|
|
14293
14360
|
}
|
|
14361
|
+
function issueKey(issue2) {
|
|
14362
|
+
return `${issue2.code}|${issue2.specId ?? ""}`;
|
|
14363
|
+
}
|
|
14364
|
+
function worstByKey(issues) {
|
|
14365
|
+
const worst = /* @__PURE__ */ new Map();
|
|
14366
|
+
for (const issue2 of issues) {
|
|
14367
|
+
const key = issueKey(issue2);
|
|
14368
|
+
const seen = worst.get(key);
|
|
14369
|
+
if (!seen || SEVERITY_RANK[issue2.severity] > SEVERITY_RANK[seen]) worst.set(key, issue2.severity);
|
|
14370
|
+
}
|
|
14371
|
+
return worst;
|
|
14372
|
+
}
|
|
14373
|
+
function stricterSeverities(parent, child) {
|
|
14374
|
+
const fromParent = parent?.sddRuleSeverity ?? {};
|
|
14375
|
+
const fromChild = child?.sddRuleSeverity ?? {};
|
|
14376
|
+
const codes = /* @__PURE__ */ new Set([...Object.keys(fromParent), ...Object.keys(fromChild)]);
|
|
14377
|
+
if (codes.size === 0) return parent ?? child;
|
|
14378
|
+
const defaults = new Map(knownIssueCodes().map((rc) => [rc.code, rc.defaultSeverity]));
|
|
14379
|
+
const merged = {};
|
|
14380
|
+
for (const code of codes) {
|
|
14381
|
+
const p = fromParent[code] ?? defaults.get(code);
|
|
14382
|
+
const c = fromChild[code] ?? defaults.get(code);
|
|
14383
|
+
merged[code] = p === void 0 || c === void 0 ? p ?? c : SEVERITY_RANK[p] >= SEVERITY_RANK[c] ? p : c;
|
|
14384
|
+
}
|
|
14385
|
+
return { ...parent ?? child, sddRuleSeverity: merged };
|
|
14386
|
+
}
|
|
14294
14387
|
function issue(severity, code, message, agentId, specId) {
|
|
14295
14388
|
return { severity, code, message, agentId, specId };
|
|
14296
14389
|
}
|
|
@@ -14372,7 +14465,7 @@ function validateProjectConfig(config) {
|
|
|
14372
14465
|
issues
|
|
14373
14466
|
};
|
|
14374
14467
|
}
|
|
14375
|
-
function
|
|
14468
|
+
function listRules2() {
|
|
14376
14469
|
const extensions = loadProjectExtensions();
|
|
14377
14470
|
registerBuiltinRules();
|
|
14378
14471
|
registerPackRules(extensions.rules);
|
|
@@ -14472,21 +14565,22 @@ function validateSddTree(rulesOrOptions, projectType = "backend") {
|
|
|
14472
14565
|
for (const rule of ruleSequence()) {
|
|
14473
14566
|
rule.check(ctx);
|
|
14474
14567
|
}
|
|
14475
|
-
const
|
|
14476
|
-
const chainingParent = crossTree !== "off" && issues.some(
|
|
14477
|
-
const resolution = chainingParent ? resolveThroughParent(getProjectRoot(), treatAllAsComplete) : null;
|
|
14568
|
+
const unresolved = (i) => RESOLUTION_FAILURE_CODES.has(i.code) && !i.surfaceResolved;
|
|
14569
|
+
const chainingParent = crossTree !== "off" && issues.some(unresolved) ? resolveChainingParent() : null;
|
|
14570
|
+
const resolution = chainingParent ? resolveThroughParent(getProjectRoot(), treatAllAsComplete, rules) : null;
|
|
14478
14571
|
if (resolution) {
|
|
14479
|
-
const
|
|
14480
|
-
|
|
14481
|
-
const
|
|
14482
|
-
if (
|
|
14483
|
-
|
|
14484
|
-
|
|
14485
|
-
|
|
14486
|
-
|
|
14487
|
-
|
|
14488
|
-
|
|
14489
|
-
|
|
14572
|
+
const judgedByParent = worstByKey(resolution.issues);
|
|
14573
|
+
const kept = issues.filter((i) => {
|
|
14574
|
+
const judged = judgedByParent.get(issueKey(i));
|
|
14575
|
+
if (judged !== void 0) return SEVERITY_RANK[judged] < SEVERITY_RANK[i.severity];
|
|
14576
|
+
return !unresolved(i);
|
|
14577
|
+
});
|
|
14578
|
+
const keptByChild = worstByKey(kept);
|
|
14579
|
+
const added = resolution.issues.filter((i) => {
|
|
14580
|
+
const own = keptByChild.get(issueKey(i));
|
|
14581
|
+
return own === void 0 || SEVERITY_RANK[own] <= SEVERITY_RANK[i.severity];
|
|
14582
|
+
});
|
|
14583
|
+
const merged = dedupeIssues([...kept, ...added]);
|
|
14490
14584
|
return {
|
|
14491
14585
|
valid: merged.every((i) => i.severity !== "error"),
|
|
14492
14586
|
issues: merged,
|
|
@@ -14503,14 +14597,14 @@ function validateSddTree(rulesOrOptions, projectType = "backend") {
|
|
|
14503
14597
|
});
|
|
14504
14598
|
}
|
|
14505
14599
|
}
|
|
14506
|
-
function resolveThroughParent(boundRoot, treatAllAsComplete) {
|
|
14600
|
+
function resolveThroughParent(boundRoot, treatAllAsComplete, childRules) {
|
|
14507
14601
|
const reach = getRequestParentReach();
|
|
14508
14602
|
if (reach && !reach.parentReach) return null;
|
|
14509
14603
|
const ceiling = reach?.topRoot ? path14.resolve(reach.topRoot) : void 0;
|
|
14510
14604
|
const chain = [];
|
|
14511
14605
|
let top = path14.resolve(boundRoot);
|
|
14512
14606
|
while (top !== ceiling) {
|
|
14513
|
-
const hop = findChainingParent(top);
|
|
14607
|
+
const hop = findChainingParent(top, ceiling);
|
|
14514
14608
|
if (!hop) break;
|
|
14515
14609
|
const next = path14.resolve(hop.parentRoot);
|
|
14516
14610
|
if (ceiling && !isWithinOrEqual(ceiling, next)) break;
|
|
@@ -14521,10 +14615,10 @@ function resolveThroughParent(boundRoot, treatAllAsComplete) {
|
|
|
14521
14615
|
const scope = chain.join("::");
|
|
14522
14616
|
const inner = runWithProjectRoot(top, () => {
|
|
14523
14617
|
invalidateSpecCache();
|
|
14524
|
-
let governing = {};
|
|
14618
|
+
let governing = { rules: stricterSeverities(void 0, childRules) };
|
|
14525
14619
|
try {
|
|
14526
14620
|
const config = loadProjectConfig();
|
|
14527
|
-
governing = { rules: config.rules, projectType: config.projectType };
|
|
14621
|
+
governing = { rules: stricterSeverities(config.rules, childRules), projectType: config.projectType };
|
|
14528
14622
|
} catch {
|
|
14529
14623
|
}
|
|
14530
14624
|
return validateSddTree({
|
|
@@ -14598,7 +14692,7 @@ function settledStatusBearing(loaded) {
|
|
|
14598
14692
|
function validateAsComplete(options) {
|
|
14599
14693
|
return validateSddTree({ ...options ?? {}, treatAllAsComplete: true });
|
|
14600
14694
|
}
|
|
14601
|
-
var path14,
|
|
14695
|
+
var path14, RESOLUTION_FAILURE_CODES, SEVERITY_RANK;
|
|
14602
14696
|
var init_validation = __esm({
|
|
14603
14697
|
"src/core/validation.ts"() {
|
|
14604
14698
|
"use strict";
|
|
@@ -14614,16 +14708,15 @@ var init_validation = __esm({
|
|
|
14614
14708
|
init_fs();
|
|
14615
14709
|
path14 = __toESM(require("path"));
|
|
14616
14710
|
init_approval();
|
|
14617
|
-
|
|
14711
|
+
RESOLUTION_FAILURE_CODES = /* @__PURE__ */ new Set([
|
|
14618
14712
|
"UNDEFINED_TYPE_REFERENCE",
|
|
14619
14713
|
"INVALID_DEPENDENCY_REFERENCE",
|
|
14620
14714
|
"INVALID_TARGET_COMPONENT_REFERENCE",
|
|
14621
14715
|
"INVALID_SUBSYSTEM_REFERENCE",
|
|
14622
|
-
"UNDECLARED_DEPENDENCY_CALL",
|
|
14623
14716
|
"INVALID_TRUSTED_LINK",
|
|
14624
|
-
"CROSS_SUBSYSTEM_NON_ADAPTER",
|
|
14625
14717
|
"CROSS_TREE_REF_UNRESOLVED"
|
|
14626
14718
|
]);
|
|
14719
|
+
SEVERITY_RANK = { off: 0, warning: 1, error: 2 };
|
|
14627
14720
|
}
|
|
14628
14721
|
});
|
|
14629
14722
|
|
|
@@ -15197,6 +15290,20 @@ function qualifyId(id, prefix, rootSubsystems) {
|
|
|
15197
15290
|
}
|
|
15198
15291
|
return prefix ? `${prefix}::${id}` : id;
|
|
15199
15292
|
}
|
|
15293
|
+
function qualifyDeclaredId(id, prefix, mountRealization = false) {
|
|
15294
|
+
if (!id || !prefix) return id;
|
|
15295
|
+
if (id.startsWith("::") || id.startsWith("super::")) {
|
|
15296
|
+
return qualifyId(id, prefix, NO_ROOT_SUBSYSTEMS);
|
|
15297
|
+
}
|
|
15298
|
+
if (mountRealization && id === prefix.split("::").pop()) {
|
|
15299
|
+
return prefix;
|
|
15300
|
+
}
|
|
15301
|
+
return `${prefix}::${id}`;
|
|
15302
|
+
}
|
|
15303
|
+
function qualifySubsystemRef(id, prefix, rootSubsystems) {
|
|
15304
|
+
if (prefix && !id.includes("::") && id === prefix.split("::").pop()) return prefix;
|
|
15305
|
+
return qualifyId(id, prefix, rootSubsystems);
|
|
15306
|
+
}
|
|
15200
15307
|
function splitNamespace(qualifiedId) {
|
|
15201
15308
|
if (!qualifiedId.includes("::")) {
|
|
15202
15309
|
return { prefix: "", localId: qualifiedId };
|
|
@@ -15227,33 +15334,75 @@ function relativizeId(id, prefix) {
|
|
|
15227
15334
|
if (common === idParts.length) common--;
|
|
15228
15335
|
return `${"super::".repeat(prefixParts.length - common)}${idParts.slice(common).join("::")}`;
|
|
15229
15336
|
}
|
|
15337
|
+
function rebaseReference(ref, mount, direction, isMoved = () => false) {
|
|
15338
|
+
if (!ref || ref.startsWith("::")) return ref;
|
|
15339
|
+
const segments = ref.split("::");
|
|
15340
|
+
let hops = 0;
|
|
15341
|
+
while (segments[hops] === "super") hops++;
|
|
15342
|
+
if (hops === segments.length) return ref;
|
|
15343
|
+
const outer = Array.from({ length: hops + 1 }, (_, i) => `<n${i}>`).join("::");
|
|
15344
|
+
const inner = `${outer}::${mount}`;
|
|
15345
|
+
const [from, to] = direction === "into" ? [outer, inner] : [inner, outer];
|
|
15346
|
+
const target = qualifyId(ref, from, NO_ROOT_SUBSYSTEMS);
|
|
15347
|
+
const left = relativizeId(target, from);
|
|
15348
|
+
const travels = !left.startsWith("super::") && (direction === "outOf" || isMoved(left));
|
|
15349
|
+
return relativizeId(travels ? qualifyId(left, to, NO_ROOT_SUBSYSTEMS) : target, to);
|
|
15350
|
+
}
|
|
15230
15351
|
function isWithin(dir, file) {
|
|
15231
15352
|
const d = path15.resolve(dir);
|
|
15232
15353
|
const f = path15.resolve(file);
|
|
15233
15354
|
return f === d || f.startsWith(d + path15.sep);
|
|
15234
15355
|
}
|
|
15356
|
+
function canonicalPath(target) {
|
|
15357
|
+
let existing = path15.resolve(target);
|
|
15358
|
+
const rest = [];
|
|
15359
|
+
for (; ; ) {
|
|
15360
|
+
try {
|
|
15361
|
+
fs9.lstatSync(existing);
|
|
15362
|
+
break;
|
|
15363
|
+
} catch {
|
|
15364
|
+
const up = path15.dirname(existing);
|
|
15365
|
+
if (up === existing) return path15.resolve(target);
|
|
15366
|
+
rest.unshift(path15.basename(existing));
|
|
15367
|
+
existing = up;
|
|
15368
|
+
}
|
|
15369
|
+
}
|
|
15370
|
+
try {
|
|
15371
|
+
return path15.join(fs9.realpathSync.native(existing), ...rest);
|
|
15372
|
+
} catch {
|
|
15373
|
+
return null;
|
|
15374
|
+
}
|
|
15375
|
+
}
|
|
15376
|
+
function chainDirKey(dir) {
|
|
15377
|
+
return canonicalPath(dir) ?? path15.resolve(dir);
|
|
15378
|
+
}
|
|
15235
15379
|
function projectPathEscapesRoot(projectRoot, projectPath, resolvedChildDir) {
|
|
15236
|
-
|
|
15380
|
+
if (path15.isAbsolute(projectPath) || !isWithin(projectRoot, resolvedChildDir)) return true;
|
|
15381
|
+
const root = canonicalPath(projectRoot);
|
|
15382
|
+
const child = canonicalPath(resolvedChildDir);
|
|
15383
|
+
return root === null || child === null || !isWithin(root, child);
|
|
15237
15384
|
}
|
|
15238
15385
|
function assertContainedProjectPath(projectRoot, projectPath) {
|
|
15239
15386
|
const root = path15.resolve(projectRoot);
|
|
15240
15387
|
const resolved = path15.resolve(root, projectPath);
|
|
15241
15388
|
if (projectPathEscapesRoot(root, projectPath, resolved)) {
|
|
15242
15389
|
throw new Error(
|
|
15243
|
-
`projectPath "${projectPath}" must resolve within the project root "${root}", but resolves to "${resolved}"; absolute
|
|
15390
|
+
`projectPath "${projectPath}" must resolve within the project root "${root}", but resolves to "${resolved}"; absolute, ../-escaping and link-escaping paths are rejected so a chained subproject is always contained by its parent.`
|
|
15244
15391
|
);
|
|
15245
15392
|
}
|
|
15246
15393
|
return resolved;
|
|
15247
15394
|
}
|
|
15248
|
-
function findChainingParent(childRoot) {
|
|
15395
|
+
function findChainingParent(childRoot, ceiling) {
|
|
15249
15396
|
let childResolved;
|
|
15250
15397
|
try {
|
|
15251
15398
|
childResolved = path15.resolve(childRoot);
|
|
15252
15399
|
} catch {
|
|
15253
15400
|
return null;
|
|
15254
15401
|
}
|
|
15402
|
+
const bound = ceiling ? path15.resolve(ceiling) : void 0;
|
|
15255
15403
|
let dir = path15.dirname(childResolved);
|
|
15256
15404
|
for (let hops = 0; hops < 32; hops++) {
|
|
15405
|
+
if (bound && !isWithin(bound, dir)) break;
|
|
15257
15406
|
const specsDir = aiPathsAt(dir).specsDir();
|
|
15258
15407
|
if (pathExists(specsDir)) {
|
|
15259
15408
|
for (const file of listFilesRecursive(specsDir, ".yaml")) {
|
|
@@ -15267,7 +15416,8 @@ function findChainingParent(childRoot) {
|
|
|
15267
15416
|
const projectPath = raw.projectPath;
|
|
15268
15417
|
if (typeof projectPath === "string" && projectPath.trim() !== "") {
|
|
15269
15418
|
try {
|
|
15270
|
-
|
|
15419
|
+
const mountDir = path15.resolve(dir, projectPath);
|
|
15420
|
+
if (mountDir === childResolved && !projectPathEscapesRoot(dir, projectPath, mountDir)) {
|
|
15271
15421
|
const id = raw.id;
|
|
15272
15422
|
return { parentRoot: dir, subsystemId: typeof id === "string" ? id : "?" };
|
|
15273
15423
|
}
|
|
@@ -15283,12 +15433,11 @@ function findChainingParent(childRoot) {
|
|
|
15283
15433
|
}
|
|
15284
15434
|
return null;
|
|
15285
15435
|
}
|
|
15286
|
-
function
|
|
15436
|
+
function inspectChainedRoots(rootDir = getProjectRoot()) {
|
|
15287
15437
|
const root = path15.resolve(rootDir);
|
|
15288
|
-
const
|
|
15289
|
-
const
|
|
15290
|
-
const walk = (projectDir, depth) => {
|
|
15291
|
-
if (depth > 32) return;
|
|
15438
|
+
const inspection = { roots: [], skipped: [] };
|
|
15439
|
+
const listed = /* @__PURE__ */ new Set();
|
|
15440
|
+
const walk = (projectDir, prefix, ancestors, depth) => {
|
|
15292
15441
|
const specsDir = aiPathsAt(projectDir).specsDir();
|
|
15293
15442
|
if (!pathExists(specsDir)) return;
|
|
15294
15443
|
for (const file of listFilesRecursive(specsDir, ".yaml")) {
|
|
@@ -15299,24 +15448,37 @@ function listChainedRoots(rootDir = getProjectRoot()) {
|
|
|
15299
15448
|
continue;
|
|
15300
15449
|
}
|
|
15301
15450
|
if (!raw || typeof raw !== "object" || !("parentSystem" in raw)) continue;
|
|
15302
|
-
const projectPath = raw
|
|
15451
|
+
const { id, projectPath } = raw;
|
|
15303
15452
|
if (typeof projectPath !== "string" || projectPath.trim() === "") continue;
|
|
15453
|
+
const localId = typeof id === "string" ? id : "?";
|
|
15304
15454
|
let childDir;
|
|
15305
15455
|
try {
|
|
15306
15456
|
childDir = path15.resolve(projectDir, projectPath);
|
|
15307
15457
|
} catch {
|
|
15308
15458
|
continue;
|
|
15309
15459
|
}
|
|
15310
|
-
|
|
15311
|
-
if (
|
|
15312
|
-
if (
|
|
15313
|
-
|
|
15314
|
-
|
|
15315
|
-
|
|
15460
|
+
let reason;
|
|
15461
|
+
if (projectPathEscapesRoot(projectDir, projectPath, childDir)) reason = "escapes";
|
|
15462
|
+
else if (ancestors.has(chainDirKey(childDir))) reason = "cyclic";
|
|
15463
|
+
else if (!fs9.existsSync(childDir)) reason = "missing";
|
|
15464
|
+
else if (depth >= 32) reason = "too-deep";
|
|
15465
|
+
if (reason) {
|
|
15466
|
+
const mount = prefix ? qualifyDeclaredId(localId, prefix, true) : localId;
|
|
15467
|
+
inspection.skipped.push({ mount, projectPath, reason });
|
|
15468
|
+
continue;
|
|
15469
|
+
}
|
|
15470
|
+
const key = chainDirKey(childDir);
|
|
15471
|
+
if (listed.has(key)) continue;
|
|
15472
|
+
listed.add(key);
|
|
15473
|
+
inspection.roots.push(path15.relative(root, childDir).split(path15.sep).join("/"));
|
|
15474
|
+
walk(childDir, prefix ? `${prefix}::${localId}` : localId, /* @__PURE__ */ new Set([...ancestors, key]), depth + 1);
|
|
15316
15475
|
}
|
|
15317
15476
|
};
|
|
15318
|
-
walk(root, 0);
|
|
15319
|
-
return
|
|
15477
|
+
walk(root, "", /* @__PURE__ */ new Set([chainDirKey(root)]), 0);
|
|
15478
|
+
return inspection;
|
|
15479
|
+
}
|
|
15480
|
+
function listChainedRoots(rootDir = getProjectRoot()) {
|
|
15481
|
+
return inspectChainedRoots(rootDir).roots;
|
|
15320
15482
|
}
|
|
15321
15483
|
function mergeMountRealizations(subs) {
|
|
15322
15484
|
const result = [];
|
|
@@ -15597,7 +15759,26 @@ function buildProjectGraph(level) {
|
|
|
15597
15759
|
return buildGraphModel(level);
|
|
15598
15760
|
}
|
|
15599
15761
|
function resolveChainingParent() {
|
|
15600
|
-
|
|
15762
|
+
const reach = getRequestParentReach();
|
|
15763
|
+
if (reach && !reach.parentReach) return null;
|
|
15764
|
+
return findChainingParent(getProjectRoot(), reach?.topRoot);
|
|
15765
|
+
}
|
|
15766
|
+
function snapshotInputKey(snapshot) {
|
|
15767
|
+
const { stateId, generatedAt, origin, ...content } = snapshot;
|
|
15768
|
+
return canonicalize(content);
|
|
15769
|
+
}
|
|
15770
|
+
function consumedSurfaceInputsAt(rootDir) {
|
|
15771
|
+
const dir = path15.join(rootDir, ".wai", "surfaces");
|
|
15772
|
+
if (!pathExists(dir)) return [];
|
|
15773
|
+
const keys = [];
|
|
15774
|
+
for (const file of fs9.readdirSync(dir)) {
|
|
15775
|
+
if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
|
|
15776
|
+
try {
|
|
15777
|
+
keys.push(snapshotInputKey(SurfaceSnapshotSchema.parse(readYamlFile(path15.join(dir, file)))));
|
|
15778
|
+
} catch {
|
|
15779
|
+
}
|
|
15780
|
+
}
|
|
15781
|
+
return keys;
|
|
15601
15782
|
}
|
|
15602
15783
|
function computeGateStateId() {
|
|
15603
15784
|
let gate = {};
|
|
@@ -15606,7 +15787,10 @@ function computeGateStateId() {
|
|
|
15606
15787
|
gate = { projectType: config.projectType, rules: config.rules };
|
|
15607
15788
|
} catch {
|
|
15608
15789
|
}
|
|
15609
|
-
|
|
15790
|
+
const root = getProjectRoot();
|
|
15791
|
+
const roots = [root, ...listChainedRoots(root).map((rel2) => path15.join(root, rel2))];
|
|
15792
|
+
const inputs = roots.flatMap(consumedSurfaceInputsAt);
|
|
15793
|
+
return hashGateState(loadProjectExtensions(), inputs, gate);
|
|
15610
15794
|
}
|
|
15611
15795
|
function readLockState() {
|
|
15612
15796
|
const record = readLockRecord();
|
|
@@ -15662,7 +15846,7 @@ function findLegacySpecFiles() {
|
|
|
15662
15846
|
function updateSpec(kind, id, delta, hooks) {
|
|
15663
15847
|
return current().updateSpec(kind, id, delta, hooks);
|
|
15664
15848
|
}
|
|
15665
|
-
var fs9, path15, SIGNATURE_TTL_MS, SpecWorkspace, workspaces;
|
|
15849
|
+
var fs9, path15, NO_ROOT_SUBSYSTEMS, SIGNATURE_TTL_MS, SpecWorkspace, workspaces;
|
|
15666
15850
|
var init_specs2 = __esm({
|
|
15667
15851
|
"src/core/specs.ts"() {
|
|
15668
15852
|
"use strict";
|
|
@@ -15677,6 +15861,7 @@ var init_specs2 = __esm({
|
|
|
15677
15861
|
init_models();
|
|
15678
15862
|
init_narrative_labels();
|
|
15679
15863
|
init_diagram();
|
|
15864
|
+
NO_ROOT_SUBSYSTEMS = /* @__PURE__ */ new Set();
|
|
15680
15865
|
SIGNATURE_TTL_MS = 2e3;
|
|
15681
15866
|
SpecWorkspace = class {
|
|
15682
15867
|
constructor(rootDir) {
|
|
@@ -15715,7 +15900,7 @@ var init_specs2 = __esm({
|
|
|
15715
15900
|
this.rootSubsystems.clear();
|
|
15716
15901
|
this.cachedRecursive = recursive;
|
|
15717
15902
|
this.scanVisitedSpecDirs = [];
|
|
15718
|
-
const visited = /* @__PURE__ */ new Set([
|
|
15903
|
+
const visited = /* @__PURE__ */ new Set([chainDirKey(this.rootDir)]);
|
|
15719
15904
|
const maxDepth = typeof recursive === "number" ? recursive : recursive ? Infinity : 0;
|
|
15720
15905
|
this.cachedIndex = this.scanSpecsForProject(this.rootDir, "", visited, maxDepth, 0);
|
|
15721
15906
|
this.cachedSpecDirs = this.scanVisitedSpecDirs;
|
|
@@ -15826,7 +16011,7 @@ var init_specs2 = __esm({
|
|
|
15826
16011
|
}
|
|
15827
16012
|
}
|
|
15828
16013
|
index.subsystems = index.subsystems.map((sub) => {
|
|
15829
|
-
const qualifiedSubId = namespacePrefix ?
|
|
16014
|
+
const qualifiedSubId = namespacePrefix ? qualifyDeclaredId(sub.id, namespacePrefix, true) : sub.id;
|
|
15830
16015
|
const componentPrefix = sub.projectPath ? qualifiedSubId : namespacePrefix;
|
|
15831
16016
|
return {
|
|
15832
16017
|
...sub,
|
|
@@ -15845,14 +16030,14 @@ var init_specs2 = __esm({
|
|
|
15845
16030
|
const originalSubsystemPaths = index.paths.subsystem;
|
|
15846
16031
|
index.paths.subsystem = {};
|
|
15847
16032
|
for (const [k, v] of Object.entries(originalSubsystemPaths)) {
|
|
15848
|
-
const qualifiedK = namespacePrefix ?
|
|
16033
|
+
const qualifiedK = namespacePrefix ? qualifyDeclaredId(k, namespacePrefix, true) : k;
|
|
15849
16034
|
index.paths.subsystem[qualifiedK] = v;
|
|
15850
16035
|
}
|
|
15851
16036
|
if (namespacePrefix) {
|
|
15852
16037
|
index.components = index.components.map((comp) => ({
|
|
15853
16038
|
...comp,
|
|
15854
|
-
id:
|
|
15855
|
-
subsystem:
|
|
16039
|
+
id: qualifyDeclaredId(comp.id, namespacePrefix),
|
|
16040
|
+
subsystem: qualifySubsystemRef(comp.subsystem, namespacePrefix, this.rootSubsystems),
|
|
15856
16041
|
owns: comp.owns.map((o) => qualifyId(o, namespacePrefix, this.rootSubsystems)),
|
|
15857
16042
|
dependsOn: comp.dependsOn.map((d) => qualifyId(d, namespacePrefix, this.rootSubsystems)),
|
|
15858
16043
|
dispatch: comp.dispatch?.map((b) => ({
|
|
@@ -15862,12 +16047,12 @@ var init_specs2 = __esm({
|
|
|
15862
16047
|
}));
|
|
15863
16048
|
index.interfaces = index.interfaces.map((intf) => ({
|
|
15864
16049
|
...intf,
|
|
15865
|
-
id:
|
|
16050
|
+
id: qualifyDeclaredId(intf.id, namespacePrefix),
|
|
15866
16051
|
component: qualifyId(intf.component, namespacePrefix, this.rootSubsystems)
|
|
15867
16052
|
}));
|
|
15868
16053
|
index.implementations = index.implementations.map((impl) => ({
|
|
15869
16054
|
...impl,
|
|
15870
|
-
id:
|
|
16055
|
+
id: qualifyDeclaredId(impl.id, namespacePrefix),
|
|
15871
16056
|
contract: qualifyId(impl.contract, namespacePrefix, this.rootSubsystems),
|
|
15872
16057
|
methods: impl.methods.map((m) => ({
|
|
15873
16058
|
...m,
|
|
@@ -15879,13 +16064,13 @@ var init_specs2 = __esm({
|
|
|
15879
16064
|
}));
|
|
15880
16065
|
index.types = index.types.map((t) => ({
|
|
15881
16066
|
...t,
|
|
15882
|
-
id:
|
|
15883
|
-
subsystem: t.subsystem ?
|
|
16067
|
+
id: qualifyDeclaredId(t.id, namespacePrefix),
|
|
16068
|
+
subsystem: t.subsystem ? qualifySubsystemRef(t.subsystem, namespacePrefix, this.rootSubsystems) : void 0,
|
|
15884
16069
|
group: t.group ? qualifyId(t.group, namespacePrefix, this.rootSubsystems) : void 0
|
|
15885
16070
|
}));
|
|
15886
16071
|
index.groups = index.groups.map((g) => ({
|
|
15887
16072
|
...g,
|
|
15888
|
-
id:
|
|
16073
|
+
id: qualifyDeclaredId(g.id, namespacePrefix)
|
|
15889
16074
|
}));
|
|
15890
16075
|
const originalPaths = index.paths;
|
|
15891
16076
|
index.paths = {
|
|
@@ -15897,39 +16082,40 @@ var init_specs2 = __esm({
|
|
|
15897
16082
|
group: {}
|
|
15898
16083
|
};
|
|
15899
16084
|
for (const [k, v] of Object.entries(originalPaths.component)) {
|
|
15900
|
-
index.paths.component[
|
|
16085
|
+
index.paths.component[qualifyDeclaredId(k, namespacePrefix)] = v;
|
|
15901
16086
|
}
|
|
15902
16087
|
for (const [k, v] of Object.entries(originalPaths.interface)) {
|
|
15903
|
-
index.paths.interface[
|
|
16088
|
+
index.paths.interface[qualifyDeclaredId(k, namespacePrefix)] = v;
|
|
15904
16089
|
}
|
|
15905
16090
|
for (const [k, v] of Object.entries(originalPaths.implementation)) {
|
|
15906
|
-
index.paths.implementation[
|
|
16091
|
+
index.paths.implementation[qualifyDeclaredId(k, namespacePrefix)] = v;
|
|
15907
16092
|
}
|
|
15908
16093
|
for (const [k, v] of Object.entries(originalPaths.type)) {
|
|
15909
|
-
index.paths.type[
|
|
16094
|
+
index.paths.type[qualifyDeclaredId(k, namespacePrefix)] = v;
|
|
15910
16095
|
}
|
|
15911
16096
|
for (const [k, v] of Object.entries(originalPaths.group)) {
|
|
15912
|
-
index.paths.group[
|
|
16097
|
+
index.paths.group[qualifyDeclaredId(k, namespacePrefix)] = v;
|
|
15913
16098
|
}
|
|
15914
16099
|
}
|
|
15915
16100
|
if (currentDepth < maxDepth) {
|
|
15916
16101
|
for (const subproj of localSubprojects) {
|
|
15917
16102
|
const childDir = path15.resolve(projectDir, subproj.projectPath);
|
|
15918
|
-
|
|
16103
|
+
const mountId = namespacePrefix ? qualifyDeclaredId(subproj.subsystemId, namespacePrefix, true) : subproj.subsystemId;
|
|
16104
|
+
if (projectPathEscapesRoot(projectDir, subproj.projectPath, childDir)) {
|
|
15919
16105
|
this.loaderIssues.push({
|
|
15920
16106
|
severity: "error",
|
|
15921
16107
|
code: "PROJECTPATH_ESCAPE",
|
|
15922
|
-
message: `Subproject path "${subproj.projectPath}" declared by subsystem "${
|
|
15923
|
-
specId:
|
|
16108
|
+
message: `Subproject path "${subproj.projectPath}" declared by subsystem "${mountId}" escapes the root of the project declaring it, "${projectDir}" (resolves to "${childDir}"); absolute, ../-escaping and link-escaping projectPaths are rejected. Skipping this subproject.`,
|
|
16109
|
+
specId: mountId
|
|
15924
16110
|
});
|
|
15925
16111
|
continue;
|
|
15926
16112
|
}
|
|
15927
|
-
if (visitedDirs.has(childDir)) {
|
|
16113
|
+
if (visitedDirs.has(chainDirKey(childDir))) {
|
|
15928
16114
|
this.loaderIssues.push({
|
|
15929
16115
|
severity: "error",
|
|
15930
16116
|
code: "CIRCULAR_SUBPROJECT_REFERENCE",
|
|
15931
|
-
message: `Circular reference detected: Subsystem "${
|
|
15932
|
-
specId:
|
|
16117
|
+
message: `Circular reference detected: Subsystem "${mountId}" refers to subproject "${childDir}" which is already loaded.`,
|
|
16118
|
+
specId: mountId
|
|
15933
16119
|
});
|
|
15934
16120
|
continue;
|
|
15935
16121
|
}
|
|
@@ -15937,14 +16123,14 @@ var init_specs2 = __esm({
|
|
|
15937
16123
|
this.loaderIssues.push({
|
|
15938
16124
|
severity: "error",
|
|
15939
16125
|
code: "SUBPROJECT_NOT_FOUND",
|
|
15940
|
-
message: `Subproject directory "${childDir}" declared by subsystem "${
|
|
15941
|
-
specId:
|
|
16126
|
+
message: `Subproject directory "${childDir}" declared by subsystem "${mountId}" does not exist.`,
|
|
16127
|
+
specId: mountId
|
|
15942
16128
|
});
|
|
15943
16129
|
continue;
|
|
15944
16130
|
}
|
|
15945
16131
|
const childNamespace = namespacePrefix ? `${namespacePrefix}::${subproj.subsystemId}` : subproj.subsystemId;
|
|
15946
16132
|
const newVisited = new Set(visitedDirs);
|
|
15947
|
-
newVisited.add(childDir);
|
|
16133
|
+
newVisited.add(chainDirKey(childDir));
|
|
15948
16134
|
const childIndex = this.scanSpecsForProject(childDir, childNamespace, newVisited, maxDepth, currentDepth + 1);
|
|
15949
16135
|
index.subsystems.push(...childIndex.subsystems);
|
|
15950
16136
|
index.components.push(...childIndex.components);
|
|
@@ -15977,11 +16163,11 @@ var init_specs2 = __esm({
|
|
|
15977
16163
|
const sub = index.subsystems.find((s) => s.id === currentPrefix);
|
|
15978
16164
|
if (sub && sub.projectPath) {
|
|
15979
16165
|
const nextDir = path15.resolve(currentDir, sub.projectPath);
|
|
15980
|
-
if (projectPathEscapesRoot(
|
|
16166
|
+
if (projectPathEscapesRoot(currentDir, sub.projectPath, nextDir)) {
|
|
15981
16167
|
this.loaderIssues.push({
|
|
15982
16168
|
severity: "error",
|
|
15983
16169
|
code: "PROJECTPATH_ESCAPE",
|
|
15984
|
-
message: `Subproject path "${sub.projectPath}" declared by subsystem "${currentPrefix}" escapes the project
|
|
16170
|
+
message: `Subproject path "${sub.projectPath}" declared by subsystem "${currentPrefix}" escapes the root of the project declaring it, "${currentDir}" (resolves to "${nextDir}"); absolute, ../-escaping and link-escaping projectPaths are rejected. Skipping this subproject.`,
|
|
15985
16171
|
specId: currentPrefix
|
|
15986
16172
|
});
|
|
15987
16173
|
continue;
|
|
@@ -21454,6 +21640,7 @@ __export(src_exports, {
|
|
|
21454
21640
|
buildRuleContext: () => buildRuleContext,
|
|
21455
21641
|
buildServerInstructions: () => buildServerInstructions2,
|
|
21456
21642
|
buildTreeArchive: () => buildTreeArchive2,
|
|
21643
|
+
canonicalize: () => canonicalize,
|
|
21457
21644
|
captureApprovedSpecs: () => captureApprovedSpecs,
|
|
21458
21645
|
checkSkillFreshness: () => checkSkillFreshness,
|
|
21459
21646
|
clearLoaderIssues: () => clearLoaderIssues,
|
|
@@ -21464,7 +21651,6 @@ __export(src_exports, {
|
|
|
21464
21651
|
composeVariantGuidance: () => composeVariantGuidance,
|
|
21465
21652
|
computeGateStateId: () => computeGateStateId,
|
|
21466
21653
|
computePackDigest: () => computePackDigest,
|
|
21467
|
-
computeParentStateId: () => computeParentStateId,
|
|
21468
21654
|
computeStateId: () => computeStateId,
|
|
21469
21655
|
computeStateIdAt: () => computeStateIdAt,
|
|
21470
21656
|
contextDir: () => contextDir,
|
|
@@ -21541,6 +21727,7 @@ __export(src_exports, {
|
|
|
21541
21727
|
hashGateState: () => hashGateState,
|
|
21542
21728
|
importSpecTree: () => importSpecTree,
|
|
21543
21729
|
importSurface: () => importSurface,
|
|
21730
|
+
inspectChainedRoots: () => inspectChainedRoots,
|
|
21544
21731
|
inspectTreeArchive: () => inspectTreeArchive2,
|
|
21545
21732
|
installPackFromDirectory: () => installPackFromDirectory,
|
|
21546
21733
|
internalizeSubsystem: () => internalizeSubsystem,
|
|
@@ -21556,7 +21743,7 @@ __export(src_exports, {
|
|
|
21556
21743
|
listInstalledPacks: () => listInstalledPacks,
|
|
21557
21744
|
listMountSnapshots: () => listMountSnapshots,
|
|
21558
21745
|
listResources: () => listResources,
|
|
21559
|
-
listRules: () =>
|
|
21746
|
+
listRules: () => listRules2,
|
|
21560
21747
|
listSkillNames: () => listSkillNames,
|
|
21561
21748
|
listSkillResources: () => listSkillResources,
|
|
21562
21749
|
listSnapshots: () => listSnapshots,
|
|
@@ -21619,6 +21806,7 @@ __export(src_exports, {
|
|
|
21619
21806
|
readResource: () => readResource,
|
|
21620
21807
|
readSkillResource: () => readSkillResource,
|
|
21621
21808
|
readYamlFile: () => readYamlFile,
|
|
21809
|
+
rebaseReference: () => rebaseReference,
|
|
21622
21810
|
registerExporter: () => registerExporter,
|
|
21623
21811
|
removeFreeStandingDomain: () => removeFreeStandingDomain,
|
|
21624
21812
|
removeSnapshot: () => removeSnapshot,
|
|
@@ -22112,6 +22300,7 @@ function externalizeSubsystem(subsystemId, projectPath) {
|
|
|
22112
22300
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
22113
22301
|
});
|
|
22114
22302
|
rewriteRefsInDir(parentSpecsDir, renameMap, fooDir);
|
|
22303
|
+
rebaseMovedRefs(childFooDir, subsystemId, "into");
|
|
22115
22304
|
invalidateSpecCache();
|
|
22116
22305
|
}
|
|
22117
22306
|
function internalizeSubsystem(subsystemId) {
|
|
@@ -22151,6 +22340,7 @@ function internalizeSubsystem(subsystemId) {
|
|
|
22151
22340
|
});
|
|
22152
22341
|
fs13.rmSync(childWai, { recursive: true, force: true });
|
|
22153
22342
|
rewriteRefsInDir(parentSpecsDir, renameMap, fooDir);
|
|
22343
|
+
rebaseMovedRefs(fooDir, subsystemId, "outOf");
|
|
22154
22344
|
invalidateSpecCache();
|
|
22155
22345
|
}
|
|
22156
22346
|
function buildRenameMap(subsystemId, externalize) {
|
|
@@ -22177,7 +22367,27 @@ function buildRenameMap(subsystemId, externalize) {
|
|
|
22177
22367
|
}
|
|
22178
22368
|
function rewriteRefsInDir(specsDir, renameMap, excludeDir) {
|
|
22179
22369
|
if (renameMap.size === 0) return;
|
|
22180
|
-
|
|
22370
|
+
rewriteRefFields(specsDir, (ref) => renameMap.get(ref) ?? ref, excludeDir);
|
|
22371
|
+
}
|
|
22372
|
+
function rebaseMovedRefs(movedDir, mount, direction) {
|
|
22373
|
+
const declared = componentIdsUnder(movedDir);
|
|
22374
|
+
rewriteRefFields(movedDir, (ref, position) => position === "component" ? rebaseReference(ref, mount, direction, (id) => declared.has(id)) : ref);
|
|
22375
|
+
}
|
|
22376
|
+
function componentIdsUnder(dir) {
|
|
22377
|
+
const ids = /* @__PURE__ */ new Set();
|
|
22378
|
+
for (const file of listFilesRecursive(dir, ".yaml")) {
|
|
22379
|
+
let raw;
|
|
22380
|
+
try {
|
|
22381
|
+
raw = readYamlFile(file);
|
|
22382
|
+
} catch {
|
|
22383
|
+
continue;
|
|
22384
|
+
}
|
|
22385
|
+
if (raw && typeof raw === "object" && "componentType" in raw && typeof raw.id === "string") ids.add(raw.id);
|
|
22386
|
+
}
|
|
22387
|
+
return ids;
|
|
22388
|
+
}
|
|
22389
|
+
function rewriteRefFields(specsDir, remap, excludeDir) {
|
|
22390
|
+
const at = (ref, position) => typeof ref === "string" ? remap(ref, position) : ref;
|
|
22181
22391
|
for (const file of listFilesRecursive(specsDir, ".yaml")) {
|
|
22182
22392
|
if (excludeDir && isWithinDir(excludeDir, file)) continue;
|
|
22183
22393
|
let raw;
|
|
@@ -22189,14 +22399,14 @@ function rewriteRefsInDir(specsDir, renameMap, excludeDir) {
|
|
|
22189
22399
|
if (!raw || typeof raw !== "object") continue;
|
|
22190
22400
|
let changed = false;
|
|
22191
22401
|
if ("componentType" in raw && Array.isArray(raw.dependsOn)) {
|
|
22192
|
-
const next = raw.dependsOn.map((d) =>
|
|
22402
|
+
const next = raw.dependsOn.map((d) => at(d, "component"));
|
|
22193
22403
|
if (next.some((v, i) => v !== raw.dependsOn[i])) {
|
|
22194
22404
|
raw.dependsOn = next;
|
|
22195
22405
|
changed = true;
|
|
22196
22406
|
}
|
|
22197
22407
|
if (Array.isArray(raw.dispatch)) {
|
|
22198
22408
|
for (const b of raw.dispatch) {
|
|
22199
|
-
const nc =
|
|
22409
|
+
const nc = at(b.component, "component");
|
|
22200
22410
|
if (nc !== b.component) {
|
|
22201
22411
|
b.component = nc;
|
|
22202
22412
|
changed = true;
|
|
@@ -22205,7 +22415,7 @@ function rewriteRefsInDir(specsDir, renameMap, excludeDir) {
|
|
|
22205
22415
|
}
|
|
22206
22416
|
} else if ("parentSystem" in raw && Array.isArray(raw.lifecycle)) {
|
|
22207
22417
|
for (const le of raw.lifecycle) {
|
|
22208
|
-
const nc =
|
|
22418
|
+
const nc = at(le.component, "component");
|
|
22209
22419
|
if (nc !== le.component) {
|
|
22210
22420
|
le.component = nc;
|
|
22211
22421
|
changed = true;
|
|
@@ -22215,7 +22425,7 @@ function rewriteRefsInDir(specsDir, renameMap, excludeDir) {
|
|
|
22215
22425
|
for (const m of raw.methods) {
|
|
22216
22426
|
if (!Array.isArray(m.params)) continue;
|
|
22217
22427
|
for (const p of m.params) {
|
|
22218
|
-
const nt =
|
|
22428
|
+
const nt = at(p.type, "type");
|
|
22219
22429
|
if (nt !== p.type) {
|
|
22220
22430
|
p.type = nt;
|
|
22221
22431
|
changed = true;
|
|
@@ -22226,7 +22436,7 @@ function rewriteRefsInDir(specsDir, renameMap, excludeDir) {
|
|
|
22226
22436
|
for (const m of raw.methods) {
|
|
22227
22437
|
if (!Array.isArray(m.narrative)) continue;
|
|
22228
22438
|
for (const step of m.narrative) {
|
|
22229
|
-
const nt =
|
|
22439
|
+
const nt = at(step.targetComponent, "component");
|
|
22230
22440
|
if (nt !== step.targetComponent) {
|
|
22231
22441
|
step.targetComponent = nt;
|
|
22232
22442
|
changed = true;
|
|
@@ -22235,7 +22445,7 @@ function rewriteRefsInDir(specsDir, renameMap, excludeDir) {
|
|
|
22235
22445
|
}
|
|
22236
22446
|
} else if ("kind" in raw && Array.isArray(raw.fields)) {
|
|
22237
22447
|
for (const f of raw.fields) {
|
|
22238
|
-
const nt =
|
|
22448
|
+
const nt = at(f.type, "type");
|
|
22239
22449
|
if (nt !== f.type) {
|
|
22240
22450
|
f.type = nt;
|
|
22241
22451
|
changed = true;
|
|
@@ -22831,18 +23041,29 @@ function discardStagingDir(stagingDir) {
|
|
|
22831
23041
|
} catch {
|
|
22832
23042
|
}
|
|
22833
23043
|
}
|
|
22834
|
-
function exportSpecTree(includeDerived) {
|
|
23044
|
+
function exportSpecTree(includeDerived, allowPartial) {
|
|
22835
23045
|
const system = loadSystemSpec();
|
|
22836
23046
|
if (!system) {
|
|
22837
23047
|
throw new Error("no spec tree to export at this project root");
|
|
22838
23048
|
}
|
|
22839
|
-
const
|
|
23049
|
+
const inspection = inspectChainedRoots();
|
|
22840
23050
|
const root = getProjectRoot();
|
|
22841
|
-
const
|
|
22842
|
-
|
|
22843
|
-
|
|
22844
|
-
|
|
22845
|
-
|
|
23051
|
+
const skipped = [...inspection.skipped];
|
|
23052
|
+
const roots = [{ relativePath: ".", waiDir: aiPathsAt(root).root() }];
|
|
23053
|
+
for (const rel2 of inspection.roots) {
|
|
23054
|
+
const waiDir = aiPathsAt(path22.resolve(root, rel2)).root();
|
|
23055
|
+
if (pathExists(waiDir)) {
|
|
23056
|
+
roots.push({ relativePath: rel2, waiDir });
|
|
23057
|
+
} else {
|
|
23058
|
+
skipped.push({ mount: rel2, projectPath: rel2, reason: "no-spec-tree" });
|
|
23059
|
+
}
|
|
23060
|
+
}
|
|
23061
|
+
if (skipped.length > 0 && !allowPartial) {
|
|
23062
|
+
const detail = skipped.map((s) => `${s.mount} (${s.reason})`).join(", ");
|
|
23063
|
+
throw new Error(
|
|
23064
|
+
`cannot export the whole spec tree \u2014 skipped: ${detail}. Pass allowPartial to export the rest anyway.`
|
|
23065
|
+
);
|
|
23066
|
+
}
|
|
22846
23067
|
const stateId = computeStateId();
|
|
22847
23068
|
const built = buildTreeArchive2(roots, system.name, stateId.digest, includeDerived);
|
|
22848
23069
|
const result = {
|
|
@@ -22851,7 +23072,8 @@ function exportSpecTree(includeDerived) {
|
|
|
22851
23072
|
projectName: built.manifest.projectName,
|
|
22852
23073
|
roots: built.manifest.roots,
|
|
22853
23074
|
fileCount: built.fileCount,
|
|
22854
|
-
stateId: stateId.digest
|
|
23075
|
+
stateId: stateId.digest,
|
|
23076
|
+
skipped
|
|
22855
23077
|
};
|
|
22856
23078
|
return result;
|
|
22857
23079
|
}
|
|
@@ -23372,6 +23594,7 @@ init_yaml();
|
|
|
23372
23594
|
buildRuleContext,
|
|
23373
23595
|
buildServerInstructions,
|
|
23374
23596
|
buildTreeArchive,
|
|
23597
|
+
canonicalize,
|
|
23375
23598
|
captureApprovedSpecs,
|
|
23376
23599
|
checkSkillFreshness,
|
|
23377
23600
|
clearLoaderIssues,
|
|
@@ -23382,7 +23605,6 @@ init_yaml();
|
|
|
23382
23605
|
composeVariantGuidance,
|
|
23383
23606
|
computeGateStateId,
|
|
23384
23607
|
computePackDigest,
|
|
23385
|
-
computeParentStateId,
|
|
23386
23608
|
computeStateId,
|
|
23387
23609
|
computeStateIdAt,
|
|
23388
23610
|
contextDir,
|
|
@@ -23459,6 +23681,7 @@ init_yaml();
|
|
|
23459
23681
|
hashGateState,
|
|
23460
23682
|
importSpecTree,
|
|
23461
23683
|
importSurface,
|
|
23684
|
+
inspectChainedRoots,
|
|
23462
23685
|
inspectTreeArchive,
|
|
23463
23686
|
installPackFromDirectory,
|
|
23464
23687
|
internalizeSubsystem,
|
|
@@ -23537,6 +23760,7 @@ init_yaml();
|
|
|
23537
23760
|
readResource,
|
|
23538
23761
|
readSkillResource,
|
|
23539
23762
|
readYamlFile,
|
|
23763
|
+
rebaseReference,
|
|
23540
23764
|
registerExporter,
|
|
23541
23765
|
removeFreeStandingDomain,
|
|
23542
23766
|
removeSnapshot,
|