@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
@@ -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,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
+ })