@open-mercato/cli 0.6.7 → 0.6.8-canary.319.1.5b4be4bc52

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 (287) hide show
  1. package/.turbo/turbo-build.log +77 -4
  2. package/build.mjs +68 -11
  3. package/dist/agentic/claude-code/hooks/entity-migration-check.ts +32 -88
  4. package/dist/agentic/codex/enforcement-rules.md +2 -16
  5. package/dist/agentic/cursor/hooks/entity-migration-check.mjs +19 -50
  6. package/dist/agentic/cursor/rules/entity-guard.mdc +9 -21
  7. package/dist/agentic/cursor/rules/generated-guard.mdc +3 -5
  8. package/dist/agentic/cursor/rules/open-mercato.mdc +3 -29
  9. package/dist/agentic/guides/ai-workflows.md +76 -0
  10. package/dist/agentic/guides/architecture.md +107 -0
  11. package/dist/agentic/guides/backend-ui.md +84 -0
  12. package/dist/agentic/guides/contracts.md +92 -0
  13. package/dist/agentic/guides/extensions.md +121 -0
  14. package/dist/agentic/guides/framework-extension-points.md +36 -0
  15. package/dist/agentic/guides/integrations.md +81 -0
  16. package/dist/agentic/guides/module-facts.json +116757 -3951
  17. package/dist/agentic/guides/module-system.md +12 -127
  18. package/dist/agentic/guides/modules/ai_assistant.md +227 -28
  19. package/dist/agentic/guides/modules/api_docs.md +58 -2
  20. package/dist/agentic/guides/modules/api_keys.md +92 -7
  21. package/dist/agentic/guides/modules/attachments.md +119 -14
  22. package/dist/agentic/guides/modules/audit_logs.md +131 -10
  23. package/dist/agentic/guides/modules/auth.md +276 -33
  24. package/dist/agentic/guides/modules/business_rules.md +149 -14
  25. package/dist/agentic/guides/modules/catalog.md +482 -43
  26. package/dist/agentic/guides/modules/channel_gmail.md +82 -3
  27. package/dist/agentic/guides/modules/channel_imap.md +82 -3
  28. package/dist/agentic/guides/modules/checkout.md +305 -27
  29. package/dist/agentic/guides/modules/communication_channels.md +315 -33
  30. package/dist/agentic/guides/modules/configs.md +104 -8
  31. package/dist/agentic/guides/modules/content.md +57 -2
  32. package/dist/agentic/guides/modules/currencies.md +152 -17
  33. package/dist/agentic/guides/modules/customer_accounts.md +387 -45
  34. package/dist/agentic/guides/modules/customers.md +746 -85
  35. package/dist/agentic/guides/modules/dashboards.md +155 -10
  36. package/dist/agentic/guides/modules/data_sync.md +149 -16
  37. package/dist/agentic/guides/modules/design_system.md +102 -0
  38. package/dist/agentic/guides/modules/dictionaries.md +107 -12
  39. package/dist/agentic/guides/modules/directory.md +148 -15
  40. package/dist/agentic/guides/modules/entities.md +145 -13
  41. package/dist/agentic/guides/modules/events.md +59 -2
  42. package/dist/agentic/guides/modules/feature_toggles.md +119 -9
  43. package/dist/agentic/guides/modules/gateway_stripe.md +92 -4
  44. package/dist/agentic/guides/modules/generators.md +45 -2
  45. package/dist/agentic/guides/modules/inbox_ops.md +207 -27
  46. package/dist/agentic/guides/modules/integrations.md +149 -16
  47. package/dist/agentic/guides/modules/messages.md +223 -24
  48. package/dist/agentic/guides/modules/notifications.md +96 -8
  49. package/dist/agentic/guides/modules/onboarding.md +77 -6
  50. package/dist/agentic/guides/modules/payment_gateways.md +168 -21
  51. package/dist/agentic/guides/modules/perspectives.md +77 -7
  52. package/dist/agentic/guides/modules/planner.md +136 -18
  53. package/dist/agentic/guides/modules/portal.md +93 -2
  54. package/dist/agentic/guides/modules/progress.md +104 -14
  55. package/dist/agentic/guides/modules/query_index.md +154 -15
  56. package/dist/agentic/guides/modules/record_locks.md +206 -21
  57. package/dist/agentic/guides/modules/resources.md +197 -30
  58. package/dist/agentic/guides/modules/sales.md +687 -84
  59. package/dist/agentic/guides/modules/scheduler.md +133 -14
  60. package/dist/agentic/guides/modules/search.md +170 -6
  61. package/dist/agentic/guides/modules/security.md +294 -35
  62. package/dist/agentic/guides/modules/shipping_carriers.md +134 -18
  63. package/dist/agentic/guides/modules/sso.md +151 -26
  64. package/dist/agentic/guides/modules/staff.md +372 -57
  65. package/dist/agentic/guides/modules/storage_s3.md +95 -5
  66. package/dist/agentic/guides/modules/sync_akeneo.md +85 -3
  67. package/dist/agentic/guides/modules/sync_excel.md +75 -6
  68. package/dist/agentic/guides/modules/system_status_overlays.md +60 -2
  69. package/dist/agentic/guides/modules/translations.md +104 -10
  70. package/dist/agentic/guides/modules/webhooks.md +203 -24
  71. package/dist/agentic/guides/modules/wms.md +469 -47
  72. package/dist/agentic/guides/modules/workflows.md +302 -43
  73. package/dist/agentic/guides/reference-module-facts.json +6370 -0
  74. package/dist/agentic/guides/reference-modules/example.md +451 -0
  75. package/dist/agentic/guides/spec-delivery.md +42 -0
  76. package/dist/agentic/guides/testing-debugging.md +80 -0
  77. package/dist/agentic/guides/upstream/AGENTS.md +299 -0
  78. package/dist/agentic/guides/upstream/BACKWARD_COMPATIBILITY.md +316 -0
  79. package/dist/agentic/guides/upstream/manifest.json +8 -0
  80. package/dist/agentic/shared/AGENTS.md.template +120 -311
  81. package/dist/agentic/shared/ai/agentic.config.json +2 -0
  82. package/dist/agentic/shared/ai/harness/README.md +50 -0
  83. package/dist/agentic/shared/ai/harness/RELEASE.md +57 -0
  84. package/dist/agentic/shared/ai/harness/cases.json +15050 -0
  85. package/dist/agentic/shared/ai/harness/cases.schema.json +188 -0
  86. package/dist/agentic/shared/ai/harness/fixtures/index.json +51 -0
  87. package/dist/agentic/shared/ai/harness/fixtures/seeds.json +166 -0
  88. package/dist/agentic/shared/ai/harness/generated-code-review-policy.md +21 -0
  89. package/dist/agentic/shared/ai/harness/generated-code-review-response.schema.json +96 -0
  90. package/dist/agentic/shared/ai/harness/generated-code-review-result.schema.json +172 -0
  91. package/dist/agentic/shared/ai/harness/knowledge-change.schema.json +228 -0
  92. package/dist/agentic/shared/ai/harness/release-matrix.json +163 -0
  93. package/dist/agentic/shared/ai/harness/release-result.schema.json +219 -0
  94. package/dist/agentic/shared/ai/harness/result.schema.json +109 -0
  95. package/dist/agentic/shared/ai/harness/routing-response.schema.json +22 -0
  96. package/dist/agentic/shared/ai/harness/target-validation-result.schema.json +73 -0
  97. package/dist/agentic/shared/ai/harness/validators.json +82 -0
  98. package/dist/agentic/shared/ai/harness/writable-ast-oracles.mjs +2121 -0
  99. package/dist/agentic/shared/ai/harness/writable-behavior-oracles.mjs +1096 -0
  100. package/dist/agentic/shared/ai/harness/writable-spec-oracles.mjs +412 -0
  101. package/dist/agentic/shared/ai/lessons/_template.md +16 -0
  102. package/dist/agentic/shared/ai/lessons.md +26 -3
  103. package/dist/agentic/shared/ai/review-checklist.md +36 -0
  104. package/dist/agentic/shared/ai/skills/om-auto-implement-spec/SKILL.md +21 -0
  105. package/dist/agentic/shared/ai/skills/om-auto-review-pr/SKILL.md +4 -0
  106. package/dist/agentic/shared/ai/skills/om-auto-upgrade-0.6.6-to-0.6.7/SKILL.md +98 -0
  107. package/dist/agentic/shared/ai/skills/om-backend-ui-design/SKILL.md +21 -241
  108. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/crud-surfaces.md +31 -0
  109. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/frontend-and-design-system.md +53 -0
  110. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/page-and-navigation.md +15 -0
  111. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/quality-states.md +11 -0
  112. package/dist/agentic/shared/ai/skills/om-build-workflow/SKILL.md +30 -0
  113. package/dist/agentic/shared/ai/skills/om-build-workflow/references/activity-contracts.md +12 -0
  114. package/dist/agentic/shared/ai/skills/om-build-workflow/references/durability-and-progress.md +13 -0
  115. package/dist/agentic/shared/ai/skills/om-build-workflow/references/workflow-design.md +14 -0
  116. package/dist/agentic/shared/ai/skills/om-create-ai-agent/SKILL.md +28 -0
  117. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/attachments-and-overrides.md +12 -0
  118. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/module-agents-and-tools.md +22 -0
  119. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/orchestrator-agents.md +12 -0
  120. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/surface-selector.md +19 -0
  121. package/dist/agentic/shared/ai/skills/om-data-model-design/SKILL.md +17 -601
  122. package/dist/agentic/shared/ai/skills/om-data-model-design/references/integrity-and-concurrency.md +21 -0
  123. package/dist/agentic/shared/ai/skills/om-data-model-design/references/migration-workflow.md +15 -0
  124. package/dist/agentic/shared/ai/skills/om-data-model-design/references/schema-design.md +16 -0
  125. package/dist/agentic/shared/ai/skills/om-data-model-design/references/sensitive-data.md +10 -0
  126. package/dist/agentic/shared/ai/skills/om-eject-and-customize/SKILL.md +15 -310
  127. package/dist/agentic/shared/ai/skills/om-eject-and-customize/references/decision-and-procedure.md +19 -0
  128. package/dist/agentic/shared/ai/skills/om-evolve-harness/SKILL.md +31 -0
  129. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-template.md +100 -0
  130. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-workflow.md +16 -0
  131. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/knowledge-change.md +115 -0
  132. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/owner-selection.md +17 -0
  133. package/dist/agentic/shared/ai/skills/om-framework-context/SKILL.md +25 -0
  134. package/dist/agentic/shared/ai/skills/om-framework-context/references/resolver-procedure.md +11 -0
  135. package/dist/agentic/shared/ai/skills/om-framework-context/references/skew-and-escalation.md +13 -0
  136. package/dist/agentic/shared/ai/skills/om-help/SKILL.md +15 -97
  137. package/dist/agentic/shared/ai/skills/om-help/references/delivery-workflows.md +18 -0
  138. package/dist/agentic/shared/ai/skills/om-help/references/task-families.md +20 -0
  139. package/dist/agentic/shared/ai/skills/om-implement-spec/SKILL.md +33 -152
  140. package/dist/agentic/shared/ai/skills/om-implement-spec/references/phases-and-gates.md +33 -0
  141. package/dist/agentic/shared/ai/skills/om-implement-spec/references/planning-and-progress.md +40 -0
  142. package/dist/agentic/shared/ai/skills/om-implement-spec/references/report-templates.md +27 -0
  143. package/dist/agentic/shared/ai/skills/om-implement-spec/references/spec-resolution.md +24 -0
  144. package/dist/agentic/shared/ai/skills/om-integration-builder/SKILL.md +25 -708
  145. package/dist/agentic/shared/ai/skills/om-integration-builder/references/package-and-activation.md +16 -0
  146. package/dist/agentic/shared/ai/skills/om-integration-builder/references/provider-families.md +25 -0
  147. package/dist/agentic/shared/ai/skills/om-integration-builder/references/security-and-reliability.md +15 -0
  148. package/dist/agentic/shared/ai/skills/om-integration-builder/references/sync-and-files.md +12 -0
  149. package/dist/agentic/shared/ai/skills/om-judge-agent-session/SKILL.md +34 -0
  150. package/dist/agentic/shared/ai/skills/om-judge-agent-session/agents/openai.yaml +4 -0
  151. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/agentic-setup.md +11 -0
  152. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/input-normalization.md +31 -0
  153. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/judge-workflow.md +39 -0
  154. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/report-template.md +43 -0
  155. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/rules.md +11 -0
  156. package/dist/agentic/shared/ai/skills/om-module-scaffold/SKILL.md +20 -820
  157. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/api-and-domain.md +32 -0
  158. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/business-one-shot-blueprints.md +172 -0
  159. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/data-and-migrations.md +14 -0
  160. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/discovery-surface-catalog.md +83 -0
  161. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/module-surfaces.md +40 -0
  162. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/planning.md +11 -0
  163. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/runtime-cache-and-queues.md +22 -0
  164. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/verification.md +13 -0
  165. package/dist/agentic/shared/ai/skills/om-share-this-session/SKILL.md +41 -0
  166. package/dist/agentic/shared/ai/skills/om-share-this-session/references/agentic-setup.md +19 -0
  167. package/dist/agentic/shared/ai/skills/om-share-this-session/references/bundle-preparation.md +44 -0
  168. package/dist/agentic/shared/ai/skills/om-share-this-session/references/consent-and-review.md +39 -0
  169. package/dist/agentic/shared/ai/skills/om-share-this-session/references/publication.md +20 -0
  170. package/dist/agentic/shared/ai/skills/om-share-this-session/references/report-templates.md +57 -0
  171. package/dist/agentic/shared/ai/skills/om-share-this-session/references/rules.md +11 -0
  172. package/dist/agentic/shared/ai/skills/om-share-this-session/scripts/prepare-share-bundle.mjs +486 -0
  173. package/dist/agentic/shared/ai/skills/om-system-extension/SKILL.md +20 -843
  174. package/dist/agentic/shared/ai/skills/om-system-extension/references/extension-branches.md +42 -0
  175. package/dist/agentic/shared/ai/skills/om-system-extension/references/mechanism-selector.md +27 -0
  176. package/dist/agentic/shared/ai/skills/om-system-extension/references/read-write-roundtrip.md +13 -0
  177. package/dist/agentic/shared/ai/skills/om-system-extension/references/unified-overrides.md +43 -0
  178. package/dist/agentic/shared/ai/skills/om-system-extension/references/verification.md +11 -0
  179. package/dist/agentic/shared/ai/skills/om-trim-unused-modules/SKILL.md +15 -63
  180. package/dist/agentic/shared/ai/skills/om-trim-unused-modules/references/dependency-and-redirect.md +15 -0
  181. package/dist/agentic/shared/ai/skills/om-troubleshooter/SKILL.md +17 -467
  182. package/dist/agentic/shared/ai/skills/om-troubleshooter/references/diagnosis-map.md +29 -0
  183. package/dist/agentic/shared/ai/skills/om-troubleshooter/references/regression-oracles.md +14 -0
  184. package/dist/agentic/shared/ai/skills/tiers.json +143 -21
  185. package/dist/agentic/shared/ai/skills/tiers.schema.json +52 -40
  186. package/dist/agentic/shared/ai/specs/README.md +4 -3
  187. package/dist/agentic/shared/ai/specs/SPEC-000-template.md +226 -10
  188. package/dist/agentic/shared/ai/trackers/github.md +108 -4
  189. package/dist/agentic/shared/scripts/agent-harness-tool-server.mjs +224 -0
  190. package/dist/agentic/shared/scripts/check-lessons.mjs +178 -0
  191. package/dist/agentic/shared/scripts/evaluate-agent-harness.mjs +3585 -0
  192. package/dist/agentic/shared/scripts/execution-sandbox.mjs +329 -0
  193. package/dist/agentic/shared/scripts/framework-context.mjs +888 -0
  194. package/dist/agentic/shared/scripts/install-skills.mjs +1029 -0
  195. package/dist/agentic/shared/scripts/install-skills.sh +4 -694
  196. package/dist/agentic/shared/scripts/prepare-agent-harness-fixture.mjs +222 -0
  197. package/dist/agentic/shared/scripts/run-agent-harness-release.mjs +1774 -0
  198. package/dist/agentic/shared/scripts/validate-knowledge-change.mjs +911 -0
  199. package/dist/bin.js +13 -1
  200. package/dist/bin.js.map +2 -2
  201. package/dist/lib/__integration__/TC-INT-008.spec.js +88 -8
  202. package/dist/lib/__integration__/TC-INT-008.spec.js.map +2 -2
  203. package/dist/lib/agentic-init.js +13 -3
  204. package/dist/lib/agentic-init.js.map +2 -2
  205. package/dist/lib/agentic-setup.js +434 -186
  206. package/dist/lib/agentic-setup.js.map +2 -2
  207. package/dist/lib/generators/extensions/injection-widgets.js +20 -0
  208. package/dist/lib/generators/extensions/injection-widgets.js.map +2 -2
  209. package/dist/lib/generators/module-extension-facts.js +1872 -0
  210. package/dist/lib/generators/module-extension-facts.js.map +7 -0
  211. package/dist/lib/generators/module-fact-sources.js +70 -0
  212. package/dist/lib/generators/module-fact-sources.js.map +7 -0
  213. package/dist/lib/generators/module-facts-discovery.js +64 -7
  214. package/dist/lib/generators/module-facts-discovery.js.map +2 -2
  215. package/dist/lib/generators/module-facts.js +1629 -52
  216. package/dist/lib/generators/module-facts.js.map +3 -3
  217. package/dist/lib/generators/module-override-targets.js +688 -0
  218. package/dist/lib/generators/module-override-targets.js.map +7 -0
  219. package/dist/lib/generators/module-registry.js +11 -5
  220. package/dist/lib/generators/module-registry.js.map +2 -2
  221. package/dist/lib/load-env.js +24 -0
  222. package/dist/lib/load-env.js.map +7 -0
  223. package/dist/lib/resolver.js +2 -0
  224. package/dist/lib/resolver.js.map +2 -2
  225. package/dist/lib/telemetry-init.js +358 -0
  226. package/dist/lib/telemetry-init.js.map +7 -0
  227. package/dist/lib/testing/integration.js +5 -2
  228. package/dist/lib/testing/integration.js.map +2 -2
  229. package/dist/mercato.js +23 -1
  230. package/dist/mercato.js.map +2 -2
  231. package/package.json +13 -11
  232. package/src/bin.ts +33 -1
  233. package/src/lib/__integration__/TC-INT-008.spec.ts +107 -9
  234. package/src/lib/__tests__/agentic-init.test.ts +41 -5
  235. package/src/lib/__tests__/agentic-setup.ownership.test.ts +386 -0
  236. package/src/lib/__tests__/injection-widget-id-validation.test.ts +184 -0
  237. package/src/lib/__tests__/load-env.test.ts +65 -0
  238. package/src/lib/__tests__/telemetry-init.test.ts +298 -0
  239. package/src/lib/agentic-init.ts +15 -3
  240. package/src/lib/agentic-setup.ts +573 -222
  241. package/src/lib/generators/__tests__/activation-adapter-coverage.test.ts +92 -0
  242. package/src/lib/generators/__tests__/module-extension-activations.test.ts +762 -0
  243. package/src/lib/generators/__tests__/module-extension-facts.test.ts +603 -0
  244. package/src/lib/generators/__tests__/module-facts.bc-guard.test.ts +139 -2
  245. package/src/lib/generators/__tests__/module-facts.computed-di-token.test.ts +88 -0
  246. package/src/lib/generators/__tests__/module-facts.customers.fixture.test.ts +1 -0
  247. package/src/lib/generators/__tests__/module-facts.discovery.test.ts +54 -10
  248. package/src/lib/generators/__tests__/module-facts.extension-hosts.test.ts +108 -0
  249. package/src/lib/generators/__tests__/module-facts.local-reference.test.ts +391 -0
  250. package/src/lib/generators/__tests__/module-facts.owned-contracts.test.ts +561 -0
  251. package/src/lib/generators/__tests__/module-facts.search-entity-id.test.ts +151 -0
  252. package/src/lib/generators/__tests__/module-facts.source-links.test.ts +160 -0
  253. package/src/lib/generators/__tests__/module-override-targets.roundtrip.test.ts +149 -0
  254. package/src/lib/generators/__tests__/module-override-targets.test.ts +328 -0
  255. package/src/lib/generators/__tests__/module-subset.test.ts +18 -0
  256. package/src/lib/generators/extensions/injection-widgets.ts +51 -0
  257. package/src/lib/generators/module-extension-facts.ts +2433 -0
  258. package/src/lib/generators/module-fact-sources.ts +108 -0
  259. package/src/lib/generators/module-facts-discovery.ts +104 -7
  260. package/src/lib/generators/module-facts.ts +2387 -138
  261. package/src/lib/generators/module-override-targets.ts +863 -0
  262. package/src/lib/generators/module-registry.ts +16 -6
  263. package/src/lib/load-env.ts +30 -0
  264. package/src/lib/resolver.ts +3 -0
  265. package/src/lib/telemetry-init.ts +461 -0
  266. package/src/lib/testing/__tests__/integration.test.ts +4 -0
  267. package/src/lib/testing/integration.ts +5 -2
  268. package/src/mercato.ts +26 -1
  269. package/dist/agentic/guides/cache.md +0 -45
  270. package/dist/agentic/guides/core.md +0 -453
  271. package/dist/agentic/guides/events.md +0 -117
  272. package/dist/agentic/guides/queue.md +0 -53
  273. package/dist/agentic/guides/search.md +0 -115
  274. package/dist/agentic/guides/shared.md +0 -108
  275. package/dist/agentic/guides/ui.md +0 -347
  276. package/dist/agentic/shared/ai/skills/om-auto-continue-pr-loop/SKILL.md +0 -27
  277. package/dist/agentic/shared/ai/skills/om-auto-create-pr-loop/SKILL.md +0 -27
  278. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/ui-components.md +0 -260
  279. package/dist/agentic/shared/ai/skills/om-data-model-design/references/mikro-orm-cheatsheet.md +0 -146
  280. package/dist/agentic/shared/ai/skills/om-help/references/skills-catalog.md +0 -84
  281. package/dist/agentic/shared/ai/skills/om-help/references/workflow-sequences.md +0 -193
  282. package/dist/agentic/shared/ai/skills/om-integration-builder/STANDALONE.md +0 -34
  283. package/dist/agentic/shared/ai/skills/om-integration-builder/references/adapter-contracts.md +0 -762
  284. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/naming-conventions.md +0 -50
  285. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/navigation-patterns.md +0 -97
  286. package/dist/agentic/shared/ai/skills/om-system-extension/references/extension-contracts.md +0 -271
  287. package/dist/agentic/shared/ai/skills/om-troubleshooter/references/diagnostic-commands.md +0 -101
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs'
2
2
  import path from 'node:path'
3
- import { extractAllModuleFacts } from '../module-facts'
3
+ import { extractAllModuleFacts, isExactSourceFilePath, renderModuleFactsJson } from '../module-facts'
4
4
  import { discoverPackageModuleSources } from '../module-facts-discovery'
5
5
  import { createResolver } from '../../resolver'
6
6
 
@@ -17,10 +17,131 @@ function isUnique(values: string[]): boolean {
17
17
  return values.length === new Set(values).size
18
18
  }
19
19
 
20
+ const MARKDOWN_LINK_TARGET = /\]\(\.\.\/\.\.\/\.\.\/([^)#]+)(?:#L\d+)?\)/g
21
+
22
+ function collectLinkTargets(markdown: string): string[] {
23
+ return [...markdown.matchAll(MARKDOWN_LINK_TARGET)].map((match) => match[1])
24
+ }
25
+
20
26
  describe('module-facts BC resolve guard (T2)', () => {
21
27
  const repoRoot = findRepoRoot()
22
28
  const sources = discoverPackageModuleSources(createResolver(repoRoot))
23
- const { factsByModule } = extractAllModuleFacts({ sources })
29
+ const extractionStartedAt = process.cpuUsage()
30
+ const { factsByModule, markdownByModule, frameworkMarkdown } = extractAllModuleFacts({ sources })
31
+ const extractionCpuUsage = process.cpuUsage(extractionStartedAt)
32
+ const extractionCpuDurationMs = (extractionCpuUsage.user + extractionCpuUsage.system) / 1_000
33
+
34
+ it('emits complete, deterministic extension catalogs for every resolved module', () => {
35
+ const repeated = extractAllModuleFacts({ sources })
36
+ expect(renderModuleFactsJson(repeated.factsByModule)).toBe(renderModuleFactsJson(factsByModule))
37
+ expect(repeated.markdownByModule).toEqual(markdownByModule)
38
+ expect(repeated.frameworkMarkdown).toBe(frameworkMarkdown)
39
+ for (const facts of Object.values(factsByModule)) {
40
+ expect(facts.extensionSurfaces).toBeDefined()
41
+ expect(facts.extensionSurfaces?.unresolved).toEqual([])
42
+ }
43
+ })
44
+
45
+ it('keeps generated extension facts within bounded build-time and context budgets', () => {
46
+ const completeJson = renderModuleFactsJson(factsByModule)
47
+ const legacyJson = renderModuleFactsJson(Object.fromEntries(
48
+ Object.entries(factsByModule).map(([moduleId, facts]) => [moduleId, { ...facts, extensionSurfaces: undefined }]),
49
+ ))
50
+ const markdownBytes = Object.values(markdownByModule)
51
+ .reduce((total, markdown) => total + Buffer.byteLength(markdown), Buffer.byteLength(frameworkMarkdown))
52
+
53
+ // Budget raised by the bidirectional-topology spec
54
+ // (2026-08-02-module-facts-extension-activation-and-incoming-index): the
55
+ // additive `activations`, cross-module `incoming`, and per-contribution
56
+ // `contributionResolutions` layers add ~210KB of compact references (no
57
+ // contribution payloads are duplicated). Incoming rows are cross-module only;
58
+ // resolution rows are required one-per-contribution by the spec's acceptance
59
+ // criteria and are the dominant term.
60
+ //
61
+ // JSON cap raised again by the exact-override-targets spec
62
+ // (2026-08-02-module-facts-exact-override-targets): the additive per-module
63
+ // `overrideTargets` project one exact key per real override entry (acl
64
+ // features, di tokens, subscribers, pages, workers, encryption, widgets,
65
+ // notifications, cli, setup, ai, interceptors/enrichers, page guards). These
66
+ // are required exhaustively by the spec's acceptance criteria; targets carry
67
+ // only compact structured path/key/factRef/source refs (no runtime values or
68
+ // contribution payloads). The delta cap is unchanged because `overrideTargets`
69
+ // live in both the complete and legacy renders (only `extensionSurfaces` is
70
+ // stripped for the legacy comparison).
71
+ //
72
+ // JSON cap raised a third time by the uniform provenance index
73
+ // (2026-08-02-module-facts-source-provenance-and-contract-inventory): every
74
+ // proven `(kind, id)` now reaches `factSources` (~630KB across the repo), so a
75
+ // consumer resolves any fact's origin through one lookup. Entries whose
76
+ // declaration site is already serialized inline (routes, pages, CLI commands,
77
+ // AI tools/agents, owned contracts, hosts, contributions) emit a typed
78
+ // `factRef` pointer instead of a duplicated source ref, and `factKey` is
79
+ // omitted when it equals the entry `id` — so the index costs references, never
80
+ // copied provenance payloads. The cap also covers the newly reachable
81
+ // framework-host activations (dashboard/menu/notification contributions now
82
+ // resolve as bound instead of silently falling back to capability-only).
83
+ // This is a blow-up detector, not a performance target. It measures CPU time
84
+ // for a whole-repo extraction, and CPU time for fixed work varies with the
85
+ // machine: the same extraction measures ~7.3s on a developer workstation and
86
+ // ~30.0s on a CI runner. At the previous 30s cap CI sat exactly on the line
87
+ // (an observed failure at 30,052.8ms), so the guard could not tell a genuine
88
+ // pathological regression from ordinary hardware variance and failed
89
+ // unrelated PRs at random. 90s keeps it meaningful — a real blow-up here is
90
+ // multiplicative, not a few percent — while leaving CI roughly 3x headroom.
91
+ expect(extractionCpuDurationMs).toBeLessThan(90_000)
92
+ // JSON cap raised a fourth time by the injection-table slot normalization:
93
+ // `extractInjectionTable` previously did `if (!Array.isArray(entries)) continue`,
94
+ // silently dropping every string and single-object slot form that
95
+ // `ModuleInjectionTable` allows. Twelve real contributions across catalog, sales,
96
+ // wms, staff, integrations and checkout were therefore invisible to every fact
97
+ // consumer — `integrations` published no contributions at all. Reading them costs
98
+ // ~28KB, which is the fix working, not drift.
99
+ expect(Buffer.byteLength(completeJson)).toBeLessThan(3_560_000)
100
+ expect(Buffer.byteLength(completeJson) - Buffer.byteLength(legacyJson)).toBeLessThan(1_800_000)
101
+ // Markdown cap raised with the source-link contract: entities, events, ACL
102
+ // features, DI tokens, search entities, notifications, UMES hosts and UMES
103
+ // contributions all render a resolved Source cell, and contribution
104
+ // resolutions render as their own source-linked section.
105
+ expect(markdownBytes).toBeLessThan(1_550_000)
106
+ })
107
+
108
+ it('links every generated fact to an exact resolvable file, never a directory', () => {
109
+ const packageLinkRoot = path.join(repoRoot, 'node_modules', '@open-mercato')
110
+ const canCheckDisk = fs.existsSync(packageLinkRoot)
111
+ const nonExactTargets = new Set<string>()
112
+ const unresolvedTargets = new Set<string>()
113
+ let checkedTargets = 0
114
+
115
+ for (const markdown of Object.values(markdownByModule)) {
116
+ for (const target of collectLinkTargets(markdown)) {
117
+ checkedTargets += 1
118
+ if (!isExactSourceFilePath(target)) {
119
+ nonExactTargets.add(target)
120
+ continue
121
+ }
122
+ if (!canCheckDisk) continue
123
+ const absolute = path.join(repoRoot, target)
124
+ if (!fs.existsSync(absolute) || !fs.statSync(absolute).isFile()) unresolvedTargets.add(target)
125
+ }
126
+ }
127
+
128
+ expect(checkedTargets).toBeGreaterThan(1_000)
129
+ expect([...nonExactTargets]).toEqual([])
130
+ expect([...unresolvedTargets]).toEqual([])
131
+ })
132
+
133
+ it('keeps directory-valued provenance readable as plain text', () => {
134
+ const frameworkHostMarkdowns = Object.values(markdownByModule)
135
+ .filter((markdown) => markdown.includes('packages/ui/src'))
136
+ expect(frameworkHostMarkdowns.length).toBeGreaterThan(0)
137
+ for (const markdown of frameworkHostMarkdowns) {
138
+ expect(markdown).not.toContain('(../../../packages/ui/src)')
139
+ }
140
+ for (const [moduleId, facts] of Object.entries(factsByModule)) {
141
+ expect(markdownByModule[moduleId]).toContain(`Source root: ${facts.sourceRoot}\n`)
142
+ expect(markdownByModule[moduleId]).not.toContain(`(../../../${facts.sourceRoot})`)
143
+ }
144
+ })
24
145
 
25
146
  it('discovers a superset of the historical core modules', () => {
26
147
  const discovered = new Set(Object.keys(factsByModule))
@@ -30,11 +151,27 @@ describe('module-facts BC resolve guard (T2)', () => {
30
151
  expect(discovered.size).toBeGreaterThan(9)
31
152
  })
32
153
 
154
+ it('keeps factory-built and generated-registry enricher contributions visible', () => {
155
+ expect(factsByModule.sales.extensionSurfaces?.contributions).toEqual(expect.arrayContaining([
156
+ expect.objectContaining({ id: 'sales.catalog-image:sales:sales_quote_line', kind: 'response-enricher' }),
157
+ expect.objectContaining({ id: 'sales.catalog-image:sales:sales_order_line', kind: 'response-enricher' }),
158
+ ]))
159
+ expect(factsByModule.wms.extensionSurfaces?.contributions).toEqual(expect.arrayContaining([
160
+ expect.objectContaining({ id: 'wms.sales-order-inventory', kind: 'response-enricher' }),
161
+ ]))
162
+ })
163
+
33
164
  for (const source of sources) {
34
165
  const moduleId = source.moduleId
35
166
  describe(`${moduleId}`, () => {
36
167
  const facts = factsByModule[moduleId]
37
168
 
169
+ it('stamps the exact providing package and version without removing coreVersion', () => {
170
+ expect(facts.sourcePackage).toBe(source.from ?? null)
171
+ expect(facts.sourceVersion).toBe(source.packageVersion ?? null)
172
+ expect(facts).toHaveProperty('coreVersion')
173
+ })
174
+
38
175
  // Entity / search / host ids are colon-namespaced under the module by construction
39
176
  // and convention; drift here means the builder or a module's data model broke.
40
177
  it('colon-namespaces entity / search / host ids under the module and keeps ids unique', () => {
@@ -0,0 +1,88 @@
1
+ import fs from 'node:fs'
2
+ import os from 'node:os'
3
+ import path from 'node:path'
4
+ import { extractModuleFacts } from '../module-facts'
5
+
6
+ /**
7
+ * A DI token registered through a computed key must still reach module facts.
8
+ *
9
+ * `container.register({ [SERVICE_TOKEN]: asFunction(...) })` — reading the token from an
10
+ * exported const — is the idiomatic, type-safe registration. `getPropertyName` returned
11
+ * undefined for a `ts.ComputedPropertyName`, so the whole registration vanished with NO
12
+ * diagnostic: the unresolved-token path is only reached for a NAMED token whose Awilix kind
13
+ * is unrecognised, so a computed key failed silently rather than being reported.
14
+ *
15
+ * That produced a capability the inventory claimed and the extractor scored zero for. Found
16
+ * by an agent that ran the real extractor instead of trusting the row.
17
+ */
18
+
19
+ function write(filePath: string, source: string): void {
20
+ fs.mkdirSync(path.dirname(filePath), { recursive: true })
21
+ fs.writeFileSync(filePath, source)
22
+ }
23
+
24
+ function factsFor(diSource: string): Array<{ id: string; metadata?: Record<string, unknown> }> {
25
+ const moduleRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'om-computed-di-'))
26
+ try {
27
+ write(path.join(moduleRoot, 'di.ts'), diSource)
28
+ const facts = extractModuleFacts({
29
+ moduleId: 'probe',
30
+ moduleRoot,
31
+ sourceRoot: 'src/modules/probe',
32
+ }) as { ownedContracts?: Record<string, Array<{ id: string; metadata?: Record<string, unknown> }>> }
33
+ return facts.ownedContracts?.['di-registration'] ?? []
34
+ } finally {
35
+ fs.rmSync(moduleRoot, { recursive: true, force: true })
36
+ }
37
+ }
38
+
39
+ describe('module-facts DI registration with a computed token', () => {
40
+ it('resolves a token declared as a same-file const', () => {
41
+ const facts = factsFor(`
42
+ import { asFunction } from 'awilix'
43
+ export const PROBE_SERVICE = 'probeService' as const
44
+ export function register(container: any) {
45
+ container.register({ [PROBE_SERVICE]: asFunction(createProbeService).scoped() })
46
+ }
47
+ `)
48
+
49
+ expect(facts).toHaveLength(1)
50
+ expect(facts[0].id).toBe('probeService')
51
+ expect(facts[0].metadata).toMatchObject({ registrationKind: 'function', lifetime: 'scoped' })
52
+ })
53
+
54
+ it('resolves a token written as a computed string literal', () => {
55
+ const facts = factsFor(`
56
+ import { asValue } from 'awilix'
57
+ export function register(container: any) {
58
+ container.register({ ['literalToken']: asValue(42) })
59
+ }
60
+ `)
61
+
62
+ expect(facts.map((fact) => fact.id)).toEqual(['literalToken'])
63
+ })
64
+
65
+ it('still resolves plain identifier and string keys', () => {
66
+ const facts = factsFor(`
67
+ import { asValue } from 'awilix'
68
+ export function register(container: any) {
69
+ container.register({ plainKey: asValue(1), 'quotedKey': asValue(2) })
70
+ }
71
+ `)
72
+
73
+ expect(facts.map((fact) => fact.id).sort()).toEqual(['plainKey', 'quotedKey'])
74
+ })
75
+
76
+ it('leaves a genuinely dynamic token unresolved rather than inventing one', () => {
77
+ // A key the reader cannot know statically must NOT be guessed. Emitting a wrong token
78
+ // would be worse than emitting none.
79
+ const facts = factsFor(`
80
+ import { asValue } from 'awilix'
81
+ export function register(container: any, name: string) {
82
+ container.register({ [name]: asValue(1) })
83
+ }
84
+ `)
85
+
86
+ expect(facts).toEqual([])
87
+ })
88
+ })
@@ -52,6 +52,7 @@ describe('module-facts customers fixture (T1 anti-drift guard)', () => {
52
52
  'customers.companies.list',
53
53
  'customers.deals.list',
54
54
  'customers.people.list',
55
+ 'customers.todos.list',
55
56
  ])
56
57
  expect(facts.hostTokens.entityIds).toEqual(['customers:customer_entity'])
57
58
  expect(facts.diTokens).toEqual([])
@@ -4,11 +4,13 @@ import path from 'node:path'
4
4
  import type { PackageResolver } from '../../resolver'
5
5
  import { discoverPackageModuleSources, hasReadableModuleSource } from '../module-facts-discovery'
6
6
 
7
- type FakePackage = { name: string; path: string; modulesPath: string }
7
+ type FakePackage = { name: string; version?: string | null; path: string; modulesPath: string }
8
+ type FakeModuleEntry = { id: string; from?: string }
8
9
 
9
- function makeResolver(packages: FakePackage[]): PackageResolver {
10
+ function makeResolver(packages: FakePackage[], enabledModules: FakeModuleEntry[] = []): PackageResolver {
10
11
  return {
11
12
  discoverPackages: () => packages,
13
+ loadEnabledModules: () => enabledModules,
12
14
  } as unknown as PackageResolver
13
15
  }
14
16
 
@@ -62,27 +64,69 @@ describe('module-facts discovery (T1)', () => {
62
64
  writeModule(path.join(pkgSrc, 'src', 'modules'), 'gamma', 'events.ts')
63
65
 
64
66
  const resolver = makeResolver([
65
- { name: '@open-mercato/tagged', path: pkgSrc, modulesPath: path.join(pkgSrc, 'src', 'modules') },
67
+ { name: '@open-mercato/tagged', version: '0.6.6', path: pkgSrc, modulesPath: path.join(pkgSrc, 'src', 'modules') },
66
68
  ])
67
69
 
68
70
  const [source] = discoverPackageModuleSources(resolver)
69
- expect(source).toMatchObject({ moduleId: 'gamma', from: '@open-mercato/tagged' })
71
+ expect(source).toMatchObject({
72
+ moduleId: 'gamma',
73
+ from: '@open-mercato/tagged',
74
+ packageVersion: '0.6.6',
75
+ })
70
76
  expect(source.moduleRoot).toBe(path.join(pkgSrc, 'src', 'modules', 'gamma'))
71
77
  })
72
78
 
73
- it('dedupes duplicate module ids first-wins', () => {
79
+ it('fails closed on duplicate module ids and reports every provider independent of discovery order', () => {
74
80
  const pkgA = path.join(tmp, 'dup-a')
75
81
  writeModule(path.join(pkgA, 'src', 'modules'), 'shared', 'index.ts')
76
82
  const pkgB = path.join(tmp, 'dup-b')
77
83
  writeModule(path.join(pkgB, 'src', 'modules'), 'shared', 'index.ts')
78
84
 
79
- const resolver = makeResolver([
85
+ const packages = [
80
86
  { name: '@open-mercato/dup-a', path: pkgA, modulesPath: path.join(pkgA, 'src', 'modules') },
81
87
  { name: '@open-mercato/dup-b', path: pkgB, modulesPath: path.join(pkgB, 'src', 'modules') },
82
- ])
88
+ ]
89
+ const expected = '[module-facts] duplicate module id "shared" is provided by '
90
+ + '@open-mercato/dup-a, @open-mercato/dup-b; src/modules.ts does not select a provider. '
91
+ + 'Select exactly one matching provider in src/modules.ts.'
92
+
93
+ expect(() => discoverPackageModuleSources(makeResolver(packages))).toThrow(expected)
94
+ expect(() => discoverPackageModuleSources(makeResolver([...packages].reverse()))).toThrow(expected)
95
+ })
96
+
97
+ it('uses the exact src/modules.ts provider even when package discovery order is reversed', () => {
98
+ const pkgA = path.join(tmp, 'selected-a')
99
+ writeModule(path.join(pkgA, 'src', 'modules'), 'shared', 'index.ts')
100
+ const pkgB = path.join(tmp, 'selected-b')
101
+ writeModule(path.join(pkgB, 'src', 'modules'), 'shared', 'index.ts')
102
+
103
+ const packages = [
104
+ { name: '@open-mercato/selected-a', path: pkgA, modulesPath: path.join(pkgA, 'src', 'modules') },
105
+ { name: '@open-mercato/selected-b', path: pkgB, modulesPath: path.join(pkgB, 'src', 'modules') },
106
+ ]
107
+ const enabled = [{ id: 'shared', from: '@open-mercato/selected-b' }]
108
+
109
+ for (const discoveredPackages of [packages, [...packages].reverse()]) {
110
+ const sources = discoverPackageModuleSources(makeResolver(discoveredPackages, enabled))
111
+ expect(sources).toHaveLength(1)
112
+ expect(sources[0]).toMatchObject({ moduleId: 'shared', from: '@open-mercato/selected-b' })
113
+ expect(sources[0].moduleRoot).toBe(path.join(pkgB, 'src', 'modules', 'shared'))
114
+ }
115
+ })
116
+
117
+ it('explains that an omitted provider implicitly selects core', () => {
118
+ const pkgA = path.join(tmp, 'implicit-a')
119
+ writeModule(path.join(pkgA, 'src', 'modules'), 'shared', 'index.ts')
120
+ const pkgB = path.join(tmp, 'implicit-b')
121
+ writeModule(path.join(pkgB, 'src', 'modules'), 'shared', 'index.ts')
122
+
123
+ const packages = [
124
+ { name: '@open-mercato/dup-a', path: pkgA, modulesPath: path.join(pkgA, 'src', 'modules') },
125
+ { name: '@open-mercato/dup-b', path: pkgB, modulesPath: path.join(pkgB, 'src', 'modules') },
126
+ ]
83
127
 
84
- const sources = discoverPackageModuleSources(resolver)
85
- expect(sources).toHaveLength(1)
86
- expect(sources[0].moduleRoot).toBe(path.join(pkgA, 'src', 'modules', 'shared'))
128
+ expect(() => discoverPackageModuleSources(makeResolver(packages, [{ id: 'shared' }]))).toThrow(
129
+ 'src/modules.ts omits "from", which defaults to @open-mercato/core',
130
+ )
87
131
  })
88
132
  })
@@ -0,0 +1,108 @@
1
+ import fs from 'node:fs'
2
+ import os from 'node:os'
3
+ import path from 'node:path'
4
+ import { extractModuleFacts } from '../module-facts'
5
+
6
+ function findCoreSrcRoot(): string {
7
+ let dir = __dirname
8
+ for (let depth = 0; depth < 10; depth += 1) {
9
+ const candidate = path.join(dir, 'packages', 'core', 'src', 'modules')
10
+ if (fs.existsSync(candidate)) return candidate
11
+ dir = path.dirname(dir)
12
+ }
13
+ throw new Error('[internal] could not locate packages/core/src/modules from the test directory')
14
+ }
15
+
16
+ function write(filePath: string, source: string): void {
17
+ fs.mkdirSync(path.dirname(filePath), { recursive: true })
18
+ fs.writeFileSync(filePath, source)
19
+ }
20
+
21
+ describe('module-facts extension host extraction', () => {
22
+ const coreSrcRoot = findCoreSrcRoot()
23
+
24
+ it('resolves generated E.<module>.<entity> custom-field declarations from shipped modules', () => {
25
+ const expectedByModule: Record<string, string[]> = {
26
+ attachments: ['attachments:attachment'],
27
+ catalog: [
28
+ 'catalog:catalog_product',
29
+ 'catalog:catalog_product_variant',
30
+ 'catalog:catalog_product_price',
31
+ ],
32
+ sales: [
33
+ 'sales:sales_order',
34
+ 'sales:sales_order_line',
35
+ 'sales:sales_order_adjustment',
36
+ 'sales:sales_quote',
37
+ 'sales:sales_quote_line',
38
+ 'sales:sales_quote_adjustment',
39
+ 'sales:sales_invoice',
40
+ 'sales:sales_invoice_line',
41
+ 'sales:sales_payment',
42
+ 'sales:sales_payment_allocation',
43
+ 'sales:sales_credit_memo',
44
+ 'sales:sales_credit_memo_line',
45
+ 'sales:sales_shipment',
46
+ 'sales:sales_shipment_item',
47
+ 'sales:sales_note',
48
+ ],
49
+ staff: ['staff:staff_team_member'],
50
+ }
51
+
52
+ for (const [moduleId, expected] of Object.entries(expectedByModule)) {
53
+ const facts = extractModuleFacts({ moduleId, coreSrcRoot })
54
+ expect(facts.entities.filter((entity) => entity.customFields).map((entity) => entity.id).sort()).toEqual(
55
+ [...expected].sort(),
56
+ )
57
+ }
58
+ })
59
+
60
+ it('discovers literal and conditional DataTable IDs outside backend while excluding test sources', () => {
61
+ const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'module-facts-extension-hosts-'))
62
+ const moduleRoot = path.join(tmpRoot, 'alpha')
63
+ try {
64
+ write(
65
+ path.join(moduleRoot, 'data', 'entities.ts'),
66
+ `@Entity({ tableName: 'alpha_records' })\nexport class AlphaRecord { updatedAt?: Date }\n`,
67
+ )
68
+ write(
69
+ path.join(moduleRoot, 'ce.ts'),
70
+ `export const entities = [{ id: E.alpha.alpha_record, fields: [] }]\n`,
71
+ )
72
+ write(
73
+ path.join(moduleRoot, 'components', 'AlphaTable.tsx'),
74
+ `export const props = {
75
+ perspective: { tableId: kind === 'one' ? 'alpha.one' : 'alpha.two' },
76
+ extensionTableId: 'alpha.extension',
77
+ }\n`,
78
+ )
79
+ write(
80
+ path.join(moduleRoot, 'components', 'Noise.test.tsx'),
81
+ `export const noise = { tableId: 'alpha.test-noise' }\n`,
82
+ )
83
+ write(
84
+ path.join(moduleRoot, 'backend', '__tests__', 'noise.tsx'),
85
+ `export const noise = { extensionTableId: 'alpha.test-directory-noise' }\n`,
86
+ )
87
+
88
+ const facts = extractModuleFacts({ moduleId: 'alpha', moduleRoot })
89
+ expect(facts.entities).toEqual([
90
+ expect.objectContaining({ id: 'alpha:alpha_record', customFields: true }),
91
+ ])
92
+ expect(facts.hostTokens.tableIds).toEqual(['alpha.extension', 'alpha.one', 'alpha.two'])
93
+ } finally {
94
+ fs.rmSync(tmpRoot, { recursive: true, force: true })
95
+ }
96
+ })
97
+
98
+ it('captures shipped component-level table hosts used by catalog and sales', () => {
99
+ const catalog = extractModuleFacts({ moduleId: 'catalog', coreSrcRoot })
100
+ expect(catalog.hostTokens.tableIds).toEqual([
101
+ 'catalog.categories.list',
102
+ 'catalog.products.list',
103
+ ])
104
+
105
+ const sales = extractModuleFacts({ moduleId: 'sales', coreSrcRoot })
106
+ expect(sales.hostTokens.tableIds).toEqual(['sales.orders', 'sales.quotes'])
107
+ })
108
+ })