@open-mercato/cli 0.6.7-develop.6863.1.61001cf9a8 → 0.6.7

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 (278) hide show
  1. package/.turbo/turbo-build.log +4 -4
  2. package/build.mjs +7 -24
  3. package/dist/agentic/claude-code/hooks/entity-migration-check.ts +88 -32
  4. package/dist/agentic/codex/enforcement-rules.md +16 -2
  5. package/dist/agentic/cursor/hooks/entity-migration-check.mjs +50 -19
  6. package/dist/agentic/cursor/rules/entity-guard.mdc +21 -9
  7. package/dist/agentic/cursor/rules/generated-guard.mdc +5 -3
  8. package/dist/agentic/cursor/rules/open-mercato.mdc +29 -3
  9. package/dist/agentic/guides/cache.md +45 -0
  10. package/dist/agentic/guides/core.md +453 -0
  11. package/dist/agentic/guides/events.md +117 -0
  12. package/dist/agentic/guides/module-facts.json +3833 -115419
  13. package/dist/agentic/guides/module-system.md +127 -12
  14. package/dist/agentic/guides/modules/ai_assistant.md +28 -227
  15. package/dist/agentic/guides/modules/api_docs.md +2 -58
  16. package/dist/agentic/guides/modules/api_keys.md +7 -92
  17. package/dist/agentic/guides/modules/attachments.md +14 -119
  18. package/dist/agentic/guides/modules/audit_logs.md +10 -131
  19. package/dist/agentic/guides/modules/auth.md +33 -276
  20. package/dist/agentic/guides/modules/business_rules.md +14 -149
  21. package/dist/agentic/guides/modules/catalog.md +43 -475
  22. package/dist/agentic/guides/modules/channel_gmail.md +3 -82
  23. package/dist/agentic/guides/modules/channel_imap.md +3 -82
  24. package/dist/agentic/guides/modules/checkout.md +27 -299
  25. package/dist/agentic/guides/modules/communication_channels.md +33 -315
  26. package/dist/agentic/guides/modules/configs.md +8 -104
  27. package/dist/agentic/guides/modules/content.md +2 -57
  28. package/dist/agentic/guides/modules/currencies.md +17 -152
  29. package/dist/agentic/guides/modules/customer_accounts.md +45 -387
  30. package/dist/agentic/guides/modules/customers.md +85 -746
  31. package/dist/agentic/guides/modules/dashboards.md +10 -155
  32. package/dist/agentic/guides/modules/data_sync.md +16 -149
  33. package/dist/agentic/guides/modules/dictionaries.md +12 -107
  34. package/dist/agentic/guides/modules/directory.md +15 -148
  35. package/dist/agentic/guides/modules/entities.md +13 -145
  36. package/dist/agentic/guides/modules/events.md +2 -59
  37. package/dist/agentic/guides/modules/feature_toggles.md +9 -119
  38. package/dist/agentic/guides/modules/gateway_stripe.md +4 -92
  39. package/dist/agentic/guides/modules/generators.md +2 -45
  40. package/dist/agentic/guides/modules/inbox_ops.md +27 -207
  41. package/dist/agentic/guides/modules/integrations.md +16 -146
  42. package/dist/agentic/guides/modules/messages.md +24 -223
  43. package/dist/agentic/guides/modules/notifications.md +8 -96
  44. package/dist/agentic/guides/modules/onboarding.md +6 -77
  45. package/dist/agentic/guides/modules/payment_gateways.md +21 -164
  46. package/dist/agentic/guides/modules/perspectives.md +7 -77
  47. package/dist/agentic/guides/modules/planner.md +18 -136
  48. package/dist/agentic/guides/modules/portal.md +2 -93
  49. package/dist/agentic/guides/modules/progress.md +14 -104
  50. package/dist/agentic/guides/modules/query_index.md +15 -154
  51. package/dist/agentic/guides/modules/record_locks.md +21 -206
  52. package/dist/agentic/guides/modules/resources.md +30 -197
  53. package/dist/agentic/guides/modules/sales.md +84 -678
  54. package/dist/agentic/guides/modules/scheduler.md +14 -133
  55. package/dist/agentic/guides/modules/search.md +6 -170
  56. package/dist/agentic/guides/modules/security.md +35 -294
  57. package/dist/agentic/guides/modules/shipping_carriers.md +18 -134
  58. package/dist/agentic/guides/modules/sso.md +26 -151
  59. package/dist/agentic/guides/modules/staff.md +57 -369
  60. package/dist/agentic/guides/modules/storage_s3.md +5 -95
  61. package/dist/agentic/guides/modules/sync_akeneo.md +3 -85
  62. package/dist/agentic/guides/modules/sync_excel.md +6 -75
  63. package/dist/agentic/guides/modules/system_status_overlays.md +2 -60
  64. package/dist/agentic/guides/modules/translations.md +10 -104
  65. package/dist/agentic/guides/modules/webhooks.md +24 -203
  66. package/dist/agentic/guides/modules/wms.md +46 -441
  67. package/dist/agentic/guides/modules/workflows.md +43 -302
  68. package/dist/agentic/guides/queue.md +53 -0
  69. package/dist/agentic/guides/search.md +115 -0
  70. package/dist/agentic/guides/shared.md +108 -0
  71. package/dist/agentic/guides/ui.md +347 -0
  72. package/dist/agentic/shared/AGENTS.md.template +311 -124
  73. package/dist/agentic/shared/ai/agentic.config.json +0 -2
  74. package/dist/agentic/shared/ai/lessons.md +3 -26
  75. package/dist/agentic/shared/ai/skills/om-auto-continue-pr-loop/SKILL.md +27 -0
  76. package/dist/agentic/shared/ai/skills/om-auto-create-pr-loop/SKILL.md +27 -0
  77. package/dist/agentic/shared/ai/skills/om-auto-review-pr/SKILL.md +0 -4
  78. package/dist/agentic/shared/ai/skills/om-backend-ui-design/SKILL.md +241 -20
  79. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/ui-components.md +260 -0
  80. package/dist/agentic/shared/ai/skills/om-data-model-design/SKILL.md +601 -16
  81. package/dist/agentic/shared/ai/skills/om-data-model-design/references/mikro-orm-cheatsheet.md +146 -0
  82. package/dist/agentic/shared/ai/skills/om-eject-and-customize/SKILL.md +310 -14
  83. package/dist/agentic/shared/ai/skills/om-help/SKILL.md +97 -15
  84. package/dist/agentic/shared/ai/skills/om-help/references/skills-catalog.md +84 -0
  85. package/dist/agentic/shared/ai/skills/om-help/references/workflow-sequences.md +193 -0
  86. package/dist/agentic/shared/ai/skills/om-implement-spec/SKILL.md +152 -33
  87. package/dist/agentic/shared/ai/skills/om-integration-builder/SKILL.md +708 -24
  88. package/dist/agentic/shared/ai/skills/om-integration-builder/STANDALONE.md +34 -0
  89. package/dist/agentic/shared/ai/skills/om-integration-builder/references/adapter-contracts.md +762 -0
  90. package/dist/agentic/shared/ai/skills/om-module-scaffold/SKILL.md +820 -20
  91. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/naming-conventions.md +50 -0
  92. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/navigation-patterns.md +97 -0
  93. package/dist/agentic/shared/ai/skills/om-system-extension/SKILL.md +843 -19
  94. package/dist/agentic/shared/ai/skills/om-system-extension/references/extension-contracts.md +271 -0
  95. package/dist/agentic/shared/ai/skills/om-trim-unused-modules/SKILL.md +63 -15
  96. package/dist/agentic/shared/ai/skills/om-troubleshooter/SKILL.md +467 -16
  97. package/dist/agentic/shared/ai/skills/om-troubleshooter/references/diagnostic-commands.md +101 -0
  98. package/dist/agentic/shared/ai/skills/tiers.json +21 -143
  99. package/dist/agentic/shared/ai/skills/tiers.schema.json +40 -52
  100. package/dist/agentic/shared/ai/specs/README.md +3 -4
  101. package/dist/agentic/shared/ai/specs/SPEC-000-template.md +10 -226
  102. package/dist/agentic/shared/ai/trackers/github.md +4 -108
  103. package/dist/agentic/shared/scripts/install-skills.sh +694 -4
  104. package/dist/bin.js +1 -13
  105. package/dist/bin.js.map +2 -2
  106. package/dist/lib/__integration__/TC-INT-008.spec.js +8 -88
  107. package/dist/lib/__integration__/TC-INT-008.spec.js.map +2 -2
  108. package/dist/lib/agentic-init.js +3 -13
  109. package/dist/lib/agentic-init.js.map +2 -2
  110. package/dist/lib/agentic-setup.js +186 -418
  111. package/dist/lib/agentic-setup.js.map +2 -2
  112. package/dist/lib/generators/extensions/injection-widgets.js +0 -20
  113. package/dist/lib/generators/extensions/injection-widgets.js.map +2 -2
  114. package/dist/lib/generators/module-facts-discovery.js +7 -41
  115. package/dist/lib/generators/module-facts-discovery.js.map +2 -2
  116. package/dist/lib/generators/module-facts.js +45 -1387
  117. package/dist/lib/generators/module-facts.js.map +3 -3
  118. package/dist/lib/generators/module-registry.js +5 -11
  119. package/dist/lib/generators/module-registry.js.map +2 -2
  120. package/dist/lib/resolver.js +0 -2
  121. package/dist/lib/resolver.js.map +2 -2
  122. package/dist/lib/testing/integration.js +0 -5
  123. package/dist/lib/testing/integration.js.map +2 -2
  124. package/dist/mercato.js +1 -23
  125. package/dist/mercato.js.map +2 -2
  126. package/package.json +11 -13
  127. package/src/bin.ts +1 -33
  128. package/src/lib/__integration__/TC-INT-008.spec.ts +9 -107
  129. package/src/lib/__tests__/agentic-init.test.ts +5 -41
  130. package/src/lib/agentic-init.ts +3 -15
  131. package/src/lib/agentic-setup.ts +224 -530
  132. package/src/lib/generators/__tests__/module-facts.bc-guard.test.ts +2 -88
  133. package/src/lib/generators/__tests__/module-facts.customers.fixture.test.ts +0 -1
  134. package/src/lib/generators/__tests__/module-facts.discovery.test.ts +10 -54
  135. package/src/lib/generators/__tests__/module-subset.test.ts +0 -18
  136. package/src/lib/generators/extensions/injection-widgets.ts +0 -51
  137. package/src/lib/generators/module-facts-discovery.ts +7 -58
  138. package/src/lib/generators/module-facts.ts +46 -1851
  139. package/src/lib/generators/module-registry.ts +6 -16
  140. package/src/lib/resolver.ts +0 -3
  141. package/src/lib/testing/__tests__/integration.test.ts +0 -4
  142. package/src/lib/testing/integration.ts +0 -5
  143. package/src/mercato.ts +1 -26
  144. package/dist/agentic/guides/ai-workflows.md +0 -76
  145. package/dist/agentic/guides/architecture.md +0 -107
  146. package/dist/agentic/guides/backend-ui.md +0 -80
  147. package/dist/agentic/guides/contracts.md +0 -92
  148. package/dist/agentic/guides/extensions.md +0 -121
  149. package/dist/agentic/guides/framework-extension-points.md +0 -36
  150. package/dist/agentic/guides/integrations.md +0 -81
  151. package/dist/agentic/guides/modules/design_system.md +0 -102
  152. package/dist/agentic/guides/spec-delivery.md +0 -22
  153. package/dist/agentic/guides/testing-debugging.md +0 -80
  154. package/dist/agentic/guides/upstream/AGENTS.md +0 -298
  155. package/dist/agentic/guides/upstream/BACKWARD_COMPATIBILITY.md +0 -316
  156. package/dist/agentic/guides/upstream/manifest.json +0 -8
  157. package/dist/agentic/shared/ai/harness/README.md +0 -50
  158. package/dist/agentic/shared/ai/harness/RELEASE.md +0 -57
  159. package/dist/agentic/shared/ai/harness/cases.json +0 -13680
  160. package/dist/agentic/shared/ai/harness/cases.schema.json +0 -133
  161. package/dist/agentic/shared/ai/harness/fixtures/index.json +0 -49
  162. package/dist/agentic/shared/ai/harness/fixtures/seeds.json +0 -162
  163. package/dist/agentic/shared/ai/harness/generated-code-review-policy.md +0 -21
  164. package/dist/agentic/shared/ai/harness/generated-code-review-response.schema.json +0 -96
  165. package/dist/agentic/shared/ai/harness/generated-code-review-result.schema.json +0 -172
  166. package/dist/agentic/shared/ai/harness/release-matrix.json +0 -158
  167. package/dist/agentic/shared/ai/harness/release-result.schema.json +0 -219
  168. package/dist/agentic/shared/ai/harness/result.schema.json +0 -76
  169. package/dist/agentic/shared/ai/harness/routing-response.schema.json +0 -12
  170. package/dist/agentic/shared/ai/harness/target-validation-result.schema.json +0 -73
  171. package/dist/agentic/shared/ai/harness/validators.json +0 -78
  172. package/dist/agentic/shared/ai/harness/writable-ast-oracles.mjs +0 -2121
  173. package/dist/agentic/shared/ai/harness/writable-behavior-oracles.mjs +0 -1096
  174. package/dist/agentic/shared/ai/lessons/_template.md +0 -16
  175. package/dist/agentic/shared/ai/review-checklist.md +0 -36
  176. package/dist/agentic/shared/ai/skills/om-auto-implement-spec/SKILL.md +0 -21
  177. package/dist/agentic/shared/ai/skills/om-auto-upgrade-0.6.6-to-0.6.7/SKILL.md +0 -98
  178. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/crud-surfaces.md +0 -16
  179. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/frontend-and-design-system.md +0 -53
  180. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/page-and-navigation.md +0 -13
  181. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/quality-states.md +0 -11
  182. package/dist/agentic/shared/ai/skills/om-build-workflow/SKILL.md +0 -30
  183. package/dist/agentic/shared/ai/skills/om-build-workflow/references/activity-contracts.md +0 -12
  184. package/dist/agentic/shared/ai/skills/om-build-workflow/references/durability-and-progress.md +0 -13
  185. package/dist/agentic/shared/ai/skills/om-build-workflow/references/workflow-design.md +0 -14
  186. package/dist/agentic/shared/ai/skills/om-create-ai-agent/SKILL.md +0 -28
  187. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/attachments-and-overrides.md +0 -12
  188. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/module-agents-and-tools.md +0 -22
  189. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/orchestrator-agents.md +0 -12
  190. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/surface-selector.md +0 -19
  191. package/dist/agentic/shared/ai/skills/om-data-model-design/references/integrity-and-concurrency.md +0 -19
  192. package/dist/agentic/shared/ai/skills/om-data-model-design/references/migration-workflow.md +0 -13
  193. package/dist/agentic/shared/ai/skills/om-data-model-design/references/schema-design.md +0 -14
  194. package/dist/agentic/shared/ai/skills/om-data-model-design/references/sensitive-data.md +0 -10
  195. package/dist/agentic/shared/ai/skills/om-eject-and-customize/references/decision-and-procedure.md +0 -17
  196. package/dist/agentic/shared/ai/skills/om-evolve-harness/SKILL.md +0 -29
  197. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-template.md +0 -100
  198. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-workflow.md +0 -16
  199. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/owner-selection.md +0 -17
  200. package/dist/agentic/shared/ai/skills/om-framework-context/SKILL.md +0 -25
  201. package/dist/agentic/shared/ai/skills/om-framework-context/references/resolver-procedure.md +0 -11
  202. package/dist/agentic/shared/ai/skills/om-framework-context/references/skew-and-escalation.md +0 -13
  203. package/dist/agentic/shared/ai/skills/om-help/references/delivery-workflows.md +0 -18
  204. package/dist/agentic/shared/ai/skills/om-help/references/task-families.md +0 -20
  205. package/dist/agentic/shared/ai/skills/om-implement-spec/references/phases-and-gates.md +0 -33
  206. package/dist/agentic/shared/ai/skills/om-implement-spec/references/planning-and-progress.md +0 -40
  207. package/dist/agentic/shared/ai/skills/om-implement-spec/references/report-templates.md +0 -27
  208. package/dist/agentic/shared/ai/skills/om-implement-spec/references/spec-resolution.md +0 -24
  209. package/dist/agentic/shared/ai/skills/om-integration-builder/references/package-and-activation.md +0 -16
  210. package/dist/agentic/shared/ai/skills/om-integration-builder/references/provider-families.md +0 -14
  211. package/dist/agentic/shared/ai/skills/om-integration-builder/references/security-and-reliability.md +0 -15
  212. package/dist/agentic/shared/ai/skills/om-integration-builder/references/sync-and-files.md +0 -12
  213. package/dist/agentic/shared/ai/skills/om-judge-agent-session/SKILL.md +0 -34
  214. package/dist/agentic/shared/ai/skills/om-judge-agent-session/agents/openai.yaml +0 -4
  215. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/agentic-setup.md +0 -11
  216. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/input-normalization.md +0 -31
  217. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/judge-workflow.md +0 -39
  218. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/report-template.md +0 -43
  219. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/rules.md +0 -11
  220. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/api-and-domain.md +0 -19
  221. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/business-one-shot-blueprints.md +0 -172
  222. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/data-and-migrations.md +0 -12
  223. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/discovery-surface-catalog.md +0 -83
  224. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/module-surfaces.md +0 -21
  225. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/planning.md +0 -11
  226. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/runtime-cache-and-queues.md +0 -22
  227. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/verification.md +0 -13
  228. package/dist/agentic/shared/ai/skills/om-share-this-session/SKILL.md +0 -41
  229. package/dist/agentic/shared/ai/skills/om-share-this-session/references/agentic-setup.md +0 -19
  230. package/dist/agentic/shared/ai/skills/om-share-this-session/references/bundle-preparation.md +0 -44
  231. package/dist/agentic/shared/ai/skills/om-share-this-session/references/consent-and-review.md +0 -39
  232. package/dist/agentic/shared/ai/skills/om-share-this-session/references/publication.md +0 -20
  233. package/dist/agentic/shared/ai/skills/om-share-this-session/references/report-templates.md +0 -57
  234. package/dist/agentic/shared/ai/skills/om-share-this-session/references/rules.md +0 -11
  235. package/dist/agentic/shared/ai/skills/om-share-this-session/scripts/prepare-share-bundle.mjs +0 -486
  236. package/dist/agentic/shared/ai/skills/om-system-extension/references/extension-branches.md +0 -18
  237. package/dist/agentic/shared/ai/skills/om-system-extension/references/mechanism-selector.md +0 -27
  238. package/dist/agentic/shared/ai/skills/om-system-extension/references/read-write-roundtrip.md +0 -13
  239. package/dist/agentic/shared/ai/skills/om-system-extension/references/unified-overrides.md +0 -41
  240. package/dist/agentic/shared/ai/skills/om-system-extension/references/verification.md +0 -11
  241. package/dist/agentic/shared/ai/skills/om-trim-unused-modules/references/dependency-and-redirect.md +0 -15
  242. package/dist/agentic/shared/ai/skills/om-troubleshooter/references/diagnosis-map.md +0 -16
  243. package/dist/agentic/shared/ai/skills/om-troubleshooter/references/regression-oracles.md +0 -14
  244. package/dist/agentic/shared/scripts/agent-harness-tool-server.mjs +0 -187
  245. package/dist/agentic/shared/scripts/check-lessons.mjs +0 -178
  246. package/dist/agentic/shared/scripts/evaluate-agent-harness.mjs +0 -2958
  247. package/dist/agentic/shared/scripts/execution-sandbox.mjs +0 -329
  248. package/dist/agentic/shared/scripts/framework-context.mjs +0 -888
  249. package/dist/agentic/shared/scripts/install-skills.mjs +0 -1029
  250. package/dist/agentic/shared/scripts/prepare-agent-harness-fixture.mjs +0 -222
  251. package/dist/agentic/shared/scripts/run-agent-harness-release.mjs +0 -1774
  252. package/dist/lib/generators/module-extension-facts.js +0 -1840
  253. package/dist/lib/generators/module-extension-facts.js.map +0 -7
  254. package/dist/lib/generators/module-fact-sources.js +0 -70
  255. package/dist/lib/generators/module-fact-sources.js.map +0 -7
  256. package/dist/lib/generators/module-override-targets.js +0 -688
  257. package/dist/lib/generators/module-override-targets.js.map +0 -7
  258. package/dist/lib/load-env.js +0 -24
  259. package/dist/lib/load-env.js.map +0 -7
  260. package/dist/lib/telemetry-init.js +0 -358
  261. package/dist/lib/telemetry-init.js.map +0 -7
  262. package/src/lib/__tests__/agentic-setup.ownership.test.ts +0 -386
  263. package/src/lib/__tests__/injection-widget-id-validation.test.ts +0 -184
  264. package/src/lib/__tests__/load-env.test.ts +0 -65
  265. package/src/lib/__tests__/telemetry-init.test.ts +0 -298
  266. package/src/lib/generators/__tests__/activation-adapter-coverage.test.ts +0 -92
  267. package/src/lib/generators/__tests__/module-extension-activations.test.ts +0 -762
  268. package/src/lib/generators/__tests__/module-extension-facts.test.ts +0 -404
  269. package/src/lib/generators/__tests__/module-facts.extension-hosts.test.ts +0 -108
  270. package/src/lib/generators/__tests__/module-facts.owned-contracts.test.ts +0 -561
  271. package/src/lib/generators/__tests__/module-facts.source-links.test.ts +0 -119
  272. package/src/lib/generators/__tests__/module-override-targets.roundtrip.test.ts +0 -149
  273. package/src/lib/generators/__tests__/module-override-targets.test.ts +0 -304
  274. package/src/lib/generators/module-extension-facts.ts +0 -2365
  275. package/src/lib/generators/module-fact-sources.ts +0 -108
  276. package/src/lib/generators/module-override-targets.ts +0 -863
  277. package/src/lib/load-env.ts +0 -30
  278. package/src/lib/telemetry-init.ts +0 -461
@@ -1,888 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import {
4
- closeSync,
5
- constants,
6
- existsSync,
7
- fstatSync,
8
- lstatSync,
9
- mkdirSync,
10
- openSync,
11
- readdirSync,
12
- readFileSync,
13
- realpathSync,
14
- rmSync,
15
- writeFileSync,
16
- } from 'node:fs'
17
- import { createRequire } from 'node:module'
18
- import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from 'node:path'
19
- import { spawnSync } from 'node:child_process'
20
- import { TextDecoder } from 'node:util'
21
-
22
- const workingDirectory = process.cwd()
23
- const workingDirectoryStat = lstatSync(workingDirectory)
24
- if (workingDirectoryStat.isSymbolicLink() || !workingDirectoryStat.isDirectory()) {
25
- throw new Error('app root must be a regular directory, not a symbolic link')
26
- }
27
- const appRoot = realpathSync(workingDirectory)
28
- const requireFromApp = createRequire(join(appRoot, 'package.json'))
29
- const SEARCH_MATCH_LIMIT = 200
30
- const INSTALLED_PACKAGE_SCAN_LIMIT = 1000
31
- const FALLBACK_TREE_ENTRY_LIMIT = 50_000
32
- const FALLBACK_SEARCH_BYTE_LIMIT = 64 * 1024 * 1024
33
- const MATERIALIZATION_ENTRY_LIMIT = 10_000
34
- const MATERIALIZATION_FILE_BYTE_LIMIT = 8 * 1024 * 1024
35
- const MATERIALIZATION_TOTAL_BYTE_LIMIT = 64 * 1024 * 1024
36
- const MATERIALIZATION_TEXT_EXTENSIONS = new Set([
37
- '.cjs', '.conf', '.css', '.csv', '.cts', '.graphql', '.html', '.ini', '.js', '.json',
38
- '.jsx', '.less', '.md', '.mdx', '.mjs', '.mts', '.prisma', '.sass', '.scss', '.sql',
39
- '.svg', '.toml', '.ts', '.tsx', '.txt', '.xml', '.yaml', '.yml',
40
- ])
41
- const MATERIALIZATION_DENIED_DIRECTORIES = new Set([
42
- '.aws', '.azure', '.git', '.gnupg', '.ssh', 'node_modules',
43
- ])
44
- const MATERIALIZATION_DENIED_FILES = new Set([
45
- '.netrc', '.npmrc', '.pypirc', '.yarnrc', '.yarnrc.yml',
46
- 'auth.json', 'credentials', 'credentials.json', 'id_dsa', 'id_ecdsa', 'id_ed25519',
47
- 'id_rsa', 'secret.json', 'secrets.json', 'secrets.yaml', 'secrets.yml',
48
- 'service-account.json',
49
- ])
50
- const MATERIALIZATION_DENIED_EXTENSIONS = new Set([
51
- '.jks', '.key', '.keystore', '.p12', '.p8', '.pem', '.pfx',
52
- ])
53
- const utf8Decoder = new TextDecoder('utf-8', { fatal: true })
54
-
55
- function fail(message) {
56
- console.error(`framework-context: ${message}`)
57
- process.exitCode = 2
58
- }
59
-
60
- function parseArgs(argv) {
61
- const args = { json: false, materialize: true }
62
- for (let index = 0; index < argv.length; index += 1) {
63
- const value = argv[index]
64
- if (value === '--json') args.json = true
65
- else if (value === '--no-materialize') args.materialize = false
66
- else if (value === '--root') args.root = true
67
- else if (value === '--module') args.module = argv[++index]
68
- else if (value.startsWith('--module=')) args.module = value.slice(9)
69
- else if (value === '--package') args.package = argv[++index]
70
- else if (value.startsWith('--package=')) args.package = value.slice(10)
71
- else if (value === '--query') args.query = argv[++index]
72
- else if (value.startsWith('--query=')) args.query = value.slice(8)
73
- else if (value === '--help' || value === '-h') args.help = true
74
- else throw new Error(`unknown argument: ${value}`)
75
- }
76
- return args
77
- }
78
-
79
- function assertToken(value, label, pattern) {
80
- if (typeof value !== 'string' || !pattern.test(value)) {
81
- throw new Error(`invalid ${label}: ${String(value)}`)
82
- }
83
- return value
84
- }
85
-
86
- function readJson(path) {
87
- return JSON.parse(readFileSync(path, 'utf8'))
88
- }
89
-
90
- function parseModuleEntries() {
91
- const modulesPath = join(appRoot, 'src', 'modules.ts')
92
- if (!existsSync(modulesPath)) return []
93
- const source = readFileSync(modulesPath, 'utf8')
94
- const entries = []
95
- const objectPattern = /\{[\s\S]*?\bid\s*:\s*['"]([^'"]+)['"][\s\S]*?\bfrom\s*:\s*['"]([^'"]+)['"][\s\S]*?\}/g
96
- for (const match of source.matchAll(objectPattern)) {
97
- entries.push({ id: match[1], from: match[2] })
98
- }
99
- return entries
100
- }
101
-
102
- function findPackageRoot(packageName) {
103
- const attempts = [`${packageName}/package.json`, packageName]
104
- for (const request of attempts) {
105
- try {
106
- let resolvedPath = requireFromApp.resolve(request)
107
- if (basename(resolvedPath) === 'package.json') return realpathSync(dirname(resolvedPath))
108
- let cursor = dirname(realpathSync(resolvedPath))
109
- while (cursor !== dirname(cursor)) {
110
- const manifestPath = join(cursor, 'package.json')
111
- if (existsSync(manifestPath)) {
112
- const manifest = readJson(manifestPath)
113
- if (manifest.name === packageName) return realpathSync(cursor)
114
- }
115
- cursor = dirname(cursor)
116
- }
117
- } catch {
118
- // Package export maps commonly hide package.json; try the entry point next.
119
- }
120
- }
121
- return null
122
- }
123
-
124
- function assertInside(root, candidate, label) {
125
- const delta = relative(root, candidate)
126
- if (delta === '' || (!delta.startsWith(`..${sep}`) && delta !== '..' && !isAbsolute(delta))) return candidate
127
- throw new Error(`${label} escapes ${root}`)
128
- }
129
-
130
- function assertStrictlyInside(root, candidate, label) {
131
- const delta = relative(root, candidate)
132
- if (delta !== '' && !delta.startsWith(`..${sep}`) && delta !== '..' && !isAbsolute(delta)) return candidate
133
- throw new Error(`${label} escapes ${root}`)
134
- }
135
-
136
- function lstatIfPresent(candidate) {
137
- try {
138
- return lstatSync(candidate)
139
- } catch (error) {
140
- if (error?.code === 'ENOENT') return null
141
- throw error
142
- }
143
- }
144
-
145
- function assertRegularDirectory(root, candidate, label) {
146
- const lexical = resolve(candidate)
147
- assertInside(root, lexical, label)
148
- const stat = lstatIfPresent(lexical)
149
- if (!stat) return false
150
- if (stat.isSymbolicLink()) throw new Error(`${label} must not be a symbolic link`)
151
- if (!stat.isDirectory()) throw new Error(`${label} must be a directory`)
152
- assertInside(root, realpathSync(lexical), label)
153
- return true
154
- }
155
-
156
- function ensureDirectoryChain(root, candidate, label) {
157
- const lexical = resolve(candidate)
158
- assertInside(root, lexical, label)
159
- if (!assertRegularDirectory(root, root, 'app root')) throw new Error('app root is unavailable')
160
- const delta = relative(root, lexical)
161
- if (!delta) return
162
-
163
- let cursor = root
164
- for (const component of delta.split(sep).filter(Boolean)) {
165
- cursor = join(cursor, component)
166
- if (assertRegularDirectory(root, cursor, `${label} parent`)) continue
167
- try {
168
- mkdirSync(cursor, { mode: 0o755 })
169
- } catch (error) {
170
- if (error?.code !== 'EEXIST') throw error
171
- }
172
- if (!assertRegularDirectory(root, cursor, `${label} parent`)) {
173
- throw new Error(`failed to create ${label} parent`)
174
- }
175
- }
176
- }
177
-
178
- function writeContextFile(destination, content) {
179
- const parent = dirname(destination)
180
- ensureDirectoryChain(appRoot, parent, 'context output')
181
- assertStrictlyInside(appRoot, resolve(destination), 'context output')
182
- const flags = constants.O_CREAT
183
- | constants.O_EXCL
184
- | constants.O_WRONLY
185
- | (constants.O_NOFOLLOW ?? 0)
186
- let descriptor
187
- try {
188
- descriptor = openSync(destination, flags, 0o644)
189
- writeFileSync(descriptor, content)
190
- } catch (error) {
191
- if (error?.code === 'EEXIST' || error?.code === 'ELOOP') {
192
- throw new Error(`context output already exists: ${relative(appRoot, destination)}`)
193
- }
194
- throw error
195
- } finally {
196
- if (descriptor !== undefined) closeSync(descriptor)
197
- }
198
- const stat = lstatSync(destination)
199
- if (stat.isSymbolicLink() || !stat.isFile()) throw new Error('context output is not a regular file')
200
- assertInside(appRoot, realpathSync(destination), 'context output')
201
- }
202
-
203
- function encodePackageVersion(value) {
204
- if (
205
- typeof value !== 'string'
206
- || value.length === 0
207
- || value.length > 128
208
- || !/^[0-9A-Za-z][0-9A-Za-z._+-]*$/.test(value)
209
- ) {
210
- throw new Error(`invalid package version: ${String(value)}`)
211
- }
212
- return encodeURIComponent(value)
213
- }
214
-
215
- function candidatePackages(moduleId) {
216
- const declared = parseModuleEntries().filter((entry) => entry.id === moduleId)
217
- if (declared.length > 0) {
218
- const providers = [...new Set(declared.map((entry) => entry.from))].sort()
219
- if (declared.length > 1 && providers.length === 1) {
220
- throw new Error(`module ${moduleId} is declared ${declared.length} times for ${providers[0]}`)
221
- }
222
- return providers
223
- }
224
-
225
- const appManifest = readJson(join(appRoot, 'package.json'))
226
- const names = Object.keys({ ...appManifest.dependencies, ...appManifest.devDependencies })
227
- .filter((name) => name.startsWith('@open-mercato/'))
228
- return names.filter((name) => {
229
- const root = findPackageRoot(name)
230
- return root && (
231
- existsSync(join(root, 'src', 'modules', moduleId))
232
- || existsSync(join(root, 'dist', 'modules', moduleId))
233
- )
234
- })
235
- }
236
-
237
- function nearestAgentsFiles(packageRoot, sourceRoot) {
238
- const files = []
239
- const packageAgents = join(packageRoot, 'AGENTS.md')
240
- if (existsSync(packageAgents)) files.push(packageAgents)
241
- if (!sourceRoot) return files
242
-
243
- let cursor = sourceRoot
244
- const nested = []
245
- while (cursor.startsWith(packageRoot)) {
246
- const candidate = join(cursor, 'AGENTS.md')
247
- if (existsSync(candidate) && candidate !== packageAgents) nested.unshift(candidate)
248
- if (cursor === packageRoot) break
249
- cursor = dirname(cursor)
250
- }
251
- files.push(...nested)
252
- return [...new Set(files)]
253
- }
254
-
255
- function deniedMaterializationPath(relativePath, directory) {
256
- const components = relativePath.split(sep).filter(Boolean).map((component) => component.toLowerCase())
257
- if (components.some((component) => MATERIALIZATION_DENIED_DIRECTORIES.has(component))) return true
258
- if (directory || components.length === 0) return false
259
- const filename = components.at(-1)
260
- if (filename === '.env' || filename.startsWith('.env.')) return true
261
- if (MATERIALIZATION_DENIED_FILES.has(filename)) return true
262
- return MATERIALIZATION_DENIED_EXTENSIONS.has(extname(filename))
263
- }
264
-
265
- function readMaterializationText(source, relativePath, state) {
266
- let descriptor
267
- try {
268
- descriptor = openSync(source, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0))
269
- const stat = fstatSync(descriptor)
270
- if (!stat.isFile()) throw new Error(`context source contains a non-regular file: ${relativePath}`)
271
- if (stat.size > MATERIALIZATION_FILE_BYTE_LIMIT) {
272
- throw new Error(`context source file exceeds ${MATERIALIZATION_FILE_BYTE_LIMIT} byte limit: ${relativePath}`)
273
- }
274
- if (state.copiedBytes + stat.size > MATERIALIZATION_TOTAL_BYTE_LIMIT) {
275
- throw new Error(`context source exceeds ${MATERIALIZATION_TOTAL_BYTE_LIMIT} materialized bytes`)
276
- }
277
- const content = readFileSync(descriptor)
278
- if (content.includes(0)) return null
279
- try {
280
- utf8Decoder.decode(content)
281
- } catch {
282
- return null
283
- }
284
- if (/-----BEGIN (?:[A-Z0-9]+ )?PRIVATE KEY-----/.test(content.toString('utf8'))) return null
285
- return content
286
- } finally {
287
- if (descriptor !== undefined) closeSync(descriptor)
288
- }
289
- }
290
-
291
- function copyContextFile(source, destination) {
292
- ensureDirectoryChain(appRoot, dirname(destination), 'context output')
293
- assertStrictlyInside(appRoot, resolve(destination), 'context output')
294
- if (lstatIfPresent(destination)) throw new Error(`context output already exists: ${relative(appRoot, destination)}`)
295
-
296
- const sourceRoot = resolve(source)
297
- const rootStat = lstatSync(sourceRoot)
298
- if (rootStat.isSymbolicLink()) throw new Error('context source must not be a symbolic link')
299
- const state = { entriesVisited: 0, copiedFiles: 0, copiedBytes: 0, omittedEntries: 0 }
300
-
301
- function copyEntry(candidate, target, relativePath, root = false) {
302
- state.entriesVisited += 1
303
- if (state.entriesVisited > MATERIALIZATION_ENTRY_LIMIT) {
304
- throw new Error(`context source exceeded ${MATERIALIZATION_ENTRY_LIMIT} filesystem entries`)
305
- }
306
-
307
- const stat = lstatSync(candidate)
308
- if (stat.isSymbolicLink()) {
309
- if (root) throw new Error('context source must not be a symbolic link')
310
- state.omittedEntries += 1
311
- return
312
- }
313
- if (stat.isDirectory()) {
314
- if (!root && deniedMaterializationPath(relativePath, true)) {
315
- state.omittedEntries += 1
316
- return
317
- }
318
- ensureDirectoryChain(appRoot, target, 'context output')
319
- for (const entry of readdirSync(candidate, { withFileTypes: true })
320
- .sort((left, right) => comparePaths(left.name, right.name))) {
321
- copyEntry(join(candidate, entry.name), join(target, entry.name), join(relativePath, entry.name))
322
- }
323
- return
324
- }
325
- if (!stat.isFile()) throw new Error(`context source contains a special filesystem entry: ${relativePath}`)
326
- if (deniedMaterializationPath(relativePath, false)
327
- || !MATERIALIZATION_TEXT_EXTENSIONS.has(extname(relativePath).toLowerCase())) {
328
- state.omittedEntries += 1
329
- return
330
- }
331
-
332
- const content = readMaterializationText(candidate, relativePath, state)
333
- if (!content) {
334
- state.omittedEntries += 1
335
- return
336
- }
337
- writeContextFile(target, content)
338
- state.copiedFiles += 1
339
- state.copiedBytes += content.byteLength
340
- }
341
-
342
- copyEntry(sourceRoot, destination, basename(sourceRoot), true)
343
- if (rootStat.isFile() && state.copiedFiles !== 1) {
344
- throw new Error(`context source is not an allowed regular text file: ${basename(sourceRoot)}`)
345
- }
346
- const stat = lstatSync(destination)
347
- if (stat.isSymbolicLink()) throw new Error('context output must not be a symbolic link')
348
- assertInside(appRoot, realpathSync(destination), 'context output')
349
- return state
350
- }
351
-
352
- function runRg(args, label, maxBuffer = 4 * 1024 * 1024) {
353
- const result = spawnSync('rg', args, {
354
- cwd: appRoot,
355
- encoding: 'utf8',
356
- maxBuffer,
357
- })
358
- if (result.error?.code === 'ENOENT') return null
359
- if (result.error) throw new Error(`${label}: ${result.error.message}`)
360
- if (result.status !== 0 && result.status !== 1) {
361
- const detail = (result.stderr || result.stdout || '').trim()
362
- throw new Error(`${label} (exit ${String(result.status)}): ${detail || 'unknown rg error'}`)
363
- }
364
- return result
365
- }
366
-
367
- function nulDelimitedPaths(output) {
368
- return output.split('\0').filter(Boolean)
369
- }
370
-
371
- function regularFileStrictlyBelow(root, candidate, label) {
372
- const lexicalRoot = resolve(root)
373
- const lexical = resolve(candidate)
374
- const canonicalRoot = realpathSync(lexicalRoot)
375
- try {
376
- assertStrictlyInside(lexicalRoot, lexical, label)
377
- } catch {
378
- assertStrictlyInside(canonicalRoot, lexical, label)
379
- }
380
- const stat = lstatIfPresent(lexical)
381
- if (!stat || stat.isSymbolicLink() || !stat.isFile()) {
382
- throw new Error(`${label} must be a regular non-symbolic file below ${lexicalRoot}`)
383
- }
384
- const canonical = realpathSync(lexical)
385
- assertStrictlyInside(canonicalRoot, canonical, label)
386
- return canonical
387
- }
388
-
389
- function comparePaths(left, right) {
390
- return left < right ? -1 : left > right ? 1 : 0
391
- }
392
-
393
- function fallbackRegularFiles(root, label) {
394
- const scanRoot = realpathSync(root)
395
- const pending = [scanRoot]
396
- const files = []
397
- let entriesVisited = 0
398
-
399
- while (pending.length > 0) {
400
- const directory = pending.pop()
401
- const entries = readdirSync(directory, { withFileTypes: true })
402
- .sort((left, right) => comparePaths(left.name, right.name))
403
- for (const entry of entries) {
404
- entriesVisited += 1
405
- if (entriesVisited > FALLBACK_TREE_ENTRY_LIMIT) {
406
- throw new Error(`${label} exceeded ${FALLBACK_TREE_ENTRY_LIMIT} filesystem entries`)
407
- }
408
- const candidate = join(directory, entry.name)
409
- const stat = lstatSync(candidate)
410
- if (stat.isSymbolicLink()) continue
411
- if (stat.isDirectory()) {
412
- assertInside(scanRoot, realpathSync(candidate), label)
413
- pending.push(candidate)
414
- } else if (stat.isFile()) {
415
- assertInside(scanRoot, realpathSync(candidate), label)
416
- files.push(candidate)
417
- }
418
- }
419
- }
420
-
421
- return files.sort(comparePaths)
422
- }
423
-
424
- function fallbackInstalledPackageManifests(nodeModulesRoot) {
425
- const scanRoot = realpathSync(nodeModulesRoot)
426
- const manifests = []
427
- const pendingNodeModules = [scanRoot]
428
- const visitedNodeModules = new Set()
429
- let entriesVisited = 0
430
-
431
- function boundedDirectories(directory) {
432
- const directories = []
433
- for (const entry of readdirSync(directory, { withFileTypes: true })
434
- .sort((left, right) => comparePaths(left.name, right.name))) {
435
- entriesVisited += 1
436
- if (entriesVisited > FALLBACK_TREE_ENTRY_LIMIT) {
437
- throw new Error(`installed package scan failed exceeded ${FALLBACK_TREE_ENTRY_LIMIT} filesystem entries`)
438
- }
439
- const candidate = join(directory, entry.name)
440
- const stat = lstatSync(candidate)
441
- if (stat.isSymbolicLink() || !stat.isDirectory()) continue
442
- assertInside(scanRoot, realpathSync(candidate), 'installed package scan failed')
443
- directories.push(candidate)
444
- }
445
- return directories
446
- }
447
-
448
- function enqueueNodeModules(candidate) {
449
- const stat = lstatIfPresent(candidate)
450
- if (!stat || stat.isSymbolicLink() || !stat.isDirectory()) return
451
- const canonical = realpathSync(candidate)
452
- assertInside(scanRoot, canonical, 'installed package scan failed')
453
- if (!visitedNodeModules.has(canonical)) pendingNodeModules.push(canonical)
454
- }
455
-
456
- function inspectPackageRoot(packageRoot, isOpenMercato) {
457
- if (isOpenMercato) {
458
- const manifest = join(packageRoot, 'package.json')
459
- const stat = lstatIfPresent(manifest)
460
- if (stat?.isFile() && !stat.isSymbolicLink()) {
461
- assertInside(scanRoot, realpathSync(manifest), 'installed package scan failed')
462
- manifests.push(manifest)
463
- if (manifests.length > INSTALLED_PACKAGE_SCAN_LIMIT) {
464
- throw new Error(`installed package scan exceeded ${INSTALLED_PACKAGE_SCAN_LIMIT} manifests`)
465
- }
466
- }
467
- }
468
- enqueueNodeModules(join(packageRoot, 'node_modules'))
469
- }
470
-
471
- while (pendingNodeModules.length > 0) {
472
- pendingNodeModules.sort(comparePaths)
473
- const directory = pendingNodeModules.shift()
474
- if (visitedNodeModules.has(directory)) continue
475
- visitedNodeModules.add(directory)
476
-
477
- for (const entryPath of boundedDirectories(directory)) {
478
- const entryName = basename(entryPath)
479
- if (entryName === '.pnpm') {
480
- for (const pnpmPackage of boundedDirectories(entryPath)) {
481
- enqueueNodeModules(join(pnpmPackage, 'node_modules'))
482
- }
483
- } else if (entryName.startsWith('@')) {
484
- for (const packageRoot of boundedDirectories(entryPath)) {
485
- inspectPackageRoot(packageRoot, entryName === '@open-mercato')
486
- }
487
- } else if (!entryName.startsWith('.')) {
488
- inspectPackageRoot(entryPath, false)
489
- }
490
- }
491
- }
492
-
493
- return manifests.sort(comparePaths)
494
- }
495
-
496
- function fallbackBoundedSearch(query, sourceRoot) {
497
- const matches = []
498
- let bytesRead = 0
499
- for (const file of fallbackRegularFiles(sourceRoot, 'bounded search failed')) {
500
- const size = lstatSync(file).size
501
- if (bytesRead + size > FALLBACK_SEARCH_BYTE_LIMIT) {
502
- throw new Error(`bounded search failed: fallback scan exceeded ${FALLBACK_SEARCH_BYTE_LIMIT} bytes`)
503
- }
504
- bytesRead += size
505
- const content = readFileSync(file)
506
- if (content.includes(0)) continue
507
-
508
- const lines = content.toString('utf8').split(/\r?\n/)
509
- for (let index = 0; index < lines.length; index += 1) {
510
- const line = lines[index]
511
- if (!line.includes(query)) continue
512
- const preview = line.length > 500 ? `${line.slice(0, 500)}…` : line
513
- matches.push(`${file}:${index + 1}:${preview}`)
514
- if (matches.length > SEARCH_MATCH_LIMIT) break
515
- }
516
- if (matches.length > SEARCH_MATCH_LIMIT) break
517
- }
518
-
519
- const truncated = matches.length > SEARCH_MATCH_LIMIT
520
- const boundedMatches = matches.slice(0, SEARCH_MATCH_LIMIT)
521
- return {
522
- output: boundedMatches.length > 0 ? `${boundedMatches.join('\n')}\n` : '',
523
- matches: boundedMatches.length,
524
- truncated,
525
- status: boundedMatches.length > 0 ? 'matched' : 'no-matches',
526
- }
527
- }
528
-
529
- function packageRecord(packageName, packageRoot) {
530
- const manifest = readJson(join(packageRoot, 'package.json'))
531
- if (manifest.name !== packageName) {
532
- throw new Error(`resolved package ${packageName} has manifest name ${String(manifest.name)}`)
533
- }
534
- const version = typeof manifest.version === 'string' ? manifest.version : 'unknown'
535
- encodePackageVersion(version)
536
- return {
537
- name: packageName,
538
- version,
539
- root: packageRoot,
540
- }
541
- }
542
-
543
- function relevantPackageNames(selectedPackage) {
544
- const appManifest = readJson(join(appRoot, 'package.json'))
545
- return [...new Set([
546
- selectedPackage,
547
- ...parseModuleEntries().map((entry) => entry.from),
548
- ...Object.keys({ ...appManifest.dependencies, ...appManifest.devDependencies }),
549
- ].filter((name) => typeof name === 'string' && name.startsWith('@open-mercato/')))].sort()
550
- }
551
-
552
- function installedPackageDiagnostics(selectedPackage, selectedRoot) {
553
- const packageNames = relevantPackageNames(selectedPackage)
554
- const packageNameSet = new Set(packageNames)
555
- const cohort = []
556
- for (const packageName of packageNames) {
557
- const packageRoot = packageName === selectedPackage ? selectedRoot : findPackageRoot(packageName)
558
- if (packageRoot) cohort.push(packageRecord(packageName, packageRoot))
559
- }
560
- cohort.sort((left, right) => left.name.localeCompare(right.name) || left.root.localeCompare(right.root))
561
-
562
- const installations = new Map()
563
- for (const record of cohort) installations.set(`${record.name}\0${record.root}`, record)
564
- const nodeModulesRoot = join(appRoot, 'node_modules')
565
- if (existsSync(nodeModulesRoot)) {
566
- const packageScan = runRg(
567
- [
568
- '--no-ignore',
569
- '--hidden',
570
- '--files',
571
- '--null',
572
- '--sort',
573
- 'path',
574
- '--glob',
575
- '**/@open-mercato/*/package.json',
576
- nodeModulesRoot,
577
- ],
578
- 'installed package scan failed',
579
- )
580
- const manifests = packageScan
581
- ? nulDelimitedPaths(packageScan.stdout)
582
- : fallbackInstalledPackageManifests(nodeModulesRoot)
583
- if (manifests.length > INSTALLED_PACKAGE_SCAN_LIMIT) {
584
- throw new Error(`installed package scan exceeded ${INSTALLED_PACKAGE_SCAN_LIMIT} manifests`)
585
- }
586
- for (const manifestPath of manifests) {
587
- const safeManifestPath = regularFileStrictlyBelow(
588
- nodeModulesRoot,
589
- manifestPath,
590
- 'installed package manifest',
591
- )
592
- const packageName = `@open-mercato/${basename(dirname(safeManifestPath))}`
593
- if (!packageNameSet.has(packageName)) continue
594
- const packageRoot = realpathSync(dirname(safeManifestPath))
595
- const record = packageRecord(packageName, packageRoot)
596
- installations.set(`${record.name}\0${record.root}`, record)
597
- }
598
- }
599
-
600
- const allInstallations = [...installations.values()]
601
- .sort((left, right) => left.name.localeCompare(right.name)
602
- || left.version.localeCompare(right.version)
603
- || left.root.localeCompare(right.root))
604
- const duplicates = []
605
- for (const packageName of packageNames) {
606
- const records = allInstallations.filter((record) => record.name === packageName)
607
- if (records.length > 1) duplicates.push({ name: packageName, installations: records })
608
- }
609
- return { cohort, duplicates }
610
- }
611
-
612
- function displayPackageRecord(record) {
613
- const location = relative(appRoot, record.root).split(sep).join('/') || '.'
614
- return `${record.name}@${record.version} (${location})`
615
- }
616
-
617
- function packageDiagnosticWarnings(diagnostics) {
618
- const warnings = []
619
- const versions = new Set(diagnostics.cohort.map((record) => record.version))
620
- if (versions.size > 1) {
621
- warnings.push(
622
- `Installed Open Mercato package cohort uses mixed versions: ${diagnostics.cohort.map(displayPackageRecord).join(', ')}. Context remains package-specific; do not combine generated facts or source across versions.`,
623
- )
624
- }
625
- for (const duplicate of diagnostics.duplicates) {
626
- const selected = diagnostics.cohort.find((record) => record.name === duplicate.name)
627
- warnings.push(
628
- `Multiple installed copies of ${duplicate.name} were found: ${duplicate.installations.map(displayPackageRecord).join(', ')}.${selected ? ` App resolution selected ${displayPackageRecord(selected)}; no other copy was read.` : ''}`,
629
- )
630
- }
631
- return warnings
632
- }
633
-
634
- function runBoundedSearch(query, sourceRoot) {
635
- const fileSearch = runRg(
636
- ['--no-ignore', '--hidden', '--fixed-strings', '--files-with-matches', '--null', '--sort', 'path', '--', query, sourceRoot],
637
- 'bounded search failed',
638
- )
639
- if (!fileSearch) return fallbackBoundedSearch(query, sourceRoot)
640
- if (fileSearch.status === 1) {
641
- return { output: '', matches: 0, truncated: false, status: 'no-matches' }
642
- }
643
-
644
- const matchingFiles = nulDelimitedPaths(fileSearch.stdout)
645
- .sort()
646
- const matches = []
647
-
648
- for (const file of matchingFiles.slice(0, SEARCH_MATCH_LIMIT + 1)) {
649
- const remaining = SEARCH_MATCH_LIMIT + 1 - matches.length
650
- if (remaining <= 0) break
651
- const safeFile = regularFileStrictlyBelow(sourceRoot, file, 'bounded search candidate')
652
- const search = runRg(
653
- [
654
- '--no-ignore',
655
- '--hidden',
656
- '--fixed-strings',
657
- '--line-number',
658
- '--with-filename',
659
- '--color',
660
- 'never',
661
- '--max-columns',
662
- '500',
663
- '--max-columns-preview',
664
- '--max-count',
665
- String(remaining),
666
- '--',
667
- query,
668
- safeFile,
669
- ],
670
- `bounded search failed for ${safeFile}`,
671
- 512 * 1024,
672
- )
673
- if (!search) return fallbackBoundedSearch(query, sourceRoot)
674
- if (search.status === 0) {
675
- matches.push(...search.stdout.split(/\r?\n/).filter(Boolean))
676
- }
677
- }
678
-
679
- const truncated = matches.length > SEARCH_MATCH_LIMIT
680
- const boundedMatches = matches.slice(0, SEARCH_MATCH_LIMIT)
681
- return {
682
- output: boundedMatches.length > 0 ? `${boundedMatches.join('\n')}\n` : '',
683
- matches: boundedMatches.length,
684
- truncated,
685
- status: boundedMatches.length > 0 ? 'matched' : 'no-matches',
686
- }
687
- }
688
-
689
- function materialize(result, query) {
690
- const safePackage = result.package.name.replace(/^@/, '').replaceAll('/', '-')
691
- const safeVersion = encodePackageVersion(result.package.version)
692
- const contextRoot = resolve(appRoot, '.ai', 'framework-context')
693
- const outputRoot = assertStrictlyInside(
694
- contextRoot,
695
- resolve(contextRoot, `${safePackage}@${safeVersion}`),
696
- 'context output',
697
- )
698
- ensureDirectoryChain(appRoot, contextRoot, 'framework context root')
699
- const existingOutput = lstatIfPresent(outputRoot)
700
- if (existingOutput) {
701
- assertRegularDirectory(appRoot, outputRoot, 'context output')
702
- ensureDirectoryChain(appRoot, contextRoot, 'framework context root')
703
- rmSync(outputRoot, { recursive: true, force: true })
704
- }
705
- ensureDirectoryChain(appRoot, outputRoot, 'context output')
706
-
707
- for (const instruction of result.instructions) {
708
- if (!instruction.path || !existsSync(instruction.path)) continue
709
- const target = join(outputRoot, 'instructions', `${instruction.kind}.md`)
710
- copyContextFile(instruction.path, target)
711
- instruction.materializedPath = relative(appRoot, target)
712
- }
713
-
714
- let materializedSourceRoot
715
- if (result.sourceRoot && existsSync(result.sourceRoot)) {
716
- const sourceTarget = join(outputRoot, 'source', result.module ?? 'package')
717
- const materialization = copyContextFile(result.sourceRoot, sourceTarget)
718
- materializedSourceRoot = sourceTarget
719
- result.materializedSource = relative(appRoot, sourceTarget)
720
- if (materialization.omittedEntries > 0) {
721
- result.warnings.push(
722
- `Materialized source omitted ${materialization.omittedEntries} credential, key, symbolic, binary, or unsupported filesystem entries.`,
723
- )
724
- }
725
- }
726
-
727
- if (query && materializedSourceRoot) {
728
- const search = runBoundedSearch(query, materializedSourceRoot)
729
- const searchPath = join(outputRoot, 'search.txt')
730
- writeContextFile(searchPath, search.output)
731
- result.searchResult = relative(appRoot, searchPath)
732
- result.boundedSearch = {
733
- query,
734
- maxMatches: SEARCH_MATCH_LIMIT,
735
- matches: search.matches,
736
- truncated: search.truncated,
737
- status: search.status,
738
- result: result.searchResult,
739
- }
740
- }
741
-
742
- const manifestPath = join(outputRoot, 'manifest.json')
743
- writeContextFile(manifestPath, `${JSON.stringify({ ...result, generatedAt: new Date().toISOString() }, null, 2)}\n`)
744
- result.manifest = relative(appRoot, manifestPath)
745
- }
746
-
747
- function buildResult(args) {
748
- const upstreamRoot = join(appRoot, '.ai', 'guides', 'upstream', 'AGENTS.md')
749
- const upstreamBc = join(appRoot, '.ai', 'guides', 'upstream', 'BACKWARD_COMPATIBILITY.md')
750
- const standaloneRoot = join(appRoot, 'AGENTS.md')
751
- const snapshotManifestPath = join(appRoot, '.ai', 'guides', 'upstream', 'manifest.json')
752
- const snapshot = existsSync(snapshotManifestPath) ? readJson(snapshotManifestPath) : null
753
-
754
- if (args.root) {
755
- return {
756
- mode: 'root',
757
- snapshot,
758
- instructions: [
759
- { kind: 'standalone-root', path: existsSync(standaloneRoot) ? standaloneRoot : null },
760
- { kind: 'upstream-bc', path: existsSync(upstreamBc) ? upstreamBc : null },
761
- { kind: 'upstream-root', path: existsSync(upstreamRoot) ? upstreamRoot : null },
762
- ],
763
- }
764
- }
765
-
766
- const moduleId = args.module
767
- ? assertToken(args.module, 'module id', /^[a-z0-9][a-z0-9_-]*$/)
768
- : null
769
- let packageName = args.package
770
- ? assertToken(args.package, 'package name', /^@open-mercato\/[a-z0-9][a-z0-9._-]*$/)
771
- : null
772
-
773
- if (moduleId && !packageName) {
774
- const candidates = candidatePackages(moduleId)
775
- if (candidates.length === 0) throw new Error(`no installed package declares module ${moduleId}`)
776
- if (candidates.length > 1) {
777
- throw new Error(`module ${moduleId} is ambiguous; pass --package (${candidates.join(', ')})`)
778
- }
779
- packageName = candidates[0]
780
- }
781
- if (!packageName) throw new Error('pass --module, --package, or --root')
782
-
783
- const packageRoot = findPackageRoot(packageName)
784
- if (!packageRoot) throw new Error(`cannot resolve ${packageName} from ${appRoot}`)
785
- const packageManifest = readJson(join(packageRoot, 'package.json'))
786
- const installedPackages = installedPackageDiagnostics(packageName, packageRoot)
787
- const sourceCandidate = moduleId
788
- ? join(packageRoot, 'src', 'modules', moduleId)
789
- : join(packageRoot, 'src')
790
- const distCandidate = moduleId
791
- ? join(packageRoot, 'dist', 'modules', moduleId)
792
- : join(packageRoot, 'dist')
793
- const sourceKind = existsSync(sourceCandidate) ? 'source' : existsSync(distCandidate) ? 'dist' : 'missing'
794
- const sourceRoot = sourceKind === 'source'
795
- ? assertInside(packageRoot, realpathSync(sourceCandidate), 'source root')
796
- : sourceKind === 'dist'
797
- ? assertInside(packageRoot, realpathSync(distCandidate), 'dist root')
798
- : null
799
- const degraded = sourceKind !== 'source'
800
- const snapshotVersion = typeof snapshot?.generator === 'string'
801
- ? snapshot.generator.match(/@(\d+\.\d+\.\d+(?:-[^\s]+)?)/)?.[1] ?? null
802
- : null
803
- const factsPath = join(appRoot, '.ai', 'guides', 'module-facts.json')
804
- const moduleFact = moduleId && existsSync(factsPath) ? readJson(factsPath)?.[moduleId] ?? null : null
805
- const factSourcePackage = moduleFact?.sourcePackage ?? null
806
- const factSourceVersion = moduleFact?.sourceVersion ?? moduleFact?.coreVersion ?? null
807
- const factsCurrent = !moduleFact || (
808
- (!factSourcePackage || factSourcePackage === packageName)
809
- && (!factSourceVersion || factSourceVersion === packageManifest.version)
810
- )
811
-
812
- return {
813
- mode: moduleId ? 'module' : 'package',
814
- module: moduleId,
815
- package: { name: packageName, version: packageManifest.version ?? 'unknown', root: packageRoot },
816
- installedPackages,
817
- sourceRoot,
818
- sourceKind,
819
- degraded,
820
- snapshot,
821
- generatedFacts: moduleFact ? {
822
- current: factsCurrent,
823
- sourcePackage: factSourcePackage,
824
- sourceVersion: factSourceVersion,
825
- } : null,
826
- instructions: [
827
- { kind: 'standalone-root', path: existsSync(standaloneRoot) ? standaloneRoot : null },
828
- { kind: 'upstream-bc', path: existsSync(upstreamBc) ? upstreamBc : null },
829
- ...nearestAgentsFiles(packageRoot, sourceRoot).map((path, index) => ({
830
- kind: index === 0 ? 'package' : `module-${index}`,
831
- path,
832
- })),
833
- { kind: 'upstream-root', path: existsSync(upstreamRoot) ? upstreamRoot : null },
834
- ],
835
- boundedSearch: sourceRoot ? {
836
- query: args.query ?? null,
837
- maxMatches: SEARCH_MATCH_LIMIT,
838
- matches: null,
839
- truncated: null,
840
- status: args.query ? 'pending' : 'query-required',
841
- result: null,
842
- } : null,
843
- warnings: [
844
- ...(degraded ? ['TypeScript package source is unavailable; analysis is limited to dist/types.'] : []),
845
- ...(!existsSync(join(packageRoot, 'AGENTS.md')) ? ['Package AGENTS.md is unavailable.'] : []),
846
- ...(snapshotVersion && snapshotVersion !== packageManifest.version
847
- ? [`Upstream snapshot ${snapshotVersion} differs from installed ${packageName}@${packageManifest.version}.`]
848
- : []),
849
- ...(!factsCurrent
850
- ? [`Generated facts for ${moduleId} are stale. After registry changes run yarn generate, then yarn mercato agentic:init --update-harness; after a dependency-only upgrade run the update-harness command.`]
851
- : []),
852
- ...packageDiagnosticWarnings(installedPackages),
853
- ],
854
- }
855
- }
856
-
857
- function printHelp() {
858
- console.log(`Usage:
859
- yarn framework:context --module <id> [--package <name>] [--query <text>] [--json]
860
- yarn framework:context --package <@open-mercato/name> [--query <text>] [--json]
861
- yarn framework:context --root [--json]
862
-
863
- The command reads the installed package selected by this app and materializes the
864
- smallest read-only instruction/source context under .ai/framework-context/.`)
865
- }
866
-
867
- try {
868
- const args = parseArgs(process.argv.slice(2))
869
- if (args.help) {
870
- printHelp()
871
- } else {
872
- const result = buildResult(args)
873
- if (args.materialize && result.package) materialize(result, args.query)
874
- if (args.json) console.log(JSON.stringify(result, null, 2))
875
- else {
876
- if (result.package) console.log(`Package: ${result.package.name}@${result.package.version}`)
877
- if (result.module) console.log(`Module: ${result.module}`)
878
- if (result.sourceRoot) console.log(`Source: ${result.sourceRoot}`)
879
- for (const instruction of result.instructions) {
880
- if (instruction.path) console.log(`Instruction (${instruction.kind}): ${instruction.path}`)
881
- }
882
- if (result.manifest) console.log(`Materialized: ${result.manifest}`)
883
- for (const warning of result.warnings ?? []) console.warn(`Warning: ${warning}`)
884
- }
885
- }
886
- } catch (error) {
887
- fail(error instanceof Error ? error.message : String(error))
888
- }