@bonesofspring/ai-rules 0.2.22 → 0.2.24
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/CHANGELOG.md +17 -0
- package/README.md +10 -2
- package/bin/cli.js +56 -9
- package/bin/mavis-install.js +441 -0
- package/bin/opencode-install.js +531 -0
- package/package.json +17 -3
- package/presets/_shared/core/agent-team/agent-team-orchestrator.md +2 -2
- package/presets/_shared/core/meta/preset-layering.md +3 -3
- package/presets/_shared/core/meta/preset-no-cross-stack-leakage.md +1 -1
- package/presets/_shared/core/meta/preset-pr-checklist.md +5 -3
- package/presets/_shared/core/meta/preset-token-budget.md +3 -0
- package/presets/_shared/core/meta/preset-twin-sync.md +32 -0
- package/presets/claude/android-kotlin/rules/tooling-and-review/preset-layering.md +3 -3
- package/presets/claude/android-kotlin/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
- package/presets/claude/android-kotlin/rules/tooling-and-review/preset-pr-checklist.md +5 -3
- package/presets/claude/android-kotlin/rules/tooling-and-review/preset-token-budget.md +3 -0
- package/presets/claude/android-kotlin/rules/tooling-and-review/preset-twin-sync.md +32 -0
- package/presets/claude/go/rules/tooling-and-review/preset-layering.md +3 -3
- package/presets/claude/go/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
- package/presets/claude/go/rules/tooling-and-review/preset-pr-checklist.md +5 -3
- package/presets/claude/go/rules/tooling-and-review/preset-token-budget.md +3 -0
- package/presets/claude/go/rules/tooling-and-review/preset-twin-sync.md +32 -0
- package/presets/claude/ios-swift/rules/tooling-and-review/preset-layering.md +3 -3
- package/presets/claude/ios-swift/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
- package/presets/claude/ios-swift/rules/tooling-and-review/preset-pr-checklist.md +5 -3
- package/presets/claude/ios-swift/rules/tooling-and-review/preset-token-budget.md +3 -0
- package/presets/claude/ios-swift/rules/tooling-and-review/preset-twin-sync.md +32 -0
- package/presets/claude/java/rules/tooling-and-review/preset-layering.md +3 -3
- package/presets/claude/java/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
- package/presets/claude/java/rules/tooling-and-review/preset-pr-checklist.md +5 -3
- package/presets/claude/java/rules/tooling-and-review/preset-token-budget.md +3 -0
- package/presets/claude/java/rules/tooling-and-review/preset-twin-sync.md +32 -0
- package/presets/claude/mcp-ts/rules/tooling-and-review/preset-layering.md +3 -3
- package/presets/claude/mcp-ts/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
- package/presets/claude/mcp-ts/rules/tooling-and-review/preset-pr-checklist.md +5 -3
- package/presets/claude/mcp-ts/rules/tooling-and-review/preset-token-budget.md +3 -0
- package/presets/claude/mcp-ts/rules/tooling-and-review/preset-twin-sync.md +32 -0
- package/presets/claude/next/REPO_AGENTS.md +10 -5
- package/presets/claude/next/agents/build-verifier.md +3 -1
- package/presets/claude/next/rules/tooling-and-review/ai-local-overlay.md +1 -1
- package/presets/claude/next/rules/tooling-and-review/preset-layering.md +3 -3
- package/presets/claude/next/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
- package/presets/claude/next/rules/tooling-and-review/preset-pr-checklist.md +5 -3
- package/presets/claude/next/rules/tooling-and-review/preset-token-budget.md +3 -0
- package/presets/claude/next/rules/tooling-and-review/preset-twin-sync.md +32 -0
- package/presets/claude/nuxt/rules/tooling-and-review/preset-layering.md +3 -3
- package/presets/claude/nuxt/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
- package/presets/claude/nuxt/rules/tooling-and-review/preset-pr-checklist.md +5 -3
- package/presets/claude/nuxt/rules/tooling-and-review/preset-token-budget.md +3 -0
- package/presets/claude/nuxt/rules/tooling-and-review/preset-twin-sync.md +32 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-layering.md +3 -3
- package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
- package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-pr-checklist.md +5 -3
- package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-token-budget.md +3 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-twin-sync.md +32 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/preset-layering.md +3 -3
- package/presets/claude/php-laravel/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
- package/presets/claude/php-laravel/rules/tooling-and-review/preset-pr-checklist.md +5 -3
- package/presets/claude/php-laravel/rules/tooling-and-review/preset-token-budget.md +3 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/preset-twin-sync.md +32 -0
- package/presets/claude/svelte/rules/tooling-and-review/preset-layering.md +3 -3
- package/presets/claude/svelte/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
- package/presets/claude/svelte/rules/tooling-and-review/preset-pr-checklist.md +5 -3
- package/presets/claude/svelte/rules/tooling-and-review/preset-token-budget.md +3 -0
- package/presets/claude/svelte/rules/tooling-and-review/preset-twin-sync.md +32 -0
- package/presets/cursor/android-kotlin/rules/preset-layering.mdc +3 -3
- package/presets/cursor/android-kotlin/rules/preset-no-cross-stack-leakage.mdc +1 -1
- package/presets/cursor/android-kotlin/rules/preset-pr-checklist.mdc +5 -3
- package/presets/cursor/android-kotlin/rules/preset-token-budget.mdc +3 -0
- package/presets/cursor/android-kotlin/rules/preset-twin-sync.mdc +32 -0
- package/presets/cursor/go/rules/preset-layering.mdc +3 -3
- package/presets/cursor/go/rules/preset-no-cross-stack-leakage.mdc +1 -1
- package/presets/cursor/go/rules/preset-pr-checklist.mdc +5 -3
- package/presets/cursor/go/rules/preset-token-budget.mdc +3 -0
- package/presets/cursor/go/rules/preset-twin-sync.mdc +32 -0
- package/presets/cursor/ios-swift/rules/preset-layering.mdc +3 -3
- package/presets/cursor/ios-swift/rules/preset-no-cross-stack-leakage.mdc +1 -1
- package/presets/cursor/ios-swift/rules/preset-pr-checklist.mdc +5 -3
- package/presets/cursor/ios-swift/rules/preset-token-budget.mdc +3 -0
- package/presets/cursor/ios-swift/rules/preset-twin-sync.mdc +32 -0
- package/presets/cursor/java/rules/preset-layering.mdc +3 -3
- package/presets/cursor/java/rules/preset-no-cross-stack-leakage.mdc +1 -1
- package/presets/cursor/java/rules/preset-pr-checklist.mdc +5 -3
- package/presets/cursor/java/rules/preset-token-budget.mdc +3 -0
- package/presets/cursor/java/rules/preset-twin-sync.mdc +32 -0
- package/presets/cursor/mcp-ts/rules/preset-layering.mdc +3 -3
- package/presets/cursor/mcp-ts/rules/preset-no-cross-stack-leakage.mdc +1 -1
- package/presets/cursor/mcp-ts/rules/preset-pr-checklist.mdc +5 -3
- package/presets/cursor/mcp-ts/rules/preset-token-budget.mdc +3 -0
- package/presets/cursor/mcp-ts/rules/preset-twin-sync.mdc +32 -0
- package/presets/cursor/next/REPO_AGENTS.md +10 -5
- package/presets/cursor/next/agents/build-verifier.md +3 -1
- package/presets/cursor/next/rules/ai-local-overlay.mdc +1 -1
- package/presets/cursor/next/rules/preset-layering.mdc +3 -3
- package/presets/cursor/next/rules/preset-no-cross-stack-leakage.mdc +1 -1
- package/presets/cursor/next/rules/preset-pr-checklist.mdc +5 -3
- package/presets/cursor/next/rules/preset-token-budget.mdc +3 -0
- package/presets/cursor/next/rules/preset-twin-sync.mdc +32 -0
- package/presets/cursor/nuxt/rules/preset-layering.mdc +3 -3
- package/presets/cursor/nuxt/rules/preset-no-cross-stack-leakage.mdc +1 -1
- package/presets/cursor/nuxt/rules/preset-pr-checklist.mdc +5 -3
- package/presets/cursor/nuxt/rules/preset-token-budget.mdc +3 -0
- package/presets/cursor/nuxt/rules/preset-twin-sync.mdc +32 -0
- package/presets/cursor/php-hexagonal/rules/preset-layering.mdc +3 -3
- package/presets/cursor/php-hexagonal/rules/preset-no-cross-stack-leakage.mdc +1 -1
- package/presets/cursor/php-hexagonal/rules/preset-pr-checklist.mdc +5 -3
- package/presets/cursor/php-hexagonal/rules/preset-token-budget.mdc +3 -0
- package/presets/cursor/php-hexagonal/rules/preset-twin-sync.mdc +32 -0
- package/presets/cursor/php-laravel/rules/preset-layering.mdc +3 -3
- package/presets/cursor/php-laravel/rules/preset-no-cross-stack-leakage.mdc +1 -1
- package/presets/cursor/php-laravel/rules/preset-pr-checklist.mdc +5 -3
- package/presets/cursor/php-laravel/rules/preset-token-budget.mdc +3 -0
- package/presets/cursor/php-laravel/rules/preset-twin-sync.mdc +32 -0
- package/presets/cursor/svelte/rules/preset-layering.mdc +3 -3
- package/presets/cursor/svelte/rules/preset-no-cross-stack-leakage.mdc +1 -1
- package/presets/cursor/svelte/rules/preset-pr-checklist.mdc +5 -3
- package/presets/cursor/svelte/rules/preset-token-budget.mdc +3 -0
- package/presets/cursor/svelte/rules/preset-twin-sync.mdc +32 -0
- package/presets/mavis/README.md +60 -0
- package/presets/mavis/next/MAVIS.md +67 -0
- package/presets/mavis/next/MCP.md +36 -0
- package/presets/mavis/next/README.md +15 -0
- package/presets/mavis/next/REPO_AGENTS.md +96 -0
- package/presets/mavis/next/adapter-map.json +959 -0
- package/presets/mavis/next/agents/README.md +206 -0
- package/presets/mavis/next/agents/accessibility-reviewer.md +61 -0
- package/presets/mavis/next/agents/api-contract-reviewer.md +57 -0
- package/presets/mavis/next/agents/build-verifier.md +112 -0
- package/presets/mavis/next/agents/ci-investigator.md +63 -0
- package/presets/mavis/next/agents/code-reviewer.md +61 -0
- package/presets/mavis/next/agents/codebase-analyzer.md +21 -0
- package/presets/mavis/next/agents/debugger.md +80 -0
- package/presets/mavis/next/agents/feature-developer.md +101 -0
- package/presets/mavis/next/agents/migration-specialist.md +67 -0
- package/presets/mavis/next/agents/mockup-reviewer.md +53 -0
- package/presets/mavis/next/agents/openspec-author.md +157 -0
- package/presets/mavis/next/agents/performance-auditor.md +68 -0
- package/presets/mavis/next/agents/playwright-test-generator.md +28 -0
- package/presets/mavis/next/agents/playwright-test-healer.md +28 -0
- package/presets/mavis/next/agents/playwright-test-planner.md +21 -0
- package/presets/mavis/next/agents/qa-tester.md +52 -0
- package/presets/mavis/next/agents/security-reviewer.md +54 -0
- package/presets/mavis/next/agents/solution-architect.md +68 -0
- package/presets/mavis/next/agents/task-analyst.md +166 -0
- package/presets/mavis/next/agents/task-router.md +178 -0
- package/presets/mavis/next/agents/tech-writer.md +57 -0
- package/presets/mavis/next/agents/unit-test-generator.md +31 -0
- package/presets/mavis/next/agents/unit-test-healer.md +32 -0
- package/presets/mavis/next/agents/unit-test-planner.md +54 -0
- package/presets/mavis/next/commands/README.md +49 -0
- package/presets/mavis/next/commands/spec-start.md +24 -0
- package/presets/mavis/next/commands/task-continue.md +50 -0
- package/presets/mavis/next/commands/task.md +50 -0
- package/presets/mavis/next/commands/technical-retro.md +80 -0
- package/presets/mavis/next/hooks/README.md +22 -0
- package/presets/mavis/next/hooks/chain-team-phases.sh +845 -0
- package/presets/mavis/next/mcp.json +19 -0
- package/presets/mavis/next/rules/README.md +16 -0
- package/presets/mavis/next/rules/agent-team-intake.md +11 -0
- package/presets/mavis/next/rules/agent-team-orchestrator.md +210 -0
- package/presets/mavis/next/rules/ai-local-overlay.md +37 -0
- package/presets/mavis/next/rules/anti-sycophancy-discipline.md +23 -0
- package/presets/mavis/next/rules/api-services.md +72 -0
- package/presets/mavis/next/rules/architecture-boundaries-ui.md +9 -0
- package/presets/mavis/next/rules/architecture-boundaries.md +86 -0
- package/presets/mavis/next/rules/arrow-functions.md +25 -0
- package/presets/mavis/next/rules/code-quality-and-refactoring.md +40 -0
- package/presets/mavis/next/rules/code-review-mr.md +40 -0
- package/presets/mavis/next/rules/css-property-order-stylelint.md +5 -0
- package/presets/mavis/next/rules/design-guidance.md +99 -0
- package/presets/mavis/next/rules/feature-delivery-workflow.md +49 -0
- package/presets/mavis/next/rules/http-client.md +55 -0
- package/presets/mavis/next/rules/layer-barrel-exports.md +68 -0
- package/presets/mavis/next/rules/mcp-usage.md +86 -0
- package/presets/mavis/next/rules/mockup-review.md +107 -0
- package/presets/mavis/next/rules/navigation-router-stack.md +56 -0
- package/presets/mavis/next/rules/navigation-router-ui.md +10 -0
- package/presets/mavis/next/rules/next-app-core.md +29 -0
- package/presets/mavis/next/rules/next-app-router.md +44 -0
- package/presets/mavis/next/rules/no-props-spread.md +56 -0
- package/presets/mavis/next/rules/no-type-assertion-as-import-export.md +51 -0
- package/presets/mavis/next/rules/package-manager.md +11 -0
- package/presets/mavis/next/rules/playwright-agents.md +67 -0
- package/presets/mavis/next/rules/post-change-lint.md +35 -0
- package/presets/mavis/next/rules/preset-layering.md +27 -0
- package/presets/mavis/next/rules/preset-no-cross-stack-leakage.md +90 -0
- package/presets/mavis/next/rules/preset-pr-checklist.md +36 -0
- package/presets/mavis/next/rules/preset-token-budget.md +39 -0
- package/presets/mavis/next/rules/preset-twin-sync.md +81 -0
- package/presets/mavis/next/rules/product-specs-authoring.md +112 -0
- package/presets/mavis/next/rules/product-specs.md +56 -0
- package/presets/mavis/next/rules/public-imports.md +50 -0
- package/presets/mavis/next/rules/react-a11y-coding.md +31 -0
- package/presets/mavis/next/rules/react-next-anti-hallucination.md +60 -0
- package/presets/mavis/next/rules/react-ui.md +105 -0
- package/presets/mavis/next/rules/reference-features.md +45 -0
- package/presets/mavis/next/rules/security-next.md +45 -0
- package/presets/mavis/next/rules/store-rtk.md +78 -0
- package/presets/mavis/next/rules/technical-retro.md +11 -0
- package/presets/mavis/next/rules/tests-e2e-structure.md +72 -0
- package/presets/mavis/next/rules/tests-unit.md +72 -0
- package/presets/mavis/next/rules/types-jsdoc.md +43 -0
- package/presets/mavis/next/rules/ux-design.md +99 -0
- package/presets/mavis/next/skills/README.md +21 -0
- package/presets/mavis/next/skills/ci-investigation/SKILL.md +39 -0
- package/presets/mavis/next/skills/code-review/SKILL.md +39 -0
- package/presets/mavis/next/skills/debug-investigation/SKILL.md +26 -0
- package/presets/mavis/next/skills/feature-delivery/SKILL.md +34 -0
- package/presets/mavis/next/skills/mockup-review/SKILL.md +24 -0
- package/presets/mavis/next/skills/playwright-e2e/SKILL.md +28 -0
- package/presets/mavis/next/skills/react-performance/SKILL.md +39 -0
- package/presets/mavis/next/skills/spec-authoring/SKILL.md +21 -0
- package/presets/mavis/next/skills/spec-discovery/SKILL.md +53 -0
- package/presets/mavis/next/skills/technical-retro/SKILL.md +49 -0
- package/presets/mavis/next/skills/unit-testing/SKILL.md +29 -0
- package/presets/mavis/next/skills/ux-design/SKILL.md +31 -0
- package/presets/mavis/next/skills/write-adr/SKILL.md +36 -0
- package/presets/mavis/next/team/README.md +148 -0
- package/presets/mavis/next/team/conventions.md +21 -0
- package/presets/mavis/next/team/fixtures/artifact-manifest.example.json +79 -0
- package/presets/mavis/next/team/fixtures/bugfix-standard.json +25 -0
- package/presets/mavis/next/team/fixtures/feature-full.json +29 -0
- package/presets/mavis/next/team/fixtures/feature-light.json +27 -0
- package/presets/mavis/next/team/fixtures/feature-with-figma-url.json +17 -0
- package/presets/mavis/next/team/fixtures/feature-with-ux-no-figma.json +17 -0
- package/presets/mavis/next/team/fixtures/memlog.example.md +9 -0
- package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/human-gate/metrics.json +69 -0
- package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/missing-ledger/status.json +5 -0
- package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/parallel-receipts/metrics.json +79 -0
- package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/serial-retry/metrics.json +124 -0
- package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/validation-failed/metrics.json +124 -0
- package/presets/mavis/next/team/fixtures/metrics.example.json +54 -0
- package/presets/mavis/next/team/fixtures/mockup-review-fail-embedded-status.json +8 -0
- package/presets/mavis/next/team/fixtures/mockup-review-standalone.json +14 -0
- package/presets/mavis/next/team/fixtures/ux-design-standalone.json +15 -0
- package/presets/mavis/next/team/tasks/.gitkeep +0 -0
- package/presets/mavis/platform-contract.json +131 -0
- package/presets/opencode/README.md +61 -0
- package/presets/opencode/next/MCP.md +36 -0
- package/presets/opencode/next/OPENCODE.md +65 -0
- package/presets/opencode/next/README.md +16 -0
- package/presets/opencode/next/REPO_AGENTS.md +97 -0
- package/presets/opencode/next/adapter-map.json +959 -0
- package/presets/opencode/next/agents/README.md +201 -0
- package/presets/opencode/next/agents/accessibility-reviewer.md +73 -0
- package/presets/opencode/next/agents/api-contract-reviewer.md +69 -0
- package/presets/opencode/next/agents/build-verifier.md +124 -0
- package/presets/opencode/next/agents/ci-investigator.md +71 -0
- package/presets/opencode/next/agents/code-reviewer.md +73 -0
- package/presets/opencode/next/agents/codebase-analyzer.md +33 -0
- package/presets/opencode/next/agents/debugger.md +88 -0
- package/presets/opencode/next/agents/feature-developer.md +109 -0
- package/presets/opencode/next/agents/migration-specialist.md +79 -0
- package/presets/opencode/next/agents/mockup-reviewer.md +65 -0
- package/presets/opencode/next/agents/openspec-author.md +169 -0
- package/presets/opencode/next/agents/performance-auditor.md +80 -0
- package/presets/opencode/next/agents/playwright-test-generator.md +36 -0
- package/presets/opencode/next/agents/playwright-test-healer.md +36 -0
- package/presets/opencode/next/agents/playwright-test-planner.md +33 -0
- package/presets/opencode/next/agents/qa-tester.md +60 -0
- package/presets/opencode/next/agents/security-reviewer.md +66 -0
- package/presets/opencode/next/agents/solution-architect.md +80 -0
- package/presets/opencode/next/agents/task-analyst.md +178 -0
- package/presets/opencode/next/agents/task-router.md +190 -0
- package/presets/opencode/next/agents/tech-writer.md +69 -0
- package/presets/opencode/next/agents/unit-test-generator.md +39 -0
- package/presets/opencode/next/agents/unit-test-healer.md +40 -0
- package/presets/opencode/next/agents/unit-test-planner.md +66 -0
- package/presets/opencode/next/commands/README.md +49 -0
- package/presets/opencode/next/commands/spec-start.md +32 -0
- package/presets/opencode/next/commands/task-continue.md +58 -0
- package/presets/opencode/next/commands/task.md +58 -0
- package/presets/opencode/next/commands/technical-retro.md +88 -0
- package/presets/opencode/next/hooks/README.md +22 -0
- package/presets/opencode/next/hooks/chain-team-phases.sh +845 -0
- package/presets/opencode/next/opencode.json +33 -0
- package/presets/opencode/next/rules/README.md +20 -0
- package/presets/opencode/next/rules/agent-team-intake.md +11 -0
- package/presets/opencode/next/rules/agent-team-orchestrator.md +214 -0
- package/presets/opencode/next/rules/ai-local-overlay.md +37 -0
- package/presets/opencode/next/rules/anti-sycophancy-discipline.md +23 -0
- package/presets/opencode/next/rules/api-services.md +72 -0
- package/presets/opencode/next/rules/architecture-boundaries-ui.md +9 -0
- package/presets/opencode/next/rules/architecture-boundaries.md +86 -0
- package/presets/opencode/next/rules/arrow-functions.md +25 -0
- package/presets/opencode/next/rules/code-quality-and-refactoring.md +40 -0
- package/presets/opencode/next/rules/code-review-mr.md +40 -0
- package/presets/opencode/next/rules/css-property-order-stylelint.md +5 -0
- package/presets/opencode/next/rules/design-guidance.md +99 -0
- package/presets/opencode/next/rules/feature-delivery-workflow.md +49 -0
- package/presets/opencode/next/rules/http-client.md +55 -0
- package/presets/opencode/next/rules/layer-barrel-exports.md +68 -0
- package/presets/opencode/next/rules/mcp-usage.md +86 -0
- package/presets/opencode/next/rules/mockup-review.md +107 -0
- package/presets/opencode/next/rules/navigation-router-stack.md +56 -0
- package/presets/opencode/next/rules/navigation-router-ui.md +10 -0
- package/presets/opencode/next/rules/next-app-core.md +29 -0
- package/presets/opencode/next/rules/next-app-router.md +44 -0
- package/presets/opencode/next/rules/no-props-spread.md +56 -0
- package/presets/opencode/next/rules/no-type-assertion-as-import-export.md +51 -0
- package/presets/opencode/next/rules/package-manager.md +11 -0
- package/presets/opencode/next/rules/playwright-agents.md +67 -0
- package/presets/opencode/next/rules/post-change-lint.md +35 -0
- package/presets/opencode/next/rules/preset-layering.md +27 -0
- package/presets/opencode/next/rules/preset-no-cross-stack-leakage.md +90 -0
- package/presets/opencode/next/rules/preset-pr-checklist.md +36 -0
- package/presets/opencode/next/rules/preset-token-budget.md +39 -0
- package/presets/opencode/next/rules/preset-twin-sync.md +81 -0
- package/presets/opencode/next/rules/product-specs-authoring.md +112 -0
- package/presets/opencode/next/rules/product-specs.md +56 -0
- package/presets/opencode/next/rules/public-imports.md +50 -0
- package/presets/opencode/next/rules/react-a11y-coding.md +31 -0
- package/presets/opencode/next/rules/react-next-anti-hallucination.md +60 -0
- package/presets/opencode/next/rules/react-ui.md +105 -0
- package/presets/opencode/next/rules/reference-features.md +45 -0
- package/presets/opencode/next/rules/security-next.md +45 -0
- package/presets/opencode/next/rules/store-rtk.md +78 -0
- package/presets/opencode/next/rules/technical-retro.md +11 -0
- package/presets/opencode/next/rules/tests-e2e-structure.md +72 -0
- package/presets/opencode/next/rules/tests-unit.md +72 -0
- package/presets/opencode/next/rules/types-jsdoc.md +43 -0
- package/presets/opencode/next/rules/ux-design.md +99 -0
- package/presets/opencode/next/skills/README.md +21 -0
- package/presets/opencode/next/skills/ci-investigation/SKILL.md +44 -0
- package/presets/opencode/next/skills/code-review/SKILL.md +44 -0
- package/presets/opencode/next/skills/debug-investigation/SKILL.md +59 -0
- package/presets/opencode/next/skills/feature-delivery/SKILL.md +39 -0
- package/presets/opencode/next/skills/mockup-review/SKILL.md +29 -0
- package/presets/opencode/next/skills/playwright-e2e/SKILL.md +33 -0
- package/presets/opencode/next/skills/react-performance/SKILL.md +44 -0
- package/presets/opencode/next/skills/spec-authoring/SKILL.md +26 -0
- package/presets/opencode/next/skills/spec-discovery/SKILL.md +58 -0
- package/presets/opencode/next/skills/technical-retro/SKILL.md +54 -0
- package/presets/opencode/next/skills/unit-testing/SKILL.md +34 -0
- package/presets/opencode/next/skills/ux-design/SKILL.md +36 -0
- package/presets/opencode/next/skills/write-adr/SKILL.md +41 -0
- package/presets/opencode/next/team/README.md +148 -0
- package/presets/opencode/next/team/conventions.md +21 -0
- package/presets/opencode/next/team/fixtures/artifact-manifest.example.json +79 -0
- package/presets/opencode/next/team/fixtures/bugfix-standard.json +25 -0
- package/presets/opencode/next/team/fixtures/feature-full.json +29 -0
- package/presets/opencode/next/team/fixtures/feature-light.json +27 -0
- package/presets/opencode/next/team/fixtures/feature-with-figma-url.json +17 -0
- package/presets/opencode/next/team/fixtures/feature-with-ux-no-figma.json +17 -0
- package/presets/opencode/next/team/fixtures/memlog.example.md +9 -0
- package/presets/opencode/next/team/fixtures/metrics-scenarios/tasks/human-gate/metrics.json +69 -0
- package/presets/opencode/next/team/fixtures/metrics-scenarios/tasks/missing-ledger/status.json +5 -0
- package/presets/opencode/next/team/fixtures/metrics-scenarios/tasks/parallel-receipts/metrics.json +79 -0
- package/presets/opencode/next/team/fixtures/metrics-scenarios/tasks/serial-retry/metrics.json +124 -0
- package/presets/opencode/next/team/fixtures/metrics-scenarios/tasks/validation-failed/metrics.json +124 -0
- package/presets/opencode/next/team/fixtures/metrics.example.json +54 -0
- package/presets/opencode/next/team/fixtures/mockup-review-fail-embedded-status.json +8 -0
- package/presets/opencode/next/team/fixtures/mockup-review-standalone.json +14 -0
- package/presets/opencode/next/team/fixtures/ux-design-standalone.json +15 -0
- package/presets/opencode/next/team/tasks/.gitkeep +0 -0
- package/presets/opencode/platform-contract.json +131 -0
- package/scripts/capture-cli-golden.mjs +48 -0
- package/scripts/check-chain-hook-coverage.sh +2 -0
- package/scripts/check-mavis-adapter-map.mjs +294 -0
- package/scripts/check-mavis-local-overlay.mjs +56 -0
- package/scripts/check-mavis-platform-contract.mjs +388 -0
- package/scripts/check-mavis-token-budget.mjs +48 -0
- package/scripts/check-opencode-adapter-map.mjs +294 -0
- package/scripts/check-opencode-local-overlay.mjs +56 -0
- package/scripts/check-opencode-platform-contract.mjs +388 -0
- package/scripts/check-opencode-token-budget.mjs +48 -0
- package/scripts/check-preset-leakage.sh +64 -3
- package/scripts/check-preset-structure.sh +108 -0
- package/scripts/check-shared-core-drift.sh +18 -0
- package/scripts/check-task-router-intents.sh +15 -2
- package/scripts/fixtures/cli-golden/claude/next.json +130 -0
- package/scripts/fixtures/cli-golden/cursor/next.json +132 -0
- package/scripts/fixtures/cli-golden/mavis/next.json +125 -0
- package/scripts/fixtures/cli-golden/opencode/next.json +125 -0
- package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/cursor/AGENTS.md +1 -0
- package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/cursor/rules/extra.mdc +1 -0
- package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/cursor/rules/sample.mdc +2 -0
- package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/mavis/MAVIS.md +1 -0
- package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/mavis/adapter-map.json +26 -0
- package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/mavis/rules/sample.md +2 -0
- package/scripts/fixtures/mavis-adapter-map/valid/cursor/AGENTS.md +1 -0
- package/scripts/fixtures/mavis-adapter-map/valid/cursor/rules/sample.mdc +2 -0
- package/scripts/fixtures/mavis-adapter-map/valid/mavis/MAVIS.md +1 -0
- package/scripts/fixtures/mavis-adapter-map/valid/mavis/adapter-map.json +26 -0
- package/scripts/fixtures/mavis-adapter-map/valid/mavis/rules/sample.md +2 -0
- package/scripts/fixtures/mavis-platform-contract/invalid-minimax-destination.json +131 -0
- package/scripts/fixtures/mavis-platform-contract/invalid-missing-capability.json +126 -0
- package/scripts/fixtures/mavis-platform-contract/invalid-released-unknown-stack.json +133 -0
- package/scripts/fixtures/mavis-platform-contract/invalid-unknown-native-path.json +131 -0
- package/scripts/fixtures/mavis-platform-contract/invalid-version-pin.json +132 -0
- package/scripts/fixtures/mavis-platform-contract/valid.json +131 -0
- package/scripts/fixtures/mavis-probe/AGENTS.md +6 -0
- package/scripts/fixtures/mavis-probe/agents/probe-agent.md +6 -0
- package/scripts/fixtures/mavis-probe/fake-mcode.mjs +98 -0
- package/scripts/fixtures/mavis-probe/output.schema.json +28 -0
- package/scripts/fixtures/mavis-probe/rules/probe.md +5 -0
- package/scripts/fixtures/mavis-probe/skills/probe/SKILL.md +11 -0
- package/scripts/fixtures/opencode-adapter-map/invalid-unmapped/cursor/AGENTS.md +1 -0
- package/scripts/fixtures/opencode-adapter-map/invalid-unmapped/cursor/rules/extra.mdc +1 -0
- package/scripts/fixtures/opencode-adapter-map/invalid-unmapped/cursor/rules/sample.mdc +2 -0
- package/scripts/fixtures/opencode-adapter-map/invalid-unmapped/opencode/OPENCODE.md +1 -0
- package/scripts/fixtures/opencode-adapter-map/invalid-unmapped/opencode/adapter-map.json +26 -0
- package/scripts/fixtures/opencode-adapter-map/invalid-unmapped/opencode/rules/sample.md +2 -0
- package/scripts/fixtures/opencode-adapter-map/valid/cursor/AGENTS.md +1 -0
- package/scripts/fixtures/opencode-adapter-map/valid/cursor/rules/sample.mdc +2 -0
- package/scripts/fixtures/opencode-adapter-map/valid/opencode/OPENCODE.md +1 -0
- package/scripts/fixtures/opencode-adapter-map/valid/opencode/adapter-map.json +26 -0
- package/scripts/fixtures/opencode-adapter-map/valid/opencode/rules/sample.md +2 -0
- package/scripts/fixtures/opencode-platform-contract/invalid-home-destination.json +131 -0
- package/scripts/fixtures/opencode-platform-contract/invalid-missing-capability.json +126 -0
- package/scripts/fixtures/opencode-platform-contract/invalid-released-unknown-stack.json +133 -0
- package/scripts/fixtures/opencode-platform-contract/invalid-unknown-native-path.json +131 -0
- package/scripts/fixtures/opencode-platform-contract/invalid-version-pin.json +132 -0
- package/scripts/fixtures/opencode-platform-contract/valid.json +131 -0
- package/scripts/generate-mavis-next.mjs +706 -0
- package/scripts/generate-opencode-next.mjs +831 -0
- package/scripts/lib/cli-golden.mjs +50 -0
- package/scripts/lib/discover-hooks.mjs +94 -0
- package/scripts/probe-mavis-capabilities.mjs +480 -0
- package/scripts/sync-dogfood-mavis.sh +90 -0
- package/scripts/sync-dogfood-opencode.sh +85 -0
- package/scripts/test-agent-task-metrics-hooks.mjs +25 -16
- package/scripts/test-chain-team-phases-coverage.mjs +15 -7
- package/scripts/test-cli-init-clean.mjs +367 -0
- package/scripts/test-cli-mcp-merge.mjs +23 -0
- package/scripts/test-mavis-context-budget.mjs +55 -0
- package/scripts/test-mavis-orchestration.mjs +649 -0
- package/scripts/test-opencode-context-budget.mjs +53 -0
- package/scripts/test-probe-mavis-capabilities.mjs +205 -0
|
@@ -0,0 +1,831 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Derive presets/opencode/next/** and adapter-map.json from cursor/next.
|
|
4
|
+
* Maintainer tool; not a consumer CLI command.
|
|
5
|
+
*/
|
|
6
|
+
import crypto from 'node:crypto';
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
|
|
11
|
+
const scriptDirectory = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const packageRoot = path.join(scriptDirectory, '..');
|
|
13
|
+
const cursorRoot = path.join(packageRoot, 'presets', 'cursor', 'next');
|
|
14
|
+
const opencodeRoot = path.join(packageRoot, 'presets', 'opencode', 'next');
|
|
15
|
+
|
|
16
|
+
const ALWAYS_ON_RULES = new Set([
|
|
17
|
+
'next-app-core',
|
|
18
|
+
'package-manager',
|
|
19
|
+
'code-quality-and-refactoring',
|
|
20
|
+
'ai-local-overlay',
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
const DEVELOPER_AGENTS = new Set([
|
|
24
|
+
'feature-developer',
|
|
25
|
+
'debugger',
|
|
26
|
+
'ci-investigator',
|
|
27
|
+
'qa-tester',
|
|
28
|
+
'unit-test-generator',
|
|
29
|
+
'unit-test-healer',
|
|
30
|
+
'playwright-test-generator',
|
|
31
|
+
'playwright-test-healer',
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
const REVIEW_AGENTS = new Set(['code-reviewer']);
|
|
35
|
+
|
|
36
|
+
const OMIT = new Map([
|
|
37
|
+
[
|
|
38
|
+
'BUGBOT.md',
|
|
39
|
+
'no-equivalent: Bugbot is Cursor-only; review stays a Verifier skill/role',
|
|
40
|
+
],
|
|
41
|
+
[
|
|
42
|
+
'hooks.json',
|
|
43
|
+
'omit until an OpenCode plugin wraps chain-team-phases.sh',
|
|
44
|
+
],
|
|
45
|
+
[
|
|
46
|
+
'hooks/guard-shell-command.sh',
|
|
47
|
+
'omit from active wiring; safety policy stays in entry prose, not enforcement',
|
|
48
|
+
],
|
|
49
|
+
[
|
|
50
|
+
'hooks/examples/format-edited.example.sh',
|
|
51
|
+
'omit until an OpenCode plugin event API is shipped',
|
|
52
|
+
],
|
|
53
|
+
[
|
|
54
|
+
'hooks/examples/secret-guard.example.sh',
|
|
55
|
+
'omit until an OpenCode plugin event API is shipped',
|
|
56
|
+
],
|
|
57
|
+
[
|
|
58
|
+
'hooks/examples/test-on-save.example.sh',
|
|
59
|
+
'omit until an OpenCode plugin event API is shipped',
|
|
60
|
+
],
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
function walkFiles(root) {
|
|
64
|
+
const files = [];
|
|
65
|
+
const visit = (dir) => {
|
|
66
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
67
|
+
const full = path.join(dir, entry.name);
|
|
68
|
+
if (entry.isDirectory()) {
|
|
69
|
+
visit(full);
|
|
70
|
+
} else if (entry.isFile()) {
|
|
71
|
+
files.push(path.relative(root, full).split(path.sep).join('/'));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
visit(root);
|
|
76
|
+
return files.sort();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function stripFrontmatter(text) {
|
|
80
|
+
if (!text.startsWith('---\n')) {
|
|
81
|
+
return { frontmatter: '', body: text };
|
|
82
|
+
}
|
|
83
|
+
const end = text.indexOf('\n---\n', 4);
|
|
84
|
+
if (end < 0) {
|
|
85
|
+
return { frontmatter: '', body: text };
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
frontmatter: text.slice(4, end),
|
|
89
|
+
body: text.slice(end + 5).replace(/^\n/, ''),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function parseFrontmatterFields(frontmatter) {
|
|
94
|
+
const fields = {};
|
|
95
|
+
for (const line of frontmatter.split('\n')) {
|
|
96
|
+
const match = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
|
|
97
|
+
if (!match) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const raw = match[2].trim();
|
|
101
|
+
fields[match[1]] = raw.replace(/^["']|["']$/g, '');
|
|
102
|
+
}
|
|
103
|
+
return fields;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const sharedCoreRoot = path.join(packageRoot, 'presets', '_shared', 'core');
|
|
107
|
+
|
|
108
|
+
function rewriteConsumerPaths(text) {
|
|
109
|
+
return text
|
|
110
|
+
.replaceAll('.cursor/team', '.opencode/team')
|
|
111
|
+
.replaceAll('.cursor/rules', '.opencode/rules')
|
|
112
|
+
.replaceAll('.cursor/skills', '.opencode/skills')
|
|
113
|
+
.replaceAll('.cursor/agents', '.opencode/agents')
|
|
114
|
+
.replaceAll('.cursor/commands', '.opencode/commands')
|
|
115
|
+
.replaceAll('.cursor/hooks', '.opencode/hooks')
|
|
116
|
+
.replaceAll('.cursor/AGENTS.md', '.opencode/AGENTS.md')
|
|
117
|
+
.replaceAll("'.cursor'", "'.opencode'")
|
|
118
|
+
.replaceAll('".cursor"', '".opencode"');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function finalizeOpencodeProse(text) {
|
|
122
|
+
return rewriteConsumerPaths(text)
|
|
123
|
+
.replace(/`([^`\n]+)\.mdc`/g, '`$1.md`')
|
|
124
|
+
.replace(/(?<![\w./-])([\w-]+)\.mdc\b/g, '$1.md')
|
|
125
|
+
.replaceAll('init cursor --preset', 'init opencode --preset')
|
|
126
|
+
.replaceAll('# MCP (preset `next`, Cursor)', '# MCP (preset `next`, OpenCode)')
|
|
127
|
+
.replaceAll('(preset `next`, Cursor)', '(preset `next`, OpenCode)')
|
|
128
|
+
.replaceAll('Copied to `.cursor/mcp.json`', 'Merged into project `opencode.json` `mcp`')
|
|
129
|
+
.replaceAll('OAuth in Cursor', 'OAuth in OpenCode (operator MCP config)');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function rewriteProse(text) {
|
|
133
|
+
return finalizeOpencodeProse(text);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function sha256(content) {
|
|
137
|
+
return crypto.createHash('sha256').update(content).digest('hex');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function writeFile(relPath, content) {
|
|
141
|
+
const dest = path.join(opencodeRoot, relPath);
|
|
142
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
143
|
+
fs.writeFileSync(dest, content);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function sharedCoreStem(text) {
|
|
147
|
+
const match = text.match(/<!--\s*shared-core:\s*([^\s>]+)\s*-->/);
|
|
148
|
+
return match ? match[1] : undefined;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function entry({
|
|
152
|
+
source,
|
|
153
|
+
target,
|
|
154
|
+
category,
|
|
155
|
+
disposition,
|
|
156
|
+
loadMode,
|
|
157
|
+
reason,
|
|
158
|
+
sourceText,
|
|
159
|
+
}) {
|
|
160
|
+
const item = {
|
|
161
|
+
source,
|
|
162
|
+
target,
|
|
163
|
+
category,
|
|
164
|
+
disposition,
|
|
165
|
+
loadMode,
|
|
166
|
+
reason,
|
|
167
|
+
};
|
|
168
|
+
const stem = sourceText ? sharedCoreStem(sourceText) : undefined;
|
|
169
|
+
if (stem) {
|
|
170
|
+
item.sharedCoreStem = stem;
|
|
171
|
+
}
|
|
172
|
+
return item;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function isEmbedEntryBody(body) {
|
|
176
|
+
const first = body
|
|
177
|
+
.split('\n')
|
|
178
|
+
.map((line) => line.trim())
|
|
179
|
+
.find((line) => line.length > 0);
|
|
180
|
+
return Boolean(first && /^<!--\s*shared-core:\s*[^\s>]+\s*-->\s*$/.test(first));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function transformMarkdown(sourceText, { allowEmbedEntry = true } = {}) {
|
|
184
|
+
const { body } = stripFrontmatter(sourceText);
|
|
185
|
+
const stem =
|
|
186
|
+
allowEmbedEntry && isEmbedEntryBody(body) ? sharedCoreStem(body) : undefined;
|
|
187
|
+
let next;
|
|
188
|
+
if (stem) {
|
|
189
|
+
const corePath = path.join(sharedCoreRoot, stem);
|
|
190
|
+
if (fs.existsSync(corePath)) {
|
|
191
|
+
const coreBody = fs.readFileSync(corePath, 'utf8').trimEnd();
|
|
192
|
+
const marker = `<!-- shared-core: ${stem} -->`;
|
|
193
|
+
next = `${marker}\n\n${coreBody}\n`;
|
|
194
|
+
next = rewriteConsumerPaths(next);
|
|
195
|
+
} else {
|
|
196
|
+
next = rewriteProse(body);
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
next = rewriteProse(body);
|
|
200
|
+
}
|
|
201
|
+
return next.endsWith('\n') ? next : `${next}\n`;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function yamlString(value) {
|
|
205
|
+
return JSON.stringify(value ?? '');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function transformAgent(source, sourceText) {
|
|
209
|
+
const { frontmatter, body } = stripFrontmatter(sourceText);
|
|
210
|
+
const fields = parseFrontmatterFields(frontmatter);
|
|
211
|
+
const stem = path.basename(source, '.md');
|
|
212
|
+
const canEditProduction = DEVELOPER_AGENTS.has(stem);
|
|
213
|
+
const permission = canEditProduction
|
|
214
|
+
? 'permission:\n edit: allow'
|
|
215
|
+
: 'permission:\n edit:\n "*": deny\n ".opencode/team/**": allow';
|
|
216
|
+
const description = fields.description || stem;
|
|
217
|
+
const header = `---\nname: ${stem}\ndescription: ${yamlString(description)}\nmode: subagent\n${permission}\n---\n\n`;
|
|
218
|
+
const transformed = rewriteProse(body);
|
|
219
|
+
let withNote = transformed;
|
|
220
|
+
if (!canEditProduction) {
|
|
221
|
+
const leadIn = REVIEW_AGENTS.has(stem)
|
|
222
|
+
? 'Write only review artifacts under `.opencode/team/**`. Do not edit production code.'
|
|
223
|
+
: 'Write only team artifacts under `.opencode/team/**`. Do not edit production code.';
|
|
224
|
+
withNote = `${leadIn}\n\n${transformed}`;
|
|
225
|
+
}
|
|
226
|
+
return `${header}${withNote.endsWith('\n') ? withNote : `${withNote}\n`}`;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function transformOrchestrator(markdown) {
|
|
230
|
+
let next = markdown.replace(
|
|
231
|
+
/\*\*Cursor frontmatter:\*\* all team pipeline agents use `readonly: false` so they can write team artifacts\. Production\/app restrictions live in the agent prompt body — do \*\*not\*\* set `readonly: true`\./,
|
|
232
|
+
'**OpenCode frontmatter:** all team pipeline agents use `mode: subagent` and `permission.edit` so they can write team artifacts (`edit: allow` for implementers; deny except `.opencode/team/**` for reviewers/planners). Production/app restrictions live in the agent prompt body. See `agents/README.md`.',
|
|
233
|
+
);
|
|
234
|
+
next = next.replace(
|
|
235
|
+
'## Team artifact I/O (Cursor Shell sandbox)',
|
|
236
|
+
'## Team artifact I/O',
|
|
237
|
+
);
|
|
238
|
+
if (!next.includes('## Stack notes')) {
|
|
239
|
+
next = next.replace(
|
|
240
|
+
'## Dynamic pipeline',
|
|
241
|
+
`## Stack notes
|
|
242
|
+
|
|
243
|
+
Roles, write scopes, and OpenCode \`mode\` / \`permission\` packaging — **\`agents/README.md\`**.
|
|
244
|
+
|
|
245
|
+
## Dynamic pipeline`,
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
return next;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function transformSkill(sourceText) {
|
|
252
|
+
const { frontmatter, body } = stripFrontmatter(sourceText);
|
|
253
|
+
const fields = parseFrontmatterFields(frontmatter);
|
|
254
|
+
const name = fields.name || '';
|
|
255
|
+
const description = fields.description || '';
|
|
256
|
+
const header = `---\nname: ${name}\ndescription: ${description}\n---\n\n`;
|
|
257
|
+
const transformed = rewriteProse(body);
|
|
258
|
+
return `${header}${transformed.endsWith('\n') ? transformed : `${transformed}\n`}`;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function transformCommand(sourceText) {
|
|
262
|
+
const { frontmatter, body } = stripFrontmatter(sourceText);
|
|
263
|
+
const fields = parseFrontmatterFields(frontmatter);
|
|
264
|
+
const description = fields.description || '';
|
|
265
|
+
let next = rewriteProse(body);
|
|
266
|
+
if (!next.includes('$ARGUMENTS')) {
|
|
267
|
+
next = `## Invocation arguments\n\n$ARGUMENTS\n\n${next}`;
|
|
268
|
+
}
|
|
269
|
+
const header = `---\ndescription: ${description}\n---\n\n`;
|
|
270
|
+
return `${header}${next.endsWith('\n') ? next : `${next}\n`}`;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function cursorMcpToOpencode(sourceText) {
|
|
274
|
+
const parsed = JSON.parse(sourceText);
|
|
275
|
+
const mcp = {};
|
|
276
|
+
for (const [id, server] of Object.entries(parsed.mcpServers || {})) {
|
|
277
|
+
if (!server || typeof server !== 'object') {
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
if (typeof server.url === 'string' && server.url) {
|
|
281
|
+
mcp[id] = { type: 'remote', url: server.url };
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
if (typeof server.command === 'string' && server.command) {
|
|
285
|
+
const command = [server.command, ...(Array.isArray(server.args) ? server.args : [])];
|
|
286
|
+
const entry = { type: 'local', command };
|
|
287
|
+
if (server.env && typeof server.env === 'object') {
|
|
288
|
+
entry.environment = server.env;
|
|
289
|
+
}
|
|
290
|
+
mcp[id] = entry;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return `${JSON.stringify({ $schema: 'https://opencode.ai/config.json', mcp }, null, 2)}\n`;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function main() {
|
|
297
|
+
fs.rmSync(opencodeRoot, { recursive: true, force: true });
|
|
298
|
+
fs.mkdirSync(opencodeRoot, { recursive: true });
|
|
299
|
+
|
|
300
|
+
const cursorFiles = walkFiles(cursorRoot);
|
|
301
|
+
const mappedSources = cursorFiles.filter((rel) => path.basename(rel) !== 'README.md');
|
|
302
|
+
const entries = [];
|
|
303
|
+
const digestParts = [];
|
|
304
|
+
|
|
305
|
+
for (const source of mappedSources) {
|
|
306
|
+
const abs = path.join(cursorRoot, source);
|
|
307
|
+
const sourceText = fs.readFileSync(abs, 'utf8');
|
|
308
|
+
digestParts.push(`${source}\t${sha256(sourceText)}`);
|
|
309
|
+
|
|
310
|
+
if (OMIT.has(source)) {
|
|
311
|
+
entries.push(
|
|
312
|
+
entry({
|
|
313
|
+
source,
|
|
314
|
+
target: null,
|
|
315
|
+
category: source.startsWith('hooks') ? 'hooks' : 'platform',
|
|
316
|
+
disposition: 'omit',
|
|
317
|
+
loadMode: 'not-installed',
|
|
318
|
+
reason: OMIT.get(source),
|
|
319
|
+
sourceText,
|
|
320
|
+
}),
|
|
321
|
+
);
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (source === 'AGENTS.md') {
|
|
326
|
+
const target = 'OPENCODE.md';
|
|
327
|
+
writeFile(target, buildOpencodeEntry(sourceText));
|
|
328
|
+
entries.push(
|
|
329
|
+
entry({
|
|
330
|
+
source,
|
|
331
|
+
target,
|
|
332
|
+
category: 'entry',
|
|
333
|
+
disposition: 'embed-entry',
|
|
334
|
+
loadMode: 'root-entry',
|
|
335
|
+
reason: 'Cursor AGENTS.md semantics feed .opencode/AGENTS.md',
|
|
336
|
+
sourceText,
|
|
337
|
+
}),
|
|
338
|
+
);
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (source === 'REPO_AGENTS.md') {
|
|
343
|
+
const target = 'REPO_AGENTS.md';
|
|
344
|
+
writeFile(target, buildRepoAgents());
|
|
345
|
+
entries.push(
|
|
346
|
+
entry({
|
|
347
|
+
source,
|
|
348
|
+
target,
|
|
349
|
+
category: 'entry',
|
|
350
|
+
disposition: 'transform',
|
|
351
|
+
loadMode: 'root-entry',
|
|
352
|
+
reason: 'Root AGENTS.md is OpenCode native always-on plus cross-tool pointers',
|
|
353
|
+
sourceText,
|
|
354
|
+
}),
|
|
355
|
+
);
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (source.startsWith('rules/') && source.endsWith('.mdc')) {
|
|
360
|
+
const stem = path.basename(source, '.mdc');
|
|
361
|
+
const target = `rules/${stem}.md`;
|
|
362
|
+
const alwaysOn = ALWAYS_ON_RULES.has(stem);
|
|
363
|
+
let markdown = transformMarkdown(sourceText);
|
|
364
|
+
if (stem === 'agent-team-orchestrator') {
|
|
365
|
+
markdown = transformOrchestrator(markdown);
|
|
366
|
+
}
|
|
367
|
+
writeFile(target, markdown);
|
|
368
|
+
entries.push(
|
|
369
|
+
entry({
|
|
370
|
+
source,
|
|
371
|
+
target,
|
|
372
|
+
category: 'rules',
|
|
373
|
+
disposition: 'transform',
|
|
374
|
+
loadMode: alwaysOn ? 'root-entry' : 'referenced',
|
|
375
|
+
reason: alwaysOn
|
|
376
|
+
? 'Essential Cursor always-on rule: listed in AGENTS.md; body under .opencode/rules'
|
|
377
|
+
: 'Requestable Cursor rule: lazy Read from .opencode/rules; not auto-loaded',
|
|
378
|
+
sourceText,
|
|
379
|
+
}),
|
|
380
|
+
);
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (source.startsWith('agents/') && source.endsWith('.md')) {
|
|
385
|
+
const target = source;
|
|
386
|
+
writeFile(target, transformAgent(source, sourceText));
|
|
387
|
+
entries.push(
|
|
388
|
+
entry({
|
|
389
|
+
source,
|
|
390
|
+
target,
|
|
391
|
+
category: 'agents',
|
|
392
|
+
disposition: 'transform',
|
|
393
|
+
loadMode: 'native-team',
|
|
394
|
+
reason: 'Native .opencode/agents discovery; OpenCode frontmatter (mode/permission)',
|
|
395
|
+
sourceText,
|
|
396
|
+
}),
|
|
397
|
+
);
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (source.startsWith('skills/') && source.endsWith('/SKILL.md')) {
|
|
402
|
+
const target = source;
|
|
403
|
+
writeFile(target, transformSkill(sourceText));
|
|
404
|
+
entries.push(
|
|
405
|
+
entry({
|
|
406
|
+
source,
|
|
407
|
+
target,
|
|
408
|
+
category: 'skills',
|
|
409
|
+
disposition: 'transform',
|
|
410
|
+
loadMode: 'native-skill',
|
|
411
|
+
reason: 'Native .opencode/skills/<name>/SKILL.md',
|
|
412
|
+
sourceText,
|
|
413
|
+
}),
|
|
414
|
+
);
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (source.startsWith('commands/') && source.endsWith('.md')) {
|
|
419
|
+
const target = source;
|
|
420
|
+
writeFile(target, transformCommand(sourceText));
|
|
421
|
+
entries.push(
|
|
422
|
+
entry({
|
|
423
|
+
source,
|
|
424
|
+
target,
|
|
425
|
+
category: 'commands',
|
|
426
|
+
disposition: 'transform',
|
|
427
|
+
loadMode: 'native-skill',
|
|
428
|
+
reason: 'Native slash commands under .opencode/commands; $ARGUMENTS kept',
|
|
429
|
+
sourceText,
|
|
430
|
+
}),
|
|
431
|
+
);
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (source === 'hooks/chain-team-phases.sh') {
|
|
436
|
+
const target = source;
|
|
437
|
+
writeFile(target, rewriteProse(sourceText));
|
|
438
|
+
entries.push(
|
|
439
|
+
entry({
|
|
440
|
+
source,
|
|
441
|
+
target,
|
|
442
|
+
category: 'hooks',
|
|
443
|
+
disposition: 'transform',
|
|
444
|
+
loadMode: 'manual',
|
|
445
|
+
reason: 'Manual/semi-auto chain runner under .opencode/hooks; not a plugin',
|
|
446
|
+
sourceText,
|
|
447
|
+
}),
|
|
448
|
+
);
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if (source === 'mcp.json') {
|
|
453
|
+
const target = 'opencode.json';
|
|
454
|
+
writeFile(target, cursorMcpToOpencode(sourceText));
|
|
455
|
+
entries.push(
|
|
456
|
+
entry({
|
|
457
|
+
source,
|
|
458
|
+
target,
|
|
459
|
+
category: 'mcp',
|
|
460
|
+
disposition: 'transform',
|
|
461
|
+
loadMode: 'manual',
|
|
462
|
+
reason: 'Cursor mcp.json → opencode.json mcp (local/remote types)',
|
|
463
|
+
sourceText,
|
|
464
|
+
}),
|
|
465
|
+
);
|
|
466
|
+
continue;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (source === 'MCP.md') {
|
|
470
|
+
const target = source;
|
|
471
|
+
writeFile(target, rewriteProse(sourceText));
|
|
472
|
+
entries.push(
|
|
473
|
+
entry({
|
|
474
|
+
source,
|
|
475
|
+
target,
|
|
476
|
+
category: 'mcp',
|
|
477
|
+
disposition: 'transform',
|
|
478
|
+
loadMode: 'manual',
|
|
479
|
+
reason: 'MCP operator notes copied to .opencode/MCP.md',
|
|
480
|
+
sourceText,
|
|
481
|
+
}),
|
|
482
|
+
);
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
if (source.startsWith('team/')) {
|
|
487
|
+
const target = source;
|
|
488
|
+
const transformed = source.endsWith('.md') ? rewriteProse(sourceText) : sourceText;
|
|
489
|
+
writeFile(
|
|
490
|
+
target,
|
|
491
|
+
transformed.endsWith('\n') || !source.endsWith('.md') ? transformed : `${transformed}\n`,
|
|
492
|
+
);
|
|
493
|
+
entries.push(
|
|
494
|
+
entry({
|
|
495
|
+
source,
|
|
496
|
+
target,
|
|
497
|
+
category: 'team',
|
|
498
|
+
disposition: source.endsWith('.md') ? 'transform' : 'copy',
|
|
499
|
+
loadMode: 'manual',
|
|
500
|
+
reason: 'File pipeline remains audit SoT under .opencode/team',
|
|
501
|
+
sourceText,
|
|
502
|
+
}),
|
|
503
|
+
);
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
throw new Error(`unmapped cursor source: ${source}`);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
writeFile('README.md', buildStackReadme());
|
|
511
|
+
writeFile('rules/README.md', buildRulesReadme());
|
|
512
|
+
writeFile('agents/README.md', buildAgentsReadme());
|
|
513
|
+
writeFile('skills/README.md', rewriteProse(readSiblingReadme('skills/README.md')));
|
|
514
|
+
writeFile('commands/README.md', buildCommandsReadme());
|
|
515
|
+
writeFile('hooks/README.md', buildHooksReadme());
|
|
516
|
+
writeFile('team/README.md', rewriteProse(readSiblingReadme('team/README.md')));
|
|
517
|
+
|
|
518
|
+
digestParts.sort();
|
|
519
|
+
const adapterMap = {
|
|
520
|
+
schemaVersion: 1,
|
|
521
|
+
platform: 'opencode',
|
|
522
|
+
stack: 'next',
|
|
523
|
+
semanticSource: 'cursor/next',
|
|
524
|
+
sourceRevision: sha256(digestParts.join('\n')),
|
|
525
|
+
entries,
|
|
526
|
+
};
|
|
527
|
+
writeFile('adapter-map.json', `${JSON.stringify(adapterMap, null, 2)}\n`);
|
|
528
|
+
console.log(
|
|
529
|
+
`generated presets/opencode/next (${entries.length} mapped sources, revision ${adapterMap.sourceRevision.slice(0, 12)})`,
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
function readSiblingReadme(rel) {
|
|
534
|
+
const filePath = path.join(cursorRoot, rel);
|
|
535
|
+
return fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : `# ${rel}\n`;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
function dropLeadingHeading(text) {
|
|
539
|
+
return text
|
|
540
|
+
.replace(/^# [^\n]+\n+/, '')
|
|
541
|
+
.replace(/^Short Cursor entry point\.[^\n]*\n+/, '');
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
function buildRepoAgents() {
|
|
545
|
+
return `# Next.js — agent instructions
|
|
546
|
+
|
|
547
|
+
Cross-tool repo-root guide. Tool-specific maps stay under \`.cursor/AGENTS.md\`,
|
|
548
|
+
\`.claude/CLAUDE.md\`, \`.mavis/AGENTS.md\`, and \`.opencode/AGENTS.md\`.
|
|
549
|
+
|
|
550
|
+
When this OpenCode preset is installed, read \`.opencode/AGENTS.md\` on every
|
|
551
|
+
turn. Do not write \`~/.config/opencode/**\`. Do not mutate
|
|
552
|
+
\`.opencode/team/tasks/<slug>/status.json\` or \`metrics.json\` — the chain
|
|
553
|
+
runner owns those files.
|
|
554
|
+
|
|
555
|
+
## Cross-tool setup
|
|
556
|
+
|
|
557
|
+
- Treat this file as the **shared** entry for any agent (Cursor, Claude Code,
|
|
558
|
+
Mavis, OpenCode, or other).
|
|
559
|
+
- Install:
|
|
560
|
+
|
|
561
|
+
\`\`\`bash
|
|
562
|
+
npx @bonesofspring/ai-rules init cursor --preset next
|
|
563
|
+
npx @bonesofspring/ai-rules init claude --preset next
|
|
564
|
+
npx @bonesofspring/ai-rules init mavis --preset next
|
|
565
|
+
npx @bonesofspring/ai-rules init opencode --preset next
|
|
566
|
+
\`\`\`
|
|
567
|
+
|
|
568
|
+
\`init\` overwrites this file from the preset (\`REPO_AGENTS.md\` → \`AGENTS.md\`).
|
|
569
|
+
Living gotchas belong in \`team/conventions.md\`, not here.
|
|
570
|
+
|
|
571
|
+
## OpenCode load map
|
|
572
|
+
|
|
573
|
+
After install, also read:
|
|
574
|
+
|
|
575
|
+
- \`.opencode/AGENTS.md\` — OpenCode load map, roles, and procedures
|
|
576
|
+
- \`.opencode/rules/next-app-core.md\`
|
|
577
|
+
- \`.opencode/rules/package-manager.md\`
|
|
578
|
+
- \`.opencode/rules/code-quality-and-refactoring.md\`
|
|
579
|
+
- \`.opencode/rules/ai-local-overlay.md\`
|
|
580
|
+
|
|
581
|
+
Do **not** preload the full \`.opencode/rules/\` catalog. Native agents live in
|
|
582
|
+
\`.opencode/agents/\`; skills in \`.opencode/skills/\`; slash commands in
|
|
583
|
+
\`.opencode/commands/\` (\`/task\`). After a producer receipt run
|
|
584
|
+
\`bash .opencode/hooks/chain-team-phases.sh\`.
|
|
585
|
+
|
|
586
|
+
## Commands (test / lint / build)
|
|
587
|
+
|
|
588
|
+
Working directory for app scripts: **\`app/\`**. Detect the package manager from
|
|
589
|
+
lockfile / \`packageManager\` (\`package-manager\` rule).
|
|
590
|
+
|
|
591
|
+
| Gate | Typical command |
|
|
592
|
+
|------|-----------------|
|
|
593
|
+
| Lint JS | \`yarn lint:js\` (or project equivalent) from \`app/\` |
|
|
594
|
+
| Lint CSS | \`yarn lint:css\` from \`app/\` |
|
|
595
|
+
| Unit tests | project unit script under \`app/\` |
|
|
596
|
+
| Build | project \`build\` under \`app/\` |
|
|
597
|
+
|
|
598
|
+
After code edits: invoke **\`post-change-lint\`** (requestable). Full gate: agent
|
|
599
|
+
\`build-verifier\`.
|
|
600
|
+
|
|
601
|
+
## Security basics
|
|
602
|
+
|
|
603
|
+
- Do not commit secrets (\`.env\`, tokens, credentials).
|
|
604
|
+
- Review destructive git (\`reset --hard\`, force-push) before running; respect
|
|
605
|
+
shell hooks.
|
|
606
|
+
- Do not weaken CI or skip hooks unless the user explicitly asks.
|
|
607
|
+
|
|
608
|
+
## Tool entry points
|
|
609
|
+
|
|
610
|
+
| Tool | Map |
|
|
611
|
+
|------|-----|
|
|
612
|
+
| Cursor | \`.cursor/AGENTS.md\` (optional if Cursor not installed) |
|
|
613
|
+
| Claude Code | \`.claude/CLAUDE.md\` (optional if Claude Code not installed) |
|
|
614
|
+
| Mavis | \`.mavis/AGENTS.md\` (optional if Mavis not installed) |
|
|
615
|
+
| OpenCode | \`.opencode/AGENTS.md\` (optional if OpenCode not installed) |
|
|
616
|
+
|
|
617
|
+
Rules: \`.cursor/rules/\`, \`.claude/rules/\`, \`.mavis/rules/\`, or \`.opencode/rules/\`.
|
|
618
|
+
Skills: \`.cursor/skills/\`, \`.claude/skills/\`, \`.mavis/skills/\`, or \`.opencode/skills/\`.
|
|
619
|
+
|
|
620
|
+
## Living conventions
|
|
621
|
+
|
|
622
|
+
Gotchas, local patterns, and team decisions:
|
|
623
|
+
**\`.cursor/team/conventions.md\`**, **\`.claude/team/conventions.md\`**,
|
|
624
|
+
**\`.mavis/team/conventions.md\`**, and/or **\`.opencode/team/conventions.md\`**
|
|
625
|
+
(fill after init; not overwritten on every dogfood sync when already present).
|
|
626
|
+
|
|
627
|
+
## Local overlay (\`.ai.local/\`) — MANDATORY
|
|
628
|
+
|
|
629
|
+
A \`.ai.local/\` directory MAY exist at the repo root or at any nesting depth in
|
|
630
|
+
monorepos. **All agents MUST read and apply it on every turn.** Rules there
|
|
631
|
+
override preset rules; in conflicts, the local rule wins.
|
|
632
|
+
\`override: kill <preset-rule-name>\` drops the named preset rule from the
|
|
633
|
+
agent's context entirely.
|
|
634
|
+
|
|
635
|
+
Plain markdown rules under \`.ai.local/rules/*.md\` are read by the agent with
|
|
636
|
+
higher priority than preset rules. Living gotchas live in
|
|
637
|
+
\`.ai.local/conventions.md\`.
|
|
638
|
+
|
|
639
|
+
Authoring guide: \`docs/LOCAL-OVERLAY.md\` in the \`@bonesofspring/ai-rules\`
|
|
640
|
+
package. The \`ai-local-overlay\` rule is the mechanism; this \`MANDATORY\`
|
|
641
|
+
section is the reinforcement.
|
|
642
|
+
`;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
function stripInstallSection(body) {
|
|
646
|
+
const index = body.search(/^## Install\r?\n/m);
|
|
647
|
+
if (index < 0) {
|
|
648
|
+
return body.trimEnd();
|
|
649
|
+
}
|
|
650
|
+
return body.slice(0, index).trimEnd();
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
function stripEmbeddedCatalogLine(body) {
|
|
654
|
+
return body.replace(
|
|
655
|
+
/^See `\.opencode\/rules\/README\.md` for the full catalog[^\n]*\n+/m,
|
|
656
|
+
'',
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
function buildOpencodeEntry(sourceText) {
|
|
661
|
+
const body = stripEmbeddedCatalogLine(
|
|
662
|
+
stripInstallSection(
|
|
663
|
+
dropLeadingHeading(rewriteProse(stripFrontmatter(sourceText).body)),
|
|
664
|
+
),
|
|
665
|
+
);
|
|
666
|
+
return `# Next.js stack — OpenCode agent team
|
|
667
|
+
|
|
668
|
+
Short OpenCode entry. Native discovery: \`.opencode/agents/\`,
|
|
669
|
+
\`.opencode/skills/\`, \`.opencode/commands/\`. Rule files under
|
|
670
|
+
\`.opencode/rules/*.md\` are **not** auto-loaded.
|
|
671
|
+
|
|
672
|
+
Root \`AGENTS.md\` is native always-on. Read it first, then this file.
|
|
673
|
+
|
|
674
|
+
## How to load
|
|
675
|
+
|
|
676
|
+
- Essential rules: Read immediately (paths below). Do not preload the catalog.
|
|
677
|
+
- Other rules: lazy \`Read\` \`.opencode/rules/<stem>.md\` when the task matches.
|
|
678
|
+
- Agents: native \`@name\` / Task from \`.opencode/agents/\`.
|
|
679
|
+
- Commands: native \`/task\` from \`.opencode/commands/\`.
|
|
680
|
+
- After a producer receipt, run \`bash .opencode/hooks/chain-team-phases.sh\`.
|
|
681
|
+
Agents must not write lifecycle fields in \`status.json\` / \`metrics.json\`.
|
|
682
|
+
|
|
683
|
+
## Essential rules (read every turn)
|
|
684
|
+
|
|
685
|
+
- \`.opencode/rules/next-app-core.md\`
|
|
686
|
+
- \`.opencode/rules/package-manager.md\`
|
|
687
|
+
- \`.opencode/rules/code-quality-and-refactoring.md\`
|
|
688
|
+
- \`.opencode/rules/ai-local-overlay.md\`
|
|
689
|
+
|
|
690
|
+
See \`.opencode/rules/README.md\` for the full catalog and loading strategy.
|
|
691
|
+
|
|
692
|
+
**Platform docs:** published with the \`@bonesofspring/ai-rules\` package
|
|
693
|
+
(\`docs/OPENCODE.md\`, \`docs/OPENCODE-COMPATIBILITY.md\`) — **not** copied into
|
|
694
|
+
the consumer repo. Source: https://github.com/bonesofspring/ai-rules
|
|
695
|
+
|
|
696
|
+
${body}
|
|
697
|
+
|
|
698
|
+
## Install
|
|
699
|
+
|
|
700
|
+
\`\`\`bash
|
|
701
|
+
npx @bonesofspring/ai-rules init opencode --preset next
|
|
702
|
+
\`\`\`
|
|
703
|
+
|
|
704
|
+
Copies rules, commands, agents, hooks, skills, team, \`OPENCODE.md\` →
|
|
705
|
+
\`.opencode/AGENTS.md\`, \`MCP.md\`, \`opencode.json\` → project \`opencode.json\`
|
|
706
|
+
(\`mcp\` merge), plus \`REPO_AGENTS.md\` → root \`AGENTS.md\`.
|
|
707
|
+
`;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
function buildCommandsReadme() {
|
|
711
|
+
let text = rewriteProse(readSiblingReadme('commands/README.md'));
|
|
712
|
+
text = text.replace(
|
|
713
|
+
'# Cursor commands (next preset)',
|
|
714
|
+
'# OpenCode commands (next preset)',
|
|
715
|
+
);
|
|
716
|
+
text = text.replace(
|
|
717
|
+
'Slash commands are copied to `.opencode/commands/` on `ai-rules init opencode --preset next`.',
|
|
718
|
+
'Slash commands are copied to `.opencode/commands/` on `ai-rules init opencode --preset next`. OpenCode loads `/<filename>` natively.',
|
|
719
|
+
);
|
|
720
|
+
text = text.replace(
|
|
721
|
+
'- Orchestrator: `../rules/agent-team-orchestrator.mdc`',
|
|
722
|
+
'- Orchestrator: `../rules/agent-team-orchestrator.md`',
|
|
723
|
+
);
|
|
724
|
+
text = text.replace(
|
|
725
|
+
'- Hooks: `../hooks.json`, `../hooks/chain-team-phases.sh`',
|
|
726
|
+
'- Hooks: `../hooks/chain-team-phases.sh` only (semi-auto runner; no `hooks.json`)',
|
|
727
|
+
);
|
|
728
|
+
return text.endsWith('\n') ? text : `${text}\n`;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
function buildAgentsReadme() {
|
|
732
|
+
let text = rewriteProse(readSiblingReadme('agents/README.md'));
|
|
733
|
+
text = text.replace(
|
|
734
|
+
'Role-based subagents for the Cursor team pipeline.',
|
|
735
|
+
'Role-based subagents for the OpenCode team pipeline (native `.opencode/agents/`).',
|
|
736
|
+
);
|
|
737
|
+
text = text.replace(
|
|
738
|
+
/## Frontmatter `readonly`[\s\S]*?(?=## Orchestration)/,
|
|
739
|
+
`## OpenCode packaging
|
|
740
|
+
|
|
741
|
+
Agents ship with OpenCode YAML frontmatter: \`description\`, \`mode: subagent\`,
|
|
742
|
+
and \`permission\`. Do **not** pin \`model\` in this preset.
|
|
743
|
+
|
|
744
|
+
- Implementers (\`feature-developer\`, \`debugger\`, \`ci-investigator\`, test generators/healers): \`permission.edit: allow\`.
|
|
745
|
+
- Reviewer / planner roles: \`edit\` deny except \`.opencode/team/**\`. Prompt bodies still forbid production edits.
|
|
746
|
+
|
|
747
|
+
**Team artifacts:** agents write \`.opencode/team/**\` deliverables. They must
|
|
748
|
+
**not** mutate lifecycle fields in \`status.json\` or \`metrics.json\` —
|
|
749
|
+
\`bash .opencode/hooks/chain-team-phases.sh\` owns those after each producer receipt.
|
|
750
|
+
|
|
751
|
+
## Model tiers (advisory)
|
|
752
|
+
|
|
753
|
+
Optional \`steps[].model\` in \`pipeline.json\` (\`cheap\` | \`standard\` | \`strong\`)
|
|
754
|
+
is advisory for the operator's OpenCode provider — see \`task-router.md\`.
|
|
755
|
+
|
|
756
|
+
`,
|
|
757
|
+
);
|
|
758
|
+
return text.endsWith('\n') ? text : `${text}\n`;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
function buildStackReadme() {
|
|
762
|
+
return `# Next.js preset (OpenCode)
|
|
763
|
+
|
|
764
|
+
Sibling adapter derived from \`presets/cursor/next\`. Platform id \`opencode\`;
|
|
765
|
+
runtime \`opencode\`. Consumer install root is \`.opencode/\` (native agents,
|
|
766
|
+
skills, commands) plus root \`AGENTS.md\` and \`opencode.json\`.
|
|
767
|
+
|
|
768
|
+
Mapping: \`adapter-map.json\`. Do not derive this tree from Claude.
|
|
769
|
+
|
|
770
|
+
\`\`\`bash
|
|
771
|
+
npx @bonesofspring/ai-rules init opencode --preset next
|
|
772
|
+
\`\`\`
|
|
773
|
+
|
|
774
|
+
\`releasedStacks\` currently lists **\`next\`** only.
|
|
775
|
+
|
|
776
|
+
Omitted from this pilot: \`BUGBOT.md\`, \`hooks.json\`, hook examples, and
|
|
777
|
+
unwired \`guard-shell-command.sh\`.
|
|
778
|
+
`;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
function buildRulesReadme() {
|
|
782
|
+
return `# OpenCode Next rules
|
|
783
|
+
|
|
784
|
+
Plain Markdown. OpenCode does **not** auto-load these files. Root \`AGENTS.md\`
|
|
785
|
+
and \`.opencode/AGENTS.md\` list four essential paths to Read immediately; the
|
|
786
|
+
rest are lazy-loaded when the task matches.
|
|
787
|
+
|
|
788
|
+
Do not put this catalog into \`opencode.json\` \`instructions\` as the only
|
|
789
|
+
always-on path (V2 may ignore that field).
|
|
790
|
+
|
|
791
|
+
## Essential (entry-critical)
|
|
792
|
+
|
|
793
|
+
\`next-app-core\`, \`package-manager\`, \`code-quality-and-refactoring\`,
|
|
794
|
+
\`ai-local-overlay\`.
|
|
795
|
+
|
|
796
|
+
## Requestable
|
|
797
|
+
|
|
798
|
+
All other \`*.md\` files in this directory. Same stems as Cursor
|
|
799
|
+
\`rules/README.md\`.
|
|
800
|
+
|
|
801
|
+
Shared-core markers (\`<!-- shared-core: … -->\`) are preserved from Cursor.
|
|
802
|
+
`;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
function buildHooksReadme() {
|
|
806
|
+
return `# OpenCode hooks
|
|
807
|
+
|
|
808
|
+
No Cursor \`hooks.json\` and no TypeScript plugin in v1.
|
|
809
|
+
|
|
810
|
+
## Shipped
|
|
811
|
+
|
|
812
|
+
\`chain-team-phases.sh\` — manual/semi-auto runner. After a producer receipt:
|
|
813
|
+
|
|
814
|
+
\`\`\`bash
|
|
815
|
+
printf '%s\\n' '{"status":"completed","attemptId":"<runtime-attempt-id>"}' \\
|
|
816
|
+
| bash .opencode/hooks/chain-team-phases.sh
|
|
817
|
+
\`\`\`
|
|
818
|
+
|
|
819
|
+
\`<runtime-attempt-id>\` comes from \`.opencode/team/tasks/<slug>/status.json\`.
|
|
820
|
+
Do not invent it. Agents never write lifecycle fields in \`status.json\` or
|
|
821
|
+
\`metrics.json\`.
|
|
822
|
+
|
|
823
|
+
## Omitted
|
|
824
|
+
|
|
825
|
+
- \`hooks.json\` — no native registration schema in this preset
|
|
826
|
+
- \`guard-shell-command.sh\` — not wired; do not describe it as enforcement
|
|
827
|
+
- \`hooks/examples/**\` — plugin port is a follow-up
|
|
828
|
+
`;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
main();
|