@open-mercato/cli 0.6.7 → 0.6.8-canary.320.1.bf889f49e4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +77 -4
- package/AGENTS.md +6 -1
- package/build.mjs +68 -11
- package/dist/agentic/claude-code/hooks/entity-migration-check.ts +32 -88
- package/dist/agentic/codex/enforcement-rules.md +2 -16
- package/dist/agentic/cursor/hooks/entity-migration-check.mjs +19 -50
- package/dist/agentic/cursor/rules/entity-guard.mdc +9 -21
- package/dist/agentic/cursor/rules/generated-guard.mdc +3 -5
- package/dist/agentic/cursor/rules/open-mercato.mdc +3 -29
- package/dist/agentic/guides/ai-workflows.md +76 -0
- package/dist/agentic/guides/architecture.md +107 -0
- package/dist/agentic/guides/backend-ui.md +86 -0
- package/dist/agentic/guides/contracts.md +92 -0
- package/dist/agentic/guides/extensions.md +121 -0
- package/dist/agentic/guides/framework-extension-points.md +36 -0
- package/dist/agentic/guides/integrations.md +81 -0
- package/dist/agentic/guides/module-facts.json +116757 -3951
- package/dist/agentic/guides/module-system.md +12 -127
- package/dist/agentic/guides/modules/ai_assistant.md +227 -28
- package/dist/agentic/guides/modules/api_docs.md +58 -2
- package/dist/agentic/guides/modules/api_keys.md +92 -7
- package/dist/agentic/guides/modules/attachments.md +119 -14
- package/dist/agentic/guides/modules/audit_logs.md +131 -10
- package/dist/agentic/guides/modules/auth.md +276 -33
- package/dist/agentic/guides/modules/business_rules.md +149 -14
- package/dist/agentic/guides/modules/catalog.md +482 -43
- package/dist/agentic/guides/modules/channel_gmail.md +82 -3
- package/dist/agentic/guides/modules/channel_imap.md +82 -3
- package/dist/agentic/guides/modules/checkout.md +305 -27
- package/dist/agentic/guides/modules/communication_channels.md +315 -33
- package/dist/agentic/guides/modules/configs.md +104 -8
- package/dist/agentic/guides/modules/content.md +57 -2
- package/dist/agentic/guides/modules/currencies.md +152 -17
- package/dist/agentic/guides/modules/customer_accounts.md +387 -45
- package/dist/agentic/guides/modules/customers.md +746 -85
- package/dist/agentic/guides/modules/dashboards.md +155 -10
- package/dist/agentic/guides/modules/data_sync.md +149 -16
- package/dist/agentic/guides/modules/design_system.md +102 -0
- package/dist/agentic/guides/modules/dictionaries.md +107 -12
- package/dist/agentic/guides/modules/directory.md +148 -15
- package/dist/agentic/guides/modules/entities.md +145 -13
- package/dist/agentic/guides/modules/events.md +59 -2
- package/dist/agentic/guides/modules/feature_toggles.md +119 -9
- package/dist/agentic/guides/modules/gateway_stripe.md +92 -4
- package/dist/agentic/guides/modules/generators.md +45 -2
- package/dist/agentic/guides/modules/inbox_ops.md +207 -27
- package/dist/agentic/guides/modules/integrations.md +149 -16
- package/dist/agentic/guides/modules/messages.md +223 -24
- package/dist/agentic/guides/modules/notifications.md +96 -8
- package/dist/agentic/guides/modules/onboarding.md +77 -6
- package/dist/agentic/guides/modules/payment_gateways.md +168 -21
- package/dist/agentic/guides/modules/perspectives.md +77 -7
- package/dist/agentic/guides/modules/planner.md +136 -18
- package/dist/agentic/guides/modules/portal.md +93 -2
- package/dist/agentic/guides/modules/progress.md +104 -14
- package/dist/agentic/guides/modules/query_index.md +154 -15
- package/dist/agentic/guides/modules/record_locks.md +206 -21
- package/dist/agentic/guides/modules/resources.md +197 -30
- package/dist/agentic/guides/modules/sales.md +687 -84
- package/dist/agentic/guides/modules/scheduler.md +133 -14
- package/dist/agentic/guides/modules/search.md +170 -6
- package/dist/agentic/guides/modules/security.md +294 -35
- package/dist/agentic/guides/modules/shipping_carriers.md +134 -18
- package/dist/agentic/guides/modules/sso.md +151 -26
- package/dist/agentic/guides/modules/staff.md +372 -57
- package/dist/agentic/guides/modules/storage_s3.md +95 -5
- package/dist/agentic/guides/modules/sync_akeneo.md +85 -3
- package/dist/agentic/guides/modules/sync_excel.md +75 -6
- package/dist/agentic/guides/modules/system_status_overlays.md +60 -2
- package/dist/agentic/guides/modules/translations.md +104 -10
- package/dist/agentic/guides/modules/webhooks.md +203 -24
- package/dist/agentic/guides/modules/wms.md +469 -47
- package/dist/agentic/guides/modules/workflows.md +302 -43
- package/dist/agentic/guides/reference-module-facts.json +6942 -0
- package/dist/agentic/guides/reference-modules/example.md +462 -0
- package/dist/agentic/guides/spec-delivery.md +56 -0
- package/dist/agentic/guides/testing-debugging.md +80 -0
- package/dist/agentic/guides/upstream/AGENTS.md +300 -0
- package/dist/agentic/guides/upstream/BACKWARD_COMPATIBILITY.md +334 -0
- package/dist/agentic/guides/upstream/manifest.json +8 -0
- package/dist/agentic/shared/AGENTS.md.template +120 -311
- package/dist/agentic/shared/ai/agentic.config.json +2 -0
- package/dist/agentic/shared/ai/harness/README.md +50 -0
- package/dist/agentic/shared/ai/harness/RELEASE.md +59 -0
- package/dist/agentic/shared/ai/harness/cases.json +20596 -0
- package/dist/agentic/shared/ai/harness/cases.schema.json +196 -0
- package/dist/agentic/shared/ai/harness/design-system-inventory.json +6326 -0
- package/dist/agentic/shared/ai/harness/fixtures/index.json +51 -0
- package/dist/agentic/shared/ai/harness/fixtures/seeds.json +166 -0
- package/dist/agentic/shared/ai/harness/generated-code-review-policy.md +21 -0
- package/dist/agentic/shared/ai/harness/generated-code-review-response.schema.json +96 -0
- package/dist/agentic/shared/ai/harness/generated-code-review-result.schema.json +172 -0
- package/dist/agentic/shared/ai/harness/knowledge-change.schema.json +228 -0
- package/dist/agentic/shared/ai/harness/release-matrix.json +163 -0
- package/dist/agentic/shared/ai/harness/release-result.schema.json +219 -0
- package/dist/agentic/shared/ai/harness/result.schema.json +136 -0
- package/dist/agentic/shared/ai/harness/routing-response.schema.json +22 -0
- package/dist/agentic/shared/ai/harness/source-link-inventory.json +1706 -0
- package/dist/agentic/shared/ai/harness/target-validation-result.schema.json +73 -0
- package/dist/agentic/shared/ai/harness/validators.json +82 -0
- package/dist/agentic/shared/ai/harness/writable-ast-oracles.mjs +2121 -0
- package/dist/agentic/shared/ai/harness/writable-behavior-oracles.mjs +1096 -0
- package/dist/agentic/shared/ai/harness/writable-spec-oracles.mjs +602 -0
- package/dist/agentic/shared/ai/lessons/_template.md +16 -0
- package/dist/agentic/shared/ai/lessons.md +26 -3
- package/dist/agentic/shared/ai/review-checklist.md +36 -0
- package/dist/agentic/shared/ai/skills/om-auto-implement-spec/SKILL.md +21 -0
- package/dist/agentic/shared/ai/skills/om-auto-review-pr/SKILL.md +4 -0
- package/dist/agentic/shared/ai/skills/om-auto-upgrade-0.6.6-to-0.6.7/SKILL.md +98 -0
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/SKILL.md +21 -241
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/crud-surfaces.md +31 -0
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/frontend-and-design-system.md +53 -0
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/page-and-navigation.md +15 -0
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/quality-states.md +11 -0
- package/dist/agentic/shared/ai/skills/om-build-workflow/SKILL.md +30 -0
- package/dist/agentic/shared/ai/skills/om-build-workflow/references/activity-contracts.md +12 -0
- package/dist/agentic/shared/ai/skills/om-build-workflow/references/durability-and-progress.md +13 -0
- package/dist/agentic/shared/ai/skills/om-build-workflow/references/workflow-design.md +14 -0
- package/dist/agentic/shared/ai/skills/om-create-ai-agent/SKILL.md +28 -0
- package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/attachments-and-overrides.md +12 -0
- package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/module-agents-and-tools.md +22 -0
- package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/orchestrator-agents.md +12 -0
- package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/surface-selector.md +19 -0
- package/dist/agentic/shared/ai/skills/om-data-model-design/SKILL.md +17 -601
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/integrity-and-concurrency.md +21 -0
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/migration-workflow.md +15 -0
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/schema-design.md +16 -0
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/sensitive-data.md +10 -0
- package/dist/agentic/shared/ai/skills/om-eject-and-customize/SKILL.md +15 -310
- package/dist/agentic/shared/ai/skills/om-eject-and-customize/references/decision-and-procedure.md +19 -0
- package/dist/agentic/shared/ai/skills/om-evolve-harness/SKILL.md +31 -0
- package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-template.md +100 -0
- package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-workflow.md +16 -0
- package/dist/agentic/shared/ai/skills/om-evolve-harness/references/knowledge-change.md +133 -0
- package/dist/agentic/shared/ai/skills/om-evolve-harness/references/owner-selection.md +17 -0
- package/dist/agentic/shared/ai/skills/om-framework-context/SKILL.md +25 -0
- package/dist/agentic/shared/ai/skills/om-framework-context/references/resolver-procedure.md +11 -0
- package/dist/agentic/shared/ai/skills/om-framework-context/references/skew-and-escalation.md +13 -0
- package/dist/agentic/shared/ai/skills/om-help/SKILL.md +15 -97
- package/dist/agentic/shared/ai/skills/om-help/references/delivery-workflows.md +18 -0
- package/dist/agentic/shared/ai/skills/om-help/references/task-families.md +20 -0
- package/dist/agentic/shared/ai/skills/om-implement-spec/SKILL.md +33 -152
- package/dist/agentic/shared/ai/skills/om-implement-spec/references/phases-and-gates.md +33 -0
- package/dist/agentic/shared/ai/skills/om-implement-spec/references/planning-and-progress.md +40 -0
- package/dist/agentic/shared/ai/skills/om-implement-spec/references/report-templates.md +27 -0
- package/dist/agentic/shared/ai/skills/om-implement-spec/references/spec-resolution.md +24 -0
- package/dist/agentic/shared/ai/skills/om-integration-builder/SKILL.md +25 -708
- package/dist/agentic/shared/ai/skills/om-integration-builder/references/package-and-activation.md +16 -0
- package/dist/agentic/shared/ai/skills/om-integration-builder/references/provider-families.md +25 -0
- package/dist/agentic/shared/ai/skills/om-integration-builder/references/security-and-reliability.md +15 -0
- package/dist/agentic/shared/ai/skills/om-integration-builder/references/sync-and-files.md +12 -0
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/SKILL.md +34 -0
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/agents/openai.yaml +4 -0
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/agentic-setup.md +11 -0
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/input-normalization.md +31 -0
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/judge-workflow.md +39 -0
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/report-template.md +43 -0
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/rules.md +11 -0
- package/dist/agentic/shared/ai/skills/om-module-scaffold/SKILL.md +20 -820
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/api-and-domain.md +32 -0
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/business-one-shot-blueprints.md +172 -0
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/data-and-migrations.md +14 -0
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/discovery-surface-catalog.md +83 -0
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/module-surfaces.md +40 -0
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/planning.md +11 -0
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/runtime-cache-and-queues.md +22 -0
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/verification.md +13 -0
- package/dist/agentic/shared/ai/skills/om-share-this-session/SKILL.md +41 -0
- package/dist/agentic/shared/ai/skills/om-share-this-session/references/agentic-setup.md +19 -0
- package/dist/agentic/shared/ai/skills/om-share-this-session/references/bundle-preparation.md +44 -0
- package/dist/agentic/shared/ai/skills/om-share-this-session/references/consent-and-review.md +39 -0
- package/dist/agentic/shared/ai/skills/om-share-this-session/references/publication.md +20 -0
- package/dist/agentic/shared/ai/skills/om-share-this-session/references/report-templates.md +57 -0
- package/dist/agentic/shared/ai/skills/om-share-this-session/references/rules.md +11 -0
- package/dist/agentic/shared/ai/skills/om-share-this-session/scripts/prepare-share-bundle.mjs +486 -0
- package/dist/agentic/shared/ai/skills/om-system-extension/SKILL.md +20 -843
- package/dist/agentic/shared/ai/skills/om-system-extension/references/extension-branches.md +42 -0
- package/dist/agentic/shared/ai/skills/om-system-extension/references/mechanism-selector.md +27 -0
- package/dist/agentic/shared/ai/skills/om-system-extension/references/read-write-roundtrip.md +13 -0
- package/dist/agentic/shared/ai/skills/om-system-extension/references/unified-overrides.md +43 -0
- package/dist/agentic/shared/ai/skills/om-system-extension/references/verification.md +11 -0
- package/dist/agentic/shared/ai/skills/om-trim-unused-modules/SKILL.md +15 -63
- package/dist/agentic/shared/ai/skills/om-trim-unused-modules/references/dependency-and-redirect.md +15 -0
- package/dist/agentic/shared/ai/skills/om-troubleshooter/SKILL.md +17 -467
- package/dist/agentic/shared/ai/skills/om-troubleshooter/references/diagnosis-map.md +29 -0
- package/dist/agentic/shared/ai/skills/om-troubleshooter/references/regression-oracles.md +14 -0
- package/dist/agentic/shared/ai/skills/tiers.json +143 -21
- package/dist/agentic/shared/ai/skills/tiers.schema.json +52 -40
- package/dist/agentic/shared/ai/specs/2026-08-06-reference-module-activation.md +248 -0
- package/dist/agentic/shared/ai/specs/README.md +4 -3
- package/dist/agentic/shared/ai/specs/SPEC-000-template.md +226 -10
- package/dist/agentic/shared/ai/trackers/github.md +108 -4
- package/dist/agentic/shared/scripts/agent-harness-tool-server.mjs +224 -0
- package/dist/agentic/shared/scripts/check-lessons.mjs +178 -0
- package/dist/agentic/shared/scripts/evaluate-agent-harness.mjs +3812 -0
- package/dist/agentic/shared/scripts/execution-sandbox.mjs +329 -0
- package/dist/agentic/shared/scripts/framework-context.mjs +888 -0
- package/dist/agentic/shared/scripts/install-skills.mjs +1029 -0
- package/dist/agentic/shared/scripts/install-skills.sh +4 -694
- package/dist/agentic/shared/scripts/prepare-agent-harness-fixture.mjs +222 -0
- package/dist/agentic/shared/scripts/run-agent-harness-release.mjs +1774 -0
- package/dist/agentic/shared/scripts/validate-knowledge-change.mjs +1172 -0
- package/dist/bin.js +32 -34
- package/dist/bin.js.map +2 -2
- package/dist/lib/__integration__/TC-INT-008.spec.js +88 -8
- package/dist/lib/__integration__/TC-INT-008.spec.js.map +2 -2
- package/dist/lib/agentic-init.js +13 -3
- package/dist/lib/agentic-init.js.map +2 -2
- package/dist/lib/agentic-setup.js +434 -186
- package/dist/lib/agentic-setup.js.map +2 -2
- package/dist/lib/cli-bootstrap-mode.js +32 -0
- package/dist/lib/cli-bootstrap-mode.js.map +7 -0
- package/dist/lib/dev-supervisor-manifest.js +105 -0
- package/dist/lib/dev-supervisor-manifest.js.map +7 -0
- package/dist/lib/generate-watch-events.js +15 -0
- package/dist/lib/generate-watch-events.js.map +2 -2
- package/dist/lib/generators/entity-ids.js +11 -24
- package/dist/lib/generators/entity-ids.js.map +2 -2
- package/dist/lib/generators/extensions/injection-widgets.js +20 -0
- package/dist/lib/generators/extensions/injection-widgets.js.map +2 -2
- package/dist/lib/generators/module-di.js +10 -23
- package/dist/lib/generators/module-di.js.map +2 -2
- package/dist/lib/generators/module-entities.js +10 -23
- package/dist/lib/generators/module-entities.js.map +2 -2
- package/dist/lib/generators/module-extension-facts.js +1882 -0
- package/dist/lib/generators/module-extension-facts.js.map +7 -0
- package/dist/lib/generators/module-fact-sources.js +70 -0
- package/dist/lib/generators/module-fact-sources.js.map +7 -0
- package/dist/lib/generators/module-facts-discovery.js +64 -7
- package/dist/lib/generators/module-facts-discovery.js.map +2 -2
- package/dist/lib/generators/module-facts.js +1913 -52
- package/dist/lib/generators/module-facts.js.map +3 -3
- package/dist/lib/generators/module-override-targets.js +712 -0
- package/dist/lib/generators/module-override-targets.js.map +7 -0
- package/dist/lib/generators/module-registry.js +405 -36
- package/dist/lib/generators/module-registry.js.map +2 -2
- package/dist/lib/generators/route-manifest-shards.js +170 -0
- package/dist/lib/generators/route-manifest-shards.js.map +7 -0
- package/dist/lib/in-process-generate-watcher.js +12 -3
- package/dist/lib/in-process-generate-watcher.js.map +2 -2
- package/dist/lib/load-env.js +24 -0
- package/dist/lib/load-env.js.map +7 -0
- package/dist/lib/queue-worker-supervisor.js.map +2 -2
- package/dist/lib/resolver.js +28 -3
- package/dist/lib/resolver.js.map +2 -2
- package/dist/lib/telemetry-init.js +358 -0
- package/dist/lib/telemetry-init.js.map +7 -0
- package/dist/lib/testing/integration.js +5 -2
- package/dist/lib/testing/integration.js.map +2 -2
- package/dist/lib/utils.js +15 -8
- package/dist/lib/utils.js.map +2 -2
- package/dist/mercato.js +35 -9
- package/dist/mercato.js.map +2 -2
- package/package.json +13 -11
- package/src/__tests__/mercato.test.ts +144 -0
- package/src/bin.ts +60 -42
- package/src/lib/__integration__/TC-INT-008.spec.ts +107 -9
- package/src/lib/__tests__/agentic-init.test.ts +41 -5
- package/src/lib/__tests__/agentic-setup.ownership.test.ts +386 -0
- package/src/lib/__tests__/cli-bootstrap-mode.test.ts +22 -0
- package/src/lib/__tests__/content-stable-writes.test.ts +74 -0
- package/src/lib/__tests__/dev-supervisor-manifest.test.ts +131 -0
- package/src/lib/__tests__/generate-watch-events.test.ts +76 -0
- package/src/lib/__tests__/in-process-generate-watcher.test.ts +52 -1
- package/src/lib/__tests__/injection-widget-id-validation.test.ts +184 -0
- package/src/lib/__tests__/load-env.test.ts +65 -0
- package/src/lib/__tests__/queue-worker-supervisor.test.ts +33 -0
- package/src/lib/__tests__/resolver.enterprise.test.ts +50 -0
- package/src/lib/__tests__/telemetry-init.test.ts +298 -0
- package/src/lib/agentic-init.ts +15 -3
- package/src/lib/agentic-setup.ts +573 -222
- package/src/lib/cli-bootstrap-mode.ts +31 -0
- package/src/lib/dev-supervisor-manifest.ts +142 -0
- package/src/lib/generate-watch-events.ts +14 -0
- package/src/lib/generators/__tests__/activation-adapter-coverage.test.ts +92 -0
- package/src/lib/generators/__tests__/entity-ids.test.ts +32 -0
- package/src/lib/generators/__tests__/helpers/override-target-diagnostic-fixtures.ts +150 -0
- package/src/lib/generators/__tests__/module-extension-activations.test.ts +762 -0
- package/src/lib/generators/__tests__/module-extension-facts.test.ts +603 -0
- package/src/lib/generators/__tests__/module-facts.bc-guard.test.ts +139 -2
- package/src/lib/generators/__tests__/module-facts.computed-di-token.test.ts +88 -0
- package/src/lib/generators/__tests__/module-facts.customers.fixture.test.ts +1 -0
- package/src/lib/generators/__tests__/module-facts.discovery.test.ts +54 -10
- package/src/lib/generators/__tests__/module-facts.example-fact-coverage.test.ts +414 -0
- package/src/lib/generators/__tests__/module-facts.extension-hosts.test.ts +108 -0
- package/src/lib/generators/__tests__/module-facts.local-reference.test.ts +393 -0
- package/src/lib/generators/__tests__/module-facts.owned-contracts.test.ts +561 -0
- package/src/lib/generators/__tests__/module-facts.search-entity-id.test.ts +151 -0
- package/src/lib/generators/__tests__/module-facts.source-links.test.ts +160 -0
- package/src/lib/generators/__tests__/module-override-targets.diagnostic-wiring.test.ts +92 -0
- package/src/lib/generators/__tests__/module-override-targets.roundtrip.test.ts +149 -0
- package/src/lib/generators/__tests__/module-override-targets.test.ts +328 -0
- package/src/lib/generators/__tests__/module-override-targets.unknown-mode.test.ts +117 -0
- package/src/lib/generators/__tests__/module-subset.test.ts +266 -0
- package/src/lib/generators/__tests__/output-snapshots.test.ts +3 -3
- package/src/lib/generators/__tests__/route-manifest-shards.test.ts +62 -0
- package/src/lib/generators/entity-ids.ts +10 -26
- package/src/lib/generators/extensions/injection-widgets.ts +51 -0
- package/src/lib/generators/module-di.ts +9 -25
- package/src/lib/generators/module-entities.ts +9 -25
- package/src/lib/generators/module-extension-facts.ts +2472 -0
- package/src/lib/generators/module-fact-sources.ts +108 -0
- package/src/lib/generators/module-facts-discovery.ts +104 -7
- package/src/lib/generators/module-facts.ts +2747 -138
- package/src/lib/generators/module-override-targets.ts +907 -0
- package/src/lib/generators/module-registry.ts +448 -35
- package/src/lib/generators/route-manifest-shards.ts +146 -0
- package/src/lib/in-process-generate-watcher.ts +13 -4
- package/src/lib/load-env.ts +30 -0
- package/src/lib/queue-worker-supervisor.ts +7 -2
- package/src/lib/resolver.ts +34 -3
- package/src/lib/telemetry-init.ts +461 -0
- package/src/lib/testing/__tests__/integration.test.ts +4 -0
- package/src/lib/testing/integration.ts +5 -2
- package/src/lib/utils.ts +24 -16
- package/src/mercato.ts +46 -9
- package/dist/agentic/guides/cache.md +0 -45
- package/dist/agentic/guides/core.md +0 -453
- package/dist/agentic/guides/events.md +0 -117
- package/dist/agentic/guides/queue.md +0 -53
- package/dist/agentic/guides/search.md +0 -115
- package/dist/agentic/guides/shared.md +0 -108
- package/dist/agentic/guides/ui.md +0 -347
- package/dist/agentic/shared/ai/skills/om-auto-continue-pr-loop/SKILL.md +0 -27
- package/dist/agentic/shared/ai/skills/om-auto-create-pr-loop/SKILL.md +0 -27
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/ui-components.md +0 -260
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/mikro-orm-cheatsheet.md +0 -146
- package/dist/agentic/shared/ai/skills/om-help/references/skills-catalog.md +0 -84
- package/dist/agentic/shared/ai/skills/om-help/references/workflow-sequences.md +0 -193
- package/dist/agentic/shared/ai/skills/om-integration-builder/STANDALONE.md +0 -34
- package/dist/agentic/shared/ai/skills/om-integration-builder/references/adapter-contracts.md +0 -762
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/naming-conventions.md +0 -50
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/navigation-patterns.md +0 -97
- package/dist/agentic/shared/ai/skills/om-system-extension/references/extension-contracts.md +0 -271
- package/dist/agentic/shared/ai/skills/om-troubleshooter/references/diagnostic-commands.md +0 -101
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import {
|
|
4
|
+
MODULE_FACT_SOURCE_KINDS,
|
|
5
|
+
MODULE_OWNED_CONTRACT_KINDS,
|
|
6
|
+
buildCoverageFamily,
|
|
7
|
+
buildModuleFactCoverageLedger,
|
|
8
|
+
countModuleFactCoverage,
|
|
9
|
+
extractAllModuleFacts,
|
|
10
|
+
extractModuleFacts,
|
|
11
|
+
type ModuleFactCoverageFamily,
|
|
12
|
+
type ModuleFactCoverageRow,
|
|
13
|
+
type ModuleFacts,
|
|
14
|
+
} from '../module-facts'
|
|
15
|
+
import {
|
|
16
|
+
ALL_OVERRIDE_DOMAINS,
|
|
17
|
+
MODULE_OVERRIDE_MODES,
|
|
18
|
+
MODULE_OVERRIDE_TARGET_DIAGNOSTIC_CODES,
|
|
19
|
+
MODULE_OVERRIDE_TARGET_NOTES,
|
|
20
|
+
} from '../module-override-targets'
|
|
21
|
+
import { OVERRIDE_TARGET_DIAGNOSTIC_FIXTURES } from './helpers/override-target-diagnostic-fixtures'
|
|
22
|
+
|
|
23
|
+
function findRepoRoot(): string {
|
|
24
|
+
let dir = __dirname
|
|
25
|
+
for (let depth = 0; depth < 10; depth += 1) {
|
|
26
|
+
if (fs.existsSync(path.join(dir, 'packages', 'core', 'src', 'modules'))) return dir
|
|
27
|
+
dir = path.dirname(dir)
|
|
28
|
+
}
|
|
29
|
+
throw new Error('[internal] could not locate repo root from the test directory')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const CLOSED_LEDGER_STATUSES = [
|
|
33
|
+
'emitted-example',
|
|
34
|
+
'framework-only',
|
|
35
|
+
'catalog-only',
|
|
36
|
+
'currently-unbound',
|
|
37
|
+
'pending-emission',
|
|
38
|
+
'negative-fixture',
|
|
39
|
+
] as const
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* A route the example module really ships, addressed the way the generated module
|
|
43
|
+
* registry addresses it. `api-route` facts are read from that registry rather than
|
|
44
|
+
* from module source, so this fixture is what turns the `requiresGeneratedRegistry`
|
|
45
|
+
* flag from an unchecked claim into a proven one: the same extraction reports zero
|
|
46
|
+
* without it and a real count with it.
|
|
47
|
+
*/
|
|
48
|
+
const REGISTRY_BACKED_ROUTE = {
|
|
49
|
+
path: '/example/todos',
|
|
50
|
+
sourceFile: 'apps/mercato/src/modules/example/api/todos/route.ts',
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function exampleRegistrySource(): string {
|
|
54
|
+
return [
|
|
55
|
+
'export const modules = [',
|
|
56
|
+
" { id: 'example', apis: [",
|
|
57
|
+
` { path: '${REGISTRY_BACKED_ROUTE.path}', handlers: { GET: getTodos, POST: createTodo } },`,
|
|
58
|
+
' ] },',
|
|
59
|
+
']',
|
|
60
|
+
].join('\n')
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function extractExampleFacts(registrySource?: string): ModuleFacts {
|
|
64
|
+
return extractModuleFacts({
|
|
65
|
+
moduleId: 'example',
|
|
66
|
+
moduleRoot: path.join(findRepoRoot(), 'apps', 'mercato', 'src', 'modules', 'example'),
|
|
67
|
+
portableSourceRoot: 'src/modules/example',
|
|
68
|
+
...(registrySource === undefined ? {} : { registrySource }),
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function familyOf(ledger: ModuleFactCoverageFamily[], name: string): ModuleFactCoverageFamily {
|
|
73
|
+
const family = ledger.find((entry) => entry.family === name)
|
|
74
|
+
if (!family) throw new Error(`[internal] factCoverage ledger has no family "${name}"`)
|
|
75
|
+
return family
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
describe('factCoverage ledger — enum derivation', () => {
|
|
79
|
+
const ledger = buildModuleFactCoverageLedger()
|
|
80
|
+
|
|
81
|
+
it('classifies every value of every enumerated family exactly once', () => {
|
|
82
|
+
const expectedSizes: Record<string, number> = {
|
|
83
|
+
ModuleFactSourceKind: MODULE_FACT_SOURCE_KINDS.length,
|
|
84
|
+
ModuleOwnedContractKind: MODULE_OWNED_CONTRACT_KINDS.length,
|
|
85
|
+
ModuleOverrideDomain: ALL_OVERRIDE_DOMAINS.length,
|
|
86
|
+
ModuleOverrideMode: MODULE_OVERRIDE_MODES.length,
|
|
87
|
+
ModuleOverrideTargetNote: MODULE_OVERRIDE_TARGET_NOTES.length,
|
|
88
|
+
ModuleOverrideTargetDiagnosticCode: MODULE_OVERRIDE_TARGET_DIAGNOSTIC_CODES.length,
|
|
89
|
+
}
|
|
90
|
+
expect(ledger.map((family) => family.family).sort()).toEqual(Object.keys(expectedSizes).sort())
|
|
91
|
+
for (const family of ledger) {
|
|
92
|
+
expect(family.rows).toHaveLength(expectedSizes[family.family])
|
|
93
|
+
const values = family.rows.map((row) => row.value)
|
|
94
|
+
expect(new Set(values).size).toBe(values.length)
|
|
95
|
+
expect(family.enumSource).toMatch(/^packages\/cli\/src\/lib\/generators\/.+#[A-Z_]+$/)
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('resolves every enumSource to a file that really exports that symbol with those values', () => {
|
|
100
|
+
for (const family of ledger) {
|
|
101
|
+
const [relativePath, symbol] = family.enumSource.split('#')
|
|
102
|
+
const absolute = path.join(findRepoRoot(), relativePath)
|
|
103
|
+
expect(fs.existsSync(absolute)).toBe(true)
|
|
104
|
+
expect(fs.readFileSync(absolute, 'utf8')).toMatch(new RegExp(`^export const ${symbol}\\b`, 'm'))
|
|
105
|
+
const exported = (require(absolute) as Record<string, unknown>)[symbol]
|
|
106
|
+
expect(Array.isArray(exported)).toBe(true)
|
|
107
|
+
expect([...(exported as string[])]).toEqual(family.rows.map((row) => row.value))
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('derives each family from the exported runtime constant, value for value', () => {
|
|
112
|
+
expect(familyOf(ledger, 'ModuleFactSourceKind').rows.map((row) => row.value)).toEqual([
|
|
113
|
+
...MODULE_FACT_SOURCE_KINDS,
|
|
114
|
+
])
|
|
115
|
+
expect(familyOf(ledger, 'ModuleOwnedContractKind').rows.map((row) => row.value)).toEqual([
|
|
116
|
+
...MODULE_OWNED_CONTRACT_KINDS,
|
|
117
|
+
])
|
|
118
|
+
expect(familyOf(ledger, 'ModuleOverrideDomain').rows.map((row) => row.value)).toEqual([...ALL_OVERRIDE_DOMAINS])
|
|
119
|
+
expect(familyOf(ledger, 'ModuleOverrideMode').rows.map((row) => row.value)).toEqual([...MODULE_OVERRIDE_MODES])
|
|
120
|
+
expect(familyOf(ledger, 'ModuleOverrideTargetNote').rows.map((row) => row.value)).toEqual([
|
|
121
|
+
...MODULE_OVERRIDE_TARGET_NOTES,
|
|
122
|
+
])
|
|
123
|
+
expect(familyOf(ledger, 'ModuleOverrideTargetDiagnosticCode').rows.map((row) => row.value)).toEqual([
|
|
124
|
+
...MODULE_OVERRIDE_TARGET_DIAGNOSTIC_CODES,
|
|
125
|
+
])
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
it('locks the ten ModuleOwnedContractKind values the spec enumerates', () => {
|
|
129
|
+
expect([...MODULE_OWNED_CONTRACT_KINDS]).toEqual([
|
|
130
|
+
'module-metadata',
|
|
131
|
+
'command',
|
|
132
|
+
'worker',
|
|
133
|
+
'page-middleware',
|
|
134
|
+
'setup',
|
|
135
|
+
'encryption',
|
|
136
|
+
'di-registration',
|
|
137
|
+
'custom-entity',
|
|
138
|
+
'ai-extension',
|
|
139
|
+
'generator-plugin',
|
|
140
|
+
])
|
|
141
|
+
expect(familyOf(ledger, 'ModuleOwnedContractKind').rows).toHaveLength(10)
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it('uses only the six closed statuses and keeps status self-sufficient', () => {
|
|
145
|
+
const allowed = new Set<string>(CLOSED_LEDGER_STATUSES)
|
|
146
|
+
for (const family of ledger) {
|
|
147
|
+
for (const row of family.rows) {
|
|
148
|
+
expect(allowed.has(row.status)).toBe(true)
|
|
149
|
+
expect(row.note.length).toBeGreaterThan(0)
|
|
150
|
+
// A reader keying on `status` alone must never be told the example emits
|
|
151
|
+
// something it does not: the pending gap lives in the status itself.
|
|
152
|
+
if (row.pendingEmission) expect(row.status).toBe('pending-emission')
|
|
153
|
+
if (row.status === 'pending-emission') expect(row.pendingEmission?.length ?? 0).toBeGreaterThan(0)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
describe('buildCoverageFamily — both directions of the enum/ledger contract', () => {
|
|
160
|
+
const row = (value: string): ModuleFactCoverageRow => ({ value, status: 'emitted-example', note: 'fixture' })
|
|
161
|
+
|
|
162
|
+
it('classifies every enumerated value when the ledger is complete', () => {
|
|
163
|
+
const family = buildCoverageFamily('Fixture', 'packages/cli/src/lib/generators/module-facts.ts#FIXTURE', ['a', 'b'], {
|
|
164
|
+
a: row('a'),
|
|
165
|
+
b: row('b'),
|
|
166
|
+
})
|
|
167
|
+
expect(family.rows.map((entry) => entry.value)).toEqual(['a', 'b'])
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
it('throws when an enumerated value has no row', () => {
|
|
171
|
+
expect(() =>
|
|
172
|
+
buildCoverageFamily('Fixture', 'packages/cli/src/lib/generators/module-facts.ts#FIXTURE', ['a', 'b'], {
|
|
173
|
+
a: row('a'),
|
|
174
|
+
}),
|
|
175
|
+
).toThrow(/has no row for: b/)
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
it('throws on a stale row for a value the enum no longer carries', () => {
|
|
179
|
+
expect(() =>
|
|
180
|
+
buildCoverageFamily('Fixture', 'packages/cli/src/lib/generators/module-facts.ts#FIXTURE', ['a'], {
|
|
181
|
+
a: row('a'),
|
|
182
|
+
removed: row('removed'),
|
|
183
|
+
}),
|
|
184
|
+
).toThrow(/classifies values absent from the enum: removed/)
|
|
185
|
+
})
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
describe('factCoverage ledger — built by fact generation, not only by this test', () => {
|
|
189
|
+
it('is built and returned on every extractAllModuleFacts run', () => {
|
|
190
|
+
const generated = extractAllModuleFacts({ sources: [] })
|
|
191
|
+
expect(generated.factCoverage).toEqual(buildModuleFactCoverageLedger())
|
|
192
|
+
})
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
describe('factCoverage ledger — checked against the real example extraction', () => {
|
|
196
|
+
const ledger = buildModuleFactCoverageLedger()
|
|
197
|
+
const facts = extractExampleFacts()
|
|
198
|
+
const counts = countModuleFactCoverage(facts)
|
|
199
|
+
|
|
200
|
+
it('extracts the real canonical example module', () => {
|
|
201
|
+
expect(facts.module).toBe('example')
|
|
202
|
+
expect(facts.sourceRoot).toBe('src/modules/example')
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
it('proves a non-zero real count for every emitted-example row', () => {
|
|
206
|
+
const unproven: string[] = []
|
|
207
|
+
let proven = 0
|
|
208
|
+
for (const family of ledger) {
|
|
209
|
+
const familyCounts = counts[family.family] ?? {}
|
|
210
|
+
for (const row of family.rows) {
|
|
211
|
+
if (row.status !== 'emitted-example') continue
|
|
212
|
+
if (row.requiresGeneratedRegistry) continue
|
|
213
|
+
const count = familyCounts[row.value] ?? 0
|
|
214
|
+
if (count <= 0) unproven.push(`${family.family}.${row.value}`)
|
|
215
|
+
else proven += 1
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
expect(unproven).toEqual([])
|
|
219
|
+
expect(proven).toBeGreaterThan(0)
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
it('keeps every pending-emission row at a real count of zero so it cannot go stale', () => {
|
|
223
|
+
const wronglyPending: string[] = []
|
|
224
|
+
const pending: string[] = []
|
|
225
|
+
for (const family of ledger) {
|
|
226
|
+
const familyCounts = counts[family.family] ?? {}
|
|
227
|
+
for (const row of family.rows) {
|
|
228
|
+
if (row.status !== 'pending-emission') continue
|
|
229
|
+
pending.push(`${family.family}.${row.value}`)
|
|
230
|
+
if ((familyCounts[row.value] ?? 0) > 0) wronglyPending.push(`${family.family}.${row.value}`)
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
expect(wronglyPending).toEqual([])
|
|
234
|
+
expect(pending).toEqual([
|
|
235
|
+
'ModuleFactSourceKind.vector',
|
|
236
|
+
'ModuleFactSourceKind.generator-plugin',
|
|
237
|
+
'ModuleOwnedContractKind.generator-plugin',
|
|
238
|
+
])
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
it('keeps every catalog-only row at a real count of zero, since the example contributes nothing for it', () => {
|
|
242
|
+
const contributing: string[] = []
|
|
243
|
+
for (const family of ledger) {
|
|
244
|
+
const familyCounts = counts[family.family] ?? {}
|
|
245
|
+
for (const row of family.rows) {
|
|
246
|
+
if (row.status !== 'catalog-only') continue
|
|
247
|
+
if ((familyCounts[row.value] ?? 0) > 0) contributing.push(`${family.family}.${row.value}`)
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
expect(contributing).toEqual([])
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
it('publishes nine of the ten owned-contract kinds today, generator-plugin being the open gap', () => {
|
|
254
|
+
const ownedCounts = counts.ModuleOwnedContractKind
|
|
255
|
+
for (const kind of MODULE_OWNED_CONTRACT_KINDS) {
|
|
256
|
+
if (kind === 'generator-plugin') {
|
|
257
|
+
expect(ownedCounts[kind] ?? 0).toBe(0)
|
|
258
|
+
continue
|
|
259
|
+
}
|
|
260
|
+
expect(ownedCounts[kind] ?? 0).toBeGreaterThan(0)
|
|
261
|
+
}
|
|
262
|
+
expect(fs.existsSync(path.join(findRepoRoot(), 'apps/mercato/src/modules/example/generators.ts'))).toBe(false)
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
it('emits a real override target for all fifteen module-owned domains and none for framework-only nav', () => {
|
|
266
|
+
const domainCounts = counts.ModuleOverrideDomain
|
|
267
|
+
for (const domain of ALL_OVERRIDE_DOMAINS) {
|
|
268
|
+
if (domain === 'nav') {
|
|
269
|
+
expect(domainCounts[domain] ?? 0).toBe(0)
|
|
270
|
+
continue
|
|
271
|
+
}
|
|
272
|
+
expect(domainCounts[domain] ?? 0).toBeGreaterThan(0)
|
|
273
|
+
}
|
|
274
|
+
expect(Object.keys(domainCounts)).toHaveLength(ALL_OVERRIDE_DOMAINS.length - 1)
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
it('round-trips all three modes and both closed notes through real targets', () => {
|
|
278
|
+
for (const mode of MODULE_OVERRIDE_MODES) {
|
|
279
|
+
expect(counts.ModuleOverrideMode[mode] ?? 0).toBeGreaterThan(0)
|
|
280
|
+
}
|
|
281
|
+
for (const note of MODULE_OVERRIDE_TARGET_NOTES) {
|
|
282
|
+
expect(counts.ModuleOverrideTargetNote[note] ?? 0).toBeGreaterThan(0)
|
|
283
|
+
}
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
it('emits zero override-target diagnostics from activated canonical output', () => {
|
|
287
|
+
expect(facts.overrideTargetDiagnostics ?? []).toEqual([])
|
|
288
|
+
for (const code of MODULE_OVERRIDE_TARGET_DIAGNOSTIC_CODES) {
|
|
289
|
+
expect(counts.ModuleOverrideTargetDiagnosticCode[code] ?? 0).toBe(0)
|
|
290
|
+
}
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
it('never classifies a diagnostic code as canonical coverage', () => {
|
|
294
|
+
for (const row of familyOf(ledger, 'ModuleOverrideTargetDiagnosticCode').rows) {
|
|
295
|
+
expect(['negative-fixture', 'currently-unbound']).toContain(row.status)
|
|
296
|
+
}
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
it('backs every negative-fixture claim with a fixture that really produces that code', () => {
|
|
300
|
+
const claimed = familyOf(ledger, 'ModuleOverrideTargetDiagnosticCode')
|
|
301
|
+
.rows.filter((row) => row.status === 'negative-fixture')
|
|
302
|
+
.map((row) => row.value)
|
|
303
|
+
.sort()
|
|
304
|
+
const produced = OVERRIDE_TARGET_DIAGNOSTIC_FIXTURES.flatMap((fixture) =>
|
|
305
|
+
fixture.run().map((diagnostic) => diagnostic.code),
|
|
306
|
+
)
|
|
307
|
+
expect([...new Set(produced)].sort()).toEqual(claimed)
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
it('classifies a code no fixture can reach as currently-unbound, not as a negative fixture', () => {
|
|
311
|
+
const unbound = familyOf(ledger, 'ModuleOverrideTargetDiagnosticCode')
|
|
312
|
+
.rows.filter((row) => row.status === 'currently-unbound')
|
|
313
|
+
.map((row) => row.value)
|
|
314
|
+
expect(unbound).toEqual(['missing-owned-fact'])
|
|
315
|
+
const produced = new Set(
|
|
316
|
+
OVERRIDE_TARGET_DIAGNOSTIC_FIXTURES.flatMap((fixture) => fixture.run().map((diagnostic) => diagnostic.code)),
|
|
317
|
+
)
|
|
318
|
+
for (const code of unbound) expect(produced.has(code)).toBe(false)
|
|
319
|
+
const projectorSource = fs.readFileSync(
|
|
320
|
+
path.join(findRepoRoot(), 'packages/cli/src/lib/generators/module-override-targets.ts'),
|
|
321
|
+
'utf8',
|
|
322
|
+
)
|
|
323
|
+
// Reserved by the closed set, but no adapter names it as a `code:` value today.
|
|
324
|
+
expect(projectorSource).not.toMatch(/code: 'missing-owned-fact'/)
|
|
325
|
+
})
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* `requiresGeneratedRegistry` is the only way a row can skip the non-zero proof, so
|
|
330
|
+
* the flag itself is proven here rather than trusted: a row carrying it must report
|
|
331
|
+
* zero from a source-only extraction (otherwise the row is extractable from source
|
|
332
|
+
* and the skip is unwarranted) AND a real count once the same extraction is handed a
|
|
333
|
+
* module registry (otherwise nothing emits it at all and the row is not
|
|
334
|
+
* `emitted-example`). Setting the flag on a row that fails either side fails here.
|
|
335
|
+
*/
|
|
336
|
+
describe('requiresGeneratedRegistry — the only skip out of the non-zero proof is itself proven', () => {
|
|
337
|
+
const ledger = buildModuleFactCoverageLedger()
|
|
338
|
+
const sourceOnlyCounts = countModuleFactCoverage(extractExampleFacts())
|
|
339
|
+
const registryBackedCounts = countModuleFactCoverage(extractExampleFacts(exampleRegistrySource()))
|
|
340
|
+
const claims = ledger.flatMap((family) =>
|
|
341
|
+
family.rows
|
|
342
|
+
.filter((row) => row.requiresGeneratedRegistry)
|
|
343
|
+
.map((row) => ({ family: family.family, row })),
|
|
344
|
+
)
|
|
345
|
+
const label = (claim: { family: string; row: ModuleFactCoverageRow }): string =>
|
|
346
|
+
`${claim.family}.${claim.row.value}`
|
|
347
|
+
|
|
348
|
+
it('is claimed by exactly the rows the rest of this suite proves', () => {
|
|
349
|
+
expect(claims.map(label)).toEqual(['ModuleFactSourceKind.api-route'])
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
it('is claimed only where it changes anything: on an emitted-example row', () => {
|
|
353
|
+
for (const claim of claims) expect(claim.row.status).toBe('emitted-example')
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
it('is claimed only by a value a source-only extraction genuinely cannot see', () => {
|
|
357
|
+
const visibleFromSource = claims
|
|
358
|
+
.filter((claim) => (sourceOnlyCounts[claim.family]?.[claim.row.value] ?? 0) > 0)
|
|
359
|
+
.map(label)
|
|
360
|
+
expect(visibleFromSource).toEqual([])
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
it('is claimed only by a value the generated registry really does yield', () => {
|
|
364
|
+
const stillZeroWithRegistry = claims
|
|
365
|
+
.filter((claim) => (registryBackedCounts[claim.family]?.[claim.row.value] ?? 0) <= 0)
|
|
366
|
+
.map(label)
|
|
367
|
+
expect(stillZeroWithRegistry).toEqual([])
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
it('drives the registry-backed count from a route the example module really ships', () => {
|
|
371
|
+
expect(fs.existsSync(path.join(findRepoRoot(), REGISTRY_BACKED_ROUTE.sourceFile))).toBe(true)
|
|
372
|
+
expect(registryBackedCounts.ModuleFactSourceKind['api-route']).toBe(1)
|
|
373
|
+
expect(sourceOnlyCounts.ModuleFactSourceKind['api-route'] ?? 0).toBe(0)
|
|
374
|
+
})
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
describe('factCoverage published into the example surface inventories', () => {
|
|
378
|
+
const ledger = buildModuleFactCoverageLedger()
|
|
379
|
+
const inventoryPaths = [
|
|
380
|
+
'apps/mercato/src/modules/example/references/surface-inventory.json',
|
|
381
|
+
'packages/create-app/template/src/modules/example/references/surface-inventory.json',
|
|
382
|
+
]
|
|
383
|
+
|
|
384
|
+
function readInventory(relativePath: string): {
|
|
385
|
+
factCoverage?: { generatedNote?: string; families?: ModuleFactCoverageFamily[] }
|
|
386
|
+
} {
|
|
387
|
+
return JSON.parse(fs.readFileSync(path.join(findRepoRoot(), relativePath), 'utf8'))
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
it.each(inventoryPaths)('%s publishes the ledger verbatim', (relativePath) => {
|
|
391
|
+
const inventory = readInventory(relativePath)
|
|
392
|
+
expect(inventory.factCoverage?.families).toEqual(ledger)
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
it.each(inventoryPaths)('%s warns that a ledger status is not proof on its own', (relativePath) => {
|
|
396
|
+
const note = readInventory(relativePath).factCoverage?.generatedNote ?? ''
|
|
397
|
+
expect(note).toContain('STATUS IS NOT PROOF ON ITS OWN')
|
|
398
|
+
expect(note).toContain('pendingEmission')
|
|
399
|
+
expect(note).toContain('requiresGeneratedRegistry')
|
|
400
|
+
})
|
|
401
|
+
|
|
402
|
+
it.each(inventoryPaths)('%s documents every status the closed set can publish', (relativePath) => {
|
|
403
|
+
const note = readInventory(relativePath).factCoverage?.generatedNote ?? ''
|
|
404
|
+
const undocumented = CLOSED_LEDGER_STATUSES.filter((status) => !note.includes(`\`${status}\``))
|
|
405
|
+
expect(undocumented).toEqual([])
|
|
406
|
+
})
|
|
407
|
+
|
|
408
|
+
it('keeps the app inventory and the create-app template mirror byte-identical', () => {
|
|
409
|
+
const [appInventory, templateInventory] = inventoryPaths.map((relativePath) =>
|
|
410
|
+
fs.readFileSync(path.join(findRepoRoot(), relativePath), 'utf8'),
|
|
411
|
+
)
|
|
412
|
+
expect(templateInventory).toBe(appInventory)
|
|
413
|
+
})
|
|
414
|
+
})
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import os from 'node:os'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { extractModuleFacts } from '../module-facts'
|
|
5
|
+
|
|
6
|
+
function findCoreSrcRoot(): string {
|
|
7
|
+
let dir = __dirname
|
|
8
|
+
for (let depth = 0; depth < 10; depth += 1) {
|
|
9
|
+
const candidate = path.join(dir, 'packages', 'core', 'src', 'modules')
|
|
10
|
+
if (fs.existsSync(candidate)) return candidate
|
|
11
|
+
dir = path.dirname(dir)
|
|
12
|
+
}
|
|
13
|
+
throw new Error('[internal] could not locate packages/core/src/modules from the test directory')
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function write(filePath: string, source: string): void {
|
|
17
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true })
|
|
18
|
+
fs.writeFileSync(filePath, source)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('module-facts extension host extraction', () => {
|
|
22
|
+
const coreSrcRoot = findCoreSrcRoot()
|
|
23
|
+
|
|
24
|
+
it('resolves generated E.<module>.<entity> custom-field declarations from shipped modules', () => {
|
|
25
|
+
const expectedByModule: Record<string, string[]> = {
|
|
26
|
+
attachments: ['attachments:attachment'],
|
|
27
|
+
catalog: [
|
|
28
|
+
'catalog:catalog_product',
|
|
29
|
+
'catalog:catalog_product_variant',
|
|
30
|
+
'catalog:catalog_product_price',
|
|
31
|
+
],
|
|
32
|
+
sales: [
|
|
33
|
+
'sales:sales_order',
|
|
34
|
+
'sales:sales_order_line',
|
|
35
|
+
'sales:sales_order_adjustment',
|
|
36
|
+
'sales:sales_quote',
|
|
37
|
+
'sales:sales_quote_line',
|
|
38
|
+
'sales:sales_quote_adjustment',
|
|
39
|
+
'sales:sales_invoice',
|
|
40
|
+
'sales:sales_invoice_line',
|
|
41
|
+
'sales:sales_payment',
|
|
42
|
+
'sales:sales_payment_allocation',
|
|
43
|
+
'sales:sales_credit_memo',
|
|
44
|
+
'sales:sales_credit_memo_line',
|
|
45
|
+
'sales:sales_shipment',
|
|
46
|
+
'sales:sales_shipment_item',
|
|
47
|
+
'sales:sales_note',
|
|
48
|
+
],
|
|
49
|
+
staff: ['staff:staff_team_member'],
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
for (const [moduleId, expected] of Object.entries(expectedByModule)) {
|
|
53
|
+
const facts = extractModuleFacts({ moduleId, coreSrcRoot })
|
|
54
|
+
expect(facts.entities.filter((entity) => entity.customFields).map((entity) => entity.id).sort()).toEqual(
|
|
55
|
+
[...expected].sort(),
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('discovers literal and conditional DataTable IDs outside backend while excluding test sources', () => {
|
|
61
|
+
const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'module-facts-extension-hosts-'))
|
|
62
|
+
const moduleRoot = path.join(tmpRoot, 'alpha')
|
|
63
|
+
try {
|
|
64
|
+
write(
|
|
65
|
+
path.join(moduleRoot, 'data', 'entities.ts'),
|
|
66
|
+
`@Entity({ tableName: 'alpha_records' })\nexport class AlphaRecord { updatedAt?: Date }\n`,
|
|
67
|
+
)
|
|
68
|
+
write(
|
|
69
|
+
path.join(moduleRoot, 'ce.ts'),
|
|
70
|
+
`export const entities = [{ id: E.alpha.alpha_record, fields: [] }]\n`,
|
|
71
|
+
)
|
|
72
|
+
write(
|
|
73
|
+
path.join(moduleRoot, 'components', 'AlphaTable.tsx'),
|
|
74
|
+
`export const props = {
|
|
75
|
+
perspective: { tableId: kind === 'one' ? 'alpha.one' : 'alpha.two' },
|
|
76
|
+
extensionTableId: 'alpha.extension',
|
|
77
|
+
}\n`,
|
|
78
|
+
)
|
|
79
|
+
write(
|
|
80
|
+
path.join(moduleRoot, 'components', 'Noise.test.tsx'),
|
|
81
|
+
`export const noise = { tableId: 'alpha.test-noise' }\n`,
|
|
82
|
+
)
|
|
83
|
+
write(
|
|
84
|
+
path.join(moduleRoot, 'backend', '__tests__', 'noise.tsx'),
|
|
85
|
+
`export const noise = { extensionTableId: 'alpha.test-directory-noise' }\n`,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
const facts = extractModuleFacts({ moduleId: 'alpha', moduleRoot })
|
|
89
|
+
expect(facts.entities).toEqual([
|
|
90
|
+
expect.objectContaining({ id: 'alpha:alpha_record', customFields: true }),
|
|
91
|
+
])
|
|
92
|
+
expect(facts.hostTokens.tableIds).toEqual(['alpha.extension', 'alpha.one', 'alpha.two'])
|
|
93
|
+
} finally {
|
|
94
|
+
fs.rmSync(tmpRoot, { recursive: true, force: true })
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('captures shipped component-level table hosts used by catalog and sales', () => {
|
|
99
|
+
const catalog = extractModuleFacts({ moduleId: 'catalog', coreSrcRoot })
|
|
100
|
+
expect(catalog.hostTokens.tableIds).toEqual([
|
|
101
|
+
'catalog.categories.list',
|
|
102
|
+
'catalog.products.list',
|
|
103
|
+
])
|
|
104
|
+
|
|
105
|
+
const sales = extractModuleFacts({ moduleId: 'sales', coreSrcRoot })
|
|
106
|
+
expect(sales.hostTokens.tableIds).toEqual(['sales.orders', 'sales.quotes'])
|
|
107
|
+
})
|
|
108
|
+
})
|