@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.
Files changed (59) hide show
  1. package/dist/ai/analyse-runner.d.ts.map +1 -1
  2. package/dist/ai/analyse-runner.js +8 -1
  3. package/dist/ai/analyse-runner.js.map +1 -1
  4. package/dist/ai/behaviours-runner.d.ts.map +1 -1
  5. package/dist/ai/behaviours-runner.js +35 -7
  6. package/dist/ai/behaviours-runner.js.map +1 -1
  7. package/dist/ai/create-runner.d.ts.map +1 -1
  8. package/dist/ai/create-runner.js +6 -0
  9. package/dist/ai/create-runner.js.map +1 -1
  10. package/dist/ai/deployment-emitter.d.ts +3 -0
  11. package/dist/ai/deployment-emitter.d.ts.map +1 -1
  12. package/dist/ai/deployment-emitter.js +145 -0
  13. package/dist/ai/deployment-emitter.js.map +1 -1
  14. package/dist/ai/manifest-emitter.d.ts +35 -10
  15. package/dist/ai/manifest-emitter.d.ts.map +1 -1
  16. package/dist/ai/manifest-emitter.js +140 -54
  17. package/dist/ai/manifest-emitter.js.map +1 -1
  18. package/dist/ai/skeleton-emitter.d.ts +1 -1
  19. package/dist/ai/skeleton-emitter.d.ts.map +1 -1
  20. package/dist/ai/skeleton-emitter.js +152 -14
  21. package/dist/ai/skeleton-emitter.js.map +1 -1
  22. package/dist/analyse-prepass/imports-graph.d.ts +407 -0
  23. package/dist/analyse-prepass/imports-graph.d.ts.map +1 -0
  24. package/dist/analyse-prepass/imports-graph.js +1200 -0
  25. package/dist/analyse-prepass/imports-graph.js.map +1 -0
  26. package/dist/analyse-prepass/index.d.ts +33 -0
  27. package/dist/analyse-prepass/index.d.ts.map +1 -1
  28. package/dist/analyse-prepass/index.js +35 -0
  29. package/dist/analyse-prepass/index.js.map +1 -1
  30. package/dist/inference/logical/generators/view-generator.d.ts +10 -0
  31. package/dist/inference/logical/generators/view-generator.d.ts.map +1 -1
  32. package/dist/inference/logical/generators/view-generator.js +20 -0
  33. package/dist/inference/logical/generators/view-generator.js.map +1 -1
  34. package/dist/libs/instance-factories/orms/templates/prisma/schema-generator.js +66 -4
  35. package/dist/parser/unified-parser.d.ts.map +1 -1
  36. package/dist/parser/unified-parser.js +103 -0
  37. package/dist/parser/unified-parser.js.map +1 -1
  38. package/dist/realize/index.d.ts.map +1 -1
  39. package/dist/realize/index.js +73 -148
  40. package/dist/realize/index.js.map +1 -1
  41. package/dist/realize/per-action-emitter.d.ts +235 -0
  42. package/dist/realize/per-action-emitter.d.ts.map +1 -0
  43. package/dist/realize/per-action-emitter.js +229 -0
  44. package/dist/realize/per-action-emitter.js.map +1 -0
  45. package/dist/realize/per-action-llm-emit.d.ts +87 -0
  46. package/dist/realize/per-action-llm-emit.d.ts.map +1 -0
  47. package/dist/realize/per-action-llm-emit.js +427 -0
  48. package/dist/realize/per-action-llm-emit.js.map +1 -0
  49. package/dist/realize/per-action-runner.d.ts +127 -0
  50. package/dist/realize/per-action-runner.d.ts.map +1 -0
  51. package/dist/realize/per-action-runner.js +269 -0
  52. package/dist/realize/per-action-runner.js.map +1 -0
  53. package/dist/realize/structural-validator.d.ts +71 -0
  54. package/dist/realize/structural-validator.d.ts.map +1 -0
  55. package/dist/realize/structural-validator.js +167 -0
  56. package/dist/realize/structural-validator.js.map +1 -0
  57. package/libs/instance-factories/orms/templates/prisma/__tests__/schema-generator.test.ts +416 -0
  58. package/libs/instance-factories/orms/templates/prisma/schema-generator.ts +182 -5
  59. 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
- * V1 covers the common cases observed in the corpus:
26
- * - Express routing ExpressAPI
27
- * - NestJS decorators NestJSAPI
28
- * - Prisma schema PrismaDriver
29
- * - Mongoose / mongodb-native MongoDBDriver
30
- * - React Native screens → ReactNativeApp
31
- * - React DOM ReactRuntime
32
- * Edge cases (drizzle, knex, raw pg without prisma, vue, svelte, etc.)
33
- * fall through to defaults that the user hand-edits. Better than
34
- * an LLM hallucinating a nonexistent factory name.
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;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,wBAAgB,YAAY,CAAC,KAAK,EAAE,qBAAqB,GAAG,sBAAsB,CAwFjF"}
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
- * V1 covers the common cases observed in the corpus:
26
- * - Express routing ExpressAPI
27
- * - NestJS decorators NestJSAPI
28
- * - Prisma schema PrismaDriver
29
- * - Mongoose / mongodb-native MongoDBDriver
30
- * - React Native screens → ReactNativeApp
31
- * - React DOM ReactRuntime
32
- * Edge cases (drizzle, knex, raw pg without prisma, vue, svelte, etc.)
33
- * fall through to defaults that the user hand-edits. Better than
34
- * an LLM hallucinating a nonexistent factory name.
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'] = 'ExpressAPI';
50
- rationale['api.rest'] = 'express-routes adapter detected Router() + verb calls';
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
- // Decorator-rich codebases are most likely NestJS in our corpus.
54
- // (TypeORM-only entities with no controller decorators wouldn't run
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
- // Default — most analyse targets are HTTP services. Express is the
62
- // most common low-friction choice.
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.relational'] = 'PrismaDriver';
69
- rationale['storage.relational'] = 'typescript-prisma adapter detected schema.prisma';
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
- // Without a Prisma signal, document storage is the analyse-time
73
- // default. Codebases extracted via TS interfaces typically use
74
- // mongoose / mongodb-native. The user can hand-edit to PostgresNativeDriver
75
- // or others if the actual storage differs.
76
- choices['storage.documents'] = 'MongoDBDriver';
77
- rationale['storage.documents'] = 'no prisma schema detected; defaulting to document-store (MongoDBDriver)';
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
- // ── ui.framework — React vs React Native vs none ──────────────────
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
- if (isReactNative) {
85
- choices['ui.framework'] = 'ReactNativeApp';
86
- rationale['ui.framework'] = 'react-views adapter detected RN screens or mobile-app structure';
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 — JWT auth presence ──────────────────────────────────
94
- // Heuristic: any RefreshToken or AuthService entity JWT path.
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
- // JWT auth in idle-meta-style monorepos uses jsonwebtoken with
103
- // express middleware. The api.rest factory (ExpressAPI / NestJSAPI)
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
- // Build the yaml document.
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: ${input.specName ?? 'AnalysedSpec'}`);
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(` ${cap}: ${choices[cap]}`);
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":"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"}
1
+ {"version":3,"file":"manifest-emitter.js","sourceRoot":"","sources":["../../src/ai/manifest-emitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAuBH;;;;GAIG;AACH;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,eAAe,GAAwB,IAAI,GAAG,CAAC;IAC1D,aAAa,EAAE,kBAAkB,EAAE,cAAc,EAAE,YAAY;IAC/D,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,UAAU;IACxD,qBAAqB,EAAE,sBAAsB,EAAE,cAAc;IAC7D,WAAW,EAAE,gBAAgB,EAAE,WAAW,EAAE,gBAAgB;IAC5D,iBAAiB,EAAE,iBAAiB,EAAE,QAAQ,EAAE,eAAe;IAC/D,aAAa,EAAE,iBAAiB,EAAE,eAAe;CAClD,CAAC,CAAC;AAEH,MAAM,UAAU,YAAY,CAAC,KAA4B;IACvD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,WAAW,IAAI,EAAE,CAAC,CAAC;IAC9D,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC;IAC5C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;IACtC,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,MAAM,SAAS,GAA2B,EAAE,CAAC;IAE7C,qEAAqE;IACrE,uEAAuE;IACvE,sEAAsE;IACtE,uEAAuE;IACvE,IAAI,QAAQ,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACnC,OAAO,CAAC,UAAU,CAAC,GAAG,YAAY,CAAC;QACnC,SAAS,CAAC,UAAU,CAAC,GAAG,oIAAoI,CAAC;IAC/J,CAAC;SAAM,IAAI,QAAQ,CAAC,GAAG,CAAC,uBAAuB,CAAC,EAAE,CAAC;QACjD,OAAO,CAAC,UAAU,CAAC,GAAG,YAAY,CAAC;QACnC,SAAS,CAAC,UAAU,CAAC,GAAG,gGAAgG,CAAC;IAC3H,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,UAAU,CAAC,GAAG,YAAY,CAAC;QACnC,SAAS,CAAC,UAAU,CAAC,GAAG,2EAA2E,CAAC;IACtG,CAAC;IAED,qEAAqE;IACrE,mEAAmE;IACnE,8DAA8D;IAC9D,mEAAmE;IACnE,sDAAsD;IACtD,kEAAkE;IAClE,oCAAoC;IACpC,IAAI,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACtC,OAAO,CAAC,kBAAkB,CAAC,GAAG,cAAc,CAAC;QAC7C,SAAS,CAAC,kBAAkB,CAAC,GAAG,8EAA8E,CAAC;QAC/G,OAAO,CAAC,YAAY,CAAC,GAAG,WAAW,CAAC;QACpC,OAAO,CAAC,YAAY,CAAC,GAAG,WAAW,CAAC;QACpC,SAAS,CAAC,YAAY,CAAC,GAAG,+CAA+C,CAAC;IAC5E,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,kBAAkB,CAAC,GAAG,qBAAqB,CAAC;QACpD,SAAS,CAAC,kBAAkB,CAAC,GAAG,uEAAuE,CAAC;IAC1G,CAAC;IAED,qEAAqE;IACrE,mEAAmE;IACnE,mEAAmE;IACnE,kEAAkE;IAClE,0DAA0D;IAC1D,MAAM,eAAe,GAAG,gBAAgB,CAAC;IACzC,KAAK,MAAM,GAAG,IAAI,CAAC,oBAAoB,EAAE,kBAAkB,EAAE,cAAc,CAAC,EAAE,CAAC;QAC7E,OAAO,CAAC,GAAG,CAAC,GAAG,eAAe,CAAC;IACjC,CAAC;IACD,SAAS,CAAC,WAAW,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC;QACxD,CAAC,CAAC,kDAAkD;QACpD,CAAC,CAAC,wGAAwG,CAAC;IAE7G,oEAAoE;IACpE,OAAO,CAAC,kBAAkB,CAAC,GAAG,cAAc,CAAC;IAC7C,SAAS,CAAC,kBAAkB,CAAC,GAAG,sGAAsG,CAAC;IAEvI,oEAAoE;IACpE,oEAAoE;IACpE,wDAAwD;IACxD,OAAO,CAAC,oBAAoB,CAAC,GAAG,eAAe,CAAC;IAChD,SAAS,CAAC,oBAAoB,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,iBAAiB,CAAC;QAC9F,CAAC,CAAC,gCAAgC;QAClC,CAAC,CAAC,iDAAiD,CAAC;IAEtD,oEAAoE;IACpE,OAAO,CAAC,gBAAgB,CAAC,GAAG,YAAY,CAAC;IACzC,OAAO,CAAC,kBAAkB,CAAC,GAAG,iBAAiB,CAAC;IAChD,SAAS,CAAC,gBAAgB,CAAC,GAAG,uCAAuC,CAAC;IACtE,SAAS,CAAC,kBAAkB,CAAC,GAAG,4CAA4C,CAAC;IAE7E,oEAAoE;IACpE,IAAI,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;QAChC,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CACrC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,CACpF,CAAC;QACF,OAAO,CAAC,cAAc,CAAC,GAAG,iBAAiB,CAAC;QAC5C,SAAS,CAAC,cAAc,CAAC,GAAG,aAAa;YACvC,CAAC,CAAC,yIAAyI;YAC3I,CAAC,CAAC,qEAAqE,CAAC;IAC5E,CAAC;IAED,oEAAoE;IACpE,kEAAkE;IAClE,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACvE,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,CAAC,cAAc,CAAC;WAC/C,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC;WAC9B,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC;WAC9B,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACjC,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,UAAU,CAAE,CAAC;QAC3C,SAAS,CAAC,UAAU,CAAC,GAAG,iGAAiG,CAAC;IAC5H,CAAC;IAED,oEAAoE;IACpE,oEAAoE;IACpE,oEAAoE;IACpE,8BAA8B;IAC9B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAE,CAAC;QAC3B,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,SAAS,CAAC,GAAG,CAAC,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,wBAAwB,IAAI,mBAAmB,CAAC;YACxF,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,iEAAiE;IACjE,mEAAmE;IACnE,0EAA0E;IAC1E,mEAAmE;IACnE,kEAAkE;IAClE,2DAA2D;IAC3D,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,cAAc,CAAC;IAClD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACjC,KAAK,CAAC,IAAI,CAAC,SAAS,QAAQ,EAAE,CAAC,CAAC;IAChC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,oEAAoE;IACpE,qEAAqE;IACrE,4CAA4C;IAC5C,MAAM,eAAe,GAAwC;QAC3D,CAAC,SAAS,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;QACxC,CAAC,YAAY,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAC;QAC7C,CAAC,SAAS,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;QACxC,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QAChC,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;QAC9B,CAAC,eAAe,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;KAC/C,CAAC;IACF,MAAM,QAAQ,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IACpE,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC/B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC5D,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IAClC,mDAAmD;IACnD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC9C,KAAK,CAAC,IAAI,CAAC,oBAAoB,GAAG,GAAG,CAAC,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC,yBAAyB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACvD,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,OAAO;QACL,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;QAC9B,cAAc,EAAE,OAAO;QACvB,SAAS;KACV,CAAC;AACJ,CAAC"}
@@ -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;AAmID;;;;;;;;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"}
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
- return { facts, classByName, classesByComponent, entityHome, entityHomeAssignments };
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
- // Dedupe by class name within the bucket — the walker may capture two
447
- // classes with the same name in different source files (e.g. an
448
- // `apps/.../FormulaEvaluator.ts` AND `shared/.../FormulaEvaluator.ts`),
449
- // both falling into this component. Emitting twice produces a yaml
450
- // duplicate-mapping-key error. First-wins keeps the spec valid.
451
- //
452
- // Plus: a class name that's ALSO an entity (already emitted in models:)
453
- // should NOT be re-emitted as a service. The TS-interfaces walker
454
- // surfaces classes with fields as entities; the method-walker surfaces
455
- // those same classes for behaviour analysis. They're the SAME thing,
456
- // and only the model emission should win in the spec.
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; // emitted as a model already
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);