@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,50 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import crypto from 'node:crypto';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
|
|
6
|
+
export function sha256File(filePath) {
|
|
7
|
+
return crypto.createHash('sha256').update(fs.readFileSync(filePath)).digest('hex');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function walkRelativeFiles(root) {
|
|
11
|
+
const files = [];
|
|
12
|
+
const visit = (dir) => {
|
|
13
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
14
|
+
const full = path.join(dir, entry.name);
|
|
15
|
+
if (entry.name === '.DS_Store') {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (entry.isDirectory()) {
|
|
19
|
+
visit(full);
|
|
20
|
+
} else if (entry.isFile()) {
|
|
21
|
+
files.push(path.relative(root, full).split(path.sep).join('/'));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
visit(root);
|
|
26
|
+
return files.sort();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function snapshotInstall(root) {
|
|
30
|
+
const files = {};
|
|
31
|
+
for (const rel of walkRelativeFiles(root)) {
|
|
32
|
+
files[rel] = sha256File(path.join(root, rel));
|
|
33
|
+
}
|
|
34
|
+
return files;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function runInit(cli, cwd, tool, preset) {
|
|
38
|
+
return execFileSync(process.execPath, [cli, 'init', tool, '--preset', preset, '--cwd', cwd], {
|
|
39
|
+
encoding: 'utf8',
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function goldenDocument({ tool, preset, files }) {
|
|
44
|
+
return {
|
|
45
|
+
schemaVersion: 1,
|
|
46
|
+
tool,
|
|
47
|
+
preset,
|
|
48
|
+
files,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
export function loadReleasedMavisStacks(presetsRoot) {
|
|
5
|
+
const contractPath = path.join(presetsRoot, 'mavis', 'platform-contract.json');
|
|
6
|
+
if (!fs.existsSync(contractPath)) {
|
|
7
|
+
return [];
|
|
8
|
+
}
|
|
9
|
+
const contract = JSON.parse(fs.readFileSync(contractPath, 'utf8'));
|
|
10
|
+
return Array.isArray(contract.releasedStacks) ? contract.releasedStacks : [];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function loadReleasedOpencodeStacks(presetsRoot) {
|
|
14
|
+
const contractPath = path.join(presetsRoot, 'opencode', 'platform-contract.json');
|
|
15
|
+
if (!fs.existsSync(contractPath)) {
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
const contract = JSON.parse(fs.readFileSync(contractPath, 'utf8'));
|
|
19
|
+
return Array.isArray(contract.releasedStacks) ? contract.releasedStacks : [];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function discoverChainHooks(presetsRoot) {
|
|
23
|
+
const hooks = [];
|
|
24
|
+
for (const platform of ['cursor', 'claude']) {
|
|
25
|
+
const platformDir = path.join(presetsRoot, platform);
|
|
26
|
+
if (!fs.existsSync(platformDir)) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
for (const stack of fs.readdirSync(platformDir)) {
|
|
30
|
+
const hook = path.join(platformDir, stack, 'hooks', 'chain-team-phases.sh');
|
|
31
|
+
if (fs.existsSync(hook)) {
|
|
32
|
+
hooks.push(hook);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
for (const stack of loadReleasedMavisStacks(presetsRoot)) {
|
|
37
|
+
const hook = path.join(presetsRoot, 'mavis', stack, 'hooks', 'chain-team-phases.sh');
|
|
38
|
+
if (fs.existsSync(hook)) {
|
|
39
|
+
hooks.push(hook);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
for (const stack of loadReleasedOpencodeStacks(presetsRoot)) {
|
|
43
|
+
const hook = path.join(presetsRoot, 'opencode', stack, 'hooks', 'chain-team-phases.sh');
|
|
44
|
+
if (fs.existsSync(hook)) {
|
|
45
|
+
hooks.push(hook);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return hooks;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function platformFromHook(hookPath) {
|
|
52
|
+
const parts = hookPath.split(path.sep);
|
|
53
|
+
const presetsIndex = parts.lastIndexOf('presets');
|
|
54
|
+
if (presetsIndex >= 0 && parts[presetsIndex + 1]) {
|
|
55
|
+
return parts[presetsIndex + 1];
|
|
56
|
+
}
|
|
57
|
+
if (hookPath.includes(`${path.sep}mavis${path.sep}`)) {
|
|
58
|
+
return 'mavis';
|
|
59
|
+
}
|
|
60
|
+
if (hookPath.includes(`${path.sep}opencode${path.sep}`)) {
|
|
61
|
+
return 'opencode';
|
|
62
|
+
}
|
|
63
|
+
if (hookPath.includes(`${path.sep}cursor${path.sep}`)) {
|
|
64
|
+
return 'cursor';
|
|
65
|
+
}
|
|
66
|
+
return 'claude';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function expectedLegacyHookCount(presetsRoot) {
|
|
70
|
+
let count = 0;
|
|
71
|
+
for (const platform of ['cursor', 'claude']) {
|
|
72
|
+
const platformDir = path.join(presetsRoot, platform);
|
|
73
|
+
if (!fs.existsSync(platformDir)) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
for (const stack of fs.readdirSync(platformDir)) {
|
|
77
|
+
const hook = path.join(platformDir, stack, 'hooks', 'chain-team-phases.sh');
|
|
78
|
+
if (fs.existsSync(hook)) {
|
|
79
|
+
count += 1;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return count;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function expectedHookCount(presetsRoot) {
|
|
87
|
+
const mavisCount = loadReleasedMavisStacks(presetsRoot).filter((stack) =>
|
|
88
|
+
fs.existsSync(path.join(presetsRoot, 'mavis', stack, 'hooks', 'chain-team-phases.sh')),
|
|
89
|
+
).length;
|
|
90
|
+
const opencodeCount = loadReleasedOpencodeStacks(presetsRoot).filter((stack) =>
|
|
91
|
+
fs.existsSync(path.join(presetsRoot, 'opencode', stack, 'hooks', 'chain-team-phases.sh')),
|
|
92
|
+
).length;
|
|
93
|
+
return expectedLegacyHookCount(presetsRoot) + mavisCount + opencodeCount;
|
|
94
|
+
}
|
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
const scriptDirectory = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const fixtureDirectory = path.join(scriptDirectory, 'fixtures', 'mavis-probe');
|
|
10
|
+
|
|
11
|
+
const LIBRARY_INPUTS = [
|
|
12
|
+
path.join('rules', 'probe.md'),
|
|
13
|
+
path.join('agents', 'probe-agent.md'),
|
|
14
|
+
path.join('skills', 'probe', 'SKILL.md'),
|
|
15
|
+
'output.schema.json',
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
function parseArguments(argv) {
|
|
19
|
+
const values = new Map();
|
|
20
|
+
for (let index = 0; index < argv.length; index += 2) {
|
|
21
|
+
const flag = argv[index];
|
|
22
|
+
const value = argv[index + 1];
|
|
23
|
+
if (!['--mcode', '--workdir'].includes(flag) || !value) {
|
|
24
|
+
throw new Error('Usage: probe-mavis-capabilities.mjs --mcode <path> --workdir <path>');
|
|
25
|
+
}
|
|
26
|
+
values.set(flag, value);
|
|
27
|
+
}
|
|
28
|
+
if (!values.has('--mcode') || !values.has('--workdir')) {
|
|
29
|
+
throw new Error('Both --mcode and --workdir are required');
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
mcode: path.resolve(values.get('--mcode')),
|
|
33
|
+
workdir: path.resolve(values.get('--workdir')),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function createRedactor({ mcode, workdir, isolatedHome }) {
|
|
38
|
+
const replacements = [
|
|
39
|
+
[mcode, '<MCODE>'],
|
|
40
|
+
[workdir, '<WORKDIR>'],
|
|
41
|
+
[isolatedHome, '<PROBE_HOME>'],
|
|
42
|
+
[os.homedir(), '<HOME>'],
|
|
43
|
+
]
|
|
44
|
+
.filter(([source]) => Boolean(source))
|
|
45
|
+
.sort(([left], [right]) => right.length - left.length);
|
|
46
|
+
|
|
47
|
+
return (value) => {
|
|
48
|
+
let redacted = String(value ?? '');
|
|
49
|
+
for (const [source, target] of replacements) {
|
|
50
|
+
redacted = redacted.split(source).join(target);
|
|
51
|
+
}
|
|
52
|
+
return redacted
|
|
53
|
+
.replace(/\/(?:Users|home)\/[^/\s"']+\/\.minimax/g, '<HOME>/.minimax')
|
|
54
|
+
.replace(/(Bearer\s+)[^\s"',]+/gi, '$1<REDACTED>')
|
|
55
|
+
.replace(
|
|
56
|
+
/((?:api[_-]?key|token|secret|password)\s*[=:]\s*)[^\s"',]+/gi,
|
|
57
|
+
'$1<REDACTED>',
|
|
58
|
+
)
|
|
59
|
+
.trim();
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function commandForEvidence(args, redact) {
|
|
64
|
+
return args.map((argument) => redact(argument));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function capability({ status, command = null, exitCode = null, observation, executed = false }) {
|
|
68
|
+
return { status, command, exitCode, observation, executed };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function loadInlineOutputSchema() {
|
|
72
|
+
return JSON.stringify(JSON.parse(fs.readFileSync(path.join(fixtureDirectory, 'output.schema.json'), 'utf8')));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function createCapabilities(redact, mcode, workdir) {
|
|
76
|
+
const documentedMcpCommand = commandForEvidence([mcode, 'mcp', 'list', '--human'], redact);
|
|
77
|
+
const execSafety = ['--permission', 'off', '--timeout', '3m', '--max-steps', '16'];
|
|
78
|
+
const model = process.env.MAVIS_PROBE_MODEL;
|
|
79
|
+
if (model) execSafety.push('--model', model);
|
|
80
|
+
const outputSchema = loadInlineOutputSchema();
|
|
81
|
+
const structuredCommand = [
|
|
82
|
+
mcode,
|
|
83
|
+
'exec',
|
|
84
|
+
'--cwd',
|
|
85
|
+
workdir,
|
|
86
|
+
'--output-format',
|
|
87
|
+
'json',
|
|
88
|
+
...execSafety,
|
|
89
|
+
'Return the requested capability sentinels.',
|
|
90
|
+
];
|
|
91
|
+
if (process.env.MAVIS_PROBE_USE_SCHEMA === '1') {
|
|
92
|
+
structuredCommand.splice(structuredCommand.indexOf('json') + 1, 0, '--output-schema', outputSchema);
|
|
93
|
+
}
|
|
94
|
+
const roleCommand = [
|
|
95
|
+
mcode,
|
|
96
|
+
'exec',
|
|
97
|
+
'--cwd',
|
|
98
|
+
workdir,
|
|
99
|
+
'--file',
|
|
100
|
+
'agents/probe-agent.md',
|
|
101
|
+
'--output-format',
|
|
102
|
+
'json',
|
|
103
|
+
...execSafety,
|
|
104
|
+
'Return the requested role sentinel.',
|
|
105
|
+
];
|
|
106
|
+
if (process.env.MAVIS_PROBE_USE_SCHEMA === '1') {
|
|
107
|
+
roleCommand.splice(roleCommand.indexOf('json') + 1, 0, '--output-schema', outputSchema);
|
|
108
|
+
}
|
|
109
|
+
const structuredEvidence = commandForEvidence(structuredCommand, redact);
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
cliVersion: capability({
|
|
113
|
+
status: 'unknown',
|
|
114
|
+
command: commandForEvidence([mcode, '--version'], redact),
|
|
115
|
+
observation: 'Not executed.',
|
|
116
|
+
}),
|
|
117
|
+
cliHelp: capability({
|
|
118
|
+
status: 'unknown',
|
|
119
|
+
command: commandForEvidence([mcode, '--help'], redact),
|
|
120
|
+
observation: 'Not executed.',
|
|
121
|
+
}),
|
|
122
|
+
freshInit: capability({
|
|
123
|
+
status: 'unknown',
|
|
124
|
+
command: commandForEvidence([mcode, 'init', workdir], redact),
|
|
125
|
+
observation: 'Not executed.',
|
|
126
|
+
}),
|
|
127
|
+
rootAgents: capability({
|
|
128
|
+
status: 'unknown',
|
|
129
|
+
command: structuredEvidence,
|
|
130
|
+
observation: 'Not executed.',
|
|
131
|
+
}),
|
|
132
|
+
referencedRule: capability({
|
|
133
|
+
status: 'unknown',
|
|
134
|
+
command: structuredEvidence,
|
|
135
|
+
observation: 'Not executed.',
|
|
136
|
+
}),
|
|
137
|
+
referencedSkill: capability({
|
|
138
|
+
status: 'unknown',
|
|
139
|
+
command: structuredEvidence,
|
|
140
|
+
observation: 'Not executed.',
|
|
141
|
+
}),
|
|
142
|
+
explicitAgentFile: capability({
|
|
143
|
+
status: 'unknown',
|
|
144
|
+
command: commandForEvidence(roleCommand, redact),
|
|
145
|
+
observation: 'Not executed.',
|
|
146
|
+
}),
|
|
147
|
+
structuredOutput: capability({
|
|
148
|
+
status: 'unknown',
|
|
149
|
+
command: structuredEvidence,
|
|
150
|
+
observation: 'Not executed.',
|
|
151
|
+
}),
|
|
152
|
+
nativeProjectRules: capability({
|
|
153
|
+
status: 'unknown',
|
|
154
|
+
command: structuredEvidence,
|
|
155
|
+
observation: 'Not executed.',
|
|
156
|
+
}),
|
|
157
|
+
nativeWorkspaceSkills: capability({
|
|
158
|
+
status: 'unknown',
|
|
159
|
+
command: structuredEvidence,
|
|
160
|
+
observation: 'Not executed.',
|
|
161
|
+
}),
|
|
162
|
+
nativeWorkspaceAgents: capability({
|
|
163
|
+
status: 'unknown',
|
|
164
|
+
command: structuredEvidence,
|
|
165
|
+
observation: 'Not executed.',
|
|
166
|
+
}),
|
|
167
|
+
projectMcp: capability({
|
|
168
|
+
status: 'unknown',
|
|
169
|
+
command: documentedMcpCommand,
|
|
170
|
+
observation:
|
|
171
|
+
'Documented inspection command only; not executed to avoid reading or changing user-global MCP state.',
|
|
172
|
+
}),
|
|
173
|
+
projectHooks: capability({
|
|
174
|
+
status: 'unknown',
|
|
175
|
+
command: null,
|
|
176
|
+
observation:
|
|
177
|
+
'No documented project hook path is assumed; manual chain execution remains the fallback.',
|
|
178
|
+
}),
|
|
179
|
+
slashCommands: capability({
|
|
180
|
+
status: 'unknown',
|
|
181
|
+
command: null,
|
|
182
|
+
observation:
|
|
183
|
+
'No file-defined slash command API is assumed; command files remain explicit procedures.',
|
|
184
|
+
}),
|
|
185
|
+
pluginSkillMcp: capability({
|
|
186
|
+
status: 'confirmed',
|
|
187
|
+
command: null,
|
|
188
|
+
observation:
|
|
189
|
+
'Plugin Skill (`skills/**/SKILL.md`) and plugin MCP (`*.mcp.json`) formats are confirmed from official MiniMax documentation; local plugin installation was not executed by this probe.',
|
|
190
|
+
}),
|
|
191
|
+
nativeTeam: capability({
|
|
192
|
+
status: 'partial',
|
|
193
|
+
command: null,
|
|
194
|
+
observation:
|
|
195
|
+
'Official Team documentation describes Leader, Worker, and Verifier; programmatic bridge controls were not executed and remain unverified.',
|
|
196
|
+
}),
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function restoreSpawnArgs(command, workdir) {
|
|
201
|
+
return command.slice(1).map((argument) => (argument === '<WORKDIR>' ? workdir : argument));
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function runMcode(mcode, args, workdir, redact, isolatedHome) {
|
|
205
|
+
const result = spawnSync(mcode, args, {
|
|
206
|
+
cwd: workdir,
|
|
207
|
+
encoding: 'utf8',
|
|
208
|
+
env: {
|
|
209
|
+
...process.env,
|
|
210
|
+
HOME: isolatedHome,
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
const exitCode = Number.isInteger(result.status) ? result.status : null;
|
|
214
|
+
let observation = `${result.stdout ?? ''}${result.stderr ?? ''}`.trim();
|
|
215
|
+
if (result.error?.code === 'ENOENT') {
|
|
216
|
+
observation = 'Executable not found.';
|
|
217
|
+
} else if (result.error) {
|
|
218
|
+
observation = result.error.message;
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
exitCode,
|
|
222
|
+
observation: redact(observation || `Exited with code ${exitCode}.`),
|
|
223
|
+
stdout: result.stdout ?? '',
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function runInit(mcode, workdir, redact, isolatedHome) {
|
|
228
|
+
return runMcode(mcode, ['init', workdir], workdir, redact, isolatedHome);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const AUTH_SEED_ENTRIES = ['cli-auth', 'local-runtime.auth.json', 'config.yaml'];
|
|
232
|
+
|
|
233
|
+
function seedIsolatedAuth(operatorHome, isolatedHome) {
|
|
234
|
+
const sourceRoot = path.join(operatorHome, '.minimax');
|
|
235
|
+
const destinationRoot = path.join(isolatedHome, '.minimax');
|
|
236
|
+
if (!fs.existsSync(sourceRoot)) return { seeded: false, entries: [] };
|
|
237
|
+
const seeded = [];
|
|
238
|
+
for (const entry of AUTH_SEED_ENTRIES) {
|
|
239
|
+
const source = path.join(sourceRoot, entry);
|
|
240
|
+
if (!fs.existsSync(source)) continue;
|
|
241
|
+
const destination = path.join(destinationRoot, entry);
|
|
242
|
+
fs.cpSync(source, destination, { recursive: true });
|
|
243
|
+
seeded.push(entry);
|
|
244
|
+
}
|
|
245
|
+
return { seeded: seeded.length > 0, entries: seeded };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function copyProbeInputs(workdir, relativeInputs) {
|
|
249
|
+
for (const relativeInput of relativeInputs) {
|
|
250
|
+
const source = path.join(fixtureDirectory, relativeInput);
|
|
251
|
+
const destination = path.join(workdir, relativeInput);
|
|
252
|
+
fs.mkdirSync(path.dirname(destination), { recursive: true });
|
|
253
|
+
fs.copyFileSync(source, destination);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function extractSentinels(value) {
|
|
258
|
+
const text = typeof value === 'string' ? value : JSON.stringify(value ?? '');
|
|
259
|
+
return [...new Set(text.match(/MAVIS_[A-Z_]+_SENTINEL/g) ?? [])];
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function parseStructuredOutput(stdout) {
|
|
263
|
+
const parsed = JSON.parse(stdout);
|
|
264
|
+
if (parsed?.status === 'ok' && Array.isArray(parsed.sentinels)) {
|
|
265
|
+
return parsed;
|
|
266
|
+
}
|
|
267
|
+
if (parsed?.type === 'exec.result') {
|
|
268
|
+
const sentinels = extractSentinels(parsed.output);
|
|
269
|
+
if (parsed.status === 'succeeded' || sentinels.length > 0) {
|
|
270
|
+
return {
|
|
271
|
+
status: 'ok',
|
|
272
|
+
sentinels,
|
|
273
|
+
observation: `mcode wrapper status ${parsed.status}`,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
throw new Error(`exec.result status ${parsed.status}`);
|
|
277
|
+
}
|
|
278
|
+
throw new Error('Structured output did not match a known probe or mcode wrapper shape');
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function updateExecutionCapability(target, result, status, observation) {
|
|
282
|
+
target.status = status;
|
|
283
|
+
target.exitCode = result.exitCode;
|
|
284
|
+
target.observation = observation;
|
|
285
|
+
target.executed = true;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function writeEvidence(evidence, exitCode) {
|
|
289
|
+
process.stdout.write(`${JSON.stringify(evidence, null, 2)}\n`);
|
|
290
|
+
process.exitCode = exitCode;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function sentinelSet(parsed) {
|
|
294
|
+
return new Set(parsed?.sentinels ?? []);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
let options;
|
|
298
|
+
try {
|
|
299
|
+
options = parseArguments(process.argv.slice(2));
|
|
300
|
+
} catch (error) {
|
|
301
|
+
process.stdout.write(
|
|
302
|
+
`${JSON.stringify({ schemaVersion: 1, probeStatus: 'blocked', error: error.message }, null, 2)}\n`,
|
|
303
|
+
);
|
|
304
|
+
process.exitCode = 2;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (options) {
|
|
308
|
+
const { mcode, workdir } = options;
|
|
309
|
+
let isolatedHome;
|
|
310
|
+
try {
|
|
311
|
+
isolatedHome = fs.mkdtempSync(path.join(os.tmpdir(), 'mavis-probe-home-'));
|
|
312
|
+
const operatorHome = process.env.HOME || os.homedir();
|
|
313
|
+
const authSeed = seedIsolatedAuth(operatorHome, isolatedHome);
|
|
314
|
+
const redact = createRedactor({ mcode, workdir, isolatedHome });
|
|
315
|
+
const capabilities = createCapabilities(redact, mcode, workdir);
|
|
316
|
+
const evidence = {
|
|
317
|
+
schemaVersion: 1,
|
|
318
|
+
probeStatus: 'completed',
|
|
319
|
+
cli: {
|
|
320
|
+
executable: '<MCODE>',
|
|
321
|
+
version: null,
|
|
322
|
+
},
|
|
323
|
+
os: {
|
|
324
|
+
platform: os.platform(),
|
|
325
|
+
release: os.release(),
|
|
326
|
+
arch: os.arch(),
|
|
327
|
+
},
|
|
328
|
+
workdir: '<WORKDIR>',
|
|
329
|
+
authSeed: {
|
|
330
|
+
seeded: authSeed.seeded,
|
|
331
|
+
entries: authSeed.entries,
|
|
332
|
+
},
|
|
333
|
+
capabilities,
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
fs.mkdirSync(workdir, { recursive: true });
|
|
337
|
+
if (fs.readdirSync(workdir).length > 0) {
|
|
338
|
+
evidence.probeStatus = 'blocked';
|
|
339
|
+
capabilities.freshInit.observation = 'Workdir must be empty before the probe starts.';
|
|
340
|
+
writeEvidence(evidence, 2);
|
|
341
|
+
} else {
|
|
342
|
+
const version = runMcode(mcode, ['--version'], workdir, redact, isolatedHome);
|
|
343
|
+
const versionText = redact(version.stdout).split(/\r?\n/, 1)[0] || null;
|
|
344
|
+
updateExecutionCapability(
|
|
345
|
+
capabilities.cliVersion,
|
|
346
|
+
version,
|
|
347
|
+
version.exitCode === 0 && versionText ? 'confirmed' : 'unknown',
|
|
348
|
+
version.exitCode === 0 && versionText ? versionText : version.observation,
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
if (capabilities.cliVersion.status !== 'confirmed') {
|
|
352
|
+
evidence.probeStatus = 'blocked';
|
|
353
|
+
writeEvidence(evidence, 2);
|
|
354
|
+
} else {
|
|
355
|
+
evidence.cli.version = versionText;
|
|
356
|
+
|
|
357
|
+
const help = runMcode(mcode, ['--help'], workdir, redact, isolatedHome);
|
|
358
|
+
updateExecutionCapability(
|
|
359
|
+
capabilities.cliHelp,
|
|
360
|
+
help,
|
|
361
|
+
help.exitCode === 0 ? 'confirmed' : 'unknown',
|
|
362
|
+
help.observation,
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
const init = runInit(mcode, workdir, redact, isolatedHome);
|
|
366
|
+
updateExecutionCapability(
|
|
367
|
+
capabilities.freshInit,
|
|
368
|
+
init,
|
|
369
|
+
init.exitCode === 0 ? 'confirmed' : 'unknown',
|
|
370
|
+
init.observation,
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
copyProbeInputs(workdir, LIBRARY_INPUTS);
|
|
374
|
+
|
|
375
|
+
const nativeArgs = restoreSpawnArgs(capabilities.nativeProjectRules.command, workdir);
|
|
376
|
+
const nativeResult = runMcode(mcode, nativeArgs, workdir, redact, isolatedHome);
|
|
377
|
+
let nativeOutput = null;
|
|
378
|
+
try {
|
|
379
|
+
nativeOutput = nativeResult.exitCode === 0 ? parseStructuredOutput(nativeResult.stdout) : null;
|
|
380
|
+
} catch (error) {
|
|
381
|
+
nativeResult.observation = redact(error.message);
|
|
382
|
+
}
|
|
383
|
+
const nativeSentinels = sentinelSet(nativeOutput);
|
|
384
|
+
const nativeObservation = redact(nativeOutput?.observation ?? nativeResult.observation);
|
|
385
|
+
updateExecutionCapability(
|
|
386
|
+
capabilities.nativeProjectRules,
|
|
387
|
+
nativeResult,
|
|
388
|
+
nativeSentinels.has('MAVIS_RULE_SENTINEL') ? 'confirmed' : 'unknown',
|
|
389
|
+
nativeSentinels.has('MAVIS_RULE_SENTINEL')
|
|
390
|
+
? 'Rule sentinel returned without an explicit root AGENTS.md reference.'
|
|
391
|
+
: nativeObservation,
|
|
392
|
+
);
|
|
393
|
+
updateExecutionCapability(
|
|
394
|
+
capabilities.nativeWorkspaceSkills,
|
|
395
|
+
nativeResult,
|
|
396
|
+
nativeSentinels.has('MAVIS_SKILL_SENTINEL') ? 'confirmed' : 'unknown',
|
|
397
|
+
nativeSentinels.has('MAVIS_SKILL_SENTINEL')
|
|
398
|
+
? 'Skill sentinel returned without an explicit root AGENTS.md reference.'
|
|
399
|
+
: nativeObservation,
|
|
400
|
+
);
|
|
401
|
+
updateExecutionCapability(
|
|
402
|
+
capabilities.nativeWorkspaceAgents,
|
|
403
|
+
nativeResult,
|
|
404
|
+
nativeSentinels.has('MAVIS_AGENT_FILE_SENTINEL') ? 'confirmed' : 'unknown',
|
|
405
|
+
nativeSentinels.has('MAVIS_AGENT_FILE_SENTINEL')
|
|
406
|
+
? 'Agent sentinel returned without mcode exec --file.'
|
|
407
|
+
: nativeObservation,
|
|
408
|
+
);
|
|
409
|
+
|
|
410
|
+
copyProbeInputs(workdir, ['AGENTS.md']);
|
|
411
|
+
|
|
412
|
+
const rootArgs = restoreSpawnArgs(capabilities.rootAgents.command, workdir);
|
|
413
|
+
const rootResult = runMcode(mcode, rootArgs, workdir, redact, isolatedHome);
|
|
414
|
+
let rootOutput = null;
|
|
415
|
+
try {
|
|
416
|
+
rootOutput = rootResult.exitCode === 0 ? parseStructuredOutput(rootResult.stdout) : null;
|
|
417
|
+
} catch (error) {
|
|
418
|
+
rootResult.observation = redact(error.message);
|
|
419
|
+
}
|
|
420
|
+
const rootSentinels = sentinelSet(rootOutput);
|
|
421
|
+
updateExecutionCapability(
|
|
422
|
+
capabilities.rootAgents,
|
|
423
|
+
rootResult,
|
|
424
|
+
rootSentinels.has('MAVIS_AGENTS_SENTINEL') ? 'confirmed' : 'unknown',
|
|
425
|
+
redact(rootOutput?.observation ?? rootResult.observation),
|
|
426
|
+
);
|
|
427
|
+
updateExecutionCapability(
|
|
428
|
+
capabilities.referencedRule,
|
|
429
|
+
rootResult,
|
|
430
|
+
rootSentinels.has('MAVIS_RULE_SENTINEL') ? 'confirmed' : 'unknown',
|
|
431
|
+
rootSentinels.has('MAVIS_RULE_SENTINEL')
|
|
432
|
+
? 'Rule sentinel returned through the explicit root AGENTS.md reference.'
|
|
433
|
+
: rootResult.observation,
|
|
434
|
+
);
|
|
435
|
+
updateExecutionCapability(
|
|
436
|
+
capabilities.referencedSkill,
|
|
437
|
+
rootResult,
|
|
438
|
+
rootSentinels.has('MAVIS_SKILL_SENTINEL') ? 'confirmed' : 'unknown',
|
|
439
|
+
rootSentinels.has('MAVIS_SKILL_SENTINEL')
|
|
440
|
+
? 'Skill sentinel returned through the explicit root AGENTS.md reference.'
|
|
441
|
+
: rootResult.observation,
|
|
442
|
+
);
|
|
443
|
+
updateExecutionCapability(
|
|
444
|
+
capabilities.structuredOutput,
|
|
445
|
+
rootResult,
|
|
446
|
+
rootOutput ? 'confirmed' : 'unknown',
|
|
447
|
+
rootOutput
|
|
448
|
+
? 'Output parsed as JSON and matched the required probe fields.'
|
|
449
|
+
: rootResult.observation,
|
|
450
|
+
);
|
|
451
|
+
|
|
452
|
+
const roleArgs = restoreSpawnArgs(capabilities.explicitAgentFile.command, workdir);
|
|
453
|
+
const roleResult = runMcode(mcode, roleArgs, workdir, redact, isolatedHome);
|
|
454
|
+
let roleOutput = null;
|
|
455
|
+
try {
|
|
456
|
+
roleOutput = roleResult.exitCode === 0 ? parseStructuredOutput(roleResult.stdout) : null;
|
|
457
|
+
} catch (error) {
|
|
458
|
+
roleResult.observation = redact(error.message);
|
|
459
|
+
}
|
|
460
|
+
updateExecutionCapability(
|
|
461
|
+
capabilities.explicitAgentFile,
|
|
462
|
+
roleResult,
|
|
463
|
+
roleOutput?.sentinels.includes('MAVIS_AGENT_FILE_SENTINEL') ? 'confirmed' : 'unknown',
|
|
464
|
+
redact(roleOutput?.observation ?? roleResult.observation),
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
const hardNoGoObserved =
|
|
468
|
+
capabilities.rootAgents.status !== 'confirmed' ||
|
|
469
|
+
capabilities.explicitAgentFile.status !== 'confirmed' ||
|
|
470
|
+
capabilities.structuredOutput.status !== 'confirmed';
|
|
471
|
+
if (hardNoGoObserved) evidence.probeStatus = 'blocked';
|
|
472
|
+
writeEvidence(evidence, hardNoGoObserved ? 2 : 0);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
} finally {
|
|
476
|
+
if (isolatedHome) {
|
|
477
|
+
fs.rmSync(isolatedHome, { recursive: true, force: true });
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|