@open-mercato/cli 0.6.8-develop.6930.1.1e5976efc3 → 0.6.8-develop.6940.1.177ea30c6e

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 (168) hide show
  1. package/.turbo/turbo-build.log +65 -1
  2. package/build.mjs +57 -7
  3. package/dist/agentic/guides/backend-ui.md +7 -1
  4. package/dist/agentic/guides/module-facts.json +565 -224
  5. package/dist/agentic/guides/module-facts.v2.json +122933 -0
  6. package/dist/agentic/guides/modules/ai_assistant.md +2 -2
  7. package/dist/agentic/guides/modules/api_docs.md +2 -2
  8. package/dist/agentic/guides/modules/api_keys.md +2 -2
  9. package/dist/agentic/guides/modules/attachments.md +2 -2
  10. package/dist/agentic/guides/modules/audit_logs.md +2 -2
  11. package/dist/agentic/guides/modules/auth.md +2 -2
  12. package/dist/agentic/guides/modules/business_rules.md +2 -2
  13. package/dist/agentic/guides/modules/catalog.md +11 -4
  14. package/dist/agentic/guides/modules/channel_gmail.md +2 -2
  15. package/dist/agentic/guides/modules/channel_imap.md +2 -2
  16. package/dist/agentic/guides/modules/checkout.md +8 -2
  17. package/dist/agentic/guides/modules/communication_channels.md +6 -6
  18. package/dist/agentic/guides/modules/configs.md +2 -2
  19. package/dist/agentic/guides/modules/content.md +2 -2
  20. package/dist/agentic/guides/modules/currencies.md +2 -2
  21. package/dist/agentic/guides/modules/customer_accounts.md +2 -2
  22. package/dist/agentic/guides/modules/customers.md +8 -8
  23. package/dist/agentic/guides/modules/dashboards.md +12 -12
  24. package/dist/agentic/guides/modules/data_sync.md +4 -4
  25. package/dist/agentic/guides/modules/design_system.md +2 -2
  26. package/dist/agentic/guides/modules/dictionaries.md +2 -2
  27. package/dist/agentic/guides/modules/directory.md +2 -2
  28. package/dist/agentic/guides/modules/entities.md +3 -3
  29. package/dist/agentic/guides/modules/eudr.md +3 -3
  30. package/dist/agentic/guides/modules/events.md +2 -2
  31. package/dist/agentic/guides/modules/feature_toggles.md +2 -2
  32. package/dist/agentic/guides/modules/gateway_stripe.md +2 -2
  33. package/dist/agentic/guides/modules/generators.md +2 -2
  34. package/dist/agentic/guides/modules/inbox_ops.md +2 -2
  35. package/dist/agentic/guides/modules/integrations.md +5 -2
  36. package/dist/agentic/guides/modules/messages.md +2 -2
  37. package/dist/agentic/guides/modules/notifications.md +2 -2
  38. package/dist/agentic/guides/modules/onboarding.md +2 -2
  39. package/dist/agentic/guides/modules/payment_gateways.md +7 -3
  40. package/dist/agentic/guides/modules/perspectives.md +2 -2
  41. package/dist/agentic/guides/modules/planner.md +2 -2
  42. package/dist/agentic/guides/modules/portal.md +2 -2
  43. package/dist/agentic/guides/modules/progress.md +2 -2
  44. package/dist/agentic/guides/modules/query_index.md +2 -2
  45. package/dist/agentic/guides/modules/record_locks.md +3 -3
  46. package/dist/agentic/guides/modules/resources.md +2 -2
  47. package/dist/agentic/guides/modules/sales.md +13 -4
  48. package/dist/agentic/guides/modules/scheduler.md +2 -2
  49. package/dist/agentic/guides/modules/search.md +4 -4
  50. package/dist/agentic/guides/modules/security.md +3 -3
  51. package/dist/agentic/guides/modules/shipping_carriers.md +2 -2
  52. package/dist/agentic/guides/modules/sso.md +2 -2
  53. package/dist/agentic/guides/modules/staff.md +7 -4
  54. package/dist/agentic/guides/modules/storage_s3.md +2 -2
  55. package/dist/agentic/guides/modules/sync_akeneo.md +4 -4
  56. package/dist/agentic/guides/modules/sync_excel.md +2 -2
  57. package/dist/agentic/guides/modules/system_status_overlays.md +2 -2
  58. package/dist/agentic/guides/modules/translations.md +2 -2
  59. package/dist/agentic/guides/modules/webhooks.md +2 -2
  60. package/dist/agentic/guides/modules/wms.md +31 -4
  61. package/dist/agentic/guides/modules/workflows.md +2 -2
  62. package/dist/agentic/guides/reference-module-facts.json +8335 -0
  63. package/dist/agentic/guides/reference-modules/example.md +489 -0
  64. package/dist/agentic/guides/spec-delivery.md +34 -0
  65. package/dist/agentic/guides/testing-debugging.md +2 -1
  66. package/dist/agentic/guides/upstream/BACKWARD_COMPATIBILITY.md +3 -2
  67. package/dist/agentic/guides/upstream/manifest.json +2 -2
  68. package/dist/agentic/shared/AGENTS.md.template +10 -14
  69. package/dist/agentic/shared/ai/harness/README.md +4 -4
  70. package/dist/agentic/shared/ai/harness/RELEASE.md +4 -4
  71. package/dist/agentic/shared/ai/harness/cases.json +11350 -5088
  72. package/dist/agentic/shared/ai/harness/cases.schema.json +70 -7
  73. package/dist/agentic/shared/ai/harness/design-system-inventory.json +6697 -0
  74. package/dist/agentic/shared/ai/harness/fixtures/index.json +3 -1
  75. package/dist/agentic/shared/ai/harness/fixtures/seeds.json +4 -0
  76. package/dist/agentic/shared/ai/harness/knowledge-change.schema.json +228 -0
  77. package/dist/agentic/shared/ai/harness/release-matrix.json +9 -4
  78. package/dist/agentic/shared/ai/harness/result.schema.json +60 -0
  79. package/dist/agentic/shared/ai/harness/routing-response.schema.json +10 -0
  80. package/dist/agentic/shared/ai/harness/source-link-inventory.json +3231 -0
  81. package/dist/agentic/shared/ai/harness/validators.json +8 -4
  82. package/dist/agentic/shared/ai/harness/writable-ast-oracles.mjs +5 -2
  83. package/dist/agentic/shared/ai/harness/writable-behavior-oracles.mjs +3 -0
  84. package/dist/agentic/shared/ai/harness/writable-spec-oracles.mjs +879 -0
  85. package/dist/agentic/shared/ai/skills/om-auto-upgrade-0.6.7-to-0.7.0/SKILL.md +102 -0
  86. package/dist/agentic/shared/ai/skills/om-backend-ui-design/SKILL.md +1 -0
  87. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/crud-surfaces.md +15 -0
  88. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/frontend-and-design-system.md +6 -0
  89. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/page-and-navigation.md +4 -0
  90. package/dist/agentic/shared/ai/skills/om-data-model-design/SKILL.md +1 -0
  91. package/dist/agentic/shared/ai/skills/om-data-model-design/references/integrity-and-concurrency.md +2 -0
  92. package/dist/agentic/shared/ai/skills/om-data-model-design/references/migration-workflow.md +2 -0
  93. package/dist/agentic/shared/ai/skills/om-data-model-design/references/schema-design.md +3 -1
  94. package/dist/agentic/shared/ai/skills/om-eject-and-customize/SKILL.md +1 -0
  95. package/dist/agentic/shared/ai/skills/om-eject-and-customize/references/decision-and-procedure.md +2 -0
  96. package/dist/agentic/shared/ai/skills/om-evolve-harness/SKILL.md +2 -0
  97. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-template.md +3 -3
  98. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-workflow.md +1 -1
  99. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/knowledge-change.md +133 -0
  100. package/dist/agentic/shared/ai/skills/om-integration-builder/SKILL.md +1 -0
  101. package/dist/agentic/shared/ai/skills/om-integration-builder/references/provider-families.md +11 -0
  102. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/judge-workflow.md +1 -1
  103. package/dist/agentic/shared/ai/skills/om-module-scaffold/SKILL.md +2 -2
  104. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/api-and-domain.md +14 -1
  105. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/data-and-migrations.md +2 -0
  106. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/module-surfaces.md +19 -0
  107. package/dist/agentic/shared/ai/skills/om-share-this-session/scripts/prepare-share-bundle.mjs +1 -4
  108. package/dist/agentic/shared/ai/skills/om-system-extension/SKILL.md +1 -0
  109. package/dist/agentic/shared/ai/skills/om-system-extension/references/extension-branches.md +24 -0
  110. package/dist/agentic/shared/ai/skills/om-system-extension/references/unified-overrides.md +3 -1
  111. package/dist/agentic/shared/ai/skills/om-troubleshooter/SKILL.md +1 -0
  112. package/dist/agentic/shared/ai/skills/om-troubleshooter/references/diagnosis-map.md +13 -0
  113. package/dist/agentic/shared/ai/skills/tiers.json +2 -1
  114. package/dist/agentic/shared/ai/specs/2026-08-06-reference-module-activation.md +248 -0
  115. package/dist/agentic/shared/scripts/agent-harness-tool-server.mjs +39 -2
  116. package/dist/agentic/shared/scripts/design-source-contract.mjs +108 -0
  117. package/dist/agentic/shared/scripts/evaluate-agent-harness.mjs +935 -28
  118. package/dist/agentic/shared/scripts/framework-context.mjs +4 -1
  119. package/dist/agentic/shared/scripts/run-agent-harness-release.mjs +1 -1
  120. package/dist/agentic/shared/scripts/validate-knowledge-change.mjs +1511 -0
  121. package/dist/lib/__integration__/TC-INT-008.spec.js +1 -0
  122. package/dist/lib/__integration__/TC-INT-008.spec.js.map +2 -2
  123. package/dist/lib/agentic-setup.js +9 -1
  124. package/dist/lib/agentic-setup.js.map +2 -2
  125. package/dist/lib/generators/module-extension-facts.js +93 -26
  126. package/dist/lib/generators/module-extension-facts.js.map +3 -3
  127. package/dist/lib/generators/module-facts-discovery.js +23 -0
  128. package/dist/lib/generators/module-facts-discovery.js.map +2 -2
  129. package/dist/lib/generators/module-facts.js +969 -41
  130. package/dist/lib/generators/module-facts.js.map +2 -2
  131. package/dist/lib/generators/module-override-targets.js +35 -11
  132. package/dist/lib/generators/module-override-targets.js.map +2 -2
  133. package/dist/lib/generators/module-registry.js +105 -2
  134. package/dist/lib/generators/module-registry.js.map +2 -2
  135. package/dist/lib/resolver.js +5 -0
  136. package/dist/lib/resolver.js.map +2 -2
  137. package/dist/lib/testing/integration-discovery.js +34 -0
  138. package/dist/lib/testing/integration-discovery.js.map +2 -2
  139. package/dist/lib/testing/integration.js +10 -2
  140. package/dist/lib/testing/integration.js.map +2 -2
  141. package/dist/mercato.js +4 -4
  142. package/dist/mercato.js.map +2 -2
  143. package/package.json +6 -6
  144. package/src/lib/__integration__/TC-INT-008.spec.ts +4 -2
  145. package/src/lib/__tests__/resolve-environment.test.ts +18 -0
  146. package/src/lib/agentic-setup.ts +10 -2
  147. package/src/lib/generators/__tests__/helpers/override-target-diagnostic-fixtures.ts +150 -0
  148. package/src/lib/generators/__tests__/module-extension-facts.test.ts +290 -0
  149. package/src/lib/generators/__tests__/module-facts.bc-guard.test.ts +72 -7
  150. package/src/lib/generators/__tests__/module-facts.computed-di-token.test.ts +88 -0
  151. package/src/lib/generators/__tests__/module-facts.example-fact-coverage.test.ts +502 -0
  152. package/src/lib/generators/__tests__/module-facts.local-reference.test.ts +414 -0
  153. package/src/lib/generators/__tests__/module-facts.search-entity-id.test.ts +151 -0
  154. package/src/lib/generators/__tests__/module-facts.source-links.test.ts +42 -1
  155. package/src/lib/generators/__tests__/module-override-targets.diagnostic-wiring.test.ts +92 -0
  156. package/src/lib/generators/__tests__/module-override-targets.test.ts +24 -0
  157. package/src/lib/generators/__tests__/module-override-targets.unknown-mode.test.ts +117 -0
  158. package/src/lib/generators/__tests__/module-subset.test.ts +60 -0
  159. package/src/lib/generators/module-extension-facts.ts +181 -25
  160. package/src/lib/generators/module-facts-discovery.ts +46 -0
  161. package/src/lib/generators/module-facts.ts +1330 -86
  162. package/src/lib/generators/module-override-targets.ts +70 -26
  163. package/src/lib/generators/module-registry.ts +135 -2
  164. package/src/lib/resolver.ts +6 -1
  165. package/src/lib/testing/__tests__/integration-discovery.test.ts +35 -0
  166. package/src/lib/testing/integration-discovery.ts +50 -0
  167. package/src/lib/testing/integration.ts +10 -2
  168. package/src/mercato.ts +3 -3
@@ -1,6 +1,25 @@
1
+ import { createHash } from "node:crypto";
1
2
  import fs from "node:fs";
2
3
  import path from "node:path";
3
4
  import ts from "typescript-js";
5
+ import {
6
+ COMPONENT_OVERRIDE_MODES,
7
+ CRUD_FORM_EXTENSION_SURFACE_KEYS,
8
+ CRUD_FORM_LIFECYCLE_PHASES,
9
+ CRUD_FORM_OPERATIONS,
10
+ DATA_TABLE_EXTENSION_SURFACE_KEYS,
11
+ EXTENSION_HOST_ACTIVATIONS,
12
+ EXTENSION_HOST_CAPABILITIES,
13
+ EXTENSION_HOST_FAMILIES,
14
+ MODULE_EXTENSION_ACTIVATION_KINDS,
15
+ MODULE_EXTENSION_CONTRIBUTION_KINDS,
16
+ MODULE_EXTENSION_HOST_RESOLUTIONS,
17
+ MODULE_EXTENSION_RESOLUTIONS,
18
+ MODULE_EXTENSION_TARGET_KINDS,
19
+ MODULE_EXTENSION_TARGET_RESOLUTIONS,
20
+ MODULE_EXTENSION_UNRESOLVED_REASONS,
21
+ MODULE_SPECIALIZED_REGISTRIES
22
+ } from "@open-mercato/shared/modules/widgets/extension-points";
4
23
  import { toSnake } from "../utils.js";
5
24
  import { extractCommandIdsFromSource } from "./module-registry.js";
6
25
  import { MODULE_CODE_EXTENSIONS } from "./scanner.js";
@@ -16,9 +35,55 @@ import {
16
35
  withModuleExtensionFactExtractionCache
17
36
  } from "./module-extension-facts.js";
18
37
  import {
38
+ ALL_OVERRIDE_DOMAINS,
39
+ MODULE_OVERRIDE_MODES,
40
+ MODULE_OVERRIDE_TARGET_DIAGNOSTIC_CODES,
41
+ MODULE_OVERRIDE_TARGET_NOTES,
19
42
  collectModuleOverrideTargets
20
43
  } from "./module-override-targets.js";
21
44
  import { buildFactSourceLookup } from "./module-fact-sources.js";
45
+ import { appendLocalReferenceModuleSource } from "./module-facts-discovery.js";
46
+ const MODULE_FACT_SOURCE_KINDS = [
47
+ "module-metadata",
48
+ "entity",
49
+ "event",
50
+ "acl-feature",
51
+ "api-route",
52
+ "di-registration",
53
+ "search",
54
+ "vector",
55
+ "notification",
56
+ "cli-command",
57
+ "backend-page",
58
+ "frontend-page",
59
+ "ai-tool",
60
+ "ai-agent",
61
+ "ai-extension",
62
+ "command",
63
+ "subscriber",
64
+ "worker",
65
+ "page-middleware",
66
+ "setup",
67
+ "encryption",
68
+ "custom-entity",
69
+ "integration",
70
+ "generator-plugin",
71
+ "extension-host",
72
+ "extension-contribution"
73
+ ];
74
+ const MODULE_OWNED_CONTRACT_KINDS = [
75
+ "module-metadata",
76
+ "command",
77
+ "worker",
78
+ "page-middleware",
79
+ "setup",
80
+ "encryption",
81
+ "di-registration",
82
+ "custom-entity",
83
+ "ai-extension",
84
+ "generator-plugin"
85
+ ];
86
+ const MODULE_FACT_DIAGNOSTIC_CODES = ["duplicate-source", "unresolved-static-contract"];
22
87
  function readSourceFile(filePath) {
23
88
  if (!fs.existsSync(filePath)) return null;
24
89
  const source = fs.readFileSync(filePath, "utf8");
@@ -79,42 +144,45 @@ function classHasUpdatedAtColumn(node) {
79
144
  }
80
145
  return false;
81
146
  }
147
+ function readStaticAccessPath(candidate) {
148
+ const access = unwrapExpression(candidate);
149
+ if (ts.isIdentifier(access)) return [access.text];
150
+ if (ts.isPropertyAccessExpression(access)) {
151
+ const parent = readStaticAccessPath(access.expression);
152
+ return parent ? [...parent, access.name.text] : null;
153
+ }
154
+ if (ts.isElementAccessExpression(access) && access.argumentExpression) {
155
+ const parent = readStaticAccessPath(access.expression);
156
+ const key = unwrapExpression(access.argumentExpression);
157
+ return parent && ts.isStringLiteralLike(key) ? [...parent, key.text] : null;
158
+ }
159
+ return null;
160
+ }
161
+ function resolveEntityIdReference(expression, initializers, visitedIdentifiers = /* @__PURE__ */ new Set()) {
162
+ const current = unwrapExpression(expression);
163
+ if (ts.isStringLiteralLike(current)) return current.text;
164
+ const accessPath = readStaticAccessPath(current);
165
+ if (accessPath?.length === 3 && accessPath[0] === "E") {
166
+ return `${accessPath[1]}:${accessPath[2]}`;
167
+ }
168
+ if (initializers && ts.isIdentifier(current) && !visitedIdentifiers.has(current.text)) {
169
+ visitedIdentifiers.add(current.text);
170
+ const declaration = initializers.get(current.text);
171
+ if (declaration) return resolveEntityIdReference(declaration, initializers, visitedIdentifiers);
172
+ }
173
+ return void 0;
174
+ }
82
175
  function collectCustomFieldEntityIds(ceFilePath) {
83
176
  const result = /* @__PURE__ */ new Set();
84
177
  if (!ceFilePath) return result;
85
178
  const sourceFile = readSourceFile(ceFilePath);
86
179
  if (!sourceFile) return result;
87
- const readEntityId = (expression) => {
88
- const current = unwrapExpression(expression);
89
- if (ts.isStringLiteralLike(current)) {
90
- return current.text.includes(":") ? current.text : void 0;
91
- }
92
- const readAccessPath = (candidate) => {
93
- const access = unwrapExpression(candidate);
94
- if (ts.isIdentifier(access)) return [access.text];
95
- if (ts.isPropertyAccessExpression(access)) {
96
- const parent = readAccessPath(access.expression);
97
- return parent ? [...parent, access.name.text] : null;
98
- }
99
- if (ts.isElementAccessExpression(access) && access.argumentExpression) {
100
- const parent = readAccessPath(access.expression);
101
- const key = unwrapExpression(access.argumentExpression);
102
- return parent && ts.isStringLiteralLike(key) ? [...parent, key.text] : null;
103
- }
104
- return null;
105
- };
106
- const accessPath = readAccessPath(current);
107
- if (accessPath?.length === 3 && accessPath[0] === "E") {
108
- return `${accessPath[1]}:${accessPath[2]}`;
109
- }
110
- return void 0;
111
- };
112
180
  const visit = (node) => {
113
181
  if (ts.isObjectLiteralExpression(node)) {
114
182
  const initializer = getObjectPropertyInitializer(node, "id");
115
183
  if (initializer) {
116
- const id = readEntityId(initializer);
117
- if (id) result.add(id);
184
+ const id = resolveEntityIdReference(initializer);
185
+ if (id && id.includes(":")) result.add(id);
118
186
  }
119
187
  }
120
188
  node.forEachChild(visit);
@@ -163,8 +231,29 @@ function getPropertyName(property) {
163
231
  if (!name) return void 0;
164
232
  if (ts.isIdentifier(name)) return name.text;
165
233
  if (ts.isStringLiteralLike(name)) return name.text;
234
+ if (ts.isComputedPropertyName(name)) return resolveComputedPropertyKey(name.expression);
166
235
  return void 0;
167
236
  }
237
+ function resolveComputedPropertyKey(expression) {
238
+ if (ts.isStringLiteralLike(expression)) return expression.text;
239
+ if (ts.isAsExpression(expression) || ts.isSatisfiesExpression(expression)) {
240
+ return resolveComputedPropertyKey(expression.expression);
241
+ }
242
+ if (ts.isParenthesizedExpression(expression)) return resolveComputedPropertyKey(expression.expression);
243
+ if (!ts.isIdentifier(expression)) return void 0;
244
+ const sourceFile = expression.getSourceFile();
245
+ if (!sourceFile) return void 0;
246
+ let resolved;
247
+ const visit = (node) => {
248
+ if (resolved) return;
249
+ if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.name.text === expression.text) {
250
+ if (node.initializer) resolved = resolveComputedPropertyKey(node.initializer);
251
+ }
252
+ node.forEachChild(visit);
253
+ };
254
+ sourceFile.forEachChild(visit);
255
+ return resolved;
256
+ }
168
257
  function getObjectPropertyInitializer(objectLiteral, propertyName) {
169
258
  for (const property of objectLiteral.properties) {
170
259
  if (!ts.isPropertyAssignment(property)) continue;
@@ -454,15 +543,25 @@ function extractSearchEntities(searchFilePath, warnings) {
454
543
  warnings.push(`[module-facts] searchConfig.entities is not an array literal: ${searchFilePath}`);
455
544
  return [];
456
545
  }
546
+ const initializers = buildVariableInitializerMap(sourceFile);
457
547
  const entityIds = [];
458
548
  const seen = /* @__PURE__ */ new Set();
459
549
  for (const element of entitiesArray.elements) {
460
550
  if (!ts.isObjectLiteralExpression(element)) continue;
461
- const entityId = readStringPropertyInitializer(element, "entityId");
462
- if (entityId && !seen.has(entityId)) {
463
- seen.add(entityId);
464
- entityIds.push(entityId);
551
+ const initializer = getObjectPropertyInitializer(element, "entityId");
552
+ const location = `${searchFilePath}:${nodeLine(sourceFile, element)}`;
553
+ if (!initializer) {
554
+ warnings.push(`[module-facts] searchConfig entity declares no entityId: ${location}`);
555
+ continue;
465
556
  }
557
+ const entityId = resolveEntityIdReference(initializer, initializers);
558
+ if (!entityId) {
559
+ warnings.push(`[module-facts] searchConfig entityId is not statically resolvable: ${location}`);
560
+ continue;
561
+ }
562
+ if (seen.has(entityId)) continue;
563
+ seen.add(entityId);
564
+ entityIds.push(entityId);
466
565
  }
467
566
  return entityIds;
468
567
  }
@@ -538,6 +637,15 @@ function listSourceFilesRecursive(directory) {
538
637
  function toPortableSourceRoot(moduleId, sourcePackage) {
539
638
  return path.posix.join("node_modules", sourcePackage ?? "@open-mercato/core", "src", "modules", moduleId);
540
639
  }
640
+ function assertPortableSourceRoot(moduleId, portableSourceRoot) {
641
+ const invalid = portableSourceRoot.length === 0 || path.posix.isAbsolute(portableSourceRoot) || /^[A-Za-z]:/.test(portableSourceRoot) || portableSourceRoot.includes("\\") || portableSourceRoot.split("/").includes("..");
642
+ if (invalid) {
643
+ throw new Error(
644
+ `[module-facts] portableSourceRoot for module "${moduleId}" must be a relative POSIX app path, received "${portableSourceRoot}"`
645
+ );
646
+ }
647
+ return portableSourceRoot;
648
+ }
541
649
  function toPortableSourcePath(moduleRoot, sourceRoot, filePath) {
542
650
  const relativePath = path.relative(moduleRoot, filePath).split(path.sep).join("/");
543
651
  return path.posix.join(sourceRoot, relativePath);
@@ -973,6 +1081,34 @@ function readResolvedStringProperty(objectLiteral, propertyName, initializers) {
973
1081
  }
974
1082
  return void 0;
975
1083
  }
1084
+ function readImportedStringIdentifier(sourceFile, sourcePath, identifier) {
1085
+ for (const statement of sourceFile.statements) {
1086
+ if (!ts.isImportDeclaration(statement) || !ts.isStringLiteralLike(statement.moduleSpecifier)) continue;
1087
+ const importClause = statement.importClause;
1088
+ const bindings = importClause?.namedBindings;
1089
+ if (!bindings || !ts.isNamedImports(bindings)) continue;
1090
+ const imported = bindings.elements.find((element) => element.name.text === identifier);
1091
+ if (!imported) continue;
1092
+ const request = statement.moduleSpecifier.text;
1093
+ if (!request.startsWith(".")) return void 0;
1094
+ const basePath = path.resolve(path.dirname(sourcePath), request);
1095
+ const candidates = [
1096
+ `${basePath}.ts`,
1097
+ `${basePath}.tsx`,
1098
+ path.join(basePath, "index.ts"),
1099
+ path.join(basePath, "index.tsx")
1100
+ ];
1101
+ const importedPath = candidates.find((candidate) => fs.existsSync(candidate));
1102
+ if (!importedPath) return void 0;
1103
+ const importedSource = readSourceFile(importedPath);
1104
+ if (!importedSource) return void 0;
1105
+ const exportName = imported.propertyName?.text ?? imported.name.text;
1106
+ const declaration = importedSource.statements.filter(ts.isVariableStatement).flatMap((variable) => [...variable.declarationList.declarations]).find((candidate) => ts.isIdentifier(candidate.name) && candidate.name.text === exportName);
1107
+ const initializer = declaration?.initializer ? unwrapExpression(declaration.initializer) : null;
1108
+ return initializer && ts.isStringLiteralLike(initializer) ? initializer.text : void 0;
1109
+ }
1110
+ return void 0;
1111
+ }
976
1112
  function extractWorkerContracts(moduleId, moduleRoot, sourceRoot) {
977
1113
  const workersRoot = path.join(moduleRoot, "workers");
978
1114
  if (!fs.existsSync(workersRoot)) return { facts: [], unresolved: [] };
@@ -988,7 +1124,8 @@ function extractWorkerContracts(moduleId, moduleRoot, sourceRoot) {
988
1124
  const initializers = buildVariableInitializerMap(sourceFile);
989
1125
  const workerId = readResolvedStringProperty(metadata, "id", initializers) ?? deriveWorkerId(moduleId, workersRoot, filePath);
990
1126
  const hasQueueProperty = getObjectPropertyInitializer(metadata, "queue") !== void 0;
991
- const queue = readResolvedStringProperty(metadata, "queue", initializers);
1127
+ const queueInitializer = getObjectPropertyInitializer(metadata, "queue");
1128
+ const queue = readResolvedStringProperty(metadata, "queue", initializers) ?? (queueInitializer && ts.isIdentifier(unwrapExpression(queueInitializer)) ? readImportedStringIdentifier(sourceFile, filePath, unwrapExpression(queueInitializer).text) : void 0);
992
1129
  if (!hasQueueProperty) {
993
1130
  unresolved.push({ code: "unresolved-static-contract", kind: "worker", id: workerId, source });
994
1131
  continue;
@@ -1318,7 +1455,7 @@ function extractModuleFacts(options) {
1318
1455
  if (!moduleRoot) {
1319
1456
  throw new Error(`[internal] extractModuleFacts requires moduleRoot or coreSrcRoot for module "${moduleId}"`);
1320
1457
  }
1321
- const sourceRoot = toPortableSourceRoot(moduleId, sourcePackage);
1458
+ const sourceRoot = options.portableSourceRoot ? assertPortableSourceRoot(moduleId, options.portableSourceRoot) : toPortableSourceRoot(moduleId, sourcePackage);
1322
1459
  const entitiesFilePath = resolveConventionFile(path.join(moduleRoot, "data"), "entities") ?? resolveConventionFile(path.join(moduleRoot, "db"), "entities") ?? resolveConventionFile(path.join(moduleRoot, "data"), "schema");
1323
1460
  const ceFilePath = resolveConventionFile(moduleRoot, "ce");
1324
1461
  const eventsFilePath = resolveConventionFile(moduleRoot, "events");
@@ -1370,7 +1507,8 @@ function extractModuleFacts(options) {
1370
1507
  searchEntities,
1371
1508
  notifications,
1372
1509
  aiTools,
1373
- aiAgents
1510
+ aiAgents,
1511
+ factsContractVersion: options.factsContractVersion ?? 2
1374
1512
  });
1375
1513
  const indexSourcePath = portableOf(indexFilePath);
1376
1514
  const diSourcePath = portableOf(diFilePath);
@@ -1556,6 +1694,7 @@ function extractModuleFacts(options) {
1556
1694
  sourcePackage,
1557
1695
  sourceVersion,
1558
1696
  sourceRoot,
1697
+ ...options.sourceKind === "local-reference" ? { sourceKind: options.sourceKind } : {},
1559
1698
  entities,
1560
1699
  events,
1561
1700
  aclFeatures,
@@ -1630,12 +1769,17 @@ ${EMPTY_SECTION_MARKER}`;
1630
1769
  const rows = values.map((value) => `| ${value} | ${renderLookedUpSource(lookup, kind, value)} |`);
1631
1770
  return [heading, "", `| ${idColumnLabel} | Source |`, "|---|---|", ...rows].join("\n");
1632
1771
  }
1772
+ function isExactSourceFilePath(sourcePath) {
1773
+ return MODULE_CODE_EXTENSIONS.some((extension) => sourcePath.endsWith(extension));
1774
+ }
1633
1775
  function renderSourceLink(sourcePath) {
1776
+ if (!isExactSourceFilePath(sourcePath)) return sourcePath;
1634
1777
  return `[${sourcePath}](../../../${sourcePath})`;
1635
1778
  }
1636
1779
  function renderSourceRefLink(source) {
1637
1780
  const anchor = source.line ? `#L${source.line}` : "";
1638
1781
  const label = source.line ? `${source.sourcePath}:${source.line}` : source.sourcePath;
1782
+ if (!isExactSourceFilePath(source.sourcePath)) return label;
1639
1783
  return `[${label}](../../../${source.sourcePath}${anchor})`;
1640
1784
  }
1641
1785
  function renderLookedUpSource(lookup, kind, id) {
@@ -1865,13 +2009,24 @@ ${EMPTY_SECTION_MARKER}`;
1865
2009
  });
1866
2010
  return ["## Exact override targets", "", header, divider, ...rows].join("\n");
1867
2011
  }
1868
- function renderModuleFactsMarkdown(facts) {
2012
+ function renderReferenceProjectionHeader(facts, fingerprints) {
2013
+ return [
2014
+ `# ${facts.module} \u2014 module facts (generated reference projection, do not edit)`,
2015
+ `<!-- generated from local reference ${facts.sourceRoot}; source-fingerprint ${fingerprints.sourceFingerprint}; taxonomy-fingerprint ${fingerprints.taxonomyFingerprint} \u2014 R1 staleness stamp -->`,
2016
+ `> Reference projection: \`${facts.module}\` is not selected by the current runtime. Its activations and exact override targets describe behavior only after opt-in in \`src/modules.ts\`.`,
2017
+ `Source root: ${renderSourceLink(facts.sourceRoot)}`
2018
+ ];
2019
+ }
2020
+ function renderModuleFactsMarkdown(facts, referenceProjection) {
1869
2021
  const extensionSurfaces = facts.extensionSurfaces ?? { hosts: [], contributions: [], unresolved: [] };
1870
2022
  const lookup = buildFactSourceLookup(facts);
1871
- const sections = [
2023
+ const header = facts.sourceKind === "local-reference" && referenceProjection ? renderReferenceProjectionHeader(facts, referenceProjection) : [
1872
2024
  `# ${facts.module} \u2014 module facts (generated, do not edit)`,
1873
2025
  renderVersionStamp(facts.coreVersion, facts.sourcePackage, facts.sourceVersion),
1874
- `Source root: ${renderSourceLink(facts.sourceRoot)}`,
2026
+ `Source root: ${renderSourceLink(facts.sourceRoot)}`
2027
+ ];
2028
+ const sections = [
2029
+ ...header,
1875
2030
  "",
1876
2031
  renderEntitiesSection(facts.entities, lookup),
1877
2032
  "",
@@ -1946,6 +2101,7 @@ function toModuleFactsJsonEntry(facts) {
1946
2101
  sourcePackage: facts.sourcePackage,
1947
2102
  sourceVersion: facts.sourceVersion,
1948
2103
  sourceRoot: facts.sourceRoot,
2104
+ ...facts.sourceKind === "local-reference" ? { sourceKind: facts.sourceKind } : {},
1949
2105
  entities: facts.entities,
1950
2106
  events: facts.events.map((event) => ({
1951
2107
  id: event.id,
@@ -1985,10 +2141,169 @@ function renderModuleFactsJson(factsByModule) {
1985
2141
  return `${JSON.stringify(buildModuleFactsJsonObject(factsByModule), null, 2)}
1986
2142
  `;
1987
2143
  }
2144
+ function assertPackageModuleFactsOnly(factsByModule) {
2145
+ const offenders = Object.values(factsByModule).filter((facts) => facts.sourceKind === "local-reference" || !facts.sourceRoot.startsWith("node_modules/")).map((facts) => `${facts.module} (${facts.sourceRoot})`).sort((left, right) => left.localeCompare(right));
2146
+ if (offenders.length > 0) {
2147
+ throw new Error(
2148
+ `[module-facts] normal package output must not contain app-local modules: ${offenders.join(", ")}`
2149
+ );
2150
+ }
2151
+ }
2152
+ function sha256Hex(value) {
2153
+ return createHash("sha256").update(value).digest("hex");
2154
+ }
2155
+ function canonicalizeFingerprintValue(value, propertyName) {
2156
+ if (Array.isArray(value)) {
2157
+ const items = value.map((item) => {
2158
+ const canonical = canonicalizeFingerprintValue(item);
2159
+ return { canonical, text: JSON.stringify(canonical) ?? "" };
2160
+ });
2161
+ if (propertyName === "path") return items.map((item) => item.canonical);
2162
+ return items.sort((left, right) => left.text < right.text ? -1 : left.text > right.text ? 1 : 0).map((item) => item.canonical);
2163
+ }
2164
+ if (value !== null && typeof value === "object") {
2165
+ const record = value;
2166
+ const result = {};
2167
+ for (const key of Object.keys(record).sort((left, right) => left < right ? -1 : left > right ? 1 : 0)) {
2168
+ if (record[key] === void 0) continue;
2169
+ result[key] = canonicalizeFingerprintValue(record[key], key);
2170
+ }
2171
+ return result;
2172
+ }
2173
+ return value;
2174
+ }
2175
+ function canonicalFingerprintJson(value) {
2176
+ return JSON.stringify(canonicalizeFingerprintValue(value));
2177
+ }
2178
+ const REFERENCE_FINGERPRINT_SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set(["__tests__", "__integration__", "node_modules"]);
2179
+ function computeModuleSourceFingerprint(moduleRoot, portableSourceRoot) {
2180
+ assertPortableSourceRoot(path.basename(portableSourceRoot), portableSourceRoot);
2181
+ const records = [];
2182
+ const walk = (directory) => {
2183
+ const entries = fs.readdirSync(directory, { withFileTypes: true });
2184
+ for (const entry of entries) {
2185
+ const fullPath = path.join(directory, entry.name);
2186
+ if (entry.isDirectory()) {
2187
+ if (REFERENCE_FINGERPRINT_SKIPPED_DIRECTORIES.has(entry.name)) continue;
2188
+ walk(fullPath);
2189
+ continue;
2190
+ }
2191
+ if (!entry.isFile()) continue;
2192
+ records.push({
2193
+ path: toPortableSourcePath(moduleRoot, portableSourceRoot, fullPath),
2194
+ sha256: sha256Hex(fs.readFileSync(fullPath))
2195
+ });
2196
+ }
2197
+ };
2198
+ walk(moduleRoot);
2199
+ records.sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0);
2200
+ return sha256Hex(canonicalFingerprintJson(records));
2201
+ }
2202
+ const TAXONOMY_EXCLUDED_SECTIONS = /* @__PURE__ */ new Set([
2203
+ "title",
2204
+ "description",
2205
+ "coreVersion",
2206
+ "sourcePackage",
2207
+ "sourceVersion",
2208
+ "sourceRoot",
2209
+ "sourceKind"
2210
+ ]);
2211
+ function collectTaxonomyRecords(setName, value, records) {
2212
+ if (value === void 0) return;
2213
+ if (Array.isArray(value)) {
2214
+ for (const item of value) records.push({ setName, value: canonicalizeFingerprintValue(item) });
2215
+ return;
2216
+ }
2217
+ if (value !== null && typeof value === "object") {
2218
+ for (const [key, child] of Object.entries(value)) {
2219
+ collectTaxonomyRecords(`${setName}.${key}`, child, records);
2220
+ }
2221
+ return;
2222
+ }
2223
+ records.push({ setName, value });
2224
+ }
2225
+ function computeModuleTaxonomyFingerprint(entry) {
2226
+ const records = [];
2227
+ for (const [setName, value] of Object.entries(entry)) {
2228
+ if (TAXONOMY_EXCLUDED_SECTIONS.has(setName)) continue;
2229
+ collectTaxonomyRecords(setName, value, records);
2230
+ }
2231
+ const decorated = records.map((record) => ({ record, text: JSON.stringify(record.value) ?? "" })).sort(
2232
+ (left, right) => left.record.setName < right.record.setName ? -1 : left.record.setName > right.record.setName ? 1 : left.text < right.text ? -1 : left.text > right.text ? 1 : 0
2233
+ );
2234
+ return sha256Hex(JSON.stringify(decorated.map((item) => item.record)));
2235
+ }
2236
+ function renderReferenceModuleFactsJson(bundle) {
2237
+ const ordered = {};
2238
+ for (const moduleId of Object.keys(bundle).sort((left, right) => left < right ? -1 : left > right ? 1 : 0)) {
2239
+ ordered[moduleId] = bundle[moduleId];
2240
+ }
2241
+ return `${JSON.stringify(ordered, null, 2)}
2242
+ `;
2243
+ }
2244
+ function extractLocalReferenceModuleFacts(options) {
2245
+ const { reference } = options;
2246
+ if (reference.sourceKind !== "local-reference") {
2247
+ throw new Error(
2248
+ `[module-facts] reference source "${reference.moduleId}" must declare sourceKind "local-reference"`
2249
+ );
2250
+ }
2251
+ const portableSourceRoot = reference.portableSourceRoot;
2252
+ if (!portableSourceRoot) {
2253
+ throw new Error(`[module-facts] reference source "${reference.moduleId}" must declare portableSourceRoot`);
2254
+ }
2255
+ assertPortableSourceRoot(reference.moduleId, portableSourceRoot);
2256
+ const sources = appendLocalReferenceModuleSource(options.packageSources, reference);
2257
+ const activated = extractAllModuleFacts({
2258
+ sources,
2259
+ registryPath: options.registryPath ?? null,
2260
+ registrySource: options.registrySource ?? null,
2261
+ coreVersion: options.coreVersion ?? null,
2262
+ // The disposable projection collects rather than throws: an app-local module can name
2263
+ // a target whose classification is still missing from the shared extension reader, and
2264
+ // aborting there would delete the whole reference bundle instead of publishing the
2265
+ // exact gap. Normal package output keeps the strict default.
2266
+ unresolvedFirstPartyTargets: "collect"
2267
+ });
2268
+ const facts = activated.factsByModule[reference.moduleId];
2269
+ if (!facts) {
2270
+ throw new Error(`[module-facts] reference module "${reference.moduleId}" produced no facts`);
2271
+ }
2272
+ if (facts.sourceRoot !== portableSourceRoot) {
2273
+ throw new Error(
2274
+ `[module-facts] reference module "${reference.moduleId}" emitted non-portable source root "${facts.sourceRoot}"`
2275
+ );
2276
+ }
2277
+ const jsonEntry = toModuleFactsJsonEntry(facts);
2278
+ const fingerprints = {
2279
+ sourceFingerprint: computeModuleSourceFingerprint(reference.moduleRoot, portableSourceRoot),
2280
+ taxonomyFingerprint: computeModuleTaxonomyFingerprint(jsonEntry)
2281
+ };
2282
+ return {
2283
+ entry: {
2284
+ moduleId: reference.moduleId,
2285
+ projectionKind: "activated-reference",
2286
+ sourceKind: "local-reference",
2287
+ runtimeSelected: false,
2288
+ ...fingerprints,
2289
+ factCoverage: activated.factCoverage ?? buildModuleFactCoverageLedger(),
2290
+ facts: jsonEntry
2291
+ },
2292
+ markdown: renderModuleFactsMarkdown(facts, fingerprints),
2293
+ warnings: activated.warnings,
2294
+ unresolvedTargets: activated.unresolvedFirstPartyTargets ?? []
2295
+ };
2296
+ }
2297
+ function collectUnresolvedFirstPartyTargets(surfacesByModule) {
2298
+ return Object.entries(surfacesByModule).flatMap(
2299
+ ([moduleId, surface]) => surface.unresolved.filter((entry) => entry.reason === "unresolved-first-party-target").map((entry) => `${moduleId}:${entry.key}`)
2300
+ ).sort((left, right) => left.localeCompare(right));
2301
+ }
1988
2302
  function extractAllModuleFacts(options) {
1989
2303
  return withModuleExtensionFactExtractionCache(() => extractAllModuleFactsWithCache(options));
1990
2304
  }
1991
2305
  function extractAllModuleFactsWithCache(options) {
2306
+ const factCoverage = buildModuleFactCoverageLedger();
1992
2307
  const sources = options.sources ? [...options.sources] : options.coreSrcRoot ? (options.moduleIds ?? []).map((moduleId) => ({
1993
2308
  moduleId,
1994
2309
  moduleRoot: path.join(options.coreSrcRoot, moduleId)
@@ -2004,7 +2319,10 @@ function extractAllModuleFactsWithCache(options) {
2004
2319
  sourcePackage: source.from ?? null,
2005
2320
  sourceVersion: source.packageVersion ?? null,
2006
2321
  registryPath: options.registryPath ?? null,
2007
- registrySource: options.registrySource ?? null
2322
+ registrySource: options.registrySource ?? null,
2323
+ ...source.portableSourceRoot ? { portableSourceRoot: source.portableSourceRoot } : {},
2324
+ ...source.sourceKind ? { sourceKind: source.sourceKind } : {},
2325
+ factsContractVersion: options.factsContractVersion ?? 2
2008
2326
  });
2009
2327
  factsByModule[source.moduleId] = facts;
2010
2328
  warnings.push(...facts.warnings);
@@ -2023,9 +2341,11 @@ function extractAllModuleFactsWithCache(options) {
2023
2341
  ...Object.values(factsByModule).flatMap((facts) => facts.apiRoutes.map((route) => route.path)),
2024
2342
  ...sources.flatMap((source) => extractKnownApiRouteIds(source.moduleId, source.moduleRoot))
2025
2343
  ]),
2026
- commandIds: new Set(sources.flatMap((source) => extractKnownCommandIds(source.moduleId, source.moduleRoot)))
2344
+ commandIds: new Set(sources.flatMap((source) => extractKnownCommandIds(source.moduleId, source.moduleRoot))),
2345
+ factsContractVersion: options.factsContractVersion ?? 2
2027
2346
  });
2028
- assertNoUnresolvedExtensionTargets(correlated);
2347
+ const unresolvedFirstPartyTargets = collectUnresolvedFirstPartyTargets(correlated);
2348
+ if ((options.unresolvedFirstPartyTargets ?? "throw") === "throw") assertNoUnresolvedExtensionTargets(correlated);
2029
2349
  const apiRouteOwners = /* @__PURE__ */ new Map();
2030
2350
  const commandOwners = /* @__PURE__ */ new Map();
2031
2351
  for (const source of [...sources].sort((left, right) => left.moduleId.localeCompare(right.moduleId))) {
@@ -2057,14 +2377,622 @@ function extractAllModuleFactsWithCache(options) {
2057
2377
  (entry) => `[module-facts] ${moduleId} ${entry.reason}: ${entry.key} (${entry.source.path})`
2058
2378
  ));
2059
2379
  }
2060
- return { factsByModule, markdownByModule, warnings, frameworkMarkdown: renderFrameworkExtensionPointsMarkdown() };
2380
+ return {
2381
+ factsByModule,
2382
+ markdownByModule,
2383
+ warnings,
2384
+ frameworkMarkdown: renderFrameworkExtensionPointsMarkdown(),
2385
+ unresolvedFirstPartyTargets,
2386
+ factCoverage
2387
+ };
2388
+ }
2389
+ const FACT_SOURCE_KIND_COVERAGE = {
2390
+ "module-metadata": { value: "module-metadata", status: "emitted-example", note: "example/index.ts ModuleInfo export" },
2391
+ entity: { value: "entity", status: "emitted-example", note: "example/data/entities.ts ORM entities" },
2392
+ event: { value: "event", status: "emitted-example", note: "example/events.ts typed event definitions" },
2393
+ "acl-feature": { value: "acl-feature", status: "emitted-example", note: "example/acl.ts RBAC features" },
2394
+ "api-route": {
2395
+ value: "api-route",
2396
+ status: "emitted-example",
2397
+ note: "example/api/**/route.ts; route facts are read from the generated module registry, not from module source",
2398
+ requiresGeneratedRegistry: true
2399
+ },
2400
+ "di-registration": { value: "di-registration", status: "emitted-example", note: "example/di.ts Awilix container.register" },
2401
+ search: { value: "search", status: "emitted-example", note: "example/search.ts indexed entity declaration" },
2402
+ vector: {
2403
+ value: "vector",
2404
+ status: "emitted-example",
2405
+ note: "example/vector.ts deterministic Todo vector declaration"
2406
+ },
2407
+ notification: { value: "notification", status: "emitted-example", note: "example/notifications.ts notification types" },
2408
+ "cli-command": { value: "cli-command", status: "emitted-example", note: "example/cli.ts module commands" },
2409
+ "backend-page": { value: "backend-page", status: "emitted-example", note: "example/backend/**/page.tsx admin pages" },
2410
+ "frontend-page": { value: "frontend-page", status: "emitted-example", note: "example/frontend/**/page.tsx portal pages" },
2411
+ "ai-tool": { value: "ai-tool", status: "emitted-example", note: "example/ai-tools.ts defineAiTool declarations" },
2412
+ "ai-agent": { value: "ai-agent", status: "emitted-example", note: "example/ai-agents.ts defineAiAgent declarations" },
2413
+ "ai-extension": { value: "ai-extension", status: "emitted-example", note: "example AI agent/tool override and extension records" },
2414
+ command: { value: "command", status: "emitted-example", note: "example/commands/todos.ts command handlers" },
2415
+ subscriber: { value: "subscriber", status: "emitted-example", note: "example/subscribers/*.ts event subscribers" },
2416
+ worker: { value: "worker", status: "emitted-example", note: "example/workers/*.ts queue workers" },
2417
+ "page-middleware": { value: "page-middleware", status: "emitted-example", note: "example/backend/middleware.ts page guard" },
2418
+ setup: { value: "setup", status: "emitted-example", note: "example/setup.ts tenant setup hooks" },
2419
+ encryption: { value: "encryption", status: "emitted-example", note: "example/encryption.ts field encryption map" },
2420
+ "custom-entity": { value: "custom-entity", status: "emitted-example", note: "example/ce.ts custom entity and field DSL" },
2421
+ integration: { value: "integration", status: "emitted-example", note: "example/lib/mock-*-adapter.ts integration registrations" },
2422
+ "generator-plugin": {
2423
+ value: "generator-plugin",
2424
+ status: "emitted-example",
2425
+ note: "example/generators.ts deterministic reference-index generator plugin"
2426
+ },
2427
+ "extension-host": { value: "extension-host", status: "emitted-example", note: "example/extension-points.ts declared hosts" },
2428
+ "extension-contribution": {
2429
+ value: "extension-contribution",
2430
+ status: "emitted-example",
2431
+ note: "example widget, DataTable, CrudForm, interceptor and enricher contributions"
2432
+ }
2433
+ };
2434
+ const OWNED_CONTRACT_KIND_COVERAGE = {
2435
+ "module-metadata": { value: "module-metadata", status: "emitted-example", note: "ModuleInfo owned contract" },
2436
+ command: { value: "command", status: "emitted-example", note: "example/commands/todos.ts" },
2437
+ worker: { value: "worker", status: "emitted-example", note: "example/workers/*.ts" },
2438
+ "page-middleware": { value: "page-middleware", status: "emitted-example", note: "example/backend/middleware.ts" },
2439
+ setup: { value: "setup", status: "emitted-example", note: "example/setup.ts" },
2440
+ encryption: { value: "encryption", status: "emitted-example", note: "example/encryption.ts" },
2441
+ "di-registration": {
2442
+ value: "di-registration",
2443
+ status: "emitted-example",
2444
+ note: "example/di.ts scoped Todo summary cache service consumed by a route"
2445
+ },
2446
+ "custom-entity": { value: "custom-entity", status: "emitted-example", note: "example/ce.ts" },
2447
+ "ai-extension": { value: "ai-extension", status: "emitted-example", note: "example AI override/extension record" },
2448
+ "generator-plugin": {
2449
+ value: "generator-plugin",
2450
+ status: "emitted-example",
2451
+ note: "example/generators.ts deterministic reference-index generator plugin"
2452
+ }
2453
+ };
2454
+ const OVERRIDE_DOMAIN_COVERAGE = {
2455
+ ai: { value: "ai", status: "emitted-example", note: "ai.agents, ai.tools and ai.extensions targets" },
2456
+ routes: { value: "routes", status: "emitted-example", note: "routes.api and routes.pages targets" },
2457
+ events: { value: "events", status: "emitted-example", note: "events.subscribers targets" },
2458
+ workers: { value: "workers", status: "emitted-example", note: "workers targets" },
2459
+ widgets: { value: "widgets", status: "emitted-example", note: "widgets.injection, .components and .dashboard targets" },
2460
+ notifications: { value: "notifications", status: "emitted-example", note: "notifications.types and notifications.handlers targets" },
2461
+ interceptors: { value: "interceptors", status: "emitted-example", note: "API interceptor targets" },
2462
+ commandInterceptors: { value: "commandInterceptors", status: "emitted-example", note: "command interceptor targets" },
2463
+ enrichers: { value: "enrichers", status: "emitted-example", note: "response enricher targets" },
2464
+ guards: { value: "guards", status: "emitted-example", note: "page-middleware guard targets" },
2465
+ cli: { value: "cli", status: "emitted-example", note: "CLI command targets" },
2466
+ setup: { value: "setup", status: "emitted-example", note: "setup hook and default-role targets" },
2467
+ acl: { value: "acl", status: "emitted-example", note: "acl.features targets" },
2468
+ di: { value: "di", status: "emitted-example", note: "DI token targets" },
2469
+ encryption: { value: "encryption", status: "emitted-example", note: "encryption.maps targets" },
2470
+ nav: {
2471
+ value: "nav",
2472
+ status: "framework-only",
2473
+ note: "nav.groupOrder is an app-level framework setting; no module target is ever emitted for it"
2474
+ }
2475
+ };
2476
+ const OVERRIDE_MODE_COVERAGE = {
2477
+ "disable-replace": {
2478
+ value: "disable-replace",
2479
+ status: "emitted-example",
2480
+ note: "default mode for most example override hosts"
2481
+ },
2482
+ replace: { value: "replace", status: "emitted-example", note: "the setup host replaces wholesale" },
2483
+ additive: { value: "additive", status: "emitted-example", note: "the ai.extensions host merges additively" }
2484
+ };
2485
+ const OVERRIDE_NOTE_COVERAGE = {
2486
+ "safe-metadata-only": {
2487
+ value: "safe-metadata-only",
2488
+ status: "emitted-example",
2489
+ note: "emitted on the metadata-only override target"
2490
+ },
2491
+ "page-middleware-not-mutation-guard": {
2492
+ value: "page-middleware-not-mutation-guard",
2493
+ status: "emitted-example",
2494
+ note: "emitted on the guards target so a page guard is not read as a mutation guard"
2495
+ }
2496
+ };
2497
+ const OVERRIDE_DIAGNOSTIC_COVERAGE = {
2498
+ "missing-owned-fact": {
2499
+ value: "missing-owned-fact",
2500
+ status: "currently-unbound",
2501
+ note: "reserved by the spec's closed diagnostic set; no adapter emits it today, so not even a broken fixture can produce it"
2502
+ },
2503
+ "missing-source": {
2504
+ value: "missing-source",
2505
+ status: "negative-fixture",
2506
+ note: "a fact whose provenance cannot be proven yields this and no target; activated canonical output emits none"
2507
+ },
2508
+ "unsupported-dynamic-key": {
2509
+ value: "unsupported-dynamic-key",
2510
+ status: "negative-fixture",
2511
+ note: "a key the runtime cannot address yields this and no target; activated canonical output emits none"
2512
+ },
2513
+ "unknown-framework-domain": {
2514
+ value: "unknown-framework-domain",
2515
+ status: "negative-fixture",
2516
+ note: "the framework catalog does not describe the dotted host at all"
2517
+ },
2518
+ "unknown-framework-mode": {
2519
+ value: "unknown-framework-mode",
2520
+ status: "negative-fixture",
2521
+ note: "the framework catalog describes the host but names an operation that is not a public mode"
2522
+ }
2523
+ };
2524
+ const CONTRIBUTION_KIND_COVERAGE = {
2525
+ widget: { value: "widget", status: "emitted-example", note: "example widget injection and dashboard registrations" },
2526
+ "data-table": { value: "data-table", status: "emitted-example", note: "example DataTable extension entries" },
2527
+ "crud-form": { value: "crud-form", status: "emitted-example", note: "example CrudForm field and lifecycle entries" },
2528
+ "component-override": { value: "component-override", status: "emitted-example", note: "example replace, wrapper and props component entries" },
2529
+ "response-enricher": { value: "response-enricher", status: "emitted-example", note: "example customer priority response enricher" },
2530
+ "api-interceptor": { value: "api-interceptor", status: "emitted-example", note: "example CRUD API interceptor entries" },
2531
+ "command-interceptor": { value: "command-interceptor", status: "emitted-example", note: "example command interceptor entries" },
2532
+ "mutation-guard": { value: "mutation-guard", status: "emitted-example", note: "example Todo mutation guard" },
2533
+ "entity-extension": { value: "entity-extension", status: "emitted-example", note: "example customer entity extension" },
2534
+ subscriber: { value: "subscriber", status: "emitted-example", note: "example synchronous and asynchronous subscribers" },
2535
+ "browser-reaction": { value: "browser-reaction", status: "emitted-example", note: "example client, portal and notification reactions" },
2536
+ "specialized-registry": { value: "specialized-registry", status: "emitted-example", note: "example notification, search, AI and mock adapter registries" },
2537
+ "module-override": { value: "module-override", status: "catalog-only", note: "app-owned configuration is not an outgoing module contribution" }
2538
+ };
2539
+ const ACTIVATION_KIND_COVERAGE = {
2540
+ "crud-response-enricher": { value: "crud-response-enricher", status: "currently-unbound", note: "example contributes a response enricher but owns no CRUD response call site for its customer target" },
2541
+ "query-enricher": { value: "query-enricher", status: "currently-unbound", note: "example contributes a query enricher but owns no query-engine call site for its customer target" },
2542
+ "mutation-guard": { value: "mutation-guard", status: "emitted-example", note: "Todo mutation-guard route bridge" },
2543
+ "api-interceptor-bridge": { value: "api-interceptor-bridge", status: "emitted-example", note: "CRUD route interceptor pipeline" },
2544
+ "command-interceptor-bridge": { value: "command-interceptor-bridge", status: "emitted-example", note: "exact Todo command bus target" },
2545
+ "widget-injection-consumer": { value: "widget-injection-consumer", status: "emitted-example", note: "bound injection host consumer" },
2546
+ "component-extension-consumer": { value: "component-extension-consumer", status: "emitted-example", note: "bound component handle consumer" },
2547
+ "dashboard-host-consumer": { value: "dashboard-host-consumer", status: "emitted-example", note: "framework dashboard registry consumer" }
2548
+ };
2549
+ const HOST_FAMILY_COVERAGE = {
2550
+ generic: { value: "generic", status: "emitted-example", note: "example headless injection host" },
2551
+ menu: { value: "menu", status: "framework-only", note: "framework menu hosts consumed by example widgets" },
2552
+ "data-table": { value: "data-table", status: "emitted-example", note: "example Todo DataTable host" },
2553
+ "crud-form": { value: "crud-form", status: "emitted-example", note: "example Todo CrudForm host" },
2554
+ detail: { value: "detail", status: "framework-only", note: "framework detail hosts consumed by example widgets" },
2555
+ "portal-page": { value: "portal-page", status: "framework-only", note: "framework portal host consumed by example widgets" },
2556
+ "component-handle": { value: "component-handle", status: "emitted-example", note: "example replaceable component host" },
2557
+ entity: { value: "entity", status: "emitted-example", note: "example entity fact-reference hosts" },
2558
+ "api-route": { value: "api-route", status: "framework-only", note: "API route hosts are owned by the target module and consumed by example interceptors" },
2559
+ command: { value: "command", status: "framework-only", note: "command hosts are owned by the target module and consumed by example interceptors" },
2560
+ event: { value: "event", status: "emitted-example", note: "example event fact-reference hosts" },
2561
+ "query-lifecycle": { value: "query-lifecycle", status: "emitted-example", note: "example Todo query lifecycle hosts" },
2562
+ dashboard: { value: "dashboard", status: "framework-only", note: "framework dashboard host consumed by example widgets" },
2563
+ notification: { value: "notification", status: "framework-only", note: "framework notification host consumed by the example registry" },
2564
+ integration: { value: "integration", status: "framework-only", note: "framework integration detail host consumed by example widgets" },
2565
+ "specialized-registry": { value: "specialized-registry", status: "framework-only", note: "framework-owned specialist registries accept example entries" },
2566
+ "module-override": { value: "module-override", status: "framework-only", note: "framework override catalog owns these hosts" }
2567
+ };
2568
+ const HOST_CAPABILITY_COVERAGE = {
2569
+ "render-widget": { value: "render-widget", status: "emitted-example", note: "example render widget host and contributions" },
2570
+ "headless-widget": { value: "headless-widget", status: "currently-unbound", note: "injection-table facts do not yet distinguish headless widget payloads" },
2571
+ "menu-item": { value: "menu-item", status: "currently-unbound", note: "injection-table facts do not yet distinguish menu item payloads" },
2572
+ "column-widget": { value: "column-widget", status: "emitted-example", note: "example DataTable column host" },
2573
+ "row-action": { value: "row-action", status: "emitted-example", note: "example DataTable row-action host" },
2574
+ "bulk-action": { value: "bulk-action", status: "emitted-example", note: "example DataTable bulk-action host" },
2575
+ "filter-widget": { value: "filter-widget", status: "emitted-example", note: "example DataTable filter host" },
2576
+ "toolbar-widget": { value: "toolbar-widget", status: "emitted-example", note: "example DataTable toolbar host" },
2577
+ "field-widget": { value: "field-widget", status: "emitted-example", note: "example CrudForm field host" },
2578
+ "lifecycle-handler": { value: "lifecycle-handler", status: "emitted-example", note: "example CrudForm lifecycle host" },
2579
+ "component-replacement": { value: "component-replacement", status: "emitted-example", note: "example replaceable DataTable, CrudForm and component hosts" },
2580
+ "response-enricher": { value: "response-enricher", status: "emitted-example", note: "example entity enricher host" },
2581
+ "query-enricher": { value: "query-enricher", status: "emitted-example", note: "example query-enricher host" },
2582
+ "api-interceptor": { value: "api-interceptor", status: "emitted-example", note: "example API interceptor contribution and route bridge" },
2583
+ "command-interceptor": { value: "command-interceptor", status: "emitted-example", note: "example command interceptor and exact command owner" },
2584
+ "mutation-guard": { value: "mutation-guard", status: "emitted-example", note: "example entity mutation guard host" },
2585
+ "entity-extension": { value: "entity-extension", status: "emitted-example", note: "example entity extension host" },
2586
+ "async-subscriber": { value: "async-subscriber", status: "emitted-example", note: "example event subscriber host" },
2587
+ "sync-subscriber": { value: "sync-subscriber", status: "emitted-example", note: "example synchronous event subscriber host" },
2588
+ "browser-client": { value: "browser-client", status: "emitted-example", note: "example client-broadcast event host" },
2589
+ "browser-portal": { value: "browser-portal", status: "emitted-example", note: "example portal-broadcast event host" },
2590
+ "registry-contribution": { value: "registry-contribution", status: "emitted-example", note: "example specialized registry contributions" },
2591
+ "module-override": { value: "module-override", status: "framework-only", note: "framework override hosts; app configuration is not a contribution" }
2592
+ };
2593
+ const HOST_ACTIVATION_COVERAGE = {
2594
+ always: { value: "always", status: "emitted-example", note: "always-active example declarations" },
2595
+ "host-opt-in": { value: "host-opt-in", status: "emitted-example", note: "example entity extension and response-enricher hosts" },
2596
+ "caller-opt-in": { value: "caller-opt-in", status: "emitted-example", note: "example query lifecycle and query enricher" },
2597
+ "feature-gated": { value: "feature-gated", status: "currently-unbound", note: "feature requirements are emitted but are not a distinct activation value" }
2598
+ };
2599
+ const TARGET_KIND_COVERAGE = {
2600
+ module: { value: "module", status: "emitted-example", note: "example module-scoped registry target" },
2601
+ entity: { value: "entity", status: "emitted-example", note: "example entity extension, enricher and guard targets" },
2602
+ "api-route": { value: "api-route", status: "emitted-example", note: "example API interceptor targets" },
2603
+ command: { value: "command", status: "emitted-example", note: "example exact and wildcard command targets" },
2604
+ "widget-spot": { value: "widget-spot", status: "emitted-example", note: "example injection targets" },
2605
+ component: { value: "component", status: "emitted-example", note: "example component override targets" },
2606
+ event: { value: "event", status: "emitted-example", note: "example subscriber targets" },
2607
+ notification: { value: "notification", status: "emitted-example", note: "example notification registry target" },
2608
+ wildcard: { value: "wildcard", status: "emitted-example", note: "example wildcard subscriber and interceptor targets" }
2609
+ };
2610
+ const HOST_RESOLUTION_COVERAGE = {
2611
+ exact: { value: "exact", status: "emitted-example", note: "example exact declared hosts" },
2612
+ pattern: { value: "pattern", status: "emitted-example", note: "example patterned host surfaces" },
2613
+ framework: { value: "framework", status: "framework-only", note: "framework catalog host identity" },
2614
+ "fact-ref": { value: "fact-ref", status: "emitted-example", note: "example entity, event and query fact-reference hosts" }
2615
+ };
2616
+ const TARGET_RESOLUTION_COVERAGE = {
2617
+ exact: { value: "exact", status: "emitted-example", note: "example exact target correlation" },
2618
+ pattern: { value: "pattern", status: "emitted-example", note: "example wildcard and patterned target correlation" },
2619
+ framework: { value: "framework", status: "emitted-example", note: "example contribution to a framework host" },
2620
+ "fact-ref": { value: "fact-ref", status: "emitted-example", note: "example contribution to a generated fact owner" },
2621
+ "optional-external": { value: "optional-external", status: "emitted-example", note: "example optional module target remains fail-soft" },
2622
+ unresolved: { value: "unresolved", status: "negative-fixture", note: "only malformed targets remain unresolved" }
2623
+ };
2624
+ const TOPOLOGY_RESOLUTION_COVERAGE = {
2625
+ bound: { value: "bound", status: "emitted-example", note: "example contribution reaches a verified runtime activation" },
2626
+ "capability-only": { value: "capability-only", status: "emitted-example", note: "declaration-backed capability without a separate caller activation" },
2627
+ "optional-target-missing": { value: "optional-target-missing", status: "emitted-example", note: "optional external target absent from the selected module set" },
2628
+ wildcard: { value: "wildcard", status: "emitted-example", note: "wildcard contribution resolves against selected targets" },
2629
+ unresolved: { value: "unresolved", status: "negative-fixture", note: "only malformed first-party targets remain unresolved" }
2630
+ };
2631
+ const SPECIALIZED_REGISTRY_COVERAGE = {
2632
+ notification: { value: "notification", status: "emitted-example", note: "example notification type registry" },
2633
+ integration: { value: "integration", status: "emitted-example", note: "example credential-free integration bundle identity" },
2634
+ search: { value: "search", status: "emitted-example", note: "example Todo search registry" },
2635
+ vector: { value: "vector", status: "emitted-example", note: "example deterministic Todo vector registry" },
2636
+ ai: { value: "ai", status: "emitted-example", note: "example AI tool and agent registries" },
2637
+ payment: { value: "payment", status: "emitted-example", note: "example mock payment descriptors" },
2638
+ shipping: { value: "shipping", status: "emitted-example", note: "example mock shipping registry identity" },
2639
+ currency: { value: "currency", status: "emitted-example", note: "example deterministic currency provider identity" },
2640
+ workflow: { value: "workflow", status: "emitted-example", note: "example event-triggered Todo workflow identity" }
2641
+ };
2642
+ const COMPONENT_MODE_COVERAGE = {
2643
+ replace: { value: "replace", status: "emitted-example", note: "example replacement component" },
2644
+ wrapper: { value: "wrapper", status: "emitted-example", note: "example decorating wrapper component" },
2645
+ props: { value: "props", status: "emitted-example", note: "example props-transform component" }
2646
+ };
2647
+ const FACT_DIAGNOSTIC_COVERAGE = {
2648
+ "duplicate-source": { value: "duplicate-source", status: "negative-fixture", note: "duplicate provenance fixture; canonical output emits none" },
2649
+ "unresolved-static-contract": { value: "unresolved-static-contract", status: "negative-fixture", note: "dynamic contract fixture; canonical output emits none" }
2650
+ };
2651
+ const UNRESOLVED_REASON_COVERAGE = {
2652
+ "unclassified-binding": { value: "unclassified-binding", status: "negative-fixture", note: "malformed extension declaration fixture" },
2653
+ "unbound-declaration": { value: "unbound-declaration", status: "negative-fixture", note: "declared host without a real caller fixture" },
2654
+ "dynamic-without-pattern": { value: "dynamic-without-pattern", status: "negative-fixture", note: "dynamic host without a declared pattern fixture" },
2655
+ "unresolved-first-party-target": { value: "unresolved-first-party-target", status: "negative-fixture", note: "broken first-party target fixture" }
2656
+ };
2657
+ const DATA_TABLE_SURFACE_COVERAGE = {
2658
+ header: { value: "header", status: "emitted-example", note: "bound Todo table header" },
2659
+ footer: { value: "footer", status: "emitted-example", note: "bound Todo table footer" },
2660
+ toolbar: { value: "toolbar", status: "emitted-example", note: "bound Todo table toolbar" },
2661
+ searchTrailing: { value: "searchTrailing", status: "emitted-example", note: "bound Todo table search trailing surface" },
2662
+ columns: { value: "columns", status: "emitted-example", note: "bound Todo table columns" },
2663
+ rowActions: { value: "rowActions", status: "emitted-example", note: "bound Todo table row actions" },
2664
+ bulkActions: { value: "bulkActions", status: "emitted-example", note: "bound Todo table bulk actions" },
2665
+ filters: { value: "filters", status: "emitted-example", note: "bound Todo table filters" },
2666
+ replacement: { value: "replacement", status: "emitted-example", note: "bound Todo table replacement" },
2667
+ emptyState: { value: "emptyState", status: "currently-unbound", note: "catalog-declared DataTable surface has no runtime host" }
2668
+ };
2669
+ const CRUD_FORM_SURFACE_COVERAGE = {
2670
+ base: { value: "base", status: "emitted-example", note: "bound Todo form base" },
2671
+ header: { value: "header", status: "emitted-example", note: "bound Todo form header" },
2672
+ fields: { value: "fields", status: "emitted-example", note: "bound Todo form fields" },
2673
+ replacement: { value: "replacement", status: "emitted-example", note: "bound Todo form replacement" },
2674
+ beforeFields: { value: "beforeFields", status: "currently-unbound", note: "catalog-declared CrudForm surface has no runtime host" },
2675
+ afterFields: { value: "afterFields", status: "currently-unbound", note: "catalog-declared CrudForm surface has no runtime host" },
2676
+ footer: { value: "footer", status: "currently-unbound", note: "catalog-declared CrudForm surface has no runtime host" },
2677
+ sidebar: { value: "sidebar", status: "currently-unbound", note: "catalog-declared CrudForm surface has no runtime host" },
2678
+ group: { value: "group", status: "currently-unbound", note: "catalog-declared CrudForm surface has no runtime host" },
2679
+ fieldBefore: { value: "fieldBefore", status: "currently-unbound", note: "catalog-declared CrudForm surface has no runtime host" },
2680
+ fieldAfter: { value: "fieldAfter", status: "currently-unbound", note: "catalog-declared CrudForm surface has no runtime host" }
2681
+ };
2682
+ const CRUD_FORM_LIFECYCLE_COVERAGE = {
2683
+ transformValidation: { value: "transformValidation", status: "emitted-example", note: "example Todo form lifecycle transformValidation" },
2684
+ transformDisplayData: { value: "transformDisplayData", status: "emitted-example", note: "example Todo form lifecycle transformDisplayData" },
2685
+ onBeforeNavigate: { value: "onBeforeNavigate", status: "emitted-example", note: "example Todo form lifecycle onBeforeNavigate" },
2686
+ onAppEvent: { value: "onAppEvent", status: "emitted-example", note: "example Todo form lifecycle onAppEvent" },
2687
+ onVisibilityChange: { value: "onVisibilityChange", status: "emitted-example", note: "example Todo form lifecycle onVisibilityChange" },
2688
+ onBeforeDelete: { value: "onBeforeDelete", status: "emitted-example", note: "example Todo form lifecycle onBeforeDelete" },
2689
+ onDelete: { value: "onDelete", status: "emitted-example", note: "example Todo form lifecycle onDelete" },
2690
+ onAfterDelete: { value: "onAfterDelete", status: "emitted-example", note: "example Todo form lifecycle onAfterDelete" },
2691
+ onDeleteError: { value: "onDeleteError", status: "emitted-example", note: "example Todo form lifecycle onDeleteError" },
2692
+ onFieldChange: { value: "onFieldChange", status: "emitted-example", note: "example Todo form lifecycle onFieldChange" },
2693
+ transformFormData: { value: "transformFormData", status: "emitted-example", note: "example Todo form lifecycle transformFormData" },
2694
+ onBeforeSave: { value: "onBeforeSave", status: "emitted-example", note: "example Todo form lifecycle onBeforeSave" },
2695
+ onSave: { value: "onSave", status: "emitted-example", note: "example Todo form lifecycle onSave" },
2696
+ onAfterSave: { value: "onAfterSave", status: "emitted-example", note: "example Todo form lifecycle onAfterSave" }
2697
+ };
2698
+ const CRUD_FORM_OPERATION_COVERAGE = {
2699
+ create: { value: "create", status: "emitted-example", note: "example Todo create lifecycle" },
2700
+ update: { value: "update", status: "currently-unbound", note: "example lifecycle contribution is currently registered for create only" },
2701
+ delete: { value: "delete", status: "currently-unbound", note: "example lifecycle contribution is currently registered for create only" }
2702
+ };
2703
+ function buildCoverageFamily(family, enumSource, values, coverage) {
2704
+ const rows = [];
2705
+ const missing = [];
2706
+ for (const value of values) {
2707
+ const row = coverage[value];
2708
+ if (!row) {
2709
+ missing.push(value);
2710
+ continue;
2711
+ }
2712
+ rows.push(row);
2713
+ }
2714
+ if (missing.length > 0) {
2715
+ throw new Error(
2716
+ `[module-facts] factCoverage family "${family}" has no row for: ${missing.join(", ")}. Add an explicit classification instead of leaving the value unclassified.`
2717
+ );
2718
+ }
2719
+ const extra = Object.keys(coverage).filter((value) => !values.includes(value));
2720
+ if (extra.length > 0) {
2721
+ throw new Error(
2722
+ `[module-facts] factCoverage family "${family}" classifies values absent from the enum: ${extra.join(", ")}.`
2723
+ );
2724
+ }
2725
+ return { family, enumSource, rows };
2726
+ }
2727
+ function buildModuleFactCoverageLedger() {
2728
+ return [
2729
+ buildCoverageFamily(
2730
+ "ModuleFactSourceKind",
2731
+ "packages/cli/src/lib/generators/module-facts.ts#MODULE_FACT_SOURCE_KINDS",
2732
+ MODULE_FACT_SOURCE_KINDS,
2733
+ FACT_SOURCE_KIND_COVERAGE
2734
+ ),
2735
+ buildCoverageFamily(
2736
+ "ModuleOwnedContractKind",
2737
+ "packages/cli/src/lib/generators/module-facts.ts#MODULE_OWNED_CONTRACT_KINDS",
2738
+ MODULE_OWNED_CONTRACT_KINDS,
2739
+ OWNED_CONTRACT_KIND_COVERAGE
2740
+ ),
2741
+ buildCoverageFamily(
2742
+ "ModuleOverrideDomain",
2743
+ "packages/cli/src/lib/generators/module-override-targets.ts#ALL_OVERRIDE_DOMAINS",
2744
+ ALL_OVERRIDE_DOMAINS,
2745
+ OVERRIDE_DOMAIN_COVERAGE
2746
+ ),
2747
+ buildCoverageFamily(
2748
+ "ModuleOverrideMode",
2749
+ "packages/cli/src/lib/generators/module-override-targets.ts#MODULE_OVERRIDE_MODES",
2750
+ MODULE_OVERRIDE_MODES,
2751
+ OVERRIDE_MODE_COVERAGE
2752
+ ),
2753
+ buildCoverageFamily(
2754
+ "ModuleOverrideTargetNote",
2755
+ "packages/cli/src/lib/generators/module-override-targets.ts#MODULE_OVERRIDE_TARGET_NOTES",
2756
+ MODULE_OVERRIDE_TARGET_NOTES,
2757
+ OVERRIDE_NOTE_COVERAGE
2758
+ ),
2759
+ buildCoverageFamily(
2760
+ "ModuleOverrideTargetDiagnosticCode",
2761
+ "packages/cli/src/lib/generators/module-override-targets.ts#MODULE_OVERRIDE_TARGET_DIAGNOSTIC_CODES",
2762
+ MODULE_OVERRIDE_TARGET_DIAGNOSTIC_CODES,
2763
+ OVERRIDE_DIAGNOSTIC_COVERAGE
2764
+ ),
2765
+ buildCoverageFamily(
2766
+ "ModuleExtensionContributionKind",
2767
+ "packages/shared/src/modules/widgets/extension-points.ts#MODULE_EXTENSION_CONTRIBUTION_KINDS",
2768
+ MODULE_EXTENSION_CONTRIBUTION_KINDS,
2769
+ CONTRIBUTION_KIND_COVERAGE
2770
+ ),
2771
+ buildCoverageFamily(
2772
+ "ModuleExtensionActivationKind",
2773
+ "packages/shared/src/modules/widgets/extension-points.ts#MODULE_EXTENSION_ACTIVATION_KINDS",
2774
+ MODULE_EXTENSION_ACTIVATION_KINDS,
2775
+ ACTIVATION_KIND_COVERAGE
2776
+ ),
2777
+ buildCoverageFamily(
2778
+ "ExtensionHostFamily",
2779
+ "packages/shared/src/modules/widgets/extension-points.ts#EXTENSION_HOST_FAMILIES",
2780
+ EXTENSION_HOST_FAMILIES,
2781
+ HOST_FAMILY_COVERAGE
2782
+ ),
2783
+ buildCoverageFamily(
2784
+ "ExtensionHostCapability",
2785
+ "packages/shared/src/modules/widgets/extension-points.ts#EXTENSION_HOST_CAPABILITIES",
2786
+ EXTENSION_HOST_CAPABILITIES,
2787
+ HOST_CAPABILITY_COVERAGE
2788
+ ),
2789
+ buildCoverageFamily(
2790
+ "ExtensionHostActivation",
2791
+ "packages/shared/src/modules/widgets/extension-points.ts#EXTENSION_HOST_ACTIVATIONS",
2792
+ EXTENSION_HOST_ACTIVATIONS,
2793
+ HOST_ACTIVATION_COVERAGE
2794
+ ),
2795
+ buildCoverageFamily(
2796
+ "ModuleExtensionTargetKind",
2797
+ "packages/shared/src/modules/widgets/extension-points.ts#MODULE_EXTENSION_TARGET_KINDS",
2798
+ MODULE_EXTENSION_TARGET_KINDS,
2799
+ TARGET_KIND_COVERAGE
2800
+ ),
2801
+ buildCoverageFamily(
2802
+ "ModuleExtensionHostResolution",
2803
+ "packages/shared/src/modules/widgets/extension-points.ts#MODULE_EXTENSION_HOST_RESOLUTIONS",
2804
+ MODULE_EXTENSION_HOST_RESOLUTIONS,
2805
+ HOST_RESOLUTION_COVERAGE
2806
+ ),
2807
+ buildCoverageFamily(
2808
+ "ModuleExtensionTargetResolution",
2809
+ "packages/shared/src/modules/widgets/extension-points.ts#MODULE_EXTENSION_TARGET_RESOLUTIONS",
2810
+ MODULE_EXTENSION_TARGET_RESOLUTIONS,
2811
+ TARGET_RESOLUTION_COVERAGE
2812
+ ),
2813
+ buildCoverageFamily(
2814
+ "ModuleExtensionResolution",
2815
+ "packages/shared/src/modules/widgets/extension-points.ts#MODULE_EXTENSION_RESOLUTIONS",
2816
+ MODULE_EXTENSION_RESOLUTIONS,
2817
+ TOPOLOGY_RESOLUTION_COVERAGE
2818
+ ),
2819
+ buildCoverageFamily(
2820
+ "SpecializedRegistry",
2821
+ "packages/shared/src/modules/widgets/extension-points.ts#MODULE_SPECIALIZED_REGISTRIES",
2822
+ MODULE_SPECIALIZED_REGISTRIES,
2823
+ SPECIALIZED_REGISTRY_COVERAGE
2824
+ ),
2825
+ buildCoverageFamily(
2826
+ "ComponentOverrideMode",
2827
+ "packages/shared/src/modules/widgets/extension-points.ts#COMPONENT_OVERRIDE_MODES",
2828
+ COMPONENT_OVERRIDE_MODES,
2829
+ COMPONENT_MODE_COVERAGE
2830
+ ),
2831
+ buildCoverageFamily(
2832
+ "ModuleFactDiagnosticCode",
2833
+ "packages/cli/src/lib/generators/module-facts.ts#MODULE_FACT_DIAGNOSTIC_CODES",
2834
+ MODULE_FACT_DIAGNOSTIC_CODES,
2835
+ FACT_DIAGNOSTIC_COVERAGE
2836
+ ),
2837
+ buildCoverageFamily(
2838
+ "ModuleExtensionUnresolvedReason",
2839
+ "packages/shared/src/modules/widgets/extension-points.ts#MODULE_EXTENSION_UNRESOLVED_REASONS",
2840
+ MODULE_EXTENSION_UNRESOLVED_REASONS,
2841
+ UNRESOLVED_REASON_COVERAGE
2842
+ ),
2843
+ buildCoverageFamily(
2844
+ "DataTableExtensionSurface",
2845
+ "packages/shared/src/modules/widgets/extension-points.ts#DATA_TABLE_EXTENSION_SURFACE_KEYS",
2846
+ DATA_TABLE_EXTENSION_SURFACE_KEYS,
2847
+ DATA_TABLE_SURFACE_COVERAGE
2848
+ ),
2849
+ buildCoverageFamily(
2850
+ "CrudFormExtensionSurface",
2851
+ "packages/shared/src/modules/widgets/extension-points.ts#CRUD_FORM_EXTENSION_SURFACE_KEYS",
2852
+ CRUD_FORM_EXTENSION_SURFACE_KEYS,
2853
+ CRUD_FORM_SURFACE_COVERAGE
2854
+ ),
2855
+ buildCoverageFamily(
2856
+ "CrudFormLifecyclePhase",
2857
+ "packages/shared/src/modules/widgets/extension-points.ts#CRUD_FORM_LIFECYCLE_PHASES",
2858
+ CRUD_FORM_LIFECYCLE_PHASES,
2859
+ CRUD_FORM_LIFECYCLE_COVERAGE
2860
+ ),
2861
+ buildCoverageFamily(
2862
+ "CrudFormOperation",
2863
+ "packages/shared/src/modules/widgets/extension-points.ts#CRUD_FORM_OPERATIONS",
2864
+ CRUD_FORM_OPERATIONS,
2865
+ CRUD_FORM_OPERATION_COVERAGE
2866
+ )
2867
+ ];
2868
+ }
2869
+ function countModuleFactCoverage(facts) {
2870
+ const increment = (counts, value) => {
2871
+ counts[value] = (counts[value] ?? 0) + 1;
2872
+ };
2873
+ const factSourceKind = {};
2874
+ for (const entry of facts.factSources ?? []) {
2875
+ increment(factSourceKind, entry.kind);
2876
+ }
2877
+ const ownedContractKind = {};
2878
+ for (const [kind, list] of Object.entries(facts.ownedContracts ?? {})) {
2879
+ ownedContractKind[kind] = (list ?? []).length;
2880
+ }
2881
+ const overrideDomain = {};
2882
+ const overrideMode = {};
2883
+ const overrideNote = {};
2884
+ for (const target of facts.overrideTargets ?? []) {
2885
+ overrideDomain[target.domain] = (overrideDomain[target.domain] ?? 0) + 1;
2886
+ for (const mode of target.modes) overrideMode[mode] = (overrideMode[mode] ?? 0) + 1;
2887
+ for (const note of target.notes ?? []) overrideNote[note] = (overrideNote[note] ?? 0) + 1;
2888
+ }
2889
+ const overrideDiagnosticCode = {};
2890
+ for (const diagnostic of facts.overrideTargetDiagnostics ?? []) {
2891
+ increment(overrideDiagnosticCode, diagnostic.code);
2892
+ }
2893
+ const contributionKind = {};
2894
+ const activationKind = {};
2895
+ const hostFamily = {};
2896
+ const hostCapability = {};
2897
+ const hostActivation = {};
2898
+ const targetKind = {};
2899
+ const hostResolution = {};
2900
+ const targetResolution = {};
2901
+ const topologyResolution = {};
2902
+ const specializedRegistry = {};
2903
+ const componentMode = {};
2904
+ const factDiagnosticCode = {};
2905
+ const unresolvedReason = {};
2906
+ const dataTableSurface = {};
2907
+ const crudFormSurface = {};
2908
+ const crudFormLifecycle = {};
2909
+ const crudFormOperation = {};
2910
+ const surfaces = facts.extensionSurfaces;
2911
+ for (const host of surfaces?.hosts ?? []) {
2912
+ increment(hostFamily, host.family);
2913
+ increment(hostResolution, host.resolution);
2914
+ increment(hostActivation, host.activation ?? "always");
2915
+ for (const capability of host.capabilities) increment(hostCapability, capability);
2916
+ for (const phase of host.phases ?? []) increment(crudFormLifecycle, phase);
2917
+ for (const operation of host.operations ?? []) increment(crudFormOperation, operation);
2918
+ const [owner, surface] = host.key.split(".");
2919
+ if (owner === "todosTable" && surface) increment(dataTableSurface, surface);
2920
+ if (owner === "todoForm" && surface) increment(crudFormSurface, surface);
2921
+ }
2922
+ for (const contribution of surfaces?.contributions ?? []) {
2923
+ increment(contributionKind, contribution.kind);
2924
+ increment(hostActivation, contribution.activation ?? "always");
2925
+ for (const target of contribution.targets) increment(targetResolution, target.resolution);
2926
+ for (const operation of contribution.operations ?? []) increment(crudFormOperation, operation);
2927
+ if (contribution.kind === "specialized-registry") increment(specializedRegistry, contribution.details.registry);
2928
+ if (contribution.kind === "component-override") increment(componentMode, contribution.details.mode);
2929
+ if (contribution.kind === "widget") {
2930
+ if (contribution.details.payload === "headless") increment(hostCapability, "headless-widget");
2931
+ if (contribution.details.payload === "menu") increment(hostCapability, "menu-item");
2932
+ if (contribution.details.payload === "dashboard" || contribution.details.payload === "notification" || contribution.details.payload === "integration") {
2933
+ increment(hostCapability, "registry-contribution");
2934
+ }
2935
+ }
2936
+ if (contribution.kind === "api-interceptor") increment(hostCapability, "api-interceptor");
2937
+ if (contribution.kind === "command-interceptor") increment(hostCapability, "command-interceptor");
2938
+ }
2939
+ for (const activation of surfaces?.activations ?? []) increment(activationKind, activation.kind);
2940
+ for (const resolution of surfaces?.contributionResolutions ?? []) {
2941
+ increment(targetKind, resolution.target.kind);
2942
+ increment(topologyResolution, resolution.resolution);
2943
+ for (const id of resolution.activationIds) {
2944
+ const kind = MODULE_EXTENSION_ACTIVATION_KINDS.find((candidate) => id.endsWith(`:${candidate}`));
2945
+ if (kind) increment(activationKind, kind);
2946
+ }
2947
+ }
2948
+ for (const diagnostic of facts.factDiagnostics ?? []) increment(factDiagnosticCode, diagnostic.code);
2949
+ for (const unresolved of surfaces?.unresolved ?? []) increment(unresolvedReason, unresolved.reason);
2950
+ return {
2951
+ ModuleFactSourceKind: factSourceKind,
2952
+ ModuleOwnedContractKind: ownedContractKind,
2953
+ ModuleOverrideDomain: overrideDomain,
2954
+ ModuleOverrideMode: overrideMode,
2955
+ ModuleOverrideTargetNote: overrideNote,
2956
+ ModuleOverrideTargetDiagnosticCode: overrideDiagnosticCode,
2957
+ ModuleExtensionContributionKind: contributionKind,
2958
+ ModuleExtensionActivationKind: activationKind,
2959
+ ExtensionHostFamily: hostFamily,
2960
+ ExtensionHostCapability: hostCapability,
2961
+ ExtensionHostActivation: hostActivation,
2962
+ ModuleExtensionTargetKind: targetKind,
2963
+ ModuleExtensionHostResolution: hostResolution,
2964
+ ModuleExtensionTargetResolution: targetResolution,
2965
+ ModuleExtensionResolution: topologyResolution,
2966
+ SpecializedRegistry: specializedRegistry,
2967
+ ComponentOverrideMode: componentMode,
2968
+ ModuleFactDiagnosticCode: factDiagnosticCode,
2969
+ ModuleExtensionUnresolvedReason: unresolvedReason,
2970
+ DataTableExtensionSurface: dataTableSurface,
2971
+ CrudFormExtensionSurface: crudFormSurface,
2972
+ CrudFormLifecyclePhase: crudFormLifecycle,
2973
+ CrudFormOperation: crudFormOperation
2974
+ };
2061
2975
  }
2062
2976
  export {
2977
+ MODULE_FACT_DIAGNOSTIC_CODES,
2978
+ MODULE_FACT_SOURCE_KINDS,
2979
+ MODULE_OWNED_CONTRACT_KINDS,
2980
+ assertPackageModuleFactsOnly,
2981
+ assertPortableSourceRoot,
2982
+ buildCoverageFamily,
2983
+ buildModuleFactCoverageLedger,
2063
2984
  buildModuleFactsJsonObject,
2985
+ collectUnresolvedFirstPartyTargets,
2986
+ computeModuleSourceFingerprint,
2987
+ computeModuleTaxonomyFingerprint,
2988
+ countModuleFactCoverage,
2064
2989
  extractAllModuleFacts,
2990
+ extractLocalReferenceModuleFacts,
2065
2991
  extractModuleFacts,
2992
+ isExactSourceFilePath,
2066
2993
  renderModuleFactsJson,
2067
2994
  renderModuleFactsMarkdown,
2995
+ renderReferenceModuleFactsJson,
2068
2996
  toModuleFactsJsonEntry
2069
2997
  };
2070
2998
  //# sourceMappingURL=module-facts.js.map