@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
|
@@ -3,33 +3,249 @@
|
|
|
3
3
|
**Date**: {YYYY-MM-DD}
|
|
4
4
|
**Status**: Draft
|
|
5
5
|
|
|
6
|
+
> Use `om-spec-writing` for every new application, multi-module feature, or other non-trivial business slice. Keep every section below; write `N/A — {reason}` when a section does not apply. Change the status to `Ready for implementation` only after every blocking open question is resolved and the traceability table covers every requirement.
|
|
7
|
+
|
|
6
8
|
## TLDR
|
|
7
9
|
|
|
8
|
-
{
|
|
10
|
+
{What is being built, who benefits, which existing Open Mercato capabilities are reused, and the smallest coherent outcome.}
|
|
9
11
|
|
|
10
12
|
## Problem Statement
|
|
11
13
|
|
|
12
|
-
{
|
|
14
|
+
{Current workflow, concrete pain, evidence, affected users, and why existing behavior is insufficient.}
|
|
15
|
+
|
|
16
|
+
## Overview and Success Measures
|
|
17
|
+
|
|
18
|
+
- **Primary outcome:** {Measurable business result and target.}
|
|
19
|
+
- **Leading indicators:** {Signals available before the final outcome.}
|
|
20
|
+
- **Baseline:** {Current measurable state or `unknown — measurement plan`.}
|
|
21
|
+
- **Market / product reference:** {Comparable product or workflow studied; what is adopted, rejected, and why.}
|
|
22
|
+
|
|
23
|
+
## Goals
|
|
24
|
+
|
|
25
|
+
- **REQ-001** — {Observable business outcome.}
|
|
26
|
+
- **REQ-002** — {Observable business outcome.}
|
|
27
|
+
|
|
28
|
+
## Non-goals
|
|
29
|
+
|
|
30
|
+
- {Explicitly excluded behavior, module, integration, or migration.}
|
|
13
31
|
|
|
14
32
|
## Proposed Solution
|
|
15
33
|
|
|
16
|
-
{
|
|
34
|
+
{Describe the product and technical approach, how it closes each stated problem, and why it is the smallest platform-native solution that can deliver the goals.}
|
|
35
|
+
|
|
36
|
+
### Design Decisions and Alternatives
|
|
37
|
+
|
|
38
|
+
| Decision | Rationale | Alternative considered | Why rejected / deferred |
|
|
39
|
+
|---|---|---|---|
|
|
40
|
+
| {choice} | {why it fits the requirements and platform} | {alternative} | {tradeoff} |
|
|
41
|
+
|
|
42
|
+
## Domain Vocabulary and Business Rules
|
|
43
|
+
|
|
44
|
+
| Term / invariant | Precise meaning or rule | Source of truth | Failure behavior |
|
|
45
|
+
|---|---|---|---|
|
|
46
|
+
| {term} | {one unambiguous meaning, formula, lifecycle, or constraint} | {module/entity/provider} | {reject/degrade/retry/audit} |
|
|
47
|
+
|
|
48
|
+
Define fields, states, transitions, calculations, ownership, and invariants precisely enough that implementation does not need to invent domain behavior.
|
|
49
|
+
|
|
50
|
+
## Users, Permissions, and Scope
|
|
51
|
+
|
|
52
|
+
| Actor | Allowed outcomes | Scope rule | Required feature IDs |
|
|
53
|
+
|---|---|---|---|
|
|
54
|
+
| {actor} | {view/create/update/etc.} | {own/team/organization/system} | `{module}.view`, `{module}.manage` |
|
|
55
|
+
|
|
56
|
+
Document how trusted `tenantId` and `organizationId` are derived. Describe any legitimate system-scope operation and the installed contract that authorizes it.
|
|
57
|
+
|
|
58
|
+
## Reuse and Ownership Map
|
|
59
|
+
|
|
60
|
+
| Capability | Reuse / extend / app-own | Existing module or new module | Integration seam | Why |
|
|
61
|
+
|---|---|---|---|---|
|
|
62
|
+
| {capability} | {reuse/UMES/app-owned} | `{module}` | {ID/snapshot/event/enricher/extension/optional DI} | {decision} |
|
|
63
|
+
|
|
64
|
+
Name the installed records that remain the source of truth. Do not duplicate CRM, auth, directory, notification, workflow, or other installed capabilities in app-owned entities.
|
|
65
|
+
|
|
66
|
+
## Architecture and Data Flow
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
{actor/surface} -> {API/command} -> {owning entity}
|
|
70
|
+
-> {event/subscriber/integration}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
- **Module boundaries:** {Why each new module owns a distinct invariant; merge modules that must remain transactionally consistent.}
|
|
74
|
+
- **Extension points:** {Installed page/menu/widget/enricher/interceptor/event seams used instead of modifying installed code.}
|
|
75
|
+
- **Alternatives considered:** {Simpler platform-native alternative and why it was not selected.}
|
|
76
|
+
- **Compatibility:** {Existing API/data/UI behavior that must remain stable.}
|
|
77
|
+
|
|
78
|
+
## User Journeys
|
|
79
|
+
|
|
80
|
+
### Journey J-001 — {Name}
|
|
81
|
+
|
|
82
|
+
1. {Actor starts from a named page or API.}
|
|
83
|
+
2. {Primary action and system response.}
|
|
84
|
+
3. {Success state and downstream side effects.}
|
|
85
|
+
4. {Recoverable failure, permission denial, conflict, and retry behavior.}
|
|
86
|
+
|
|
87
|
+
## UI and Interaction Contracts
|
|
88
|
+
|
|
89
|
+
List every new or changed page before implementation. Inspect the closest existing Open Mercato page and `.ai/guides/backend-ui.md`; record that reference below. Tabular admin data uses `DataTable`, CRUD create/edit surfaces use `CrudForm`, and backend reads use the shared API helpers. Any custom page or component exception needs an explicit rationale and approval in this section.
|
|
90
|
+
|
|
91
|
+
| Surface / route | Purpose and primary actions | Data source / mutations | Closest installed reference | Canonical shell / components | Required states | Requirement IDs |
|
|
92
|
+
|---|---|---|---|---|---|---|
|
|
93
|
+
| `/backend/{route}` | {list/create/edit/etc.} | `{API paths / command IDs}` | `{module/path or component family}` | `Page`, `PageBody`, `DataTable`, `CrudForm`, {others} | loading, empty, error, conflict, success, permission denied | REQ-001 |
|
|
94
|
+
|
|
95
|
+
### UI architecture
|
|
96
|
+
|
|
97
|
+
| Role | Navigation groups in order | Dashboard / injected widgets | Login-to-primary-task flow |
|
|
98
|
+
|---|---|---|---|
|
|
99
|
+
| {role} | {group → item} | {widget, host, click-through} | {page → action → result; target ≤3 clicks} |
|
|
100
|
+
|
|
101
|
+
| Surface / widget | Empty state guidance and action | Responsive behavior | Keyboard / focus behavior |
|
|
102
|
+
|---|---|---|---|
|
|
103
|
+
| {surface} | {localized explanation + next action} | {narrow/mobile layout} | {focus order, submit/cancel, announcements} |
|
|
104
|
+
|
|
105
|
+
### `/backend/{route}` — {Page name}
|
|
106
|
+
|
|
107
|
+
```text
|
|
108
|
+
┌────────────────────────────────────────────────────────────┐
|
|
109
|
+
│ {Page title} [{Primary action}]│
|
|
110
|
+
│ {Filters / summary / navigation} │
|
|
111
|
+
├────────────────────────────────────────────────────────────┤
|
|
112
|
+
│ {DataTable, CrudForm groups, calendar, or detail sections} │
|
|
113
|
+
├────────────────────────────────────────────────────────────┤
|
|
114
|
+
│ {Pagination / save-delete actions / status feedback} │
|
|
115
|
+
└────────────────────────────────────────────────────────────┘
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- **Behavior:** {sorting/filtering/pagination, validation, keyboard behavior, navigation, destructive confirmation, optimistic-lock conflict recovery.}
|
|
119
|
+
- **Responsive and accessibility:** {focus order, labels, screen-reader status, small-screen behavior.}
|
|
120
|
+
- **Localization:** {translation namespaces and dynamic values.}
|
|
121
|
+
- **Design-system and theming:** {semantic tokens and shared primitives; verify light and dark mode, contrast, reduced motion, and no hard-coded palette/status colors.}
|
|
122
|
+
|
|
123
|
+
For backend UI, implementation must invoke `om-backend-ui-design` and follow `.ai/guides/backend-ui.md`. Raw `<table>`, raw admin `<form>`, raw `fetch`, copied component families, arbitrary Tailwind values, hard-coded light-only colors, and manual `dark:` patches fail readiness unless the approved contract explains why the platform primitive cannot support the interaction. A custom calendar, board, or clinical workspace may be justified, but its surrounding shell, controls, status treatment, dialogs, states, and tokens remain platform-native.
|
|
17
124
|
|
|
18
125
|
## Data Models
|
|
19
126
|
|
|
20
|
-
{Entity
|
|
127
|
+
### `{Entity}`
|
|
128
|
+
|
|
129
|
+
| Field | Type / nullability | Scope / index | Sensitive / encrypted | Lifecycle and validation |
|
|
130
|
+
|---|---|---|---|---|
|
|
131
|
+
| `id` | UUID, required | primary key | no | immutable |
|
|
132
|
+
| `tenant_id` / `organization_id` | UUID, required | composite scope indexes | no | trusted context only |
|
|
133
|
+
| `updated_at` | timestamp, required | optimistic-lock version | no | updated on every edit |
|
|
134
|
+
|
|
135
|
+
Document entity ownership, soft-delete or append-only rules, cross-module IDs/snapshots, uniqueness, transactions, encryption maps, retention, migrations, and compatibility impact.
|
|
136
|
+
|
|
137
|
+
## API, Command, and Error Contracts
|
|
138
|
+
|
|
139
|
+
| Method / command | Path / ID | Auth and feature gate | Input | Success response / event | Errors and concurrency | Requirement IDs |
|
|
140
|
+
|---|---|---|---|---|---|---|
|
|
141
|
+
| `GET` | `/api/{path}` | auth + `{module}.view` | {query schema} | `{ items, totalCount }` | 400/401/403 | REQ-001 |
|
|
142
|
+
| `POST` | `/api/{path}` | auth + `{module}.manage` | {body schema} | 201 + `{module}.{entity}.created` | 400/403/409 | REQ-002 |
|
|
143
|
+
|
|
144
|
+
State whether each route uses `makeCrudRoute` or a custom guarded command route. Include per-method `metadata`, OpenAPI schemas, scope derivation, idempotency, optimistic locking, and stable public-contract implications.
|
|
145
|
+
|
|
146
|
+
## Events, Jobs, Notifications, and Cross-Module Flows
|
|
147
|
+
|
|
148
|
+
| Trigger | Producer | Consumer | Side effect | Retry / idempotency / audit behavior |
|
|
149
|
+
|---|---|---|---|---|
|
|
150
|
+
| `{module}.{entity}.{action}` | `{module}` | `{subscriber}` | {result} | {contract} |
|
|
151
|
+
|
|
152
|
+
Describe scheduled work, progress, cache invalidation, failure recovery, and optional-module behavior where applicable.
|
|
153
|
+
|
|
154
|
+
## Security, Privacy, and Compliance
|
|
155
|
+
|
|
156
|
+
- **Authorization:** {feature gates and record-level scope; never role-name checks.}
|
|
157
|
+
- **Tenant isolation:** {read/write filters and fail-closed behavior.}
|
|
158
|
+
- **Sensitive data:** {encryption map, safe reads, redaction, retention, audit policy.}
|
|
159
|
+
- **Abuse and failure modes:** {enumeration, injection, replay, concurrency, destructive action, secret exposure.}
|
|
160
|
+
|
|
161
|
+
## Integration Coverage
|
|
162
|
+
|
|
163
|
+
Tests must be self-contained and map to real API and UI paths.
|
|
164
|
+
|
|
165
|
+
| Test ID | Level | Setup / fixture | Actions | Assertions | Requirement IDs |
|
|
166
|
+
|---|---|---|---|---|---|
|
|
167
|
+
| TEST-001 | integration | {tenant/org/users/records} | {API or browser flow} | {success + persisted state + event} | REQ-001 |
|
|
168
|
+
| TEST-002 | security | {second tenant / insufficient feature} | {forbidden read/write} | {fail closed; no data leak} | REQ-001 |
|
|
169
|
+
| TEST-003 | UI | {records and permissions} | {loading/empty/error/conflict/keyboard flow} | {observable result} | REQ-002 |
|
|
170
|
+
|
|
171
|
+
## Implementation Phases
|
|
172
|
+
|
|
173
|
+
Phases are dependency ordered. Only the current phase may enter implementation; parallel work is limited to independent slices inside that phase. Each phase must leave a working app and close with its own evidence before the next phase starts.
|
|
21
174
|
|
|
22
|
-
|
|
175
|
+
### Phase 1 — {Foundation or first complete vertical slice}
|
|
23
176
|
|
|
24
|
-
|
|
177
|
+
- **Depends on:** none
|
|
178
|
+
- **Outcome:** {user-visible or independently verifiable result}
|
|
179
|
+
- **Why this order / value delivered:** {dependency and measurable business value available at phase completion}
|
|
180
|
+
- **Deliverables:** {specific entities, commands, routes, pages, subscribers, migrations}
|
|
181
|
+
- **Independent slices / estimated commits:** {bounded work that may run in parallel inside this phase only}
|
|
182
|
+
- **Requirements closed:** REQ-001
|
|
183
|
+
- **Tests:** TEST-001, TEST-002
|
|
184
|
+
- **Validation:** `yarn generate`, {focused typecheck/tests/integration paths}
|
|
185
|
+
- **Exit gate:** {observable criteria proving this phase works end to end, including affected UI in light/dark and narrow-width states}
|
|
186
|
+
|
|
187
|
+
### Phase 2 — {Next complete vertical slice}
|
|
188
|
+
|
|
189
|
+
- **Depends on:** Phase 1 exit gate
|
|
190
|
+
- **Outcome:** {result}
|
|
191
|
+
- **Why this order / value delivered:** {dependency and measurable business value}
|
|
192
|
+
- **Deliverables:** {specific files/seams}
|
|
193
|
+
- **Independent slices / estimated commits:** {bounded work inside this phase}
|
|
194
|
+
- **Requirements closed:** REQ-002
|
|
195
|
+
- **Tests:** TEST-003
|
|
196
|
+
- **Validation:** {focused commands}
|
|
197
|
+
- **Exit gate:** {observable criteria}
|
|
198
|
+
|
|
199
|
+
## Requirement Traceability
|
|
200
|
+
|
|
201
|
+
| Requirement | Journey / surface | Data/API/event contracts | Phase | Tests | Acceptance criterion |
|
|
202
|
+
|---|---|---|---|---|---|
|
|
203
|
+
| REQ-001 | J-001, `/backend/{route}` | `{entity}`, `GET /api/{path}` | Phase 1 | TEST-001, TEST-002 | AC-001 |
|
|
204
|
+
|
|
205
|
+
Every requirement must map to a phase, at least one test oracle, and a measurable acceptance criterion. No phase may be a catch-all “integration and polish” bucket for behavior required by earlier slices.
|
|
206
|
+
|
|
207
|
+
## Rollout, Migration, and Rollback
|
|
208
|
+
|
|
209
|
+
{Migration generation/application boundary, seed/setup work, feature flags, compatibility bridge, observability, rollout order, and reversible rollback steps.}
|
|
210
|
+
|
|
211
|
+
## Risks and Tradeoffs
|
|
212
|
+
|
|
213
|
+
| Risk / tradeoff | Impact | Mitigation / detection | Residual risk |
|
|
214
|
+
|---|---|---|---|
|
|
215
|
+
| {risk} | {impact} | {test/metric/guard} | {accepted remainder} |
|
|
216
|
+
|
|
217
|
+
Cover data integrity and concurrency, cascading/event failures, tenant isolation and privacy, migration/rollback, external-service degradation, scale/storage, and operational detection. Do not use “standard risks” as a substitute for concrete failure scenarios.
|
|
25
218
|
|
|
26
219
|
## Acceptance Criteria
|
|
27
220
|
|
|
28
|
-
- [ ] {
|
|
29
|
-
- [ ] {
|
|
221
|
+
- [ ] **AC-001** — {Measurable end-to-end result, including actor and scope.}
|
|
222
|
+
- [ ] **AC-002** — {Measurable failure/safety result.}
|
|
223
|
+
- [ ] Every listed backend surface matches its recorded Open Mercato reference and uses the canonical shell/components, shared API helpers, semantic tokens, and complete loading, empty, error, conflict, keyboard, accessibility, responsive, light-mode, and dark-mode states.
|
|
224
|
+
- [ ] Every affected API and UI path has self-contained integration coverage and the configured validation gate passes.
|
|
225
|
+
|
|
226
|
+
## Final Compliance Report
|
|
227
|
+
|
|
228
|
+
| Check | Status | Evidence / resolution |
|
|
229
|
+
|---|---|---|
|
|
230
|
+
| Applicable `AGENTS.md` files and routed guides/skills reviewed | pass/fail | {paths} |
|
|
231
|
+
| Data models, APIs, events, UI, and tests are internally consistent | pass/fail | {traceability rows} |
|
|
232
|
+
| Every workflow completes end to end without a catch-all integration phase | pass/fail | {journeys/phases} |
|
|
233
|
+
| Platform-native reuse and extension points were chosen before custom code | pass/fail | {reuse decisions} |
|
|
234
|
+
| UI contracts identify references, canonical components, and theme/state coverage | pass/fail | {surfaces} |
|
|
235
|
+
| Every phase has dependencies, bounded slices, tests, value, and an observable exit gate | pass/fail | {phases} |
|
|
236
|
+
|
|
237
|
+
Verdict must be exactly `Ready for implementation` or `Blocked — {unresolved items}`. The document status may change to ready only when every row passes.
|
|
238
|
+
|
|
239
|
+
## Open Questions
|
|
240
|
+
|
|
241
|
+
Blocking questions must be resolved before setting `Status: Ready for implementation`.
|
|
242
|
+
|
|
243
|
+
| ID | Question | Owner | Blocking? | Resolution / decision date |
|
|
244
|
+
|---|---|---|---|---|
|
|
245
|
+
| Q-001 | {question} | {owner} | yes/no | {pending or decision} |
|
|
30
246
|
|
|
31
247
|
## Changelog
|
|
32
248
|
|
|
33
249
|
| Date | Change |
|
|
34
|
-
|
|
35
|
-
| {date} | Initial
|
|
250
|
+
|---|---|
|
|
251
|
+
| {date} | Initial draft |
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Tracker provider: GitHub
|
|
2
2
|
|
|
3
|
-
This file is the GitHub implementation of the tracker operations contract (see `TEMPLATE.md` for the contract itself).
|
|
3
|
+
This file is the GitHub implementation of the tracker operations contract (see `TEMPLATE.md` for the contract itself). Skills perform issue/PR state management through **named tracker operations** — `**get-issue**`, `**comment-pr**`, and so on — and this file defines what each operation means for GitHub, using the `gh` CLI.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
At runtime: `om-setup-agent-pipeline` copies this file into the repository at `.ai/trackers/github.md`, and the config's `tracker` field selects it. When a skill says "tracker operation **get-pr**", execute the command documented under that operation heading in the repo's copy. The repo's copy is authoritative: teams extend or override any operation by editing it, and every skill picks the change up on its next run. An operation not covered by an edit keeps its behavior from this file's text as copied.
|
|
6
6
|
|
|
7
7
|
## Prerequisites
|
|
8
8
|
|
|
@@ -14,7 +14,7 @@ How it is used at runtime: `om-setup-agent-pipeline` copies this file into the r
|
|
|
14
14
|
- Issue and PR identifiers are numbers; in text they are written `#123`.
|
|
15
15
|
- A PR is linked to the issue it resolves with `Fixes #{issueId}` (or `Closes #{issueId}`) in the PR body; GitHub then closes the issue on merge. To reference without auto-closing, use a plain issue link.
|
|
16
16
|
- PRs open as **drafts** when a skill says so; a human (or **mark-pr-ready**) promotes them.
|
|
17
|
-
- Claim/lock signals on an issue or PR are: assignee set to the automation user, the `in-progress` label, and a `🤖`-prefixed claim comment. All three are set on claim; the label is guarded (below).
|
|
17
|
+
- Claim/lock signals on an issue or PR are: assignee set to the automation user, the `in-progress` label, and a `🤖`-prefixed claim comment. All three are set on claim; the label is guarded (below). The `ci-monitoring` label is **not** a claim/lock signal: it marks a PR whose work is finished and already reported while an agent watches CI, so a PR carrying `ci-monitoring` without any of the three signals above MUST be treated as unclaimed and is free to claim.
|
|
18
18
|
- Long, multi-line comment bodies are posted with `--body-file` (or a heredoc via process substitution) so formatting is preserved.
|
|
19
19
|
- CI status truth comes from **get-pr-checks**; the set of *required* checks comes from **get-required-checks** (branch protection). When branch protection is not readable (404), treat every reported check as required.
|
|
20
20
|
|
|
@@ -98,6 +98,84 @@ BASE_BRANCH=$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name'
|
|
|
98
98
|
[ -z "$BASE_BRANCH" ] && BASE_BRANCH="main"
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
+
### Public session-share artifacts
|
|
102
|
+
|
|
103
|
+
#### publish-session-share
|
|
104
|
+
`{owner}/{repo}`, `{branch}`, `{shareName}`, and a local `{bundleDir}` → atomically publish the four reviewed session-share artifacts on a new public branch and return repository, branch, commit, branch URL, and raw artifact URLs as JSON.
|
|
105
|
+
|
|
106
|
+
This operation is intentionally strict: the repository must already be public; the branch must be a new slash-free `session-share-…` ref; and the bundle directory must contain regular, non-symlinked `session.json`, `generated-files.zip`, `manifest.json`, and `privacy-report.json` files within the documented size cap. Git blobs, a tree, and a commit are created first; the public ref is created last, so a preparation failure does not expose a partial branch.
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
TARGET_REPO="{owner}/{repo}"
|
|
110
|
+
SHARE_BRANCH="{branch}"
|
|
111
|
+
SHARE_NAME="{shareName}"
|
|
112
|
+
BUNDLE_DIR="{bundleDir}"
|
|
113
|
+
printf '%s' "$TARGET_REPO" | grep -Eq '^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$' || exit 1
|
|
114
|
+
printf '%s' "$SHARE_NAME" | grep -Eq '^[a-z0-9][a-z0-9-]{1,46}[a-z0-9]$' || exit 1
|
|
115
|
+
[ "$SHARE_BRANCH" = "session-share-$SHARE_NAME" ] || exit 1
|
|
116
|
+
[ "$(gh repo view "$TARGET_REPO" --json visibility --jq .visibility)" = "PUBLIC" ] || exit 1
|
|
117
|
+
gh api "repos/${TARGET_REPO}/git/ref/heads/${SHARE_BRANCH}" >/dev/null 2>&1 && exit 1
|
|
118
|
+
|
|
119
|
+
SESSION_SHARE_TMP=$(mktemp -d)
|
|
120
|
+
trap 'rm -rf "$SESSION_SHARE_TMP"' EXIT HUP INT TERM
|
|
121
|
+
printf '[]\n' > "$SESSION_SHARE_TMP/tree.json"
|
|
122
|
+
TOTAL_BYTES=0
|
|
123
|
+
for ARTIFACT in session.json generated-files.zip manifest.json privacy-report.json; do
|
|
124
|
+
ARTIFACT_PATH="$BUNDLE_DIR/$ARTIFACT"
|
|
125
|
+
[ -f "$ARTIFACT_PATH" ] && [ ! -L "$ARTIFACT_PATH" ] || exit 1
|
|
126
|
+
ARTIFACT_BYTES=$(wc -c < "$ARTIFACT_PATH" | tr -d ' ')
|
|
127
|
+
TOTAL_BYTES=$((TOTAL_BYTES + ARTIFACT_BYTES))
|
|
128
|
+
[ "$ARTIFACT_BYTES" -le 26214400 ] && [ "$TOTAL_BYTES" -le 31457280 ] || exit 1
|
|
129
|
+
done
|
|
130
|
+
|
|
131
|
+
for ARTIFACT in session.json generated-files.zip manifest.json privacy-report.json; do
|
|
132
|
+
ARTIFACT_PATH="$BUNDLE_DIR/$ARTIFACT"
|
|
133
|
+
base64 < "$ARTIFACT_PATH" | tr -d '\n' > "$SESSION_SHARE_TMP/content.b64"
|
|
134
|
+
BLOB_SHA=$(jq -n --rawfile content "$SESSION_SHARE_TMP/content.b64" '{content:$content,encoding:"base64"}' \
|
|
135
|
+
| gh api -X POST "repos/${TARGET_REPO}/git/blobs" --input - --jq .sha) || exit 1
|
|
136
|
+
jq --arg path "$ARTIFACT" --arg sha "$BLOB_SHA" \
|
|
137
|
+
'. + [{path:$path,mode:"100644",type:"blob",sha:$sha}]' \
|
|
138
|
+
"$SESSION_SHARE_TMP/tree.json" > "$SESSION_SHARE_TMP/tree.next.json" || exit 1
|
|
139
|
+
mv "$SESSION_SHARE_TMP/tree.next.json" "$SESSION_SHARE_TMP/tree.json"
|
|
140
|
+
done
|
|
141
|
+
|
|
142
|
+
DEFAULT_BRANCH=$(gh repo view "$TARGET_REPO" --json defaultBranchRef --jq .defaultBranchRef.name) || exit 1
|
|
143
|
+
BASE_COMMIT=$(gh api "repos/${TARGET_REPO}/git/ref/heads/${DEFAULT_BRANCH}" --jq .object.sha) || exit 1
|
|
144
|
+
BASE_TREE=$(gh api "repos/${TARGET_REPO}/git/commits/${BASE_COMMIT}" --jq .tree.sha) || exit 1
|
|
145
|
+
TREE_SHA=$(jq -n --arg base "$BASE_TREE" --slurpfile entries "$SESSION_SHARE_TMP/tree.json" \
|
|
146
|
+
'{base_tree:$base,tree:$entries[0]}' \
|
|
147
|
+
| gh api -X POST "repos/${TARGET_REPO}/git/trees" --input - --jq .sha) || exit 1
|
|
148
|
+
COMMIT_SHA=$(jq -n --arg message "session share ${SHARE_NAME}" --arg tree "$TREE_SHA" --arg parent "$BASE_COMMIT" \
|
|
149
|
+
'{message:$message,tree:$tree,parents:[$parent]}' \
|
|
150
|
+
| gh api -X POST "repos/${TARGET_REPO}/git/commits" --input - --jq .sha) || exit 1
|
|
151
|
+
jq -n --arg ref "refs/heads/${SHARE_BRANCH}" --arg sha "$COMMIT_SHA" '{ref:$ref,sha:$sha}' \
|
|
152
|
+
| gh api -X POST "repos/${TARGET_REPO}/git/refs" --input - >/dev/null || exit 1
|
|
153
|
+
|
|
154
|
+
jq -n \
|
|
155
|
+
--arg repository "$TARGET_REPO" \
|
|
156
|
+
--arg branch "$SHARE_BRANCH" \
|
|
157
|
+
--arg commit "$COMMIT_SHA" \
|
|
158
|
+
--arg branchUrl "https://github.com/${TARGET_REPO}/tree/${SHARE_BRANCH}" \
|
|
159
|
+
--arg sessionUrl "https://raw.githubusercontent.com/${TARGET_REPO}/${SHARE_BRANCH}/session.json" \
|
|
160
|
+
--arg archiveUrl "https://raw.githubusercontent.com/${TARGET_REPO}/${SHARE_BRANCH}/generated-files.zip" \
|
|
161
|
+
--arg manifestUrl "https://raw.githubusercontent.com/${TARGET_REPO}/${SHARE_BRANCH}/manifest.json" \
|
|
162
|
+
--arg privacyUrl "https://raw.githubusercontent.com/${TARGET_REPO}/${SHARE_BRANCH}/privacy-report.json" \
|
|
163
|
+
'{repository:$repository,branch:$branch,commit:$commit,branchUrl:$branchUrl,artifacts:{session:$sessionUrl,archive:$archiveUrl,manifest:$manifestUrl,privacy:$privacyUrl}}'
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
#### delete-session-share
|
|
167
|
+
`{owner}/{repo}`, `{branch}`, and `{shareName}` → remove only the exact derived session-share ref after a failed issue creation or an explicit retention cleanup request. Deleting a public ref cannot guarantee erasure from clones, forks, caches, logs, or archives.
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
TARGET_REPO="{owner}/{repo}"
|
|
171
|
+
SHARE_BRANCH="{branch}"
|
|
172
|
+
SHARE_NAME="{shareName}"
|
|
173
|
+
printf '%s' "$TARGET_REPO" | grep -Eq '^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$' || exit 1
|
|
174
|
+
printf '%s' "$SHARE_NAME" | grep -Eq '^[a-z0-9][a-z0-9-]{1,46}[a-z0-9]$' || exit 1
|
|
175
|
+
[ "$SHARE_BRANCH" = "session-share-$SHARE_NAME" ] || exit 1
|
|
176
|
+
gh api -X DELETE "repos/${TARGET_REPO}/git/refs/heads/${SHARE_BRANCH}"
|
|
177
|
+
```
|
|
178
|
+
|
|
101
179
|
### Issues
|
|
102
180
|
|
|
103
181
|
#### get-issue
|
|
@@ -109,7 +187,9 @@ gh issue view {issueId} --repo {owner}/{repo} --json number,title,body,state,aut
|
|
|
109
187
|
#### search-issues
|
|
110
188
|
Query (text, `in:title,body`, state) → matching issues.
|
|
111
189
|
```bash
|
|
112
|
-
|
|
190
|
+
ISSUE_STATE="{state}"
|
|
191
|
+
case "$ISSUE_STATE" in open|closed|all) ;; *) exit 1 ;; esac
|
|
192
|
+
gh issue list --repo {owner}/{repo} --state "$ISSUE_STATE" --search "<query> in:title,body" --json number,title,url
|
|
113
193
|
```
|
|
114
194
|
|
|
115
195
|
#### create-issue
|
|
@@ -130,6 +210,12 @@ gh issue close {issueId} --repo {owner}/{repo} --reason completed --comment "<co
|
|
|
130
210
|
gh issue comment {issueId} --repo {owner}/{repo} --body "<body>"
|
|
131
211
|
```
|
|
132
212
|
|
|
213
|
+
#### update-issue
|
|
214
|
+
`{issueId}`, new title and/or body (use a body-file for multi-line bodies). Edits the issue's own fields; does not touch labels or assignees (those have their own operations).
|
|
215
|
+
```bash
|
|
216
|
+
gh issue edit {issueId} --repo {owner}/{repo} --title "<title>" --body-file <file>
|
|
217
|
+
```
|
|
218
|
+
|
|
133
219
|
#### assign-issue / unassign-issue
|
|
134
220
|
```bash
|
|
135
221
|
gh issue edit {issueId} --repo {owner}/{repo} --add-assignee "<login>"
|
|
@@ -151,6 +237,12 @@ gh api repos/{owner}/{repo}/issues/comments/{commentId} --jq '{body,user:.user.l
|
|
|
151
237
|
gh api repos/{owner}/{repo}/issues/{number}/comments --jq '.[] | {id,user:.user.login,body}'
|
|
152
238
|
```
|
|
153
239
|
|
|
240
|
+
#### update-comment
|
|
241
|
+
`{commentId}`, new body → rewrite an existing conversation comment in place (works for issue and PR conversation comments alike). This is how marker-idempotent comments (label rationale, verification, claim take-overs) are updated on re-runs: find your `🤖 …` marker via **list-issue-comments**, then update that comment instead of posting a new one. Use a body file so multi-line bodies survive.
|
|
242
|
+
```bash
|
|
243
|
+
gh api -X PATCH repos/{owner}/{repo}/issues/comments/{commentId} -F body=@<path>
|
|
244
|
+
```
|
|
245
|
+
|
|
154
246
|
### Pull requests
|
|
155
247
|
|
|
156
248
|
#### get-pr
|
|
@@ -181,6 +273,17 @@ PR_URL=$(gh pr view --json url --jq .url)
|
|
|
181
273
|
PR_NUMBER=$(gh pr view --json number --jq .number)
|
|
182
274
|
```
|
|
183
275
|
|
|
276
|
+
#### update-pr
|
|
277
|
+
`{prNumber}`, new title and/or new body → the PR's own title/body rewritten in place (not a comment), e.g. reframing a doc-originated spec PR that grew a feature implementation. Pass whichever of `--title` / `--body-file` changed; omit the other. Use a body file so multi-line bodies survive.
|
|
278
|
+
```bash
|
|
279
|
+
gh pr edit {prNumber} --title "<title>"
|
|
280
|
+
gh pr edit {prNumber} --body-file <path-or-process-substitution>
|
|
281
|
+
```
|
|
282
|
+
If `gh pr edit` silently no-ops in this repo (some GitHub setups do), fall back to the REST API:
|
|
283
|
+
```bash
|
|
284
|
+
gh api -X PATCH repos/{owner}/{repo}/pulls/{prNumber} -f title="<title>" -f body="$(cat <path>)"
|
|
285
|
+
```
|
|
286
|
+
|
|
184
287
|
#### comment-pr
|
|
185
288
|
`{prNumber}`, body. For long structured comments:
|
|
186
289
|
```bash
|
|
@@ -365,6 +468,7 @@ gh label create skip-qa --color 0e8a16 --description "Low risk, QA not
|
|
|
365
468
|
gh label create qa-approved --color 0e8a16 --description "Manual QA passed"
|
|
366
469
|
gh label create qa-self-verified --color c5def5 --description "Self-QA exception used"
|
|
367
470
|
gh label create in-progress --color c5def5 --description "An automated skill is working on this"
|
|
471
|
+
gh label create ci-monitoring --color 00b8d9 --description "Work complete and reported; agent is watching CI results"
|
|
368
472
|
gh label create do-not-close --color c5def5 --description "Humans only: never auto-close this issue"
|
|
369
473
|
gh label create priority-low --color e4e669 --description "Cosmetic or follow-up work"
|
|
370
474
|
gh label create priority-medium --color fbca04 --description "Ordinary bug or feature"
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'node:fs'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import process from 'node:process'
|
|
6
|
+
|
|
7
|
+
const MAX_READ_BYTES = 256 * 1024
|
|
8
|
+
const MAX_WRITE_BYTES = 256 * 1024
|
|
9
|
+
const SAFE_TEXT_EXTENSIONS = new Set([
|
|
10
|
+
'.cjs', '.css', '.graphql', '.html', '.js', '.json', '.jsx', '.md', '.mdx',
|
|
11
|
+
'.mjs', '.prisma', '.sql', '.ts', '.tsx', '.txt', '.xml', '.yaml', '.yml',
|
|
12
|
+
])
|
|
13
|
+
const FORBIDDEN_SEGMENTS = new Set(['.git', '.docker', '.kube', '.aws', '.ssh', '.codex', '.claude', '.next', 'dist'])
|
|
14
|
+
const FORBIDDEN_BASENAMES = new Set([
|
|
15
|
+
'.npmrc', '.netrc', '.pypirc', '.git-credentials', 'secrets.json', 'credentials.json',
|
|
16
|
+
'service-account-credentials.json',
|
|
17
|
+
])
|
|
18
|
+
const FORBIDDEN_SECRET_EXTENSIONS = new Set(['.key', '.pem', '.p12', '.pfx'])
|
|
19
|
+
// Declarative provenance for a read outside the canonical example root. The server does
|
|
20
|
+
// NOT authorize on it — the read allowlist still governs what may be read — but it refuses
|
|
21
|
+
// an unrecognized value so the runner trace cannot carry an arbitrary string into the
|
|
22
|
+
// evaluator's reason-gated fallback accounting. Mirrors `cases.schema.json`.
|
|
23
|
+
const INSTALLED_FALLBACK_REASON_CODES = new Set([
|
|
24
|
+
'SPECIALIST_ROUTE_NOT_DECLARED',
|
|
25
|
+
'INSTALLED_VERSION_CONTRACT_MISMATCH',
|
|
26
|
+
])
|
|
27
|
+
|
|
28
|
+
function fail(message) {
|
|
29
|
+
process.stderr.write(`agent-harness-tool-server: ${message}\n`)
|
|
30
|
+
process.exit(2)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function isInside(root, candidate) {
|
|
34
|
+
const relative = path.relative(root, candidate)
|
|
35
|
+
return relative === '' || (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function isInstalledSourcePath(value, allowPatterns) {
|
|
39
|
+
const normalized = value.replaceAll('\\', '/')
|
|
40
|
+
const segments = normalized.split('/')
|
|
41
|
+
if (segments.length < 5 || segments[0] !== 'node_modules' || segments[1] !== '@open-mercato' || segments[3] !== 'src') return false
|
|
42
|
+
if (!segments[2] || segments.slice(4).some((entry) => !entry)) return false
|
|
43
|
+
return allowPatterns || !normalized.includes('*') && !normalized.includes('?')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function safeRelative(value, { allowInstalledSourcePatterns = false } = {}) {
|
|
47
|
+
if (typeof value !== 'string' || !value || value.includes('\0') || path.isAbsolute(value)) return false
|
|
48
|
+
const normalized = value.replaceAll('\\', '/')
|
|
49
|
+
if (normalized === '.' || normalized.startsWith('../') || normalized.includes('/../')) return false
|
|
50
|
+
const segments = normalized.split('/')
|
|
51
|
+
const basename = segments.at(-1) ?? ''
|
|
52
|
+
const installedSource = segments.includes('node_modules')
|
|
53
|
+
if (installedSource && !isInstalledSourcePath(normalized, allowInstalledSourcePatterns)) return false
|
|
54
|
+
if ((installedSource ? segments.slice(4) : segments).some((entry) => FORBIDDEN_SEGMENTS.has(entry))) return false
|
|
55
|
+
if (normalized === '.ai/harness' || normalized.startsWith('.ai/harness/')) return false
|
|
56
|
+
if (basename === '.env' || basename.startsWith('.env.') || FORBIDDEN_BASENAMES.has(basename)) return false
|
|
57
|
+
return !FORBIDDEN_SECRET_EXTENSIONS.has(path.extname(basename).toLowerCase())
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function globToRegExp(pattern) {
|
|
61
|
+
let source = '^'
|
|
62
|
+
for (let index = 0; index < pattern.length; index += 1) {
|
|
63
|
+
const char = pattern[index]
|
|
64
|
+
if (char === '*' && pattern[index + 1] === '*') { source += '.*'; index += 1 }
|
|
65
|
+
else if (char === '*') source += '[^/]*'
|
|
66
|
+
else if (char === '?') source += '[^/]'
|
|
67
|
+
else source += char.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
68
|
+
}
|
|
69
|
+
return new RegExp(`${source}$`)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const rootArg = process.argv[2]
|
|
73
|
+
const mode = process.argv[3]
|
|
74
|
+
let allowedReads
|
|
75
|
+
let allowedWrites
|
|
76
|
+
let immutableRoots
|
|
77
|
+
try { allowedReads = JSON.parse(process.argv[4] ?? '[]') } catch { fail('allowed read set is invalid JSON') }
|
|
78
|
+
try { allowedWrites = JSON.parse(process.argv[5] ?? '[]') } catch { fail('allowed write set is invalid JSON') }
|
|
79
|
+
try { immutableRoots = JSON.parse(process.env.OM_HARNESS_IMMUTABLE_ROOTS ?? '[]') } catch { fail('immutable root set is invalid JSON') }
|
|
80
|
+
if (!path.isAbsolute(rootArg ?? '')) fail('root must be absolute')
|
|
81
|
+
if (!['read-only', 'writable'].includes(mode)) fail('mode must be read-only or writable')
|
|
82
|
+
if (!Array.isArray(allowedReads) || allowedReads.some((entry) => !safeRelative(entry, { allowInstalledSourcePatterns: true }) || ['*', '**'].includes(entry))) fail('allowed read set is invalid')
|
|
83
|
+
if (!Array.isArray(allowedWrites) || allowedWrites.some((entry) => !safeRelative(entry))) fail('allowed write set is invalid')
|
|
84
|
+
if (!Array.isArray(immutableRoots) || immutableRoots.some((entry) => !safeRelative(entry) || entry.includes('*') || entry.includes('?'))) fail('immutable root set is invalid')
|
|
85
|
+
const root = fs.realpathSync(rootArg)
|
|
86
|
+
const readMatchers = allowedReads.map(globToRegExp)
|
|
87
|
+
const writeMatchers = allowedWrites.map(globToRegExp)
|
|
88
|
+
const immutablePrefixes = immutableRoots.map((entry) => entry.replaceAll('\\', '/'))
|
|
89
|
+
|
|
90
|
+
// Root immutability precedence: declared read-only roots are resolved BEFORE the write
|
|
91
|
+
// allowlist, so a broader writable grant such as `src/modules/**` can never reach inside one.
|
|
92
|
+
function isImmutablePath(normalized) {
|
|
93
|
+
return immutablePrefixes.some((prefix) => normalized === prefix || normalized.startsWith(`${prefix}/`))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function resolveRead(relative) {
|
|
97
|
+
if (!safeRelative(relative)) throw new Error('path is outside the allowed app context')
|
|
98
|
+
const normalized = relative.replaceAll('\\', '/')
|
|
99
|
+
if (!readMatchers.some((matcher) => matcher.test(normalized))) throw new Error('path is outside the case read allowlist')
|
|
100
|
+
const lexical = path.resolve(root, relative)
|
|
101
|
+
if (!isInside(root, lexical)) throw new Error('path escapes the app root')
|
|
102
|
+
const real = fs.realpathSync(lexical)
|
|
103
|
+
if (isInstalledSourcePath(normalized, false)) {
|
|
104
|
+
const dependencyRoot = fs.realpathSync(path.join(root, 'node_modules'))
|
|
105
|
+
if (!isInside(dependencyRoot, real)) throw new Error('installed source resolves outside the protected dependency root')
|
|
106
|
+
} else if (!isInside(root, real)) throw new Error('path resolves outside the app root')
|
|
107
|
+
const stat = fs.statSync(real)
|
|
108
|
+
if (!stat.isFile() || stat.size > MAX_READ_BYTES) throw new Error('path must be a bounded regular file')
|
|
109
|
+
if (!SAFE_TEXT_EXTENSIONS.has(path.extname(real).toLowerCase()) && path.basename(real) !== 'AGENTS.md') throw new Error('path is not an allowed text file')
|
|
110
|
+
return { real, stat }
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function resolveWrite(relative) {
|
|
114
|
+
if (mode !== 'writable') throw new Error('writes are disabled for this evaluation')
|
|
115
|
+
if (!safeRelative(relative)) throw new Error('path is outside the case write allowlist')
|
|
116
|
+
const normalized = relative.replaceAll('\\', '/')
|
|
117
|
+
if (isImmutablePath(normalized)) throw new Error('path is inside a read-only declared root and can never be written')
|
|
118
|
+
if (!writeMatchers.some((matcher) => matcher.test(normalized))) throw new Error('path is outside the case write allowlist')
|
|
119
|
+
const lexical = path.resolve(root, relative)
|
|
120
|
+
if (!isInside(root, lexical)) throw new Error('path escapes the app root')
|
|
121
|
+
let cursor = path.dirname(lexical)
|
|
122
|
+
const missing = []
|
|
123
|
+
while (cursor !== root && !fs.existsSync(cursor)) { missing.push(cursor); cursor = path.dirname(cursor) }
|
|
124
|
+
if (!isInside(root, cursor)) throw new Error('write ancestor escapes the app root')
|
|
125
|
+
for (let current = cursor; current !== root; current = path.dirname(current)) {
|
|
126
|
+
const stat = fs.lstatSync(current)
|
|
127
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error('write ancestor must be a regular directory')
|
|
128
|
+
}
|
|
129
|
+
if (fs.existsSync(lexical)) {
|
|
130
|
+
const stat = fs.lstatSync(lexical)
|
|
131
|
+
if (!stat.isFile() || stat.isSymbolicLink() || !isInside(root, fs.realpathSync(lexical))) throw new Error('write target must be a contained regular file')
|
|
132
|
+
}
|
|
133
|
+
for (const directory of missing.reverse()) fs.mkdirSync(directory, { mode: 0o700 })
|
|
134
|
+
return lexical
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const tools = [
|
|
138
|
+
{
|
|
139
|
+
name: 'read',
|
|
140
|
+
description: 'Read one exact app-relative instruction, fact, source, or allowed target file. Fact-linked @open-mercato package source reads are allowed; absolute paths, discovery, credentials, dependency writes, Git, and harness internals are rejected.',
|
|
141
|
+
inputSchema: {
|
|
142
|
+
type: 'object',
|
|
143
|
+
additionalProperties: false,
|
|
144
|
+
required: ['path'],
|
|
145
|
+
properties: {
|
|
146
|
+
path: { type: 'string' },
|
|
147
|
+
reason: { type: 'string', enum: [...INSTALLED_FALLBACK_REASON_CODES] },
|
|
148
|
+
capabilityId: { type: 'string' },
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
...(mode === 'writable' ? [{
|
|
153
|
+
name: 'write',
|
|
154
|
+
description: 'Replace one exact app-relative file declared in the current case write allowlist. The content must be the complete file.',
|
|
155
|
+
inputSchema: { type: 'object', additionalProperties: false, required: ['path', 'content'], properties: { path: { type: 'string' }, content: { type: 'string' } } },
|
|
156
|
+
}] : []),
|
|
157
|
+
]
|
|
158
|
+
|
|
159
|
+
function result(id, value) {
|
|
160
|
+
process.stdout.write(`${JSON.stringify({ jsonrpc: '2.0', id, result: value })}\n`)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function toolResult(id, text, isError = false) {
|
|
164
|
+
result(id, { content: [{ type: 'text', text }], ...(isError ? { isError: true } : {}) })
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function handle(message) {
|
|
168
|
+
if (!message || message.jsonrpc !== '2.0') return
|
|
169
|
+
if (message.method === 'initialize') {
|
|
170
|
+
result(message.id, {
|
|
171
|
+
protocolVersion: message.params?.protocolVersion ?? '2025-06-18',
|
|
172
|
+
capabilities: { tools: { listChanged: false } },
|
|
173
|
+
serverInfo: { name: 'open-mercato-agent-harness', version: '1.0.0' },
|
|
174
|
+
})
|
|
175
|
+
return
|
|
176
|
+
}
|
|
177
|
+
if (message.method === 'ping') { result(message.id, {}); return }
|
|
178
|
+
if (message.method === 'tools/list') { result(message.id, { tools }); return }
|
|
179
|
+
if (message.method !== 'tools/call') return
|
|
180
|
+
try {
|
|
181
|
+
const name = message.params?.name
|
|
182
|
+
const input = message.params?.arguments ?? {}
|
|
183
|
+
if (name === 'read') {
|
|
184
|
+
if (input.reason !== undefined && !INSTALLED_FALLBACK_REASON_CODES.has(input.reason)) {
|
|
185
|
+
throw new Error('read reason must be a declared installed-source fallback reason code')
|
|
186
|
+
}
|
|
187
|
+
if (input.capabilityId !== undefined
|
|
188
|
+
&& (typeof input.capabilityId !== 'string' || !/^[a-z0-9][a-z0-9.-]{0,63}$/.test(input.capabilityId))) {
|
|
189
|
+
throw new Error('read capabilityId must be a bounded surface-inventory capability id')
|
|
190
|
+
}
|
|
191
|
+
const { real } = resolveRead(input.path)
|
|
192
|
+
toolResult(message.id, fs.readFileSync(real, 'utf8'))
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
if (name === 'write') {
|
|
196
|
+
if (typeof input.content !== 'string' || Buffer.byteLength(input.content) > MAX_WRITE_BYTES) throw new Error('content must be a bounded string')
|
|
197
|
+
const target = resolveWrite(input.path)
|
|
198
|
+
const temporary = `${target}.om-harness-${process.pid}.tmp`
|
|
199
|
+
fs.writeFileSync(temporary, input.content, { encoding: 'utf8', mode: 0o600, flag: 'wx' })
|
|
200
|
+
fs.renameSync(temporary, target)
|
|
201
|
+
toolResult(message.id, `wrote ${input.path}`)
|
|
202
|
+
return
|
|
203
|
+
}
|
|
204
|
+
throw new Error('unknown tool')
|
|
205
|
+
} catch (error) {
|
|
206
|
+
toolResult(message.id, error instanceof Error ? error.message : String(error), true)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
let buffer = ''
|
|
211
|
+
process.stdin.setEncoding('utf8')
|
|
212
|
+
process.stdin.on('data', (chunk) => {
|
|
213
|
+
buffer += chunk
|
|
214
|
+
while (true) {
|
|
215
|
+
const newline = buffer.indexOf('\n')
|
|
216
|
+
if (newline < 0) break
|
|
217
|
+
const line = buffer.slice(0, newline).replace(/\r$/, '')
|
|
218
|
+
buffer = buffer.slice(newline + 1)
|
|
219
|
+
if (!line.trim()) continue
|
|
220
|
+
try { handle(JSON.parse(line)) } catch (error) {
|
|
221
|
+
process.stderr.write(`agent-harness-tool-server: invalid request: ${error instanceof Error ? error.message : String(error)}\n`)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
})
|