@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.
- package/.turbo/turbo-build.log +4 -4
- package/build.mjs +7 -24
- package/dist/agentic/claude-code/hooks/entity-migration-check.ts +88 -32
- package/dist/agentic/codex/enforcement-rules.md +16 -2
- package/dist/agentic/cursor/hooks/entity-migration-check.mjs +50 -19
- package/dist/agentic/cursor/rules/entity-guard.mdc +21 -9
- package/dist/agentic/cursor/rules/generated-guard.mdc +5 -3
- package/dist/agentic/cursor/rules/open-mercato.mdc +29 -3
- package/dist/agentic/guides/cache.md +45 -0
- package/dist/agentic/guides/core.md +453 -0
- package/dist/agentic/guides/events.md +117 -0
- package/dist/agentic/guides/module-facts.json +3833 -115419
- package/dist/agentic/guides/module-system.md +127 -12
- package/dist/agentic/guides/modules/ai_assistant.md +28 -227
- package/dist/agentic/guides/modules/api_docs.md +2 -58
- package/dist/agentic/guides/modules/api_keys.md +7 -92
- package/dist/agentic/guides/modules/attachments.md +14 -119
- package/dist/agentic/guides/modules/audit_logs.md +10 -131
- package/dist/agentic/guides/modules/auth.md +33 -276
- package/dist/agentic/guides/modules/business_rules.md +14 -149
- package/dist/agentic/guides/modules/catalog.md +43 -475
- package/dist/agentic/guides/modules/channel_gmail.md +3 -82
- package/dist/agentic/guides/modules/channel_imap.md +3 -82
- package/dist/agentic/guides/modules/checkout.md +27 -299
- package/dist/agentic/guides/modules/communication_channels.md +33 -315
- package/dist/agentic/guides/modules/configs.md +8 -104
- package/dist/agentic/guides/modules/content.md +2 -57
- package/dist/agentic/guides/modules/currencies.md +17 -152
- package/dist/agentic/guides/modules/customer_accounts.md +45 -387
- package/dist/agentic/guides/modules/customers.md +85 -746
- package/dist/agentic/guides/modules/dashboards.md +10 -155
- package/dist/agentic/guides/modules/data_sync.md +16 -149
- package/dist/agentic/guides/modules/dictionaries.md +12 -107
- package/dist/agentic/guides/modules/directory.md +15 -148
- package/dist/agentic/guides/modules/entities.md +13 -145
- package/dist/agentic/guides/modules/events.md +2 -59
- package/dist/agentic/guides/modules/feature_toggles.md +9 -119
- package/dist/agentic/guides/modules/gateway_stripe.md +4 -92
- package/dist/agentic/guides/modules/generators.md +2 -45
- package/dist/agentic/guides/modules/inbox_ops.md +27 -207
- package/dist/agentic/guides/modules/integrations.md +16 -146
- package/dist/agentic/guides/modules/messages.md +24 -223
- package/dist/agentic/guides/modules/notifications.md +8 -96
- package/dist/agentic/guides/modules/onboarding.md +6 -77
- package/dist/agentic/guides/modules/payment_gateways.md +21 -164
- package/dist/agentic/guides/modules/perspectives.md +7 -77
- package/dist/agentic/guides/modules/planner.md +18 -136
- package/dist/agentic/guides/modules/portal.md +2 -93
- package/dist/agentic/guides/modules/progress.md +14 -104
- package/dist/agentic/guides/modules/query_index.md +15 -154
- package/dist/agentic/guides/modules/record_locks.md +21 -206
- package/dist/agentic/guides/modules/resources.md +30 -197
- package/dist/agentic/guides/modules/sales.md +84 -678
- package/dist/agentic/guides/modules/scheduler.md +14 -133
- package/dist/agentic/guides/modules/search.md +6 -170
- package/dist/agentic/guides/modules/security.md +35 -294
- package/dist/agentic/guides/modules/shipping_carriers.md +18 -134
- package/dist/agentic/guides/modules/sso.md +26 -151
- package/dist/agentic/guides/modules/staff.md +57 -369
- package/dist/agentic/guides/modules/storage_s3.md +5 -95
- package/dist/agentic/guides/modules/sync_akeneo.md +3 -85
- package/dist/agentic/guides/modules/sync_excel.md +6 -75
- package/dist/agentic/guides/modules/system_status_overlays.md +2 -60
- package/dist/agentic/guides/modules/translations.md +10 -104
- package/dist/agentic/guides/modules/webhooks.md +24 -203
- package/dist/agentic/guides/modules/wms.md +46 -441
- package/dist/agentic/guides/modules/workflows.md +43 -302
- package/dist/agentic/guides/queue.md +53 -0
- package/dist/agentic/guides/search.md +115 -0
- package/dist/agentic/guides/shared.md +108 -0
- package/dist/agentic/guides/ui.md +347 -0
- package/dist/agentic/shared/AGENTS.md.template +311 -124
- package/dist/agentic/shared/ai/agentic.config.json +0 -2
- package/dist/agentic/shared/ai/lessons.md +3 -26
- package/dist/agentic/shared/ai/skills/om-auto-continue-pr-loop/SKILL.md +27 -0
- package/dist/agentic/shared/ai/skills/om-auto-create-pr-loop/SKILL.md +27 -0
- package/dist/agentic/shared/ai/skills/om-auto-review-pr/SKILL.md +0 -4
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/SKILL.md +241 -20
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/ui-components.md +260 -0
- package/dist/agentic/shared/ai/skills/om-data-model-design/SKILL.md +601 -16
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/mikro-orm-cheatsheet.md +146 -0
- package/dist/agentic/shared/ai/skills/om-eject-and-customize/SKILL.md +310 -14
- package/dist/agentic/shared/ai/skills/om-help/SKILL.md +97 -15
- package/dist/agentic/shared/ai/skills/om-help/references/skills-catalog.md +84 -0
- package/dist/agentic/shared/ai/skills/om-help/references/workflow-sequences.md +193 -0
- package/dist/agentic/shared/ai/skills/om-implement-spec/SKILL.md +152 -33
- package/dist/agentic/shared/ai/skills/om-integration-builder/SKILL.md +708 -24
- package/dist/agentic/shared/ai/skills/om-integration-builder/STANDALONE.md +34 -0
- package/dist/agentic/shared/ai/skills/om-integration-builder/references/adapter-contracts.md +762 -0
- package/dist/agentic/shared/ai/skills/om-module-scaffold/SKILL.md +820 -20
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/naming-conventions.md +50 -0
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/navigation-patterns.md +97 -0
- package/dist/agentic/shared/ai/skills/om-system-extension/SKILL.md +843 -19
- package/dist/agentic/shared/ai/skills/om-system-extension/references/extension-contracts.md +271 -0
- package/dist/agentic/shared/ai/skills/om-trim-unused-modules/SKILL.md +63 -15
- package/dist/agentic/shared/ai/skills/om-troubleshooter/SKILL.md +467 -16
- package/dist/agentic/shared/ai/skills/om-troubleshooter/references/diagnostic-commands.md +101 -0
- package/dist/agentic/shared/ai/skills/tiers.json +21 -143
- package/dist/agentic/shared/ai/skills/tiers.schema.json +40 -52
- package/dist/agentic/shared/ai/specs/README.md +3 -4
- package/dist/agentic/shared/ai/specs/SPEC-000-template.md +10 -226
- package/dist/agentic/shared/ai/trackers/github.md +4 -108
- package/dist/agentic/shared/scripts/install-skills.sh +694 -4
- package/dist/bin.js +1 -13
- package/dist/bin.js.map +2 -2
- package/dist/lib/__integration__/TC-INT-008.spec.js +8 -88
- package/dist/lib/__integration__/TC-INT-008.spec.js.map +2 -2
- package/dist/lib/agentic-init.js +3 -13
- package/dist/lib/agentic-init.js.map +2 -2
- package/dist/lib/agentic-setup.js +186 -418
- package/dist/lib/agentic-setup.js.map +2 -2
- package/dist/lib/generators/extensions/injection-widgets.js +0 -20
- package/dist/lib/generators/extensions/injection-widgets.js.map +2 -2
- package/dist/lib/generators/module-facts-discovery.js +7 -41
- package/dist/lib/generators/module-facts-discovery.js.map +2 -2
- package/dist/lib/generators/module-facts.js +45 -1387
- package/dist/lib/generators/module-facts.js.map +3 -3
- package/dist/lib/generators/module-registry.js +5 -11
- package/dist/lib/generators/module-registry.js.map +2 -2
- package/dist/lib/resolver.js +0 -2
- package/dist/lib/resolver.js.map +2 -2
- package/dist/lib/testing/integration.js +0 -5
- package/dist/lib/testing/integration.js.map +2 -2
- package/dist/mercato.js +1 -23
- package/dist/mercato.js.map +2 -2
- package/package.json +11 -13
- package/src/bin.ts +1 -33
- package/src/lib/__integration__/TC-INT-008.spec.ts +9 -107
- package/src/lib/__tests__/agentic-init.test.ts +5 -41
- package/src/lib/agentic-init.ts +3 -15
- package/src/lib/agentic-setup.ts +224 -530
- package/src/lib/generators/__tests__/module-facts.bc-guard.test.ts +2 -88
- package/src/lib/generators/__tests__/module-facts.customers.fixture.test.ts +0 -1
- package/src/lib/generators/__tests__/module-facts.discovery.test.ts +10 -54
- package/src/lib/generators/__tests__/module-subset.test.ts +0 -18
- package/src/lib/generators/extensions/injection-widgets.ts +0 -51
- package/src/lib/generators/module-facts-discovery.ts +7 -58
- package/src/lib/generators/module-facts.ts +46 -1851
- package/src/lib/generators/module-registry.ts +6 -16
- package/src/lib/resolver.ts +0 -3
- package/src/lib/testing/__tests__/integration.test.ts +0 -4
- package/src/lib/testing/integration.ts +0 -5
- package/src/mercato.ts +1 -26
- package/dist/agentic/guides/ai-workflows.md +0 -76
- package/dist/agentic/guides/architecture.md +0 -107
- package/dist/agentic/guides/backend-ui.md +0 -80
- package/dist/agentic/guides/contracts.md +0 -92
- package/dist/agentic/guides/extensions.md +0 -121
- package/dist/agentic/guides/framework-extension-points.md +0 -36
- package/dist/agentic/guides/integrations.md +0 -81
- package/dist/agentic/guides/modules/design_system.md +0 -102
- package/dist/agentic/guides/spec-delivery.md +0 -22
- package/dist/agentic/guides/testing-debugging.md +0 -80
- package/dist/agentic/guides/upstream/AGENTS.md +0 -298
- package/dist/agentic/guides/upstream/BACKWARD_COMPATIBILITY.md +0 -316
- package/dist/agentic/guides/upstream/manifest.json +0 -8
- package/dist/agentic/shared/ai/harness/README.md +0 -50
- package/dist/agentic/shared/ai/harness/RELEASE.md +0 -57
- package/dist/agentic/shared/ai/harness/cases.json +0 -13680
- package/dist/agentic/shared/ai/harness/cases.schema.json +0 -133
- package/dist/agentic/shared/ai/harness/fixtures/index.json +0 -49
- package/dist/agentic/shared/ai/harness/fixtures/seeds.json +0 -162
- package/dist/agentic/shared/ai/harness/generated-code-review-policy.md +0 -21
- package/dist/agentic/shared/ai/harness/generated-code-review-response.schema.json +0 -96
- package/dist/agentic/shared/ai/harness/generated-code-review-result.schema.json +0 -172
- package/dist/agentic/shared/ai/harness/release-matrix.json +0 -158
- package/dist/agentic/shared/ai/harness/release-result.schema.json +0 -219
- package/dist/agentic/shared/ai/harness/result.schema.json +0 -76
- package/dist/agentic/shared/ai/harness/routing-response.schema.json +0 -12
- package/dist/agentic/shared/ai/harness/target-validation-result.schema.json +0 -73
- package/dist/agentic/shared/ai/harness/validators.json +0 -78
- package/dist/agentic/shared/ai/harness/writable-ast-oracles.mjs +0 -2121
- package/dist/agentic/shared/ai/harness/writable-behavior-oracles.mjs +0 -1096
- package/dist/agentic/shared/ai/lessons/_template.md +0 -16
- package/dist/agentic/shared/ai/review-checklist.md +0 -36
- package/dist/agentic/shared/ai/skills/om-auto-implement-spec/SKILL.md +0 -21
- package/dist/agentic/shared/ai/skills/om-auto-upgrade-0.6.6-to-0.6.7/SKILL.md +0 -98
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/crud-surfaces.md +0 -16
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/frontend-and-design-system.md +0 -53
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/page-and-navigation.md +0 -13
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/quality-states.md +0 -11
- package/dist/agentic/shared/ai/skills/om-build-workflow/SKILL.md +0 -30
- package/dist/agentic/shared/ai/skills/om-build-workflow/references/activity-contracts.md +0 -12
- package/dist/agentic/shared/ai/skills/om-build-workflow/references/durability-and-progress.md +0 -13
- package/dist/agentic/shared/ai/skills/om-build-workflow/references/workflow-design.md +0 -14
- package/dist/agentic/shared/ai/skills/om-create-ai-agent/SKILL.md +0 -28
- package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/attachments-and-overrides.md +0 -12
- package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/module-agents-and-tools.md +0 -22
- package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/orchestrator-agents.md +0 -12
- package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/surface-selector.md +0 -19
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/integrity-and-concurrency.md +0 -19
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/migration-workflow.md +0 -13
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/schema-design.md +0 -14
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/sensitive-data.md +0 -10
- package/dist/agentic/shared/ai/skills/om-eject-and-customize/references/decision-and-procedure.md +0 -17
- package/dist/agentic/shared/ai/skills/om-evolve-harness/SKILL.md +0 -29
- package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-template.md +0 -100
- package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-workflow.md +0 -16
- package/dist/agentic/shared/ai/skills/om-evolve-harness/references/owner-selection.md +0 -17
- package/dist/agentic/shared/ai/skills/om-framework-context/SKILL.md +0 -25
- package/dist/agentic/shared/ai/skills/om-framework-context/references/resolver-procedure.md +0 -11
- package/dist/agentic/shared/ai/skills/om-framework-context/references/skew-and-escalation.md +0 -13
- package/dist/agentic/shared/ai/skills/om-help/references/delivery-workflows.md +0 -18
- package/dist/agentic/shared/ai/skills/om-help/references/task-families.md +0 -20
- package/dist/agentic/shared/ai/skills/om-implement-spec/references/phases-and-gates.md +0 -33
- package/dist/agentic/shared/ai/skills/om-implement-spec/references/planning-and-progress.md +0 -40
- package/dist/agentic/shared/ai/skills/om-implement-spec/references/report-templates.md +0 -27
- package/dist/agentic/shared/ai/skills/om-implement-spec/references/spec-resolution.md +0 -24
- package/dist/agentic/shared/ai/skills/om-integration-builder/references/package-and-activation.md +0 -16
- package/dist/agentic/shared/ai/skills/om-integration-builder/references/provider-families.md +0 -14
- package/dist/agentic/shared/ai/skills/om-integration-builder/references/security-and-reliability.md +0 -15
- package/dist/agentic/shared/ai/skills/om-integration-builder/references/sync-and-files.md +0 -12
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/SKILL.md +0 -34
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/agents/openai.yaml +0 -4
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/agentic-setup.md +0 -11
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/input-normalization.md +0 -31
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/judge-workflow.md +0 -39
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/report-template.md +0 -43
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/rules.md +0 -11
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/api-and-domain.md +0 -19
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/business-one-shot-blueprints.md +0 -172
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/data-and-migrations.md +0 -12
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/discovery-surface-catalog.md +0 -83
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/module-surfaces.md +0 -21
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/planning.md +0 -11
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/runtime-cache-and-queues.md +0 -22
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/verification.md +0 -13
- package/dist/agentic/shared/ai/skills/om-share-this-session/SKILL.md +0 -41
- package/dist/agentic/shared/ai/skills/om-share-this-session/references/agentic-setup.md +0 -19
- package/dist/agentic/shared/ai/skills/om-share-this-session/references/bundle-preparation.md +0 -44
- package/dist/agentic/shared/ai/skills/om-share-this-session/references/consent-and-review.md +0 -39
- package/dist/agentic/shared/ai/skills/om-share-this-session/references/publication.md +0 -20
- package/dist/agentic/shared/ai/skills/om-share-this-session/references/report-templates.md +0 -57
- package/dist/agentic/shared/ai/skills/om-share-this-session/references/rules.md +0 -11
- package/dist/agentic/shared/ai/skills/om-share-this-session/scripts/prepare-share-bundle.mjs +0 -486
- package/dist/agentic/shared/ai/skills/om-system-extension/references/extension-branches.md +0 -18
- package/dist/agentic/shared/ai/skills/om-system-extension/references/mechanism-selector.md +0 -27
- package/dist/agentic/shared/ai/skills/om-system-extension/references/read-write-roundtrip.md +0 -13
- package/dist/agentic/shared/ai/skills/om-system-extension/references/unified-overrides.md +0 -41
- package/dist/agentic/shared/ai/skills/om-system-extension/references/verification.md +0 -11
- package/dist/agentic/shared/ai/skills/om-trim-unused-modules/references/dependency-and-redirect.md +0 -15
- package/dist/agentic/shared/ai/skills/om-troubleshooter/references/diagnosis-map.md +0 -16
- package/dist/agentic/shared/ai/skills/om-troubleshooter/references/regression-oracles.md +0 -14
- package/dist/agentic/shared/scripts/agent-harness-tool-server.mjs +0 -187
- package/dist/agentic/shared/scripts/check-lessons.mjs +0 -178
- package/dist/agentic/shared/scripts/evaluate-agent-harness.mjs +0 -2958
- package/dist/agentic/shared/scripts/execution-sandbox.mjs +0 -329
- package/dist/agentic/shared/scripts/framework-context.mjs +0 -888
- package/dist/agentic/shared/scripts/install-skills.mjs +0 -1029
- package/dist/agentic/shared/scripts/prepare-agent-harness-fixture.mjs +0 -222
- package/dist/agentic/shared/scripts/run-agent-harness-release.mjs +0 -1774
- package/dist/lib/generators/module-extension-facts.js +0 -1840
- package/dist/lib/generators/module-extension-facts.js.map +0 -7
- package/dist/lib/generators/module-fact-sources.js +0 -70
- package/dist/lib/generators/module-fact-sources.js.map +0 -7
- package/dist/lib/generators/module-override-targets.js +0 -688
- package/dist/lib/generators/module-override-targets.js.map +0 -7
- package/dist/lib/load-env.js +0 -24
- package/dist/lib/load-env.js.map +0 -7
- package/dist/lib/telemetry-init.js +0 -358
- package/dist/lib/telemetry-init.js.map +0 -7
- package/src/lib/__tests__/agentic-setup.ownership.test.ts +0 -386
- package/src/lib/__tests__/injection-widget-id-validation.test.ts +0 -184
- package/src/lib/__tests__/load-env.test.ts +0 -65
- package/src/lib/__tests__/telemetry-init.test.ts +0 -298
- package/src/lib/generators/__tests__/activation-adapter-coverage.test.ts +0 -92
- package/src/lib/generators/__tests__/module-extension-activations.test.ts +0 -762
- package/src/lib/generators/__tests__/module-extension-facts.test.ts +0 -404
- package/src/lib/generators/__tests__/module-facts.extension-hosts.test.ts +0 -108
- package/src/lib/generators/__tests__/module-facts.owned-contracts.test.ts +0 -561
- package/src/lib/generators/__tests__/module-facts.source-links.test.ts +0 -119
- package/src/lib/generators/__tests__/module-override-targets.roundtrip.test.ts +0 -149
- package/src/lib/generators/__tests__/module-override-targets.test.ts +0 -304
- package/src/lib/generators/module-extension-facts.ts +0 -2365
- package/src/lib/generators/module-fact-sources.ts +0 -108
- package/src/lib/generators/module-override-targets.ts +0 -863
- package/src/lib/load-env.ts +0 -30
- 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
|
-
}
|