@specverse/engines 6.32.0 → 6.33.0
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/ai/analyse-runner.d.ts.map +1 -1
- package/dist/ai/analyse-runner.js +8 -1
- package/dist/ai/analyse-runner.js.map +1 -1
- package/dist/ai/behaviours-runner.d.ts.map +1 -1
- package/dist/ai/behaviours-runner.js +35 -7
- package/dist/ai/behaviours-runner.js.map +1 -1
- package/dist/ai/create-runner.d.ts.map +1 -1
- package/dist/ai/create-runner.js +6 -0
- package/dist/ai/create-runner.js.map +1 -1
- package/dist/ai/deployment-emitter.d.ts +3 -0
- package/dist/ai/deployment-emitter.d.ts.map +1 -1
- package/dist/ai/deployment-emitter.js +145 -0
- package/dist/ai/deployment-emitter.js.map +1 -1
- package/dist/ai/manifest-emitter.d.ts +35 -10
- package/dist/ai/manifest-emitter.d.ts.map +1 -1
- package/dist/ai/manifest-emitter.js +140 -54
- package/dist/ai/manifest-emitter.js.map +1 -1
- package/dist/ai/skeleton-emitter.d.ts +1 -1
- package/dist/ai/skeleton-emitter.d.ts.map +1 -1
- package/dist/ai/skeleton-emitter.js +152 -14
- package/dist/ai/skeleton-emitter.js.map +1 -1
- package/dist/analyse-prepass/imports-graph.d.ts +407 -0
- package/dist/analyse-prepass/imports-graph.d.ts.map +1 -0
- package/dist/analyse-prepass/imports-graph.js +1200 -0
- package/dist/analyse-prepass/imports-graph.js.map +1 -0
- package/dist/analyse-prepass/index.d.ts +33 -0
- package/dist/analyse-prepass/index.d.ts.map +1 -1
- package/dist/analyse-prepass/index.js +35 -0
- package/dist/analyse-prepass/index.js.map +1 -1
- package/dist/inference/logical/generators/view-generator.d.ts +10 -0
- package/dist/inference/logical/generators/view-generator.d.ts.map +1 -1
- package/dist/inference/logical/generators/view-generator.js +20 -0
- package/dist/inference/logical/generators/view-generator.js.map +1 -1
- package/dist/libs/instance-factories/orms/templates/prisma/schema-generator.js +66 -4
- package/dist/parser/unified-parser.d.ts.map +1 -1
- package/dist/parser/unified-parser.js +103 -0
- package/dist/parser/unified-parser.js.map +1 -1
- package/dist/realize/index.d.ts.map +1 -1
- package/dist/realize/index.js +73 -148
- package/dist/realize/index.js.map +1 -1
- package/dist/realize/per-action-emitter.d.ts +235 -0
- package/dist/realize/per-action-emitter.d.ts.map +1 -0
- package/dist/realize/per-action-emitter.js +229 -0
- package/dist/realize/per-action-emitter.js.map +1 -0
- package/dist/realize/per-action-llm-emit.d.ts +87 -0
- package/dist/realize/per-action-llm-emit.d.ts.map +1 -0
- package/dist/realize/per-action-llm-emit.js +427 -0
- package/dist/realize/per-action-llm-emit.js.map +1 -0
- package/dist/realize/per-action-runner.d.ts +127 -0
- package/dist/realize/per-action-runner.d.ts.map +1 -0
- package/dist/realize/per-action-runner.js +269 -0
- package/dist/realize/per-action-runner.js.map +1 -0
- package/dist/realize/structural-validator.d.ts +71 -0
- package/dist/realize/structural-validator.d.ts.map +1 -0
- package/dist/realize/structural-validator.js +167 -0
- package/dist/realize/structural-validator.js.map +1 -0
- package/libs/instance-factories/orms/templates/prisma/__tests__/schema-generator.test.ts +416 -0
- package/libs/instance-factories/orms/templates/prisma/schema-generator.ts +182 -5
- package/package.json +3 -3
|
@@ -22,16 +22,25 @@
|
|
|
22
22
|
*
|
|
23
23
|
* The mapping IS a lookup table. This module IS that lookup table.
|
|
24
24
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
25
|
+
* V2 (engines 6.32.2+) — every emitted factory name MUST resolve in
|
|
26
|
+
* the registered InstanceFactoryLibrary. The previous hand-curated
|
|
27
|
+
* mapping referenced names that don't exist (`ExpressAPI`, `NestJSAPI`,
|
|
28
|
+
* `MongoDBDriver`, `ReactRuntime`, `ReactNativeApp`) — realize then
|
|
29
|
+
* left every model with `factory: unknown` and produced no code.
|
|
30
|
+
*
|
|
31
|
+
* Current mapping (registered factory names only — see
|
|
32
|
+
* `libs/instance-factories/<category>/<name>.yaml`):
|
|
33
|
+
* - api.rest → FastifyAPI (only HTTP factory shipped)
|
|
34
|
+
* - storage.database → PostgreSQL15 | MongoDBNativeDriver
|
|
35
|
+
* - orm.schema/client → PrismaORM (when prisma signal present)
|
|
36
|
+
* - service.controller/business/crud → PrismaServices
|
|
37
|
+
* - app.frontend → ReactAppRuntime (no RN factory exists yet)
|
|
38
|
+
* - messaging.events → EventEmitter
|
|
39
|
+
* - validation.runtime → ZodValidation
|
|
40
|
+
* - app.entrypoint → GenericApp
|
|
41
|
+
* - project.scaffold → GenericScaffold
|
|
42
|
+
* Edge cases (drizzle, knex, vue, svelte, react-native, etc.) fall
|
|
43
|
+
* through to the closest valid default and the user hand-edits.
|
|
35
44
|
*/
|
|
36
45
|
import type { SpecVerseFacts } from '../analyse-prepass/index.js';
|
|
37
46
|
export interface ManifestEmissionInput {
|
|
@@ -56,5 +65,21 @@ export interface ManifestEmissionResult {
|
|
|
56
65
|
* complete top-level YAML document (with specVersion) suitable for
|
|
57
66
|
* writing to `manifests/implementation.yaml`.
|
|
58
67
|
*/
|
|
68
|
+
/**
|
|
69
|
+
* Engines 6.32.2+ — registry of factory names actually present in the
|
|
70
|
+
* shipped instance-factory library (`engines/libs/instance-factories/`).
|
|
71
|
+
* Source: `find libs/instance-factories -name '*.yaml' | xargs grep '^name:'`.
|
|
72
|
+
*
|
|
73
|
+
* Manifest emission MUST pick from this set; emitting a non-existent
|
|
74
|
+
* name leaves every realize-time model with `factory: unknown` and
|
|
75
|
+
* produces no code. The previous emitter referenced ExpressAPI /
|
|
76
|
+
* NestJSAPI / MongoDBDriver / ReactNativeApp / ReactRuntime — none of
|
|
77
|
+
* which exist — and bored-stiff realize would silently emit nothing.
|
|
78
|
+
*
|
|
79
|
+
* Hand-edit consumers can still write any factory name they like in
|
|
80
|
+
* the manifest; this guard only protects auto-emitted manifests from
|
|
81
|
+
* the analyse pipeline.
|
|
82
|
+
*/
|
|
83
|
+
export declare const KNOWN_FACTORIES: ReadonlySet<string>;
|
|
59
84
|
export declare function emitManifest(input: ManifestEmissionInput): ManifestEmissionResult;
|
|
60
85
|
//# sourceMappingURL=manifest-emitter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest-emitter.d.ts","sourceRoot":"","sources":["../../src/ai/manifest-emitter.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"manifest-emitter.d.ts","sourceRoot":"","sources":["../../src/ai/manifest-emitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE,MAAM,WAAW,qBAAqB;IACpC,+CAA+C;IAC/C,KAAK,EAAE,cAAc,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACrC,6EAA6E;IAC7E,YAAY,EAAE,MAAM,CAAC;IACrB,mEAAmE;IACnE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED;;;;GAIG;AACH;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CAO9C,CAAC;AAEH,wBAAgB,YAAY,CAAC,KAAK,EAAE,qBAAqB,GAAG,sBAAsB,CAqJjF"}
|
|
@@ -22,22 +22,54 @@
|
|
|
22
22
|
*
|
|
23
23
|
* The mapping IS a lookup table. This module IS that lookup table.
|
|
24
24
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
25
|
+
* V2 (engines 6.32.2+) — every emitted factory name MUST resolve in
|
|
26
|
+
* the registered InstanceFactoryLibrary. The previous hand-curated
|
|
27
|
+
* mapping referenced names that don't exist (`ExpressAPI`, `NestJSAPI`,
|
|
28
|
+
* `MongoDBDriver`, `ReactRuntime`, `ReactNativeApp`) — realize then
|
|
29
|
+
* left every model with `factory: unknown` and produced no code.
|
|
30
|
+
*
|
|
31
|
+
* Current mapping (registered factory names only — see
|
|
32
|
+
* `libs/instance-factories/<category>/<name>.yaml`):
|
|
33
|
+
* - api.rest → FastifyAPI (only HTTP factory shipped)
|
|
34
|
+
* - storage.database → PostgreSQL15 | MongoDBNativeDriver
|
|
35
|
+
* - orm.schema/client → PrismaORM (when prisma signal present)
|
|
36
|
+
* - service.controller/business/crud → PrismaServices
|
|
37
|
+
* - app.frontend → ReactAppRuntime (no RN factory exists yet)
|
|
38
|
+
* - messaging.events → EventEmitter
|
|
39
|
+
* - validation.runtime → ZodValidation
|
|
40
|
+
* - app.entrypoint → GenericApp
|
|
41
|
+
* - project.scaffold → GenericScaffold
|
|
42
|
+
* Edge cases (drizzle, knex, vue, svelte, react-native, etc.) fall
|
|
43
|
+
* through to the closest valid default and the user hand-edits.
|
|
35
44
|
*/
|
|
36
45
|
/**
|
|
37
46
|
* Emit a deterministic manifest from prepass facts. The output is a
|
|
38
47
|
* complete top-level YAML document (with specVersion) suitable for
|
|
39
48
|
* writing to `manifests/implementation.yaml`.
|
|
40
49
|
*/
|
|
50
|
+
/**
|
|
51
|
+
* Engines 6.32.2+ — registry of factory names actually present in the
|
|
52
|
+
* shipped instance-factory library (`engines/libs/instance-factories/`).
|
|
53
|
+
* Source: `find libs/instance-factories -name '*.yaml' | xargs grep '^name:'`.
|
|
54
|
+
*
|
|
55
|
+
* Manifest emission MUST pick from this set; emitting a non-existent
|
|
56
|
+
* name leaves every realize-time model with `factory: unknown` and
|
|
57
|
+
* produces no code. The previous emitter referenced ExpressAPI /
|
|
58
|
+
* NestJSAPI / MongoDBDriver / ReactNativeApp / ReactRuntime — none of
|
|
59
|
+
* which exist — and bored-stiff realize would silently emit nothing.
|
|
60
|
+
*
|
|
61
|
+
* Hand-edit consumers can still write any factory name they like in
|
|
62
|
+
* the manifest; this guard only protects auto-emitted manifests from
|
|
63
|
+
* the analyse pipeline.
|
|
64
|
+
*/
|
|
65
|
+
export const KNOWN_FACTORIES = new Set([
|
|
66
|
+
'CommanderJS', 'DockerKubernetes', 'EventEmitter', 'FastifyAPI',
|
|
67
|
+
'GenericApp', 'GenericScaffold', 'MCPServer', 'MongoDB6',
|
|
68
|
+
'MongoDBNativeDriver', 'PostgresNativeDriver', 'PostgreSQL15',
|
|
69
|
+
'PrismaORM', 'PrismaServices', 'PythonSDK', 'RabbitMQEvents',
|
|
70
|
+
'ReactAppRuntime', 'ReactAppStarter', 'Redis7', 'TypeScriptSDK',
|
|
71
|
+
'VitestTests', 'VSCodeExtension', 'ZodValidation',
|
|
72
|
+
]);
|
|
41
73
|
export function emitManifest(input) {
|
|
42
74
|
const adapters = new Set(input.facts.meta?.adaptersRun ?? []);
|
|
43
75
|
const entities = input.facts.entities ?? [];
|
|
@@ -45,76 +77,130 @@ export function emitManifest(input) {
|
|
|
45
77
|
const choices = {};
|
|
46
78
|
const rationale = {};
|
|
47
79
|
// ── api.rest — HTTP framework ─────────────────────────────────────
|
|
80
|
+
// Only FastifyAPI exists in the registry today. Express / Nest signals
|
|
81
|
+
// are recorded in rationale so a human knows the framework the source
|
|
82
|
+
// actually uses, but the auto-emitted choice is FastifyAPI either way.
|
|
48
83
|
if (adapters.has('express-routes')) {
|
|
49
|
-
choices['api.rest'] = '
|
|
50
|
-
rationale['api.rest'] = 'express-
|
|
84
|
+
choices['api.rest'] = 'FastifyAPI';
|
|
85
|
+
rationale['api.rest'] = 'source uses express; auto-mapped to FastifyAPI (only HTTP factory in registry — hand-edit to a real ExpressAPI factory once added)';
|
|
51
86
|
}
|
|
52
87
|
else if (adapters.has('typescript-decorators')) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
// this path, but if they did, NestJSAPI is still a reasonable default
|
|
56
|
-
// since it ships off NestJS conventions.)
|
|
57
|
-
choices['api.rest'] = 'NestJSAPI';
|
|
58
|
-
rationale['api.rest'] = 'typescript-decorators adapter — NestJS is the dominant decorator-based REST framework in the corpus';
|
|
88
|
+
choices['api.rest'] = 'FastifyAPI';
|
|
89
|
+
rationale['api.rest'] = 'source uses NestJS-style decorators; auto-mapped to FastifyAPI (only HTTP factory in registry)';
|
|
59
90
|
}
|
|
60
91
|
else {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
choices['api.rest'] = 'ExpressAPI';
|
|
64
|
-
rationale['api.rest'] = 'no framework signal detected; defaulting to ExpressAPI (most common in the corpus)';
|
|
92
|
+
choices['api.rest'] = 'FastifyAPI';
|
|
93
|
+
rationale['api.rest'] = 'no specific framework signal; FastifyAPI is the registry default for HTTP';
|
|
65
94
|
}
|
|
66
|
-
// ── storage — relational vs document
|
|
95
|
+
// ── storage.database — relational vs document ─────────────────────
|
|
96
|
+
// Choose between PostgreSQL15 (relational) and MongoDBNativeDriver
|
|
97
|
+
// (document) based on prisma signal. Both are real registered
|
|
98
|
+
// factories. Storage.relational and storage.documents capabilities
|
|
99
|
+
// are NOT what the realize engine asks for — it wants
|
|
100
|
+
// `storage.database` plus an optional `orm.schema` / `orm.client`
|
|
101
|
+
// pair when the source uses an ORM.
|
|
67
102
|
if (adapters.has('typescript-prisma')) {
|
|
68
|
-
choices['storage.
|
|
69
|
-
rationale['storage.
|
|
103
|
+
choices['storage.database'] = 'PostgreSQL15';
|
|
104
|
+
rationale['storage.database'] = 'typescript-prisma adapter detected schema.prisma — pairing with PostgreSQL15';
|
|
105
|
+
choices['orm.schema'] = 'PrismaORM';
|
|
106
|
+
choices['orm.client'] = 'PrismaORM';
|
|
107
|
+
rationale['orm.schema'] = 'prisma signal — PrismaORM for schema + client';
|
|
70
108
|
}
|
|
71
109
|
else {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
110
|
+
choices['storage.database'] = 'MongoDBNativeDriver';
|
|
111
|
+
rationale['storage.database'] = 'no prisma signal — defaulting to MongoDBNativeDriver (document store)';
|
|
112
|
+
}
|
|
113
|
+
// ── service.controller / business / crud ──────────────────────────
|
|
114
|
+
// The only services factory shipped today is PrismaServices, which
|
|
115
|
+
// works against PostgreSQL15 + PrismaORM. For document-store paths
|
|
116
|
+
// there's currently no equivalent — the user must hand-edit. Emit
|
|
117
|
+
// PrismaServices as the default; rationale notes the gap.
|
|
118
|
+
const servicesFactory = 'PrismaServices';
|
|
119
|
+
for (const cap of ['service.controller', 'service.business', 'service.crud']) {
|
|
120
|
+
choices[cap] = servicesFactory;
|
|
78
121
|
}
|
|
79
|
-
|
|
122
|
+
rationale['service.*'] = adapters.has('typescript-prisma')
|
|
123
|
+
? 'PrismaServices — paired with the PrismaORM stack'
|
|
124
|
+
: 'PrismaServices is the only services factory in the registry today; non-prisma stacks need hand-editing';
|
|
125
|
+
// ── messaging.events ─────────────────────────────────────────────
|
|
126
|
+
choices['messaging.events'] = 'EventEmitter';
|
|
127
|
+
rationale['messaging.events'] = 'in-process EventEmitter is the simplest default — swap for RabbitMQEvents when distribution required';
|
|
128
|
+
// ── validation.runtime ───────────────────────────────────────────
|
|
129
|
+
// Always emit ZodValidation when a `const-schemas` adapter ran (Zod
|
|
130
|
+
// const schemas detected) OR as a low-friction default.
|
|
131
|
+
choices['validation.runtime'] = 'ZodValidation';
|
|
132
|
+
rationale['validation.runtime'] = adapters.has('zod-schemas') || adapters.has('backend-schemas')
|
|
133
|
+
? 'zod schemas detected in source'
|
|
134
|
+
: 'ZodValidation as low-friction validator default';
|
|
135
|
+
// ── app.entrypoint + project.scaffold (always emit) ──────────────
|
|
136
|
+
choices['app.entrypoint'] = 'GenericApp';
|
|
137
|
+
choices['project.scaffold'] = 'GenericScaffold';
|
|
138
|
+
rationale['app.entrypoint'] = 'GenericApp — single entry-point shell';
|
|
139
|
+
rationale['project.scaffold'] = 'GenericScaffold — root-level project files';
|
|
140
|
+
// ── app.frontend (when React detected) ───────────────────────────
|
|
80
141
|
if (adapters.has('react-views')) {
|
|
81
|
-
// RN signal: any view file path contains `react-native` or has
|
|
82
|
-
// `Screen` in the name (the screen convention).
|
|
83
142
|
const isReactNative = views.some((v) => v.filePath.includes('react-native') || v.filePath.includes('-mobile') || v.isScreen);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
else {
|
|
89
|
-
choices['ui.framework'] = 'ReactRuntime';
|
|
90
|
-
rationale['ui.framework'] = 'react-views adapter detected JSX components without RN signals';
|
|
91
|
-
}
|
|
143
|
+
choices['app.frontend'] = 'ReactAppRuntime';
|
|
144
|
+
rationale['app.frontend'] = isReactNative
|
|
145
|
+
? 'react-views adapter detected RN screens — auto-mapped to ReactAppRuntime (no RN factory in registry yet; emits a web SPA shell instead)'
|
|
146
|
+
: 'react-views adapter detected JSX components — using ReactAppRuntime';
|
|
92
147
|
}
|
|
93
|
-
// ── auth.jwt
|
|
94
|
-
//
|
|
95
|
-
// This is a weak signal but better than asking an LLM to guess.
|
|
148
|
+
// ── auth.jwt ─────────────────────────────────────────────────────
|
|
149
|
+
// Reuses the api.rest factory — Fastify ships JWT plugin support.
|
|
96
150
|
const entityNames = new Set(entities.map((e) => e.name.toLowerCase()));
|
|
97
151
|
const hasJwtSignal = entityNames.has('refreshtoken')
|
|
98
152
|
|| entityNames.has('authsession')
|
|
99
153
|
|| entityNames.has('authservice')
|
|
100
154
|
|| entityNames.has('apitoken');
|
|
101
155
|
if (hasJwtSignal) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// also handles auth.jwt by default. We still emit the mapping so
|
|
105
|
-
// the realize engine doesn't have to guess.
|
|
106
|
-
choices['auth.jwt'] = choices['api.rest'] ?? 'ExpressAPI';
|
|
107
|
-
rationale['auth.jwt'] = 'detected RefreshToken/AuthSession entity — using api.rest factory for JWT path';
|
|
156
|
+
choices['auth.jwt'] = choices['api.rest'];
|
|
157
|
+
rationale['auth.jwt'] = 'detected RefreshToken/AuthSession/AuthService entity — JWT path handled by the api.rest factory';
|
|
108
158
|
}
|
|
109
|
-
//
|
|
159
|
+
// ── Final guard: drop any choice that isn't a registered factory ─
|
|
160
|
+
// Belt-and-braces — if a future code path emits a name we forgot to
|
|
161
|
+
// register, log + drop instead of silently shipping a manifest that
|
|
162
|
+
// realize will refuse to use.
|
|
163
|
+
for (const cap of Object.keys(choices)) {
|
|
164
|
+
const name = choices[cap];
|
|
165
|
+
if (!KNOWN_FACTORIES.has(name)) {
|
|
166
|
+
rationale[cap] = `${rationale[cap] ?? ''} — DROPPED: factory "${name}" not in registry`;
|
|
167
|
+
delete choices[cap];
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// Build the yaml document. Engines 6.32.4+ — emit the array form
|
|
171
|
+
// `capabilityMappings: [{ capability, instanceFactory }, …]` and a
|
|
172
|
+
// `defaultMappings` block. The realize-engine loader (manifest-loader.ts)
|
|
173
|
+
// expects the array form; the previous hashmap form parsed cleanly
|
|
174
|
+
// but resolveCapability() then never matched any factory, leaving
|
|
175
|
+
// every model with `factory: unknown` and no code emitted.
|
|
176
|
+
const specName = input.specName ?? 'AnalysedSpec';
|
|
110
177
|
const lines = [];
|
|
111
178
|
lines.push('specVersion: "1.0"');
|
|
112
|
-
lines.push(`name: ${
|
|
179
|
+
lines.push(`name: ${specName}`);
|
|
113
180
|
lines.push('');
|
|
181
|
+
// defaultMappings — quick fallback the realize engine consults when
|
|
182
|
+
// a capability has no explicit row. Pull from the choice set when we
|
|
183
|
+
// emitted one for the canonical capability.
|
|
184
|
+
const defaultMappings = [
|
|
185
|
+
['storage', choices['storage.database']],
|
|
186
|
+
['controller', choices['service.controller']],
|
|
187
|
+
['service', choices['service.business']],
|
|
188
|
+
['routing', choices['api.rest']],
|
|
189
|
+
['orm', choices['orm.schema']],
|
|
190
|
+
['communication', choices['messaging.events']],
|
|
191
|
+
];
|
|
192
|
+
const defaults = defaultMappings.filter(([, v]) => v !== undefined);
|
|
193
|
+
if (defaults.length > 0) {
|
|
194
|
+
lines.push('defaultMappings:');
|
|
195
|
+
for (const [k, v] of defaults)
|
|
196
|
+
lines.push(` ${k}: "${v}"`);
|
|
197
|
+
lines.push('');
|
|
198
|
+
}
|
|
114
199
|
lines.push('capabilityMappings:');
|
|
115
200
|
// Stable ordering — sort keys for reproducibility.
|
|
116
201
|
for (const cap of Object.keys(choices).sort()) {
|
|
117
|
-
lines.push(`
|
|
202
|
+
lines.push(` - capability: "${cap}"`);
|
|
203
|
+
lines.push(` instanceFactory: "${choices[cap]}"`);
|
|
118
204
|
}
|
|
119
205
|
lines.push('');
|
|
120
206
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest-emitter.js","sourceRoot":"","sources":["../../src/ai/manifest-emitter.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"manifest-emitter.js","sourceRoot":"","sources":["../../src/ai/manifest-emitter.ts"],"names":[],"mappings":"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"}
|
|
@@ -34,7 +34,7 @@ export interface SkeletonEmissionDecision {
|
|
|
34
34
|
/** Free-form note for human readers. */
|
|
35
35
|
note?: string;
|
|
36
36
|
}
|
|
37
|
-
export type SkeletonEmissionRule = 'header-component-from-suggested' | 'header-component-default-when-none-suggested' | 'model-from-detected-entity' | 'model-attribute-from-detected-attribute' | 'model-relationship-from-detected-relationship' | 'model-lifecycle-from-detected-lifecycle' | 'model-lifecycle-transition-from-detected-transition' | 'controller-from-walked-class' | 'service-from-walked-class' | 'cured-op-from-level1-curved-method' | 'action-stub-from-business-method' | 'event-from-detected-emit' | 'view-from-react-component' | 'view-description-from-react-kind' | 'view-description-from-source-docstring' | 'view-description-from-humanized-name' | 'view-type-from-jsx-classifier' | 'view-uses-from-jsx-composition' | 'view-action-from-jsx-handler' | 'view-empty-state-from-jsx-conditional' | 'comment-skeleton-marker';
|
|
37
|
+
export type SkeletonEmissionRule = 'header-component-from-suggested' | 'header-component-default-when-none-suggested' | 'model-from-detected-entity' | 'model-attribute-from-detected-attribute' | 'model-relationship-from-detected-relationship' | 'model-lifecycle-from-detected-lifecycle' | 'model-lifecycle-transition-from-detected-transition' | 'controller-from-walked-class' | 'service-from-walked-class' | 'cured-op-from-level1-curved-method' | 'action-stub-from-business-method' | 'event-from-detected-emit' | 'view-from-react-component' | 'view-description-from-react-kind' | 'view-description-from-source-docstring' | 'view-description-from-humanized-name' | 'view-type-from-jsx-classifier' | 'view-uses-from-jsx-composition' | 'view-action-from-jsx-handler' | 'view-empty-state-from-jsx-conditional' | 'import-from-component-imports-graph' | 'import-from-non-library-subprocess' | 'import-from-non-library-service-client' | 'import-from-non-library-messaging' | 'import-from-non-library-managed-sdk' | 'comment-skeleton-marker';
|
|
38
38
|
export interface SkeletonProvenance {
|
|
39
39
|
schemaVersion: '1.0';
|
|
40
40
|
/** When the skeleton was emitted (ISO timestamp). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skeleton-emitter.d.ts","sourceRoot":"","sources":["../../src/ai/skeleton-emitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE,MAAM,WAAW,wBAAwB;IACvC,mEAAmE;IACnE,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,IAAI,EAAE,oBAAoB,CAAC;IAC3B,+EAA+E;IAC/E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iFAAiF;IACjF,cAAc,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IACnE,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,oBAAoB,GAC5B,iCAAiC,GACjC,8CAA8C,GAC9C,4BAA4B,GAC5B,yCAAyC,GACzC,+CAA+C,GAC/C,yCAAyC,GACzC,qDAAqD,GACrD,8BAA8B,GAC9B,2BAA2B,GAC3B,oCAAoC,GACpC,kCAAkC,GAClC,0BAA0B,GAC1B,2BAA2B,GAC3B,kCAAkC,GAClC,wCAAwC,GACxC,sCAAsC,GACtC,+BAA+B,GAC/B,gCAAgC,GAChC,8BAA8B,GAC9B,uCAAuC,GACvC,yBAAyB,CAAC;AAE9B,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,KAAK,CAAC;IACrB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,aAAa,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,mDAAmD;IACnD,SAAS,EAAE,wBAAwB,EAAE,CAAC;IACtC;;sDAEkD;IAClD,WAAW,EAAE,KAAK,CAAC;QACjB,aAAa,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,YAAY,GAAG,SAAS,CAAC;QACpC,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,cAAc,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;SAAE,CAAC;QAClE,sEAAsE;QACtE,kBAAkB,EAAE;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,MAAM,CAAA;SAAE,CAAC;QAC/D,4EAA4E;QAC5E,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;IACH;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,KAAK,CAAC;QAC5B,UAAU,EAAE,MAAM,CAAC;QACnB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,MAAM,EAAE,mBAAmB,GAAG,UAAU,CAAC;QACzC,6BAA6B,CAAC,EAAE,MAAM,CAAC;KACxC,CAAC,CAAC;CACJ;
|
|
1
|
+
{"version":3,"file":"skeleton-emitter.d.ts","sourceRoot":"","sources":["../../src/ai/skeleton-emitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE,MAAM,WAAW,wBAAwB;IACvC,mEAAmE;IACnE,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,IAAI,EAAE,oBAAoB,CAAC;IAC3B,+EAA+E;IAC/E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iFAAiF;IACjF,cAAc,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IACnE,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,oBAAoB,GAC5B,iCAAiC,GACjC,8CAA8C,GAC9C,4BAA4B,GAC5B,yCAAyC,GACzC,+CAA+C,GAC/C,yCAAyC,GACzC,qDAAqD,GACrD,8BAA8B,GAC9B,2BAA2B,GAC3B,oCAAoC,GACpC,kCAAkC,GAClC,0BAA0B,GAC1B,2BAA2B,GAC3B,kCAAkC,GAClC,wCAAwC,GACxC,sCAAsC,GACtC,+BAA+B,GAC/B,gCAAgC,GAChC,8BAA8B,GAC9B,uCAAuC,GACvC,qCAAqC,GACrC,oCAAoC,GACpC,wCAAwC,GACxC,mCAAmC,GACnC,qCAAqC,GACrC,yBAAyB,CAAC;AAE9B,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,KAAK,CAAC;IACrB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,aAAa,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,mDAAmD;IACnD,SAAS,EAAE,wBAAwB,EAAE,CAAC;IACtC;;sDAEkD;IAClD,WAAW,EAAE,KAAK,CAAC;QACjB,aAAa,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,YAAY,GAAG,SAAS,CAAC;QACpC,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,cAAc,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;SAAE,CAAC;QAClE,sEAAsE;QACtE,kBAAkB,EAAE;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,MAAM,CAAA;SAAE,CAAC;QAC/D,4EAA4E;QAC5E,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;IACH;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,KAAK,CAAC;QAC5B,UAAU,EAAE,MAAM,CAAC;QACnB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,MAAM,EAAE,mBAAmB,GAAG,UAAU,CAAC;QACzC,6BAA6B,CAAC,EAAE,MAAM,CAAC;KACxC,CAAC,CAAC;CACJ;AAqLD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,cAAc,GAAG;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,kBAAkB,CAAC;IAC/B;;;;OAIG;IACH,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACjF,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC,CAkHA"}
|
|
@@ -76,7 +76,41 @@ function buildContext(facts) {
|
|
|
76
76
|
matchedComponentSuggestedName: matchedComp?.suggestedName,
|
|
77
77
|
});
|
|
78
78
|
}
|
|
79
|
-
|
|
79
|
+
// Engines 6.32.2+ — global single-home for service classes. Walk
|
|
80
|
+
// components in iteration order; first bucket to claim a className
|
|
81
|
+
// owns it. Duplicates in later buckets get skipped at emit time.
|
|
82
|
+
const serviceHome = new Map();
|
|
83
|
+
for (const comp of components) {
|
|
84
|
+
const bucket = classesByComponent.get(comp.suggestedName) ?? [];
|
|
85
|
+
for (const cm of bucket) {
|
|
86
|
+
if (!serviceHome.has(cm.entityName)) {
|
|
87
|
+
serviceHome.set(cm.entityName, comp.suggestedName);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
for (const cm of classesByComponent.get('_unassigned') ?? []) {
|
|
92
|
+
if (!serviceHome.has(cm.entityName)) {
|
|
93
|
+
serviceHome.set(cm.entityName, '_unassigned');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Engines 6.32.2+ — global single-home for views. First component
|
|
97
|
+
// whose sourceDir prefixes the view's filePath owns it; duplicates
|
|
98
|
+
// in later components get skipped.
|
|
99
|
+
const viewHome = new Map();
|
|
100
|
+
for (const v of facts.views ?? []) {
|
|
101
|
+
if (viewHome.has(v.name))
|
|
102
|
+
continue;
|
|
103
|
+
let assigned = null;
|
|
104
|
+
for (const comp of components) {
|
|
105
|
+
const sd = comp.structural?.sourceDir;
|
|
106
|
+
if (sd && v.filePath.startsWith(sd)) {
|
|
107
|
+
assigned = comp.suggestedName;
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
viewHome.set(v.name, assigned ?? '_unassigned');
|
|
112
|
+
}
|
|
113
|
+
return { facts, classByName, classesByComponent, entityHome, serviceHome, viewHome, entityHomeAssignments };
|
|
80
114
|
}
|
|
81
115
|
/**
|
|
82
116
|
* Stateful builder collecting yaml lines + provenance entries in step.
|
|
@@ -239,6 +273,99 @@ export function emitFaithfulSkeleton(facts) {
|
|
|
239
273
|
};
|
|
240
274
|
}
|
|
241
275
|
function emitComponentBody(b, ctx, specName, bucketKey, _comp) {
|
|
276
|
+
// ── import: (engines 6.32.6+) ─────────────────────────────────────
|
|
277
|
+
// Cross-component `import:` blocks emitted from facts.importsByComponent
|
|
278
|
+
// (built by analyse-prepass/imports-graph.ts). For each consumer-target
|
|
279
|
+
// pair, emit one entry under `import:` with the symbols pulled in.
|
|
280
|
+
// Target-component name is the post-strip spec name; symbols are
|
|
281
|
+
// sorted for stable diffs.
|
|
282
|
+
//
|
|
283
|
+
// V2 Phase 2 (2026-05-08): also emit entries for detected non-library
|
|
284
|
+
// dependencies — subprocess executables, service clients, messaging
|
|
285
|
+
// brokers, managed-SDK clients. These come from
|
|
286
|
+
// facts.nonLibraryImportsByComponent and live in the same `import:`
|
|
287
|
+
// block as in-tree component refs (V2's principle: one place for all
|
|
288
|
+
// dependency declarations on the consumer side).
|
|
289
|
+
const importsForThis = ctx.facts.importsByComponent?.[bucketKey];
|
|
290
|
+
const nonLibraryHints = ctx.facts.nonLibraryImportsByComponent?.[bucketKey];
|
|
291
|
+
const hasInTreeImports = importsForThis && Object.keys(importsForThis).length > 0;
|
|
292
|
+
const hasNonLibraryImports = nonLibraryHints && nonLibraryHints.length > 0;
|
|
293
|
+
if (hasInTreeImports || hasNonLibraryImports) {
|
|
294
|
+
b.emit(` import:\n`, {
|
|
295
|
+
yamlPath: `components.${specName}.import`,
|
|
296
|
+
rule: 'comment-skeleton-marker',
|
|
297
|
+
});
|
|
298
|
+
if (hasInTreeImports) {
|
|
299
|
+
for (const targetSuggestedName of Object.keys(importsForThis).sort()) {
|
|
300
|
+
const targetSpecName = targetSuggestedName.replace(/Component$/, '') || targetSuggestedName;
|
|
301
|
+
const symbols = importsForThis[targetSuggestedName] ?? [];
|
|
302
|
+
b.emit(` - from: "${targetSpecName}"\n`, {
|
|
303
|
+
yamlPath: `components.${specName}.import[${targetSpecName}]`,
|
|
304
|
+
rule: 'import-from-component-imports-graph',
|
|
305
|
+
});
|
|
306
|
+
if (symbols.length > 0) {
|
|
307
|
+
// Engines 6.32.10+: block-array form when the symbol list is
|
|
308
|
+
// long. Single-line flow-arrays are valid YAML but unreadable
|
|
309
|
+
// when dozens of symbols pile up (mythology-mobile imports 28
|
|
310
|
+
// symbols from Ui).
|
|
311
|
+
const useBlockForm = symbols.length > 4 || symbols.join(', ').length > 70;
|
|
312
|
+
if (useBlockForm) {
|
|
313
|
+
b.emit(` select:\n`, {
|
|
314
|
+
yamlPath: `components.${specName}.import[${targetSpecName}].select`,
|
|
315
|
+
rule: 'import-from-component-imports-graph',
|
|
316
|
+
});
|
|
317
|
+
for (const sym of symbols) {
|
|
318
|
+
b.emit(` - ${sym}\n`, {
|
|
319
|
+
yamlPath: `components.${specName}.import[${targetSpecName}].select.${sym}`,
|
|
320
|
+
rule: 'import-from-component-imports-graph',
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
b.emit(` select: [${symbols.join(', ')}]\n`, {
|
|
326
|
+
yamlPath: `components.${specName}.import[${targetSpecName}].select`,
|
|
327
|
+
rule: 'import-from-component-imports-graph',
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
if (hasNonLibraryImports) {
|
|
334
|
+
for (const hint of nonLibraryHints) {
|
|
335
|
+
b.emit(` - from: "${hint.from}"\n`, {
|
|
336
|
+
yamlPath: `components.${specName}.import[${hint.from}]`,
|
|
337
|
+
rule: `import-from-non-library-${hint.pattern}`,
|
|
338
|
+
});
|
|
339
|
+
if (hint.version) {
|
|
340
|
+
b.emit(` version: "${hint.version}"\n`, {
|
|
341
|
+
yamlPath: `components.${specName}.import[${hint.from}].version`,
|
|
342
|
+
rule: `import-from-non-library-${hint.pattern}`,
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
if (hint.select && hint.select.length > 0) {
|
|
346
|
+
const useBlockForm = hint.select.length > 4 || hint.select.join(', ').length > 70;
|
|
347
|
+
if (useBlockForm) {
|
|
348
|
+
b.emit(` select:\n`, {
|
|
349
|
+
yamlPath: `components.${specName}.import[${hint.from}].select`,
|
|
350
|
+
rule: `import-from-non-library-${hint.pattern}`,
|
|
351
|
+
});
|
|
352
|
+
for (const op of hint.select) {
|
|
353
|
+
b.emit(` - ${op}\n`, {
|
|
354
|
+
yamlPath: `components.${specName}.import[${hint.from}].select.${op}`,
|
|
355
|
+
rule: `import-from-non-library-${hint.pattern}`,
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
b.emit(` select: [${hint.select.join(', ')}]\n`, {
|
|
361
|
+
yamlPath: `components.${specName}.import[${hint.from}].select`,
|
|
362
|
+
rule: `import-from-non-library-${hint.pattern}`,
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
242
369
|
// ── Models (only when adapters detected entities) ─────────────────
|
|
243
370
|
// Single-home entity mapping (Option A, 2026-05-04): every detected
|
|
244
371
|
// entity maps to EXACTLY ONE component via ctx.entityHome. Eliminates
|
|
@@ -443,23 +570,26 @@ function emitComponentBody(b, ctx, specName, bucketKey, _comp) {
|
|
|
443
570
|
}
|
|
444
571
|
}
|
|
445
572
|
// ── Controllers + services from walker ────────────────────────────
|
|
446
|
-
//
|
|
447
|
-
//
|
|
448
|
-
//
|
|
449
|
-
//
|
|
450
|
-
//
|
|
451
|
-
//
|
|
452
|
-
//
|
|
453
|
-
//
|
|
454
|
-
//
|
|
455
|
-
//
|
|
456
|
-
//
|
|
573
|
+
// Three-stage dedup:
|
|
574
|
+
// 1. Skip if this class name is ALSO an entity — TS-interfaces and
|
|
575
|
+
// method walker can both surface the same class; only the model
|
|
576
|
+
// emission should win.
|
|
577
|
+
// 2. Engines 6.32.2+ — skip if a different component owns this name
|
|
578
|
+
// via ctx.serviceHome (single-home across components). Without
|
|
579
|
+
// this, idle_meta produces `services.GameService` in both
|
|
580
|
+
// IdleApiService AND Editor since both source dirs contain a
|
|
581
|
+
// file by that name; realize then errors on the collision.
|
|
582
|
+
// 3. Local first-wins inside this component's bucket as a defense
|
|
583
|
+
// against a single bucket containing the same name twice.
|
|
457
584
|
const allEntityNames = new Set((ctx.facts.entities ?? []).map((e) => e.name));
|
|
458
585
|
const rawClasses = ctx.classesByComponent.get(bucketKey) ?? [];
|
|
459
586
|
const seenOwnerNames = new Set();
|
|
460
587
|
const classes = rawClasses.filter((c) => {
|
|
461
588
|
if (allEntityNames.has(c.entityName))
|
|
462
|
-
return false;
|
|
589
|
+
return false;
|
|
590
|
+
const home = ctx.serviceHome.get(c.entityName);
|
|
591
|
+
if (home !== undefined && home !== bucketKey)
|
|
592
|
+
return false;
|
|
463
593
|
if (seenOwnerNames.has(c.entityName))
|
|
464
594
|
return false;
|
|
465
595
|
seenOwnerNames.add(c.entityName);
|
|
@@ -473,15 +603,23 @@ function emitComponentBody(b, ctx, specName, bucketKey, _comp) {
|
|
|
473
603
|
// sourceDir to land here. Falls through silently when no structural
|
|
474
604
|
// info exists (community-detection-only suggestion) — those views
|
|
475
605
|
// wind up in the `Unassigned` / `Application` catch-all.
|
|
606
|
+
//
|
|
607
|
+
// Engines 6.32.2+ — single-home check (ctx.viewHome) drops duplicate
|
|
608
|
+
// names that already landed in another component. idle_meta has
|
|
609
|
+
// `LoginScreen` in two RN apps and `ToastProvider` in two `contexts/`
|
|
610
|
+
// dirs; without the global home, both components emit the same view
|
|
611
|
+
// and realize errors.
|
|
476
612
|
const componentViews = (ctx.facts.views ?? []).filter((v) => {
|
|
477
613
|
const sd = _comp?.structural?.sourceDir;
|
|
478
614
|
if (!sd)
|
|
479
615
|
return bucketKey === '_unassigned'; // catch-all only
|
|
480
616
|
return v.filePath.startsWith(sd);
|
|
481
617
|
});
|
|
482
|
-
// Per-name dedup within this component.
|
|
483
618
|
const seenViewNames = new Set();
|
|
484
619
|
const dedupViews = componentViews.filter((v) => {
|
|
620
|
+
const home = ctx.viewHome.get(v.name);
|
|
621
|
+
if (home !== undefined && home !== bucketKey)
|
|
622
|
+
return false;
|
|
485
623
|
if (seenViewNames.has(v.name))
|
|
486
624
|
return false;
|
|
487
625
|
seenViewNames.add(v.name);
|