@open-mercato/cli 0.6.7 → 0.6.8-canary.320.1.bf889f49e4

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 (335) hide show
  1. package/.turbo/turbo-build.log +77 -4
  2. package/AGENTS.md +6 -1
  3. package/build.mjs +68 -11
  4. package/dist/agentic/claude-code/hooks/entity-migration-check.ts +32 -88
  5. package/dist/agentic/codex/enforcement-rules.md +2 -16
  6. package/dist/agentic/cursor/hooks/entity-migration-check.mjs +19 -50
  7. package/dist/agentic/cursor/rules/entity-guard.mdc +9 -21
  8. package/dist/agentic/cursor/rules/generated-guard.mdc +3 -5
  9. package/dist/agentic/cursor/rules/open-mercato.mdc +3 -29
  10. package/dist/agentic/guides/ai-workflows.md +76 -0
  11. package/dist/agentic/guides/architecture.md +107 -0
  12. package/dist/agentic/guides/backend-ui.md +86 -0
  13. package/dist/agentic/guides/contracts.md +92 -0
  14. package/dist/agentic/guides/extensions.md +121 -0
  15. package/dist/agentic/guides/framework-extension-points.md +36 -0
  16. package/dist/agentic/guides/integrations.md +81 -0
  17. package/dist/agentic/guides/module-facts.json +116757 -3951
  18. package/dist/agentic/guides/module-system.md +12 -127
  19. package/dist/agentic/guides/modules/ai_assistant.md +227 -28
  20. package/dist/agentic/guides/modules/api_docs.md +58 -2
  21. package/dist/agentic/guides/modules/api_keys.md +92 -7
  22. package/dist/agentic/guides/modules/attachments.md +119 -14
  23. package/dist/agentic/guides/modules/audit_logs.md +131 -10
  24. package/dist/agentic/guides/modules/auth.md +276 -33
  25. package/dist/agentic/guides/modules/business_rules.md +149 -14
  26. package/dist/agentic/guides/modules/catalog.md +482 -43
  27. package/dist/agentic/guides/modules/channel_gmail.md +82 -3
  28. package/dist/agentic/guides/modules/channel_imap.md +82 -3
  29. package/dist/agentic/guides/modules/checkout.md +305 -27
  30. package/dist/agentic/guides/modules/communication_channels.md +315 -33
  31. package/dist/agentic/guides/modules/configs.md +104 -8
  32. package/dist/agentic/guides/modules/content.md +57 -2
  33. package/dist/agentic/guides/modules/currencies.md +152 -17
  34. package/dist/agentic/guides/modules/customer_accounts.md +387 -45
  35. package/dist/agentic/guides/modules/customers.md +746 -85
  36. package/dist/agentic/guides/modules/dashboards.md +155 -10
  37. package/dist/agentic/guides/modules/data_sync.md +149 -16
  38. package/dist/agentic/guides/modules/design_system.md +102 -0
  39. package/dist/agentic/guides/modules/dictionaries.md +107 -12
  40. package/dist/agentic/guides/modules/directory.md +148 -15
  41. package/dist/agentic/guides/modules/entities.md +145 -13
  42. package/dist/agentic/guides/modules/events.md +59 -2
  43. package/dist/agentic/guides/modules/feature_toggles.md +119 -9
  44. package/dist/agentic/guides/modules/gateway_stripe.md +92 -4
  45. package/dist/agentic/guides/modules/generators.md +45 -2
  46. package/dist/agentic/guides/modules/inbox_ops.md +207 -27
  47. package/dist/agentic/guides/modules/integrations.md +149 -16
  48. package/dist/agentic/guides/modules/messages.md +223 -24
  49. package/dist/agentic/guides/modules/notifications.md +96 -8
  50. package/dist/agentic/guides/modules/onboarding.md +77 -6
  51. package/dist/agentic/guides/modules/payment_gateways.md +168 -21
  52. package/dist/agentic/guides/modules/perspectives.md +77 -7
  53. package/dist/agentic/guides/modules/planner.md +136 -18
  54. package/dist/agentic/guides/modules/portal.md +93 -2
  55. package/dist/agentic/guides/modules/progress.md +104 -14
  56. package/dist/agentic/guides/modules/query_index.md +154 -15
  57. package/dist/agentic/guides/modules/record_locks.md +206 -21
  58. package/dist/agentic/guides/modules/resources.md +197 -30
  59. package/dist/agentic/guides/modules/sales.md +687 -84
  60. package/dist/agentic/guides/modules/scheduler.md +133 -14
  61. package/dist/agentic/guides/modules/search.md +170 -6
  62. package/dist/agentic/guides/modules/security.md +294 -35
  63. package/dist/agentic/guides/modules/shipping_carriers.md +134 -18
  64. package/dist/agentic/guides/modules/sso.md +151 -26
  65. package/dist/agentic/guides/modules/staff.md +372 -57
  66. package/dist/agentic/guides/modules/storage_s3.md +95 -5
  67. package/dist/agentic/guides/modules/sync_akeneo.md +85 -3
  68. package/dist/agentic/guides/modules/sync_excel.md +75 -6
  69. package/dist/agentic/guides/modules/system_status_overlays.md +60 -2
  70. package/dist/agentic/guides/modules/translations.md +104 -10
  71. package/dist/agentic/guides/modules/webhooks.md +203 -24
  72. package/dist/agentic/guides/modules/wms.md +469 -47
  73. package/dist/agentic/guides/modules/workflows.md +302 -43
  74. package/dist/agentic/guides/reference-module-facts.json +6942 -0
  75. package/dist/agentic/guides/reference-modules/example.md +462 -0
  76. package/dist/agentic/guides/spec-delivery.md +56 -0
  77. package/dist/agentic/guides/testing-debugging.md +80 -0
  78. package/dist/agentic/guides/upstream/AGENTS.md +300 -0
  79. package/dist/agentic/guides/upstream/BACKWARD_COMPATIBILITY.md +334 -0
  80. package/dist/agentic/guides/upstream/manifest.json +8 -0
  81. package/dist/agentic/shared/AGENTS.md.template +120 -311
  82. package/dist/agentic/shared/ai/agentic.config.json +2 -0
  83. package/dist/agentic/shared/ai/harness/README.md +50 -0
  84. package/dist/agentic/shared/ai/harness/RELEASE.md +59 -0
  85. package/dist/agentic/shared/ai/harness/cases.json +20596 -0
  86. package/dist/agentic/shared/ai/harness/cases.schema.json +196 -0
  87. package/dist/agentic/shared/ai/harness/design-system-inventory.json +6326 -0
  88. package/dist/agentic/shared/ai/harness/fixtures/index.json +51 -0
  89. package/dist/agentic/shared/ai/harness/fixtures/seeds.json +166 -0
  90. package/dist/agentic/shared/ai/harness/generated-code-review-policy.md +21 -0
  91. package/dist/agentic/shared/ai/harness/generated-code-review-response.schema.json +96 -0
  92. package/dist/agentic/shared/ai/harness/generated-code-review-result.schema.json +172 -0
  93. package/dist/agentic/shared/ai/harness/knowledge-change.schema.json +228 -0
  94. package/dist/agentic/shared/ai/harness/release-matrix.json +163 -0
  95. package/dist/agentic/shared/ai/harness/release-result.schema.json +219 -0
  96. package/dist/agentic/shared/ai/harness/result.schema.json +136 -0
  97. package/dist/agentic/shared/ai/harness/routing-response.schema.json +22 -0
  98. package/dist/agentic/shared/ai/harness/source-link-inventory.json +1706 -0
  99. package/dist/agentic/shared/ai/harness/target-validation-result.schema.json +73 -0
  100. package/dist/agentic/shared/ai/harness/validators.json +82 -0
  101. package/dist/agentic/shared/ai/harness/writable-ast-oracles.mjs +2121 -0
  102. package/dist/agentic/shared/ai/harness/writable-behavior-oracles.mjs +1096 -0
  103. package/dist/agentic/shared/ai/harness/writable-spec-oracles.mjs +602 -0
  104. package/dist/agentic/shared/ai/lessons/_template.md +16 -0
  105. package/dist/agentic/shared/ai/lessons.md +26 -3
  106. package/dist/agentic/shared/ai/review-checklist.md +36 -0
  107. package/dist/agentic/shared/ai/skills/om-auto-implement-spec/SKILL.md +21 -0
  108. package/dist/agentic/shared/ai/skills/om-auto-review-pr/SKILL.md +4 -0
  109. package/dist/agentic/shared/ai/skills/om-auto-upgrade-0.6.6-to-0.6.7/SKILL.md +98 -0
  110. package/dist/agentic/shared/ai/skills/om-backend-ui-design/SKILL.md +21 -241
  111. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/crud-surfaces.md +31 -0
  112. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/frontend-and-design-system.md +53 -0
  113. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/page-and-navigation.md +15 -0
  114. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/quality-states.md +11 -0
  115. package/dist/agentic/shared/ai/skills/om-build-workflow/SKILL.md +30 -0
  116. package/dist/agentic/shared/ai/skills/om-build-workflow/references/activity-contracts.md +12 -0
  117. package/dist/agentic/shared/ai/skills/om-build-workflow/references/durability-and-progress.md +13 -0
  118. package/dist/agentic/shared/ai/skills/om-build-workflow/references/workflow-design.md +14 -0
  119. package/dist/agentic/shared/ai/skills/om-create-ai-agent/SKILL.md +28 -0
  120. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/attachments-and-overrides.md +12 -0
  121. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/module-agents-and-tools.md +22 -0
  122. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/orchestrator-agents.md +12 -0
  123. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/surface-selector.md +19 -0
  124. package/dist/agentic/shared/ai/skills/om-data-model-design/SKILL.md +17 -601
  125. package/dist/agentic/shared/ai/skills/om-data-model-design/references/integrity-and-concurrency.md +21 -0
  126. package/dist/agentic/shared/ai/skills/om-data-model-design/references/migration-workflow.md +15 -0
  127. package/dist/agentic/shared/ai/skills/om-data-model-design/references/schema-design.md +16 -0
  128. package/dist/agentic/shared/ai/skills/om-data-model-design/references/sensitive-data.md +10 -0
  129. package/dist/agentic/shared/ai/skills/om-eject-and-customize/SKILL.md +15 -310
  130. package/dist/agentic/shared/ai/skills/om-eject-and-customize/references/decision-and-procedure.md +19 -0
  131. package/dist/agentic/shared/ai/skills/om-evolve-harness/SKILL.md +31 -0
  132. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-template.md +100 -0
  133. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-workflow.md +16 -0
  134. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/knowledge-change.md +133 -0
  135. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/owner-selection.md +17 -0
  136. package/dist/agentic/shared/ai/skills/om-framework-context/SKILL.md +25 -0
  137. package/dist/agentic/shared/ai/skills/om-framework-context/references/resolver-procedure.md +11 -0
  138. package/dist/agentic/shared/ai/skills/om-framework-context/references/skew-and-escalation.md +13 -0
  139. package/dist/agentic/shared/ai/skills/om-help/SKILL.md +15 -97
  140. package/dist/agentic/shared/ai/skills/om-help/references/delivery-workflows.md +18 -0
  141. package/dist/agentic/shared/ai/skills/om-help/references/task-families.md +20 -0
  142. package/dist/agentic/shared/ai/skills/om-implement-spec/SKILL.md +33 -152
  143. package/dist/agentic/shared/ai/skills/om-implement-spec/references/phases-and-gates.md +33 -0
  144. package/dist/agentic/shared/ai/skills/om-implement-spec/references/planning-and-progress.md +40 -0
  145. package/dist/agentic/shared/ai/skills/om-implement-spec/references/report-templates.md +27 -0
  146. package/dist/agentic/shared/ai/skills/om-implement-spec/references/spec-resolution.md +24 -0
  147. package/dist/agentic/shared/ai/skills/om-integration-builder/SKILL.md +25 -708
  148. package/dist/agentic/shared/ai/skills/om-integration-builder/references/package-and-activation.md +16 -0
  149. package/dist/agentic/shared/ai/skills/om-integration-builder/references/provider-families.md +25 -0
  150. package/dist/agentic/shared/ai/skills/om-integration-builder/references/security-and-reliability.md +15 -0
  151. package/dist/agentic/shared/ai/skills/om-integration-builder/references/sync-and-files.md +12 -0
  152. package/dist/agentic/shared/ai/skills/om-judge-agent-session/SKILL.md +34 -0
  153. package/dist/agentic/shared/ai/skills/om-judge-agent-session/agents/openai.yaml +4 -0
  154. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/agentic-setup.md +11 -0
  155. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/input-normalization.md +31 -0
  156. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/judge-workflow.md +39 -0
  157. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/report-template.md +43 -0
  158. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/rules.md +11 -0
  159. package/dist/agentic/shared/ai/skills/om-module-scaffold/SKILL.md +20 -820
  160. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/api-and-domain.md +32 -0
  161. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/business-one-shot-blueprints.md +172 -0
  162. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/data-and-migrations.md +14 -0
  163. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/discovery-surface-catalog.md +83 -0
  164. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/module-surfaces.md +40 -0
  165. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/planning.md +11 -0
  166. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/runtime-cache-and-queues.md +22 -0
  167. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/verification.md +13 -0
  168. package/dist/agentic/shared/ai/skills/om-share-this-session/SKILL.md +41 -0
  169. package/dist/agentic/shared/ai/skills/om-share-this-session/references/agentic-setup.md +19 -0
  170. package/dist/agentic/shared/ai/skills/om-share-this-session/references/bundle-preparation.md +44 -0
  171. package/dist/agentic/shared/ai/skills/om-share-this-session/references/consent-and-review.md +39 -0
  172. package/dist/agentic/shared/ai/skills/om-share-this-session/references/publication.md +20 -0
  173. package/dist/agentic/shared/ai/skills/om-share-this-session/references/report-templates.md +57 -0
  174. package/dist/agentic/shared/ai/skills/om-share-this-session/references/rules.md +11 -0
  175. package/dist/agentic/shared/ai/skills/om-share-this-session/scripts/prepare-share-bundle.mjs +486 -0
  176. package/dist/agentic/shared/ai/skills/om-system-extension/SKILL.md +20 -843
  177. package/dist/agentic/shared/ai/skills/om-system-extension/references/extension-branches.md +42 -0
  178. package/dist/agentic/shared/ai/skills/om-system-extension/references/mechanism-selector.md +27 -0
  179. package/dist/agentic/shared/ai/skills/om-system-extension/references/read-write-roundtrip.md +13 -0
  180. package/dist/agentic/shared/ai/skills/om-system-extension/references/unified-overrides.md +43 -0
  181. package/dist/agentic/shared/ai/skills/om-system-extension/references/verification.md +11 -0
  182. package/dist/agentic/shared/ai/skills/om-trim-unused-modules/SKILL.md +15 -63
  183. package/dist/agentic/shared/ai/skills/om-trim-unused-modules/references/dependency-and-redirect.md +15 -0
  184. package/dist/agentic/shared/ai/skills/om-troubleshooter/SKILL.md +17 -467
  185. package/dist/agentic/shared/ai/skills/om-troubleshooter/references/diagnosis-map.md +29 -0
  186. package/dist/agentic/shared/ai/skills/om-troubleshooter/references/regression-oracles.md +14 -0
  187. package/dist/agentic/shared/ai/skills/tiers.json +143 -21
  188. package/dist/agentic/shared/ai/skills/tiers.schema.json +52 -40
  189. package/dist/agentic/shared/ai/specs/2026-08-06-reference-module-activation.md +248 -0
  190. package/dist/agentic/shared/ai/specs/README.md +4 -3
  191. package/dist/agentic/shared/ai/specs/SPEC-000-template.md +226 -10
  192. package/dist/agentic/shared/ai/trackers/github.md +108 -4
  193. package/dist/agentic/shared/scripts/agent-harness-tool-server.mjs +224 -0
  194. package/dist/agentic/shared/scripts/check-lessons.mjs +178 -0
  195. package/dist/agentic/shared/scripts/evaluate-agent-harness.mjs +3812 -0
  196. package/dist/agentic/shared/scripts/execution-sandbox.mjs +329 -0
  197. package/dist/agentic/shared/scripts/framework-context.mjs +888 -0
  198. package/dist/agentic/shared/scripts/install-skills.mjs +1029 -0
  199. package/dist/agentic/shared/scripts/install-skills.sh +4 -694
  200. package/dist/agentic/shared/scripts/prepare-agent-harness-fixture.mjs +222 -0
  201. package/dist/agentic/shared/scripts/run-agent-harness-release.mjs +1774 -0
  202. package/dist/agentic/shared/scripts/validate-knowledge-change.mjs +1172 -0
  203. package/dist/bin.js +32 -34
  204. package/dist/bin.js.map +2 -2
  205. package/dist/lib/__integration__/TC-INT-008.spec.js +88 -8
  206. package/dist/lib/__integration__/TC-INT-008.spec.js.map +2 -2
  207. package/dist/lib/agentic-init.js +13 -3
  208. package/dist/lib/agentic-init.js.map +2 -2
  209. package/dist/lib/agentic-setup.js +434 -186
  210. package/dist/lib/agentic-setup.js.map +2 -2
  211. package/dist/lib/cli-bootstrap-mode.js +32 -0
  212. package/dist/lib/cli-bootstrap-mode.js.map +7 -0
  213. package/dist/lib/dev-supervisor-manifest.js +105 -0
  214. package/dist/lib/dev-supervisor-manifest.js.map +7 -0
  215. package/dist/lib/generate-watch-events.js +15 -0
  216. package/dist/lib/generate-watch-events.js.map +2 -2
  217. package/dist/lib/generators/entity-ids.js +11 -24
  218. package/dist/lib/generators/entity-ids.js.map +2 -2
  219. package/dist/lib/generators/extensions/injection-widgets.js +20 -0
  220. package/dist/lib/generators/extensions/injection-widgets.js.map +2 -2
  221. package/dist/lib/generators/module-di.js +10 -23
  222. package/dist/lib/generators/module-di.js.map +2 -2
  223. package/dist/lib/generators/module-entities.js +10 -23
  224. package/dist/lib/generators/module-entities.js.map +2 -2
  225. package/dist/lib/generators/module-extension-facts.js +1882 -0
  226. package/dist/lib/generators/module-extension-facts.js.map +7 -0
  227. package/dist/lib/generators/module-fact-sources.js +70 -0
  228. package/dist/lib/generators/module-fact-sources.js.map +7 -0
  229. package/dist/lib/generators/module-facts-discovery.js +64 -7
  230. package/dist/lib/generators/module-facts-discovery.js.map +2 -2
  231. package/dist/lib/generators/module-facts.js +1913 -52
  232. package/dist/lib/generators/module-facts.js.map +3 -3
  233. package/dist/lib/generators/module-override-targets.js +712 -0
  234. package/dist/lib/generators/module-override-targets.js.map +7 -0
  235. package/dist/lib/generators/module-registry.js +405 -36
  236. package/dist/lib/generators/module-registry.js.map +2 -2
  237. package/dist/lib/generators/route-manifest-shards.js +170 -0
  238. package/dist/lib/generators/route-manifest-shards.js.map +7 -0
  239. package/dist/lib/in-process-generate-watcher.js +12 -3
  240. package/dist/lib/in-process-generate-watcher.js.map +2 -2
  241. package/dist/lib/load-env.js +24 -0
  242. package/dist/lib/load-env.js.map +7 -0
  243. package/dist/lib/queue-worker-supervisor.js.map +2 -2
  244. package/dist/lib/resolver.js +28 -3
  245. package/dist/lib/resolver.js.map +2 -2
  246. package/dist/lib/telemetry-init.js +358 -0
  247. package/dist/lib/telemetry-init.js.map +7 -0
  248. package/dist/lib/testing/integration.js +5 -2
  249. package/dist/lib/testing/integration.js.map +2 -2
  250. package/dist/lib/utils.js +15 -8
  251. package/dist/lib/utils.js.map +2 -2
  252. package/dist/mercato.js +35 -9
  253. package/dist/mercato.js.map +2 -2
  254. package/package.json +13 -11
  255. package/src/__tests__/mercato.test.ts +144 -0
  256. package/src/bin.ts +60 -42
  257. package/src/lib/__integration__/TC-INT-008.spec.ts +107 -9
  258. package/src/lib/__tests__/agentic-init.test.ts +41 -5
  259. package/src/lib/__tests__/agentic-setup.ownership.test.ts +386 -0
  260. package/src/lib/__tests__/cli-bootstrap-mode.test.ts +22 -0
  261. package/src/lib/__tests__/content-stable-writes.test.ts +74 -0
  262. package/src/lib/__tests__/dev-supervisor-manifest.test.ts +131 -0
  263. package/src/lib/__tests__/generate-watch-events.test.ts +76 -0
  264. package/src/lib/__tests__/in-process-generate-watcher.test.ts +52 -1
  265. package/src/lib/__tests__/injection-widget-id-validation.test.ts +184 -0
  266. package/src/lib/__tests__/load-env.test.ts +65 -0
  267. package/src/lib/__tests__/queue-worker-supervisor.test.ts +33 -0
  268. package/src/lib/__tests__/resolver.enterprise.test.ts +50 -0
  269. package/src/lib/__tests__/telemetry-init.test.ts +298 -0
  270. package/src/lib/agentic-init.ts +15 -3
  271. package/src/lib/agentic-setup.ts +573 -222
  272. package/src/lib/cli-bootstrap-mode.ts +31 -0
  273. package/src/lib/dev-supervisor-manifest.ts +142 -0
  274. package/src/lib/generate-watch-events.ts +14 -0
  275. package/src/lib/generators/__tests__/activation-adapter-coverage.test.ts +92 -0
  276. package/src/lib/generators/__tests__/entity-ids.test.ts +32 -0
  277. package/src/lib/generators/__tests__/helpers/override-target-diagnostic-fixtures.ts +150 -0
  278. package/src/lib/generators/__tests__/module-extension-activations.test.ts +762 -0
  279. package/src/lib/generators/__tests__/module-extension-facts.test.ts +603 -0
  280. package/src/lib/generators/__tests__/module-facts.bc-guard.test.ts +139 -2
  281. package/src/lib/generators/__tests__/module-facts.computed-di-token.test.ts +88 -0
  282. package/src/lib/generators/__tests__/module-facts.customers.fixture.test.ts +1 -0
  283. package/src/lib/generators/__tests__/module-facts.discovery.test.ts +54 -10
  284. package/src/lib/generators/__tests__/module-facts.example-fact-coverage.test.ts +414 -0
  285. package/src/lib/generators/__tests__/module-facts.extension-hosts.test.ts +108 -0
  286. package/src/lib/generators/__tests__/module-facts.local-reference.test.ts +393 -0
  287. package/src/lib/generators/__tests__/module-facts.owned-contracts.test.ts +561 -0
  288. package/src/lib/generators/__tests__/module-facts.search-entity-id.test.ts +151 -0
  289. package/src/lib/generators/__tests__/module-facts.source-links.test.ts +160 -0
  290. package/src/lib/generators/__tests__/module-override-targets.diagnostic-wiring.test.ts +92 -0
  291. package/src/lib/generators/__tests__/module-override-targets.roundtrip.test.ts +149 -0
  292. package/src/lib/generators/__tests__/module-override-targets.test.ts +328 -0
  293. package/src/lib/generators/__tests__/module-override-targets.unknown-mode.test.ts +117 -0
  294. package/src/lib/generators/__tests__/module-subset.test.ts +266 -0
  295. package/src/lib/generators/__tests__/output-snapshots.test.ts +3 -3
  296. package/src/lib/generators/__tests__/route-manifest-shards.test.ts +62 -0
  297. package/src/lib/generators/entity-ids.ts +10 -26
  298. package/src/lib/generators/extensions/injection-widgets.ts +51 -0
  299. package/src/lib/generators/module-di.ts +9 -25
  300. package/src/lib/generators/module-entities.ts +9 -25
  301. package/src/lib/generators/module-extension-facts.ts +2472 -0
  302. package/src/lib/generators/module-fact-sources.ts +108 -0
  303. package/src/lib/generators/module-facts-discovery.ts +104 -7
  304. package/src/lib/generators/module-facts.ts +2747 -138
  305. package/src/lib/generators/module-override-targets.ts +907 -0
  306. package/src/lib/generators/module-registry.ts +448 -35
  307. package/src/lib/generators/route-manifest-shards.ts +146 -0
  308. package/src/lib/in-process-generate-watcher.ts +13 -4
  309. package/src/lib/load-env.ts +30 -0
  310. package/src/lib/queue-worker-supervisor.ts +7 -2
  311. package/src/lib/resolver.ts +34 -3
  312. package/src/lib/telemetry-init.ts +461 -0
  313. package/src/lib/testing/__tests__/integration.test.ts +4 -0
  314. package/src/lib/testing/integration.ts +5 -2
  315. package/src/lib/utils.ts +24 -16
  316. package/src/mercato.ts +46 -9
  317. package/dist/agentic/guides/cache.md +0 -45
  318. package/dist/agentic/guides/core.md +0 -453
  319. package/dist/agentic/guides/events.md +0 -117
  320. package/dist/agentic/guides/queue.md +0 -53
  321. package/dist/agentic/guides/search.md +0 -115
  322. package/dist/agentic/guides/shared.md +0 -108
  323. package/dist/agentic/guides/ui.md +0 -347
  324. package/dist/agentic/shared/ai/skills/om-auto-continue-pr-loop/SKILL.md +0 -27
  325. package/dist/agentic/shared/ai/skills/om-auto-create-pr-loop/SKILL.md +0 -27
  326. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/ui-components.md +0 -260
  327. package/dist/agentic/shared/ai/skills/om-data-model-design/references/mikro-orm-cheatsheet.md +0 -146
  328. package/dist/agentic/shared/ai/skills/om-help/references/skills-catalog.md +0 -84
  329. package/dist/agentic/shared/ai/skills/om-help/references/workflow-sequences.md +0 -193
  330. package/dist/agentic/shared/ai/skills/om-integration-builder/STANDALONE.md +0 -34
  331. package/dist/agentic/shared/ai/skills/om-integration-builder/references/adapter-contracts.md +0 -762
  332. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/naming-conventions.md +0 -50
  333. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/navigation-patterns.md +0 -97
  334. package/dist/agentic/shared/ai/skills/om-system-extension/references/extension-contracts.md +0 -271
  335. package/dist/agentic/shared/ai/skills/om-troubleshooter/references/diagnostic-commands.md +0 -101
@@ -0,0 +1,151 @@
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 search entity declared with a non-literal `entityId` must still reach module facts.
8
+ *
9
+ * `extractSearchEntities` accepted only a bare string literal, but modules reference the
10
+ * entity through `E.<module>.<entity>` (the generated entity-id registry, where
11
+ * `E[module][entity] === '<module>:<entity>'`) or through a same-file `const ENTITY_ID`.
12
+ * Every such entry was dropped with NO diagnostic, so a module shipping `search.ts` scored
13
+ * zero search facts while looking healthy — the same class of defect as the computed DI
14
+ * token. Repo-wide this moved the search family from 47 ids across 9 modules to 52 across 11.
15
+ *
16
+ * The second half of this file pins the other direction: an `entityId` the reader genuinely
17
+ * cannot know statically (an imported constant object) must NOT be guessed, and must produce
18
+ * a warning rather than a silent zero.
19
+ */
20
+
21
+ type Probe = {
22
+ searchEntities: string[]
23
+ warnings: string[]
24
+ searchRegistryIds: string[]
25
+ }
26
+
27
+ function probe(searchSource: string): Probe {
28
+ const moduleRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'om-search-entity-id-'))
29
+ try {
30
+ fs.writeFileSync(path.join(moduleRoot, 'search.ts'), searchSource)
31
+ const facts = extractModuleFacts({
32
+ moduleId: 'probe',
33
+ moduleRoot,
34
+ sourceRoot: 'src/modules/probe',
35
+ }) as unknown as {
36
+ searchEntities: string[]
37
+ warnings: string[]
38
+ extensionSurfaces?: {
39
+ contributions?: Array<{ kind: string; details?: { registry?: string; registryId?: string } }>
40
+ }
41
+ }
42
+ return {
43
+ searchEntities: facts.searchEntities,
44
+ warnings: facts.warnings.filter((warning) => warning.includes('searchConfig')),
45
+ searchRegistryIds: (facts.extensionSurfaces?.contributions ?? [])
46
+ .filter((contribution) => contribution.details?.registry === 'search')
47
+ .map((contribution) => contribution.details?.registryId ?? ''),
48
+ }
49
+ } finally {
50
+ fs.rmSync(moduleRoot, { recursive: true, force: true })
51
+ }
52
+ }
53
+
54
+ describe('module-facts search entityId resolution', () => {
55
+ it('resolves an entityId declared as a same-file const', () => {
56
+ const result = probe(`
57
+ const ENTITY_ID = 'probe:todo' as const
58
+ export const searchConfig = {
59
+ entities: [{ entityId: ENTITY_ID, enabled: true }],
60
+ }
61
+ `)
62
+
63
+ expect(result.searchEntities).toEqual(['probe:todo'])
64
+ expect(result.warnings).toEqual([])
65
+ // The whole chain matters: `searchEntities` feeds the specialized-registry contribution
66
+ // that downstream consumers actually read.
67
+ expect(result.searchRegistryIds).toEqual(['probe:todo'])
68
+ })
69
+
70
+ it('resolves an entityId read from the generated entity-id registry', () => {
71
+ const result = probe(`
72
+ import { E } from '#generated/entities.ids.generated'
73
+ export const searchConfig = {
74
+ entities: [
75
+ { entityId: E.probe.todo, enabled: true },
76
+ { entityId: E['probe']['note'], enabled: true },
77
+ ],
78
+ }
79
+ `)
80
+
81
+ expect(result.searchEntities).toEqual(['probe:todo', 'probe:note'])
82
+ expect(result.warnings).toEqual([])
83
+ })
84
+
85
+ it('still resolves a plain string literal and de-duplicates repeats', () => {
86
+ const result = probe(`
87
+ export const searchConfig = {
88
+ entities: [
89
+ { entityId: 'probe:todo' },
90
+ { entityId: 'probe:todo' },
91
+ { entityId: 'probe:note' },
92
+ ],
93
+ }
94
+ `)
95
+
96
+ expect(result.searchEntities).toEqual(['probe:todo', 'probe:note'])
97
+ expect(result.warnings).toEqual([])
98
+ })
99
+
100
+ it('reports rather than invents an entityId it cannot resolve statically', () => {
101
+ // `CHECKOUT_ENTITY_IDS` lives in another file, so a single-file reader cannot know the
102
+ // value. Emitting a guessed id would be worse than emitting none — but staying silent is
103
+ // what let this family read zero for years, so the entry must surface as a warning.
104
+ const result = probe(`
105
+ import { CHECKOUT_ENTITY_IDS } from './lib/constants'
106
+ import { CONSTANTS } from './lib/other'
107
+ export const searchConfig = {
108
+ entities: [
109
+ { entityId: CHECKOUT_ENTITY_IDS.link, enabled: true },
110
+ { entityId: CONSTANTS.entities.todo, enabled: true },
111
+ { entityId: 'probe:known' },
112
+ ],
113
+ }
114
+ `)
115
+
116
+ // Neither the two-segment access nor the three-segment access rooted at something other
117
+ // than the generated `E` registry may be folded into an id.
118
+ expect(result.searchEntities).toEqual(['probe:known'])
119
+ expect(result.searchRegistryIds).toEqual(['probe:known'])
120
+ expect(result.warnings).toHaveLength(2)
121
+ for (const warning of result.warnings) {
122
+ expect(warning).toContain('searchConfig entityId is not statically resolvable')
123
+ }
124
+ })
125
+
126
+ it('reports an entity that declares no entityId at all', () => {
127
+ const result = probe(`
128
+ export const searchConfig = {
129
+ entities: [{ enabled: true, priority: 5 }],
130
+ }
131
+ `)
132
+
133
+ expect(result.searchEntities).toEqual([])
134
+ expect(result.warnings).toHaveLength(1)
135
+ expect(result.warnings[0]).toContain('searchConfig entity declares no entityId')
136
+ })
137
+
138
+ it('does not follow a self-referential const into an infinite loop', () => {
139
+ const result = probe(`
140
+ const A = B
141
+ const B = A
142
+ export const searchConfig = {
143
+ entities: [{ entityId: A }],
144
+ }
145
+ `)
146
+
147
+ expect(result.searchEntities).toEqual([])
148
+ expect(result.warnings).toHaveLength(1)
149
+ expect(result.warnings[0]).toContain('searchConfig entityId is not statically resolvable')
150
+ })
151
+ })
@@ -0,0 +1,160 @@
1
+ import fs from 'node:fs'
2
+ import os from 'node:os'
3
+ import path from 'node:path'
4
+ import { extractModuleFacts, isExactSourceFilePath, renderModuleFactsMarkdown } from '../module-facts'
5
+
6
+ const MARKDOWN_LINK_TARGET = /\]\(\.\.\/\.\.\/\.\.\/([^)#]+)(?:#L\d+)?\)/g
7
+
8
+ function collectLinkTargets(markdown: string): string[] {
9
+ return [...markdown.matchAll(MARKDOWN_LINK_TARGET)].map((match) => match[1])
10
+ }
11
+
12
+ function writeFixture(root: string, relativePath: string, source: string): void {
13
+ const filePath = path.join(root, relativePath)
14
+ fs.mkdirSync(path.dirname(filePath), { recursive: true })
15
+ fs.writeFileSync(filePath, source)
16
+ }
17
+
18
+ describe('module-facts source-linked extension surfaces', () => {
19
+ let temporaryRoot: string
20
+ let moduleRoot: string
21
+
22
+ beforeAll(() => {
23
+ temporaryRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'module-facts-source-links-'))
24
+ moduleRoot = path.join(temporaryRoot, 'facts')
25
+ writeFixture(moduleRoot, 'index.ts', "export const metadata = { title: 'Facts' }\n")
26
+ writeFixture(
27
+ moduleRoot,
28
+ 'api/records/route.ts',
29
+ "export const metadata = { path: '/facts/records-custom' }\nexport async function GET() {}\n",
30
+ )
31
+ writeFixture(moduleRoot, 'backend/page.tsx', 'export default function FactsPage() { return null }\n')
32
+ writeFixture(
33
+ moduleRoot,
34
+ 'backend/facts/items/[id]/page.tsx',
35
+ 'export default function FactItemPage() { return null }\n',
36
+ )
37
+ writeFixture(
38
+ moduleRoot,
39
+ 'frontend/facts/portal/[id]/page.tsx',
40
+ 'export default function FactPortalPage() { return null }\n',
41
+ )
42
+ writeFixture(
43
+ moduleRoot,
44
+ 'cli.ts',
45
+ "const commands = [{ command: 'facts:sync' }, { command: 'facts:check' }]\nexport default commands\n",
46
+ )
47
+ writeFixture(
48
+ moduleRoot,
49
+ 'ai-tools/tools-pack.ts',
50
+ "type FactsAiToolDefinition = { name: string; description: string }\nconst inspectTool: FactsAiToolDefinition = { name: 'facts.inspect', description: 'Inspect facts' }\nexport default [inspectTool]\n",
51
+ )
52
+ writeFixture(
53
+ moduleRoot,
54
+ 'ai-tools.ts',
55
+ "type FactsAiToolDefinition = { name: string; description: string }\nconst listTool: FactsAiToolDefinition = { name: 'facts.list', description: 'List facts' }\nexport const aiTools = [listTool]\nexport default aiTools\n",
56
+ )
57
+ writeFixture(
58
+ moduleRoot,
59
+ 'ai-agents.ts',
60
+ "type AiAgentDefinition = { id: string; label: string }\nconst AGENT_ID = 'facts.assistant'\nconst agent: AiAgentDefinition = { id: AGENT_ID, label: 'Facts assistant' }\nexport const aiAgents = [agent]\nexport default aiAgents\n",
61
+ )
62
+ })
63
+
64
+ afterAll(() => {
65
+ fs.rmSync(temporaryRoot, { recursive: true, force: true })
66
+ })
67
+
68
+ it('emits portable source links for routes, pages, commands, tools, and agents', () => {
69
+ const registrySource = `export const modules = [{
70
+ id: 'facts',
71
+ apis: [{
72
+ path: '/facts/records-custom',
73
+ handlers: { GET: async () => undefined },
74
+ metadata: { GET: { requireFeatures: ['facts.view'] } },
75
+ }],
76
+ }]`
77
+ const facts = extractModuleFacts({
78
+ moduleId: 'facts',
79
+ moduleRoot,
80
+ sourcePackage: '@open-mercato/example',
81
+ sourceVersion: '1.2.3',
82
+ registrySource,
83
+ })
84
+
85
+ expect(facts.sourceRoot).toBe('node_modules/@open-mercato/example/src/modules/facts')
86
+ expect(facts.apiRoutes).toEqual([
87
+ {
88
+ path: '/facts/records-custom',
89
+ methods: ['GET'],
90
+ auth: { GET: { requireFeatures: ['facts.view'] } },
91
+ sourcePath: 'node_modules/@open-mercato/example/src/modules/facts/api/records/route.ts',
92
+ },
93
+ ])
94
+ expect(facts.backendPages).toEqual([
95
+ {
96
+ path: '/backend/facts',
97
+ sourcePath: 'node_modules/@open-mercato/example/src/modules/facts/backend/page.tsx',
98
+ },
99
+ {
100
+ path: '/backend/facts/items/[id]',
101
+ sourcePath: 'node_modules/@open-mercato/example/src/modules/facts/backend/facts/items/[id]/page.tsx',
102
+ },
103
+ ])
104
+ expect(facts.frontendPages).toEqual([
105
+ {
106
+ path: '/facts/portal/[id]',
107
+ sourcePath: 'node_modules/@open-mercato/example/src/modules/facts/frontend/facts/portal/[id]/page.tsx',
108
+ },
109
+ ])
110
+ expect(facts.cli).toEqual(['facts:sync', 'facts:check'])
111
+ expect(facts.cliCommands.map((command) => command.command)).toEqual(['facts:sync', 'facts:check'])
112
+ expect(facts.aiTools.map((tool) => tool.name)).toEqual(['facts.inspect', 'facts.list'])
113
+ expect(facts.aiAgents.map((agentFact) => agentFact.id)).toEqual(['facts.assistant'])
114
+
115
+ const markdown = renderModuleFactsMarkdown(facts)
116
+ expect(markdown).toContain('## Backend pages')
117
+ expect(markdown).toContain('## Frontend pages')
118
+ expect(markdown).toContain('## CLI commands')
119
+ expect(markdown).toContain('## AI tools / MCP capabilities')
120
+ expect(markdown).toContain('## AI agents')
121
+ expect(markdown).toContain(
122
+ '(../../../node_modules/@open-mercato/example/src/modules/facts/api/records/route.ts)',
123
+ )
124
+ })
125
+
126
+ it('links only exact module code files and never a directory', () => {
127
+ const facts = extractModuleFacts({
128
+ moduleId: 'facts',
129
+ moduleRoot,
130
+ sourcePackage: '@open-mercato/example',
131
+ sourceVersion: '1.2.3',
132
+ })
133
+ const markdown = renderModuleFactsMarkdown(facts)
134
+ const targets = collectLinkTargets(markdown)
135
+
136
+ expect(targets.length).toBeGreaterThan(0)
137
+ expect(targets.filter((target) => !isExactSourceFilePath(target))).toEqual([])
138
+ })
139
+
140
+ it('renders the directory-valued source root as plain text instead of a folder link', () => {
141
+ const facts = extractModuleFacts({
142
+ moduleId: 'facts',
143
+ moduleRoot,
144
+ sourcePackage: '@open-mercato/example',
145
+ sourceVersion: '1.2.3',
146
+ })
147
+ const markdown = renderModuleFactsMarkdown(facts)
148
+
149
+ expect(markdown).toContain('Source root: node_modules/@open-mercato/example/src/modules/facts\n')
150
+ expect(markdown).not.toContain('(../../../node_modules/@open-mercato/example/src/modules/facts)')
151
+ })
152
+
153
+ it('classifies exact files and directories consistently', () => {
154
+ expect(isExactSourceFilePath('packages/core/src/modules/customers/index.ts')).toBe(true)
155
+ expect(isExactSourceFilePath('packages/ui/src/backend/DataTable.tsx')).toBe(true)
156
+ expect(isExactSourceFilePath('node_modules/@open-mercato/core/dist/modules/customers/acl.js')).toBe(true)
157
+ expect(isExactSourceFilePath('packages/ui/src')).toBe(false)
158
+ expect(isExactSourceFilePath('node_modules/@open-mercato/core/src/modules/customers')).toBe(false)
159
+ })
160
+ })
@@ -0,0 +1,92 @@
1
+ import { collectModuleOverrideTargets } from '../module-override-targets'
2
+ import {
3
+ FIXTURE_MODULE_ID,
4
+ FIXTURE_SOURCE_ROOT,
5
+ OVERRIDE_TARGET_DIAGNOSTIC_FIXTURES,
6
+ catalogWith,
7
+ catalogWithout,
8
+ collectWithCatalogOperations,
9
+ fixtureFacts,
10
+ realCatalogOperations,
11
+ } from './helpers/override-target-diagnostic-fixtures'
12
+
13
+ function codesFor(
14
+ diagnostics: { code: string; domain: string }[],
15
+ domain: string,
16
+ ): string[] {
17
+ return diagnostics.filter((diagnostic) => diagnostic.domain === domain).map((diagnostic) => diagnostic.code)
18
+ }
19
+
20
+ describe('override-target diagnostic wiring — the published code names the real cause', () => {
21
+ it('publishes unknown-framework-mode when the catalog describes the host with an unusable operation', () => {
22
+ const { overrideTargets, overrideTargetDiagnostics } = collectWithCatalogOperations(
23
+ catalogWith('cli', 'merge-deep'),
24
+ fixtureFacts(),
25
+ )
26
+ const cliDiagnostics = overrideTargetDiagnostics.filter((diagnostic) => diagnostic.domain === 'cli')
27
+ expect(cliDiagnostics.map((diagnostic) => diagnostic.code)).toEqual(['unknown-framework-mode'])
28
+ expect(cliDiagnostics[0]).toEqual({
29
+ code: 'unknown-framework-mode',
30
+ moduleId: FIXTURE_MODULE_ID,
31
+ domain: 'cli',
32
+ candidatePath: ['cli', 'fixture:seed'],
33
+ source: { sourcePath: `${FIXTURE_SOURCE_ROOT}/cli.ts` },
34
+ })
35
+ expect(overrideTargets.some((target) => target.domain === 'cli')).toBe(false)
36
+ })
37
+
38
+ it('publishes unknown-framework-domain when the catalog does not describe the host at all', () => {
39
+ const { overrideTargets, overrideTargetDiagnostics } = collectWithCatalogOperations(
40
+ catalogWithout('cli'),
41
+ fixtureFacts(),
42
+ )
43
+ expect(codesFor(overrideTargetDiagnostics, 'cli')).toEqual(['unknown-framework-domain'])
44
+ expect(overrideTargets.some((target) => target.domain === 'cli')).toBe(false)
45
+ })
46
+
47
+ it('never collapses the two causes: one run emits a distinct code per failing domain', () => {
48
+ const operations = catalogWithout('cli')
49
+ operations.workers = 'merge-deep'
50
+ const { overrideTargetDiagnostics } = collectWithCatalogOperations(
51
+ operations,
52
+ fixtureFacts({
53
+ ownedContracts: {
54
+ worker: [
55
+ {
56
+ kind: 'worker',
57
+ id: 'fixture.worker',
58
+ source: { sourcePath: `${FIXTURE_SOURCE_ROOT}/workers/fixture.ts`, line: 1 },
59
+ },
60
+ ],
61
+ },
62
+ }),
63
+ )
64
+ expect(codesFor(overrideTargetDiagnostics, 'cli')).toEqual(['unknown-framework-domain'])
65
+ expect(codesFor(overrideTargetDiagnostics, 'workers')).toEqual(['unknown-framework-mode'])
66
+ expect(new Set(overrideTargetDiagnostics.map((diagnostic) => diagnostic.code)).size).toBe(2)
67
+ })
68
+
69
+ it('emits the target and no diagnostic when the real catalog describes the host', () => {
70
+ const stubbed = collectWithCatalogOperations(realCatalogOperations(), fixtureFacts())
71
+ const direct = collectModuleOverrideTargets(fixtureFacts())
72
+ expect(stubbed).toEqual(direct)
73
+ expect(direct.overrideTargetDiagnostics).toEqual([])
74
+ expect(direct.overrideTargets.map((target) => target.path)).toEqual([['cli', 'fixture:seed']])
75
+ expect(direct.overrideTargets[0].modes).toEqual(['disable-replace'])
76
+ })
77
+ })
78
+
79
+ describe('every negative-fixture diagnostic code is produced by a real fixture', () => {
80
+ it.each(OVERRIDE_TARGET_DIAGNOSTIC_FIXTURES.map((fixture) => [fixture.code, fixture] as const))(
81
+ '%s',
82
+ (code, fixture) => {
83
+ const diagnostics = fixture.run()
84
+ expect(diagnostics.map((diagnostic) => diagnostic.code)).toContain(code)
85
+ },
86
+ )
87
+
88
+ it('covers each code with exactly one fixture', () => {
89
+ const codes = OVERRIDE_TARGET_DIAGNOSTIC_FIXTURES.map((fixture) => fixture.code)
90
+ expect(new Set(codes).size).toBe(codes.length)
91
+ })
92
+ })
@@ -0,0 +1,149 @@
1
+ import {
2
+ applyApiOverridesToManifests,
3
+ applyDiOverrides,
4
+ applyDiOverridesToContainer,
5
+ applyInjectionWidgetOverridesToEntries,
6
+ applyPageGuardOverridesToEntries,
7
+ applyPageOverridesToManifests,
8
+ applyWorkerOverridesToDescriptors,
9
+ resetModuleContractOverridesForTests,
10
+ } from '@open-mercato/shared/modules/overrides'
11
+ import type { ModuleFactsJsonEntry } from '../module-facts'
12
+ import { collectModuleOverrideTargets, type ModuleOverrideTarget } from '../module-override-targets'
13
+
14
+ const SOURCE_ROOT = 'node_modules/@open-mercato/core/src/modules/demo'
15
+
16
+ function facts(): ModuleFactsJsonEntry {
17
+ return {
18
+ title: null, description: null, coreVersion: null, sourcePackage: '@open-mercato/core',
19
+ sourceVersion: null, sourceRoot: SOURCE_ROOT,
20
+ entities: [], events: [], aclFeatures: ['demo.view'],
21
+ apiRoutes: [{ path: '/demo/items', methods: ['GET', 'POST'], auth: {}, sourcePath: `${SOURCE_ROOT}/api/items/route.ts` }],
22
+ diTokens: ['demoService'], searchEntities: [], hostTokens: { entityIds: [], tableIds: [] },
23
+ notifications: [], cli: [], backendPages: [{ path: '/backend/demo/list', sourcePath: `${SOURCE_ROOT}/backend/demo/list/page.tsx` }],
24
+ frontendPages: [{ path: '/demo-portal', sourcePath: `${SOURCE_ROOT}/frontend/demo-portal/page.tsx` }],
25
+ cliCommands: [], aiTools: [], aiAgents: [],
26
+ factSources: [{ kind: 'acl-feature', id: 'demo.view', source: { sourcePath: `${SOURCE_ROOT}/acl.ts` } }],
27
+ ownedContracts: {
28
+ worker: [{ kind: 'worker', id: 'demo.worker', source: { sourcePath: `${SOURCE_ROOT}/workers/demo.ts`, line: 3 }, metadata: { queue: 'demo', concurrency: 1 } }],
29
+ 'page-middleware': [{ kind: 'page-middleware', id: 'demo.guard', source: { sourcePath: `${SOURCE_ROOT}/backend/middleware.ts`, line: 2 }, metadata: { surface: 'backend' } }],
30
+ 'di-registration': [{ kind: 'di-registration', id: 'demoService', source: { sourcePath: `${SOURCE_ROOT}/di.ts`, line: 5 }, metadata: { registrationKind: 'class' } }],
31
+ },
32
+ extensionSurfaces: {
33
+ hosts: [], unresolved: [],
34
+ contributions: [
35
+ { id: 'demo.widget@profile:demo:slot', kind: 'widget', targets: [], scopeContract: '', source: { path: `${SOURCE_ROOT}/widgets/injection-table.ts`, symbol: 'injectionTable' }, details: { payload: 'render', registryKey: 'demo.widget', executionGuard: 'host' } },
36
+ { id: 'demo.mutation-guard', kind: 'mutation-guard', targets: [], scopeContract: '', source: { path: `${SOURCE_ROOT}/data/guards.ts`, symbol: 'demo.mutation-guard' }, details: { entityId: 'demo.entity', operations: ['create'], capabilities: ['block'], optimisticLock: 'preserved' } },
37
+ ],
38
+ },
39
+ }
40
+ }
41
+
42
+ const TARGETS = collectModuleOverrideTargets(facts()).overrideTargets
43
+ function key(domain: string, pathTail: string): string {
44
+ const target = TARGETS.find((t: ModuleOverrideTarget) => t.domain === domain && t.path[t.path.length - 1] === pathTail)
45
+ if (!target || target.key === undefined) throw new Error(`[internal] no keyed ${domain} target for ${pathTail}`)
46
+ return target.key
47
+ }
48
+
49
+ afterEach(() => resetModuleContractOverridesForTests())
50
+
51
+ describe('runtime resolver round-trip — positive', () => {
52
+ it('selects the intended API route method by the generated public key', () => {
53
+ const getKey = key('routes', 'GET /api/demo/items')
54
+ const routes = [{ moduleId: 'demo', path: '/demo/items', methods: ['GET', 'POST'], load: async () => ({}) }]
55
+ const result = applyApiOverridesToManifests(routes as never, { [getKey]: null })
56
+ expect(result).toHaveLength(1)
57
+ expect(result[0].methods).toEqual(['POST'])
58
+ })
59
+
60
+ it('selects the intended backend and frontend page by the generated application-route key', () => {
61
+ const backendKey = key('routes', 'backend:/backend/demo/list')
62
+ const frontendKey = key('routes', 'frontend:/demo-portal')
63
+ const backend = applyPageOverridesToManifests([{ moduleId: 'demo', path: '/backend/demo/list', load: async () => ({}) }] as never, { [backendKey]: null }, 'backend')
64
+ const frontend = applyPageOverridesToManifests([{ moduleId: 'demo', path: '/demo-portal', load: async () => ({}) }] as never, { [frontendKey]: null }, 'frontend')
65
+ expect(backend).toHaveLength(0)
66
+ expect(frontend).toHaveLength(0)
67
+ })
68
+
69
+ it('selects the intended worker / injection widget / page middleware by exact key', () => {
70
+ const workers = applyWorkerOverridesToDescriptors(
71
+ [{ id: 'demo.worker', queue: 'demo', concurrency: 1, handler: () => undefined }],
72
+ { [key('workers', 'demo.worker')]: null },
73
+ )
74
+ expect(workers).toHaveLength(0)
75
+
76
+ const widgets = applyInjectionWidgetOverridesToEntries(
77
+ [{ moduleId: 'demo', key: 'demo.widget', loader: async () => ({}) }] as never,
78
+ { [key('widgets', 'demo.widget')]: null },
79
+ )
80
+ expect(widgets).toHaveLength(0)
81
+
82
+ const guards = applyPageGuardOverridesToEntries(
83
+ [{ moduleId: 'demo', middleware: [{ id: 'demo.guard', run: async () => undefined }] }] as never,
84
+ { [key('guards', 'demo.guard')]: null },
85
+ )
86
+ expect(guards[0].middleware).toHaveLength(0)
87
+ })
88
+
89
+ it('unregisters the exact DI token via the generated key', () => {
90
+ const unregistered: string[] = []
91
+ const container = {
92
+ register: () => container,
93
+ unregister: (name: string) => { unregistered.push(name); return container },
94
+ registrations: { demoService: {} as unknown },
95
+ }
96
+ applyDiOverrides({ [key('di', 'demoService')]: null })
97
+ applyDiOverridesToContainer(container)
98
+ expect(unregistered).toEqual(['demoService'])
99
+ })
100
+ })
101
+
102
+ describe('runtime resolver round-trip — negative (malformed variants do not select)', () => {
103
+ it('a lowercased / method-less API key does not select the manifest entry', () => {
104
+ const getKey = key('routes', 'GET /api/demo/items')
105
+ expect(getKey).toMatch(/^(GET|POST|PUT|PATCH|DELETE) \/api\//)
106
+ const routes = [{ moduleId: 'demo', path: '/demo/items', methods: ['GET', 'POST'], load: async () => ({}) }]
107
+ const lowercased = applyApiOverridesToManifests(routes as never, { 'get /api/demo/items': null })
108
+ expect(lowercased[0].methods).toEqual(['GET', 'POST'])
109
+ const methodless = applyApiOverridesToManifests(routes as never, { '/api/demo/items': null })
110
+ expect(methodless[0].methods).toEqual(['GET', 'POST'])
111
+ })
112
+
113
+ it('a UI filesystem path does not select a page; the generated application route does', () => {
114
+ const filesystemPath = `${SOURCE_ROOT}/backend/demo/list/page.tsx`
115
+ const wrong = applyPageOverridesToManifests([{ moduleId: 'demo', path: '/backend/demo/list', load: async () => ({}) }] as never, { [filesystemPath]: null }, 'backend')
116
+ expect(wrong).toHaveLength(1)
117
+ const backendKey = key('routes', 'backend:/backend/demo/list')
118
+ expect(backendKey).not.toContain('.tsx')
119
+ expect(backendKey.startsWith('backend:')).toBe(true)
120
+ })
121
+
122
+ it('a flattened nested widget key does not select the injection entry', () => {
123
+ const flattened = applyInjectionWidgetOverridesToEntries(
124
+ [{ moduleId: 'demo', key: 'demo.widget', loader: async () => ({}) }] as never,
125
+ { 'widgets.injection.demo.widget': null },
126
+ )
127
+ expect(flattened).toHaveLength(1)
128
+ })
129
+
130
+ it('a mutation-guard id under page guards does not drop the page middleware', () => {
131
+ const guards = applyPageGuardOverridesToEntries(
132
+ [{ moduleId: 'demo', middleware: [{ id: 'demo.guard', run: async () => undefined }] }] as never,
133
+ { 'demo.mutation-guard': null },
134
+ )
135
+ expect(guards[0].middleware).toHaveLength(1)
136
+ // the mutation guard is never emitted as a guards target
137
+ expect(TARGETS.some((t) => t.domain === 'guards' && t.key === 'demo.mutation-guard')).toBe(false)
138
+ })
139
+
140
+ it('an unknown DI token is never emitted; emitted tokens correspond to real registrations', () => {
141
+ expect(TARGETS.some((t) => t.domain === 'di' && t.key === 'nope')).toBe(false)
142
+ expect(TARGETS.some((t) => t.domain === 'di' && t.key === 'demoService')).toBe(true)
143
+ })
144
+
145
+ it('framework-only nav.groupOrder is never attached to a module target', () => {
146
+ expect(TARGETS.some((t) => t.domain === 'nav')).toBe(false)
147
+ expect(TARGETS.some((t) => JSON.stringify(t.path) === JSON.stringify(['nav', 'groupOrder']))).toBe(false)
148
+ })
149
+ })