@bonesofspring/ai-rules 0.2.20 → 0.2.21
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 +28 -0
- package/README.md +17 -2
- package/bin/cli.js +83 -6
- package/package.json +5 -2
- package/presets/_shared/README.md +2 -1
- package/presets/_shared/assets/docs-specs/INDEX.md +4 -1
- package/presets/_shared/core/agent-team/agent-artifact-contracts.md +13 -0
- package/presets/_shared/core/agent-team/agent-task-metrics.md +1 -1
- package/presets/_shared/core/agent-team/agent-team-orchestrator.md +1 -3
- package/presets/_shared/core/meta/preset-pr-checklist.md +5 -1
- package/presets/_shared/core/meta/preset-token-budget.md +7 -3
- package/presets/_shared/core/meta/preset-twin-sync.md +2 -0
- package/presets/_shared/core/testing/testing-principles.md +70 -0
- package/presets/claude/android-kotlin/agents/README.md +2 -1
- package/presets/claude/android-kotlin/agents/feature-developer.md +1 -1
- package/presets/claude/android-kotlin/agents/openspec-author.md +163 -0
- package/presets/claude/android-kotlin/agents/task-analyst.md +1 -1
- package/presets/claude/android-kotlin/agents/task-router.md +5 -1
- package/presets/claude/android-kotlin/agents/tech-writer.md +4 -0
- package/presets/claude/android-kotlin/commands/README.md +0 -2
- package/presets/claude/android-kotlin/commands/task-continue.md +1 -1
- package/presets/claude/android-kotlin/commands/task.md +1 -5
- package/presets/claude/android-kotlin/commands/technical-retro.md +2 -2
- package/presets/claude/android-kotlin/hooks/chain-team-phases.sh +54 -2
- package/presets/claude/android-kotlin/rules/README.md +1 -0
- package/presets/claude/android-kotlin/rules/tooling-and-review/agent-team-orchestrator.md +7 -4
- package/presets/claude/android-kotlin/rules/tooling-and-review/ai-local-overlay.md +48 -0
- package/presets/claude/android-kotlin/rules/tooling-and-review/preset-pr-checklist.md +5 -1
- package/presets/claude/android-kotlin/rules/tooling-and-review/preset-token-budget.md +7 -3
- package/presets/claude/android-kotlin/rules/tooling-and-review/preset-twin-sync.md +2 -0
- package/presets/claude/go/README.md +1 -1
- package/presets/claude/go/agents/README.md +3 -2
- package/presets/claude/go/agents/openspec-author.md +163 -0
- package/presets/claude/go/agents/task-router.md +5 -1
- package/presets/claude/go/agents/tech-writer.md +4 -0
- package/presets/claude/go/commands/README.md +0 -2
- package/presets/claude/go/commands/task-continue.md +1 -1
- package/presets/claude/go/commands/task.md +1 -4
- package/presets/claude/go/hooks/chain-team-phases.sh +54 -3
- package/presets/claude/go/rules/README.md +1 -0
- package/presets/claude/go/rules/tooling-and-review/agent-team-orchestrator.md +2 -4
- package/presets/claude/go/rules/tooling-and-review/ai-local-overlay.md +48 -0
- package/presets/claude/go/rules/tooling-and-review/preset-pr-checklist.md +5 -1
- package/presets/claude/go/rules/tooling-and-review/preset-token-budget.md +7 -3
- package/presets/claude/go/rules/tooling-and-review/preset-twin-sync.md +2 -0
- package/presets/claude/ios-swift/agents/README.md +3 -2
- package/presets/claude/ios-swift/agents/feature-developer.md +1 -1
- package/presets/claude/ios-swift/agents/openspec-author.md +163 -0
- package/presets/claude/ios-swift/agents/task-analyst.md +1 -1
- package/presets/claude/ios-swift/agents/task-router.md +5 -1
- package/presets/claude/ios-swift/agents/tech-writer.md +4 -0
- package/presets/claude/ios-swift/commands/README.md +0 -2
- package/presets/claude/ios-swift/commands/task-continue.md +1 -1
- package/presets/claude/ios-swift/commands/task.md +1 -5
- package/presets/claude/ios-swift/commands/technical-retro.md +2 -2
- package/presets/claude/ios-swift/hooks/chain-team-phases.sh +54 -2
- package/presets/claude/ios-swift/rules/README.md +1 -0
- package/presets/claude/ios-swift/rules/tooling-and-review/agent-team-orchestrator.md +7 -4
- package/presets/claude/ios-swift/rules/tooling-and-review/ai-local-overlay.md +48 -0
- package/presets/claude/ios-swift/rules/tooling-and-review/preset-pr-checklist.md +5 -1
- package/presets/claude/ios-swift/rules/tooling-and-review/preset-token-budget.md +7 -3
- package/presets/claude/ios-swift/rules/tooling-and-review/preset-twin-sync.md +2 -0
- package/presets/claude/java/CLAUDE.md +1 -1
- package/presets/claude/java/agents/README.md +3 -2
- package/presets/claude/java/agents/openspec-author.md +163 -0
- package/presets/claude/java/agents/task-router.md +5 -1
- package/presets/claude/java/agents/tech-writer.md +4 -0
- package/presets/claude/java/commands/README.md +0 -2
- package/presets/claude/java/commands/task-continue.md +1 -1
- package/presets/claude/java/commands/task.md +1 -4
- package/presets/claude/java/hooks/chain-team-phases.sh +54 -3
- package/presets/claude/java/rules/README.md +1 -0
- package/presets/claude/java/rules/tooling-and-review/agent-team-orchestrator.md +2 -4
- package/presets/claude/java/rules/tooling-and-review/ai-local-overlay.md +48 -0
- package/presets/claude/java/rules/tooling-and-review/preset-pr-checklist.md +5 -1
- package/presets/claude/java/rules/tooling-and-review/preset-token-budget.md +7 -3
- package/presets/claude/java/rules/tooling-and-review/preset-twin-sync.md +2 -0
- package/presets/claude/mcp-ts/agents/task-analyst.md +1 -1
- package/presets/claude/mcp-ts/commands/README.md +0 -2
- package/presets/claude/mcp-ts/commands/task-continue.md +1 -1
- package/presets/claude/mcp-ts/commands/task.md +1 -4
- package/presets/claude/mcp-ts/commands/technical-retro.md +2 -2
- package/presets/claude/mcp-ts/hooks/chain-team-phases.sh +40 -9
- package/presets/claude/mcp-ts/rules/README.md +1 -0
- package/presets/claude/mcp-ts/rules/tooling-and-review/agent-team-orchestrator.md +2 -4
- package/presets/claude/mcp-ts/rules/tooling-and-review/ai-local-overlay.md +48 -0
- package/presets/claude/mcp-ts/rules/tooling-and-review/preset-pr-checklist.md +5 -1
- package/presets/claude/mcp-ts/rules/tooling-and-review/preset-token-budget.md +7 -3
- package/presets/claude/mcp-ts/rules/tooling-and-review/preset-twin-sync.md +2 -0
- package/presets/claude/next/README.md +1 -0
- package/presets/claude/next/agents/README.md +2 -2
- package/presets/claude/next/agents/build-verifier.md +11 -1
- package/presets/claude/next/agents/feature-developer.md +1 -1
- package/presets/claude/next/agents/openspec-author.md +163 -0
- package/presets/claude/next/agents/task-analyst.md +1 -1
- package/presets/claude/next/agents/task-router.md +5 -1
- package/presets/claude/next/agents/tech-writer.md +4 -0
- package/presets/claude/next/commands/README.md +0 -2
- package/presets/claude/next/commands/task-continue.md +1 -1
- package/presets/claude/next/commands/task.md +1 -4
- package/presets/claude/next/hooks/chain-team-phases.sh +54 -2
- package/presets/claude/next/rules/README.md +1 -0
- package/presets/claude/next/rules/testing/README.md +6 -0
- package/presets/claude/next/rules/testing/tests-e2e-structure.md +84 -48
- package/presets/claude/next/rules/testing/tests-unit.md +79 -50
- package/presets/claude/next/rules/tooling-and-review/agent-team-orchestrator.md +3 -4
- package/presets/claude/next/rules/tooling-and-review/ai-local-overlay.md +48 -0
- package/presets/claude/next/rules/tooling-and-review/preset-pr-checklist.md +5 -1
- package/presets/claude/next/rules/tooling-and-review/preset-token-budget.md +7 -3
- package/presets/claude/next/rules/tooling-and-review/preset-twin-sync.md +2 -0
- package/presets/claude/next/team/README.md +0 -3
- package/presets/claude/nuxt/agents/README.md +1 -1
- package/presets/claude/nuxt/agents/feature-developer.md +1 -1
- package/presets/claude/nuxt/agents/openspec-author.md +163 -0
- package/presets/claude/nuxt/agents/task-analyst.md +1 -1
- package/presets/claude/nuxt/agents/task-router.md +5 -1
- package/presets/claude/nuxt/agents/tech-writer.md +4 -0
- package/presets/claude/nuxt/commands/README.md +0 -2
- package/presets/claude/nuxt/commands/task-continue.md +1 -1
- package/presets/claude/nuxt/commands/task.md +1 -5
- package/presets/claude/nuxt/commands/technical-retro.md +2 -2
- package/presets/claude/nuxt/hooks/chain-team-phases.sh +54 -2
- package/presets/claude/nuxt/rules/README.md +1 -0
- package/presets/claude/nuxt/rules/testing/README.md +6 -0
- package/presets/claude/nuxt/rules/testing/tests-e2e-structure.md +86 -43
- package/presets/claude/nuxt/rules/testing/tests-unit.md +58 -45
- package/presets/claude/nuxt/rules/tooling-and-review/agent-team-orchestrator.md +8 -5
- package/presets/claude/nuxt/rules/tooling-and-review/ai-local-overlay.md +48 -0
- package/presets/claude/nuxt/rules/tooling-and-review/preset-pr-checklist.md +5 -1
- package/presets/claude/nuxt/rules/tooling-and-review/preset-token-budget.md +7 -3
- package/presets/claude/nuxt/rules/tooling-and-review/preset-twin-sync.md +2 -0
- package/presets/claude/nuxt/team/README.md +0 -3
- package/presets/claude/php-hexagonal/CLAUDE.md +1 -1
- package/presets/claude/php-hexagonal/agents/README.md +3 -2
- package/presets/claude/php-hexagonal/agents/openspec-author.md +163 -0
- package/presets/claude/php-hexagonal/agents/task-router.md +5 -1
- package/presets/claude/php-hexagonal/agents/tech-writer.md +4 -0
- package/presets/claude/php-hexagonal/commands/README.md +0 -2
- package/presets/claude/php-hexagonal/commands/task-continue.md +1 -1
- package/presets/claude/php-hexagonal/commands/task.md +1 -4
- package/presets/claude/php-hexagonal/hooks/chain-team-phases.sh +54 -3
- package/presets/claude/php-hexagonal/rules/README.md +1 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/agent-team-orchestrator.md +2 -4
- package/presets/claude/php-hexagonal/rules/tooling-and-review/ai-local-overlay.md +48 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-pr-checklist.md +5 -1
- package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-token-budget.md +7 -3
- package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-twin-sync.md +2 -0
- package/presets/claude/php-laravel/agents/README.md +3 -2
- package/presets/claude/php-laravel/agents/openspec-author.md +163 -0
- package/presets/claude/php-laravel/agents/task-router.md +5 -1
- package/presets/claude/php-laravel/agents/tech-writer.md +4 -0
- package/presets/claude/php-laravel/commands/README.md +0 -2
- package/presets/claude/php-laravel/commands/task-continue.md +1 -1
- package/presets/claude/php-laravel/commands/task.md +1 -4
- package/presets/claude/php-laravel/hooks/chain-team-phases.sh +54 -3
- package/presets/claude/php-laravel/rules/README.md +1 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/agent-team-orchestrator.md +2 -4
- package/presets/claude/php-laravel/rules/tooling-and-review/ai-local-overlay.md +48 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/preset-pr-checklist.md +5 -1
- package/presets/claude/php-laravel/rules/tooling-and-review/preset-token-budget.md +7 -3
- package/presets/claude/php-laravel/rules/tooling-and-review/preset-twin-sync.md +2 -0
- package/presets/claude/svelte/agents/README.md +1 -1
- package/presets/claude/svelte/agents/feature-developer.md +1 -1
- package/presets/claude/svelte/agents/openspec-author.md +163 -0
- package/presets/claude/svelte/agents/task-analyst.md +1 -1
- package/presets/claude/svelte/agents/task-router.md +5 -1
- package/presets/claude/svelte/agents/tech-writer.md +4 -0
- package/presets/claude/svelte/commands/README.md +0 -2
- package/presets/claude/svelte/commands/task-continue.md +1 -1
- package/presets/claude/svelte/commands/task.md +1 -5
- package/presets/claude/svelte/commands/technical-retro.md +2 -2
- package/presets/claude/svelte/hooks/chain-team-phases.sh +54 -2
- package/presets/claude/svelte/rules/README.md +1 -0
- package/presets/claude/svelte/rules/testing/README.md +6 -0
- package/presets/claude/svelte/rules/testing/tests-e2e-structure.md +87 -45
- package/presets/claude/svelte/rules/testing/tests-unit.md +70 -23
- package/presets/claude/svelte/rules/tooling-and-review/agent-team-orchestrator.md +8 -5
- package/presets/claude/svelte/rules/tooling-and-review/ai-local-overlay.md +48 -0
- package/presets/claude/svelte/rules/tooling-and-review/preset-pr-checklist.md +5 -1
- package/presets/claude/svelte/rules/tooling-and-review/preset-token-budget.md +7 -3
- package/presets/claude/svelte/rules/tooling-and-review/preset-twin-sync.md +2 -0
- package/presets/claude/svelte/team/README.md +0 -3
- package/presets/cursor/android-kotlin/agents/README.md +2 -1
- package/presets/cursor/android-kotlin/agents/feature-developer.md +1 -1
- package/presets/cursor/android-kotlin/agents/openspec-author.md +164 -0
- package/presets/cursor/android-kotlin/agents/task-analyst.md +1 -1
- package/presets/cursor/android-kotlin/agents/task-router.md +5 -1
- package/presets/cursor/android-kotlin/agents/tech-writer.md +4 -0
- package/presets/cursor/android-kotlin/commands/README.md +0 -2
- package/presets/cursor/android-kotlin/commands/task-continue.md +1 -1
- package/presets/cursor/android-kotlin/commands/task.md +1 -5
- package/presets/cursor/android-kotlin/commands/technical-retro.md +2 -2
- package/presets/cursor/android-kotlin/hooks/chain-team-phases.sh +54 -2
- package/presets/cursor/android-kotlin/rules/agent-team-orchestrator.mdc +7 -4
- package/presets/cursor/android-kotlin/rules/ai-local-overlay.mdc +43 -0
- package/presets/cursor/android-kotlin/rules/preset-pr-checklist.mdc +5 -1
- package/presets/cursor/android-kotlin/rules/preset-token-budget.mdc +7 -3
- package/presets/cursor/android-kotlin/rules/preset-twin-sync.mdc +2 -0
- package/presets/cursor/go/README.md +6 -6
- package/presets/cursor/go/agents/README.md +3 -2
- package/presets/cursor/go/agents/openspec-author.md +164 -0
- package/presets/cursor/go/agents/task-router.md +5 -1
- package/presets/cursor/go/agents/tech-writer.md +4 -0
- package/presets/cursor/go/commands/README.md +0 -2
- package/presets/cursor/go/commands/task-continue.md +1 -1
- package/presets/cursor/go/commands/task.md +1 -4
- package/presets/cursor/go/commands/technical-retro.md +2 -2
- package/presets/cursor/go/hooks/chain-team-phases.sh +54 -3
- package/presets/cursor/go/rules/agent-team-orchestrator.mdc +2 -4
- package/presets/cursor/go/rules/ai-local-overlay.mdc +43 -0
- package/presets/cursor/go/rules/preset-pr-checklist.mdc +5 -1
- package/presets/cursor/go/rules/preset-token-budget.mdc +7 -3
- package/presets/cursor/go/rules/preset-twin-sync.mdc +2 -0
- package/presets/cursor/ios-swift/README.md +6 -6
- package/presets/cursor/ios-swift/agents/README.md +3 -2
- package/presets/cursor/ios-swift/agents/feature-developer.md +1 -1
- package/presets/cursor/ios-swift/agents/openspec-author.md +164 -0
- package/presets/cursor/ios-swift/agents/task-analyst.md +1 -1
- package/presets/cursor/ios-swift/agents/task-router.md +5 -1
- package/presets/cursor/ios-swift/agents/tech-writer.md +4 -0
- package/presets/cursor/ios-swift/commands/README.md +1 -3
- package/presets/cursor/ios-swift/commands/task-continue.md +1 -1
- package/presets/cursor/ios-swift/commands/task.md +1 -5
- package/presets/cursor/ios-swift/commands/technical-retro.md +2 -2
- package/presets/cursor/ios-swift/hooks/chain-team-phases.sh +54 -2
- package/presets/cursor/ios-swift/rules/agent-team-orchestrator.mdc +7 -4
- package/presets/cursor/ios-swift/rules/ai-local-overlay.mdc +43 -0
- package/presets/cursor/ios-swift/rules/preset-pr-checklist.mdc +5 -1
- package/presets/cursor/ios-swift/rules/preset-token-budget.mdc +7 -3
- package/presets/cursor/ios-swift/rules/preset-twin-sync.mdc +2 -0
- package/presets/cursor/java/AGENTS.md +1 -1
- package/presets/cursor/java/agents/README.md +3 -2
- package/presets/cursor/java/agents/openspec-author.md +164 -0
- package/presets/cursor/java/agents/task-router.md +5 -1
- package/presets/cursor/java/agents/tech-writer.md +4 -0
- package/presets/cursor/java/commands/README.md +0 -2
- package/presets/cursor/java/commands/task-continue.md +1 -1
- package/presets/cursor/java/commands/task.md +1 -4
- package/presets/cursor/java/commands/technical-retro.md +2 -2
- package/presets/cursor/java/hooks/chain-team-phases.sh +54 -3
- package/presets/cursor/java/rules/agent-team-orchestrator.mdc +2 -4
- package/presets/cursor/java/rules/ai-local-overlay.mdc +43 -0
- package/presets/cursor/java/rules/preset-pr-checklist.mdc +5 -1
- package/presets/cursor/java/rules/preset-token-budget.mdc +7 -3
- package/presets/cursor/java/rules/preset-twin-sync.mdc +2 -0
- package/presets/cursor/mcp-ts/agents/task-analyst.md +1 -1
- package/presets/cursor/mcp-ts/commands/README.md +0 -2
- package/presets/cursor/mcp-ts/commands/task-continue.md +1 -1
- package/presets/cursor/mcp-ts/commands/task.md +1 -4
- package/presets/cursor/mcp-ts/commands/technical-retro.md +2 -2
- package/presets/cursor/mcp-ts/hooks/chain-team-phases.sh +40 -9
- package/presets/cursor/mcp-ts/rules/agent-team-orchestrator.mdc +2 -4
- package/presets/cursor/mcp-ts/rules/ai-local-overlay.mdc +43 -0
- package/presets/cursor/mcp-ts/rules/preset-pr-checklist.mdc +5 -1
- package/presets/cursor/mcp-ts/rules/preset-token-budget.mdc +7 -3
- package/presets/cursor/mcp-ts/rules/preset-twin-sync.mdc +2 -0
- package/presets/cursor/next/README.md +8 -6
- package/presets/cursor/next/REPO_AGENTS.md +8 -0
- package/presets/cursor/next/agents/README.md +2 -2
- package/presets/cursor/next/agents/build-verifier.md +11 -1
- package/presets/cursor/next/agents/feature-developer.md +1 -1
- package/presets/cursor/next/agents/openspec-author.md +164 -0
- package/presets/cursor/next/agents/task-analyst.md +1 -1
- package/presets/cursor/next/agents/task-router.md +5 -1
- package/presets/cursor/next/agents/tech-writer.md +4 -0
- package/presets/cursor/next/commands/README.md +0 -2
- package/presets/cursor/next/commands/task-continue.md +1 -1
- package/presets/cursor/next/commands/task.md +1 -4
- package/presets/cursor/next/commands/technical-retro.md +2 -2
- package/presets/cursor/next/hooks/chain-team-phases.sh +54 -2
- package/presets/cursor/next/rules/README.md +6 -3
- package/presets/cursor/next/rules/agent-team-orchestrator.mdc +7 -5
- package/presets/cursor/next/rules/ai-local-overlay.mdc +43 -0
- package/presets/cursor/next/rules/preset-pr-checklist.mdc +5 -1
- package/presets/cursor/next/rules/preset-token-budget.mdc +7 -3
- package/presets/cursor/next/rules/preset-twin-sync.mdc +2 -0
- package/presets/cursor/next/rules/tests-e2e-structure.mdc +83 -43
- package/presets/cursor/next/rules/tests-unit.mdc +78 -45
- package/presets/cursor/next/team/README.md +0 -3
- package/presets/cursor/nuxt/README.md +6 -6
- package/presets/cursor/nuxt/agents/README.md +1 -1
- package/presets/cursor/nuxt/agents/feature-developer.md +1 -1
- package/presets/cursor/nuxt/agents/openspec-author.md +164 -0
- package/presets/cursor/nuxt/agents/task-analyst.md +1 -1
- package/presets/cursor/nuxt/agents/task-router.md +5 -1
- package/presets/cursor/nuxt/agents/tech-writer.md +4 -0
- package/presets/cursor/nuxt/commands/README.md +0 -2
- package/presets/cursor/nuxt/commands/task-continue.md +1 -1
- package/presets/cursor/nuxt/commands/task.md +1 -5
- package/presets/cursor/nuxt/commands/technical-retro.md +2 -2
- package/presets/cursor/nuxt/hooks/chain-team-phases.sh +54 -2
- package/presets/cursor/nuxt/rules/README.md +3 -1
- package/presets/cursor/nuxt/rules/agent-team-orchestrator.mdc +8 -5
- package/presets/cursor/nuxt/rules/ai-local-overlay.mdc +43 -0
- package/presets/cursor/nuxt/rules/preset-pr-checklist.mdc +5 -1
- package/presets/cursor/nuxt/rules/preset-token-budget.mdc +7 -3
- package/presets/cursor/nuxt/rules/preset-twin-sync.mdc +2 -0
- package/presets/cursor/nuxt/rules/tests-e2e-structure.mdc +87 -43
- package/presets/cursor/nuxt/rules/tests-unit.mdc +62 -47
- package/presets/cursor/nuxt/team/README.md +0 -3
- package/presets/cursor/php-hexagonal/AGENTS.md +1 -1
- package/presets/cursor/php-hexagonal/agents/README.md +3 -2
- package/presets/cursor/php-hexagonal/agents/openspec-author.md +164 -0
- package/presets/cursor/php-hexagonal/agents/task-router.md +5 -1
- package/presets/cursor/php-hexagonal/agents/tech-writer.md +4 -0
- package/presets/cursor/php-hexagonal/commands/README.md +0 -2
- package/presets/cursor/php-hexagonal/commands/task-continue.md +1 -1
- package/presets/cursor/php-hexagonal/commands/task.md +1 -4
- package/presets/cursor/php-hexagonal/commands/technical-retro.md +2 -2
- package/presets/cursor/php-hexagonal/hooks/chain-team-phases.sh +54 -3
- package/presets/cursor/php-hexagonal/rules/agent-team-orchestrator.mdc +2 -4
- package/presets/cursor/php-hexagonal/rules/ai-local-overlay.mdc +43 -0
- package/presets/cursor/php-hexagonal/rules/preset-pr-checklist.mdc +5 -1
- package/presets/cursor/php-hexagonal/rules/preset-token-budget.mdc +7 -3
- package/presets/cursor/php-hexagonal/rules/preset-twin-sync.mdc +2 -0
- package/presets/cursor/php-laravel/AGENTS.md +1 -1
- package/presets/cursor/php-laravel/agents/README.md +3 -2
- package/presets/cursor/php-laravel/agents/openspec-author.md +164 -0
- package/presets/cursor/php-laravel/agents/task-router.md +5 -1
- package/presets/cursor/php-laravel/agents/tech-writer.md +4 -0
- package/presets/cursor/php-laravel/commands/README.md +0 -2
- package/presets/cursor/php-laravel/commands/task-continue.md +1 -1
- package/presets/cursor/php-laravel/commands/task.md +1 -4
- package/presets/cursor/php-laravel/commands/technical-retro.md +2 -2
- package/presets/cursor/php-laravel/hooks/chain-team-phases.sh +54 -3
- package/presets/cursor/php-laravel/rules/agent-team-orchestrator.mdc +2 -4
- package/presets/cursor/php-laravel/rules/ai-local-overlay.mdc +43 -0
- package/presets/cursor/php-laravel/rules/preset-pr-checklist.mdc +5 -1
- package/presets/cursor/php-laravel/rules/preset-token-budget.mdc +7 -3
- package/presets/cursor/php-laravel/rules/preset-twin-sync.mdc +2 -0
- package/presets/cursor/svelte/README.md +6 -6
- package/presets/cursor/svelte/agents/README.md +1 -1
- package/presets/cursor/svelte/agents/feature-developer.md +1 -1
- package/presets/cursor/svelte/agents/openspec-author.md +164 -0
- package/presets/cursor/svelte/agents/task-analyst.md +1 -1
- package/presets/cursor/svelte/agents/task-router.md +5 -1
- package/presets/cursor/svelte/agents/tech-writer.md +4 -0
- package/presets/cursor/svelte/commands/README.md +0 -2
- package/presets/cursor/svelte/commands/task-continue.md +1 -1
- package/presets/cursor/svelte/commands/task.md +1 -5
- package/presets/cursor/svelte/commands/technical-retro.md +2 -2
- package/presets/cursor/svelte/hooks/chain-team-phases.sh +54 -2
- package/presets/cursor/svelte/rules/README.md +3 -1
- package/presets/cursor/svelte/rules/agent-team-orchestrator.mdc +8 -5
- package/presets/cursor/svelte/rules/ai-local-overlay.mdc +43 -0
- package/presets/cursor/svelte/rules/preset-pr-checklist.mdc +5 -1
- package/presets/cursor/svelte/rules/preset-token-budget.mdc +7 -3
- package/presets/cursor/svelte/rules/preset-twin-sync.mdc +2 -0
- package/presets/cursor/svelte/rules/tests-e2e-structure.mdc +87 -43
- package/presets/cursor/svelte/rules/tests-unit.mdc +72 -23
- package/presets/cursor/svelte/team/README.md +0 -3
- package/scripts/_lib/embed-stems.json +31 -0
- package/scripts/aggregate-agent-task-metrics.mjs +23 -0
- package/scripts/check-chain-hook-coverage.sh +109 -0
- package/scripts/check-local-overlay.sh +136 -0
- package/scripts/check-preset-i18n.sh +2 -2
- package/scripts/check-preset-leakage.sh +4 -1
- package/scripts/check-preset-structure.sh +21 -1
- package/scripts/check-preset-token-budget.sh +20 -10
- package/scripts/check-rule-eval.mjs +16 -0
- package/scripts/check-shared-core-drift.sh +10 -32
- package/scripts/close-agent-task-human-gate.mjs +22 -5
- package/scripts/sync-shared-core-embeds.sh +9 -20
- package/scripts/test-agent-task-metrics-hooks.mjs +1 -1
- package/scripts/test-chain-team-phases-coverage.mjs +411 -0
- package/presets/claude/android-kotlin/commands/feature-continue.md +0 -23
- package/presets/claude/android-kotlin/commands/feature-start.md +0 -41
- package/presets/claude/go/commands/feature-continue.md +0 -23
- package/presets/claude/go/commands/feature-start.md +0 -38
- package/presets/claude/ios-swift/commands/feature-continue.md +0 -23
- package/presets/claude/ios-swift/commands/feature-start.md +0 -41
- package/presets/claude/java/commands/feature-continue.md +0 -23
- package/presets/claude/java/commands/feature-start.md +0 -38
- package/presets/claude/mcp-ts/commands/feature-continue.md +0 -23
- package/presets/claude/mcp-ts/commands/feature-start.md +0 -41
- package/presets/claude/next/commands/feature-continue.md +0 -23
- package/presets/claude/next/commands/feature-start.md +0 -38
- package/presets/claude/nuxt/commands/feature-continue.md +0 -23
- package/presets/claude/nuxt/commands/feature-start.md +0 -41
- package/presets/claude/php-hexagonal/commands/feature-continue.md +0 -23
- package/presets/claude/php-hexagonal/commands/feature-start.md +0 -38
- package/presets/claude/php-laravel/commands/feature-continue.md +0 -23
- package/presets/claude/php-laravel/commands/feature-start.md +0 -38
- package/presets/claude/svelte/commands/feature-continue.md +0 -23
- package/presets/claude/svelte/commands/feature-start.md +0 -41
- package/presets/cursor/android-kotlin/commands/feature-continue.md +0 -23
- package/presets/cursor/android-kotlin/commands/feature-start.md +0 -41
- package/presets/cursor/go/commands/feature-continue.md +0 -23
- package/presets/cursor/go/commands/feature-start.md +0 -41
- package/presets/cursor/ios-swift/commands/feature-continue.md +0 -23
- package/presets/cursor/ios-swift/commands/feature-start.md +0 -41
- package/presets/cursor/java/commands/feature-continue.md +0 -23
- package/presets/cursor/java/commands/feature-start.md +0 -41
- package/presets/cursor/mcp-ts/commands/feature-continue.md +0 -23
- package/presets/cursor/mcp-ts/commands/feature-start.md +0 -41
- package/presets/cursor/next/commands/feature-continue.md +0 -23
- package/presets/cursor/next/commands/feature-start.md +0 -41
- package/presets/cursor/nuxt/commands/feature-continue.md +0 -23
- package/presets/cursor/nuxt/commands/feature-start.md +0 -41
- package/presets/cursor/php-hexagonal/commands/feature-continue.md +0 -23
- package/presets/cursor/php-hexagonal/commands/feature-start.md +0 -41
- package/presets/cursor/php-laravel/commands/feature-continue.md +0 -23
- package/presets/cursor/php-laravel/commands/feature-start.md +0 -41
- package/presets/cursor/svelte/commands/feature-continue.md +0 -23
- package/presets/cursor/svelte/commands/feature-start.md +0 -41
|
@@ -1,50 +1,94 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: E2E test and plan structure (Playwright)
|
|
3
3
|
globs: tests/e2e/**/*
|
|
4
4
|
alwaysApply: false
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
<!-- shared-core: testing/testing-principles.md -->
|
|
8
8
|
|
|
9
|
+
# Testing principles
|
|
10
|
+
|
|
11
|
+
Stack-agnostic; concrete paths, runners, and selectors live in the stack adapter (`## Stack notes`).
|
|
12
|
+
|
|
13
|
+
## Behavior vs. implementation
|
|
14
|
+
|
|
15
|
+
- Verify **behavior and business rules**, not implementation or internal details.
|
|
16
|
+
|
|
17
|
+
## File naming
|
|
18
|
+
|
|
19
|
+
- For **new** tests use `*.spec.ts` / `*.spec.tsx`. Do not rename existing `*.test.ts` / `*.test.tsx` without a separate task (legacy).
|
|
20
|
+
|
|
21
|
+
## Runner and matchers
|
|
22
|
+
|
|
23
|
+
- Use the project's runner (Jest or Vitest are common); components — the project's Testing Library integration. Reuse existing matchers — no new micro-framework.
|
|
24
|
+
|
|
25
|
+
## Test title locale
|
|
26
|
+
|
|
27
|
+
- Consumer apps **may use the project locale** (often Russian) — clear business phrases stating what is checked and the expected outcome.
|
|
28
|
+
- When ESLint enforces the locale (e.g. `jest/valid-title`): each sentence must start with a **capital letter** (including after `.`, `!`, `?`); a space after `.` followed by a lowercase letter is forbidden ("capital after period" violation).
|
|
29
|
+
|
|
30
|
+
Good (Russian locale in consumer app):
|
|
31
|
+
|
|
32
|
+
- `it('Возвращает пустой список. Пользователь не авторизован', () => {})` <!-- i18n-keep: E5 --> (Returns empty list. User is not authorized)
|
|
33
|
+
|
|
34
|
+
Bad (no capital after period; or wrong locale for configured ESLint):
|
|
35
|
+
|
|
36
|
+
- `it('Возвращает пустой список. пользователь не авторизован', () => {})` <!-- i18n-keep: E5 -->
|
|
37
|
+
- `it('Returns empty list when user is guest', () => {})` (wrong locale if ESLint enforces Russian)
|
|
38
|
+
|
|
39
|
+
## Isolation and mocks
|
|
40
|
+
|
|
41
|
+
- Mock at the **public-contract boundary**; use the project's accepted HTTP/API/store mock approach. Do not mock what is part of the feature's public contract if that breaks the test's meaning.
|
|
42
|
+
|
|
43
|
+
## Coverage of cross-cutting modules
|
|
44
|
+
|
|
45
|
+
- When changing a **shared cross-cutting module** (e.g. HTTP client body parsing, headers, error / auth handling) — **update or add behavior tests** covering success, error, and edge branches relevant to the module under change.
|
|
46
|
+
|
|
47
|
+
## Data transformation coverage
|
|
48
|
+
|
|
49
|
+
- Data transformation functions with computed fields and branches must have unit tests covering edge cases (boundary values, missing fields, unexpected value combinations).
|
|
50
|
+
|
|
51
|
+
## Reuse fixtures over ad-hoc random data
|
|
52
|
+
|
|
53
|
+
- Prefer shared fixtures / handlers from the project's accepted mocks module; do not duplicate interfaces in tests. Use the API response types (DTO types) and the **target domain types** from the project's public type surface.
|
|
54
|
+
|
|
55
|
+
## E2E: one canonical scenario plan per feature
|
|
56
|
+
|
|
57
|
+
- For each feature keep a **single canonical scenario plan** (distinct from implementation specs; the stack adapter names the file — typically `*.cases.md`).
|
|
58
|
+
|
|
59
|
+
## E2E: scenario ↔ test traceability
|
|
60
|
+
|
|
61
|
+
- Every scenario has a corresponding test. **Do not weaken** assertions to match an outdated implementation — tests must reflect business expectations from the plan. Colocate plan and executable tests in the same directory.
|
|
62
|
+
|
|
63
|
+
## E2E: page objects / shared helpers
|
|
64
|
+
|
|
65
|
+
- Prefer page objects and shared helpers over scattered selectors and per-test setup duplication.
|
|
66
|
+
|
|
67
|
+
## E2E: stable identifiers (PREFIX-XXX)
|
|
68
|
+
|
|
69
|
+
- When scenarios need stable IDs, prefix the title with `PREFIX-XXX`: `PREFIX` = first letters of words in the entity under test (Latin uppercase); `XXX` = sequential number with three digits and leading zeros. Within one `PREFIX`, numbers must form a consistent sequence with no duplicates.
|
|
70
|
+
- Example: `test('OH-001 Отображается список заказов', async ({ page }) => { ... })` <!-- i18n-keep: E5 --> (Order list is displayed)
|
|
71
|
+
|
|
72
|
+
## E2E: selector priority
|
|
73
|
+
|
|
74
|
+
- Prefer role/label selectors for accessibility and forms; fall back to `data-testid` for stable elements. Use a **hierarchical naming convention** on page roots and key interactive elements (stack adapter defines the scheme — typically `{parent}__{element}`).
|
|
75
|
+
|
|
76
|
+
## E2E: keep plans and selectors in sync with UI
|
|
77
|
+
|
|
78
|
+
- When changing UI: update selectors in page objects and cross-check with the scenario plan. When adding/changing tests: read the matching plan and sync scenario titles first.
|
|
79
|
+
|
|
80
|
+
## Stack notes
|
|
81
|
+
|
|
82
|
+
- Runner: Playwright (`@playwright/test`).
|
|
9
83
|
- E2E folder: `tests/e2e/**`.
|
|
10
|
-
- Scenario plans:
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
- Prefer:
|
|
22
|
-
- page objects (e.g. `OrderHistoryPage.ts`);
|
|
23
|
-
- shared helpers from `_shared`.
|
|
24
|
-
|
|
25
|
-
# E2E test naming
|
|
26
|
-
|
|
27
|
-
- Language:
|
|
28
|
-
- all `test` / `it` names, `describe` blocks, and steps in `*.cases.md` must be formulated **in Russian**, describing behavior and the expected result. <!-- i18n-keep: E5 -->
|
|
29
|
-
- E2E title format (`test(...)` / `it(...)`):
|
|
30
|
-
- before the scenario description, put a **numbered prefix** in the form: `PREFIX-XXX Scenario description`.
|
|
31
|
-
- `PREFIX` — abbreviation from the **first letters of the words** of the entity under test, written in **Latin uppercase**.
|
|
32
|
-
- example: `OrderHistory` → `OH`, `BillingReport` → `BR`.
|
|
33
|
-
- `XXX` — sequential test number **with three digits and leading zeros**: `001`, `002`, `010`, `123`, etc.
|
|
34
|
-
- full e2e title example:
|
|
35
|
-
- `test('OH-001 Отображается список заказов', async ({ page }) => { ... })` <!-- i18n-keep: E5 -->
|
|
36
|
-
- within one entity (`PREFIX`), test numbers must form a **consistent sequence** without duplicate numbers.
|
|
37
|
-
|
|
38
|
-
# data-testid for e2e
|
|
39
|
-
|
|
40
|
-
- **Selector priority:** `data-testid` for stable elements; `getByRole` and `getByLabel` for forms and accessible elements.
|
|
41
|
-
- **Naming:** scheme `{parent}__{element}` (e.g. `history-page__title`, `history-page__recognition-banner__attach-files-button`).
|
|
42
|
-
- **Where to add:** on page root containers and key interactive elements (buttons, links, fields) that page objects target.
|
|
43
|
-
- **When UI changes:** update data-testid in components and matching selectors in page objects; align with `*.cases.md`.
|
|
44
|
-
|
|
45
|
-
# Agent requirement
|
|
46
|
-
|
|
47
|
-
When adding/changing e2e tests:
|
|
48
|
-
- First look at the matching `*.cases.md` and sync scenario names.
|
|
49
|
-
- Place specs next to plans in the same directory.
|
|
50
|
-
- Reuse shared page objects and helpers; do not copy selectors into every test.
|
|
84
|
+
- Scenario plans: `*.cases.md` — canonical source.
|
|
85
|
+
- Tests: `*.spec.ts` — Playwright implementations.
|
|
86
|
+
- Shared utilities: `tests/e2e/_shared/**`.
|
|
87
|
+
- **Russian-locale HARD policy:** all `test` / `it` titles, `describe` blocks, and `*.cases.md` steps MUST be in Russian, describing behavior + expected result. <!-- i18n-keep: E5 -->
|
|
88
|
+
- `data-testid` priority: `data-testid` for stable; `getByRole` / `getByLabel` for forms.
|
|
89
|
+
- `data-testid` naming scheme `{parent}__{element}` — example `history-page__title`, `history-page__recognition-banner__attach-files-button`.
|
|
90
|
+
- `PREFIX-XXX` example: `OrderHistory` → `OH`, `BillingReport` → `BR`.
|
|
91
|
+
- Russian example: `test('OH-001 Отображается список заказов', async ({ page }) => { ... })` <!-- i18n-keep: E5 --> (Order list is displayed).
|
|
92
|
+
- Page object example filename: `OrderHistoryPage.ts`.
|
|
93
|
+
- Cross-reference: See also **`playwright-agents.mdc`**.
|
|
94
|
+
- `## Stack notes` content is stripped by `scripts/check-shared-core-drift.sh` before byte-comparing this file against `_shared/core/testing/testing-principles.md`; keep prose above (core content) verbatim against the core file.
|
|
@@ -6,37 +6,86 @@ alwaysApply: false
|
|
|
6
6
|
impact: MEDIUM
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
<!-- shared-core: testing/testing-principles.md -->
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
- **Runner:** Vitest (or as in the project). Components — **`@testing-library/svelte`** (not `@vue/test-utils`, not React Testing Library as default).
|
|
13
|
-
- Assert **behavior**, not internals.
|
|
14
|
-
- **`describe` / `it` naming:** formulate titles **in Russian**, each sentence capitalized (as with ESLint `jest/valid-title` if enabled). <!-- i18n-keep: E5 -->
|
|
11
|
+
# Testing principles
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
// ✅
|
|
18
|
-
it('Возвращает пустой список. Пользователь не авторизован', () => {}) // <!-- i18n-keep: E5 -->
|
|
13
|
+
Stack-agnostic; concrete paths, runners, and selectors live in the stack adapter (`## Stack notes`).
|
|
19
14
|
|
|
20
|
-
|
|
21
|
-
it('Returns empty list when user is guest', () => {})
|
|
22
|
-
```
|
|
15
|
+
## Behavior vs. implementation
|
|
23
16
|
|
|
24
|
-
|
|
17
|
+
- Verify **behavior and business rules**, not implementation or internal details.
|
|
25
18
|
|
|
26
|
-
|
|
27
|
-
- Interactions: `userEvent` from `@testing-library/user-event` when that is the repo convention.
|
|
19
|
+
## File naming
|
|
28
20
|
|
|
29
|
-
|
|
21
|
+
- For **new** tests use `*.spec.ts` / `*.spec.tsx`. Do not rename existing `*.test.ts` / `*.test.tsx` without a separate task (legacy).
|
|
30
22
|
|
|
31
|
-
|
|
32
|
-
- Do not mock the feature’s public contract without need.
|
|
23
|
+
## Runner and matchers
|
|
33
24
|
|
|
34
|
-
|
|
25
|
+
- Use the project's runner (Jest or Vitest are common); components — the project's Testing Library integration. Reuse existing matchers — no new micro-framework.
|
|
35
26
|
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
## Test title locale
|
|
28
|
+
|
|
29
|
+
- Consumer apps **may use the project locale** (often Russian) — clear business phrases stating what is checked and the expected outcome.
|
|
30
|
+
- When ESLint enforces the locale (e.g. `jest/valid-title`): each sentence must start with a **capital letter** (including after `.`, `!`, `?`); a space after `.` followed by a lowercase letter is forbidden ("capital after period" violation).
|
|
31
|
+
|
|
32
|
+
Good (Russian locale in consumer app):
|
|
33
|
+
|
|
34
|
+
- `it('Возвращает пустой список. Пользователь не авторизован', () => {})` <!-- i18n-keep: E5 --> (Returns empty list. User is not authorized)
|
|
35
|
+
|
|
36
|
+
Bad (no capital after period; or wrong locale for configured ESLint):
|
|
37
|
+
|
|
38
|
+
- `it('Возвращает пустой список. пользователь не авторизован', () => {})` <!-- i18n-keep: E5 -->
|
|
39
|
+
- `it('Returns empty list when user is guest', () => {})` (wrong locale if ESLint enforces Russian)
|
|
40
|
+
|
|
41
|
+
## Isolation and mocks
|
|
42
|
+
|
|
43
|
+
- Mock at the **public-contract boundary**; use the project's accepted HTTP/API/store mock approach. Do not mock what is part of the feature's public contract if that breaks the test's meaning.
|
|
44
|
+
|
|
45
|
+
## Coverage of cross-cutting modules
|
|
46
|
+
|
|
47
|
+
- When changing a **shared cross-cutting module** (e.g. HTTP client body parsing, headers, error / auth handling) — **update or add behavior tests** covering success, error, and edge branches relevant to the module under change.
|
|
48
|
+
|
|
49
|
+
## Data transformation coverage
|
|
50
|
+
|
|
51
|
+
- Data transformation functions with computed fields and branches must have unit tests covering edge cases (boundary values, missing fields, unexpected value combinations).
|
|
52
|
+
|
|
53
|
+
## Reuse fixtures over ad-hoc random data
|
|
54
|
+
|
|
55
|
+
- Prefer shared fixtures / handlers from the project's accepted mocks module; do not duplicate interfaces in tests. Use the API response types (DTO types) and the **target domain types** from the project's public type surface.
|
|
38
56
|
|
|
39
|
-
|
|
57
|
+
## E2E: one canonical scenario plan per feature
|
|
40
58
|
|
|
41
|
-
-
|
|
42
|
-
|
|
59
|
+
- For each feature keep a **single canonical scenario plan** (distinct from implementation specs; the stack adapter names the file — typically `*.cases.md`).
|
|
60
|
+
|
|
61
|
+
## E2E: scenario ↔ test traceability
|
|
62
|
+
|
|
63
|
+
- Every scenario has a corresponding test. **Do not weaken** assertions to match an outdated implementation — tests must reflect business expectations from the plan. Colocate plan and executable tests in the same directory.
|
|
64
|
+
|
|
65
|
+
## E2E: page objects / shared helpers
|
|
66
|
+
|
|
67
|
+
- Prefer page objects and shared helpers over scattered selectors and per-test setup duplication.
|
|
68
|
+
|
|
69
|
+
## E2E: stable identifiers (PREFIX-XXX)
|
|
70
|
+
|
|
71
|
+
- When scenarios need stable IDs, prefix the title with `PREFIX-XXX`: `PREFIX` = first letters of words in the entity under test (Latin uppercase); `XXX` = sequential number with three digits and leading zeros. Within one `PREFIX`, numbers must form a consistent sequence with no duplicates.
|
|
72
|
+
- Example: `test('OH-001 Отображается список заказов', async ({ page }) => { ... })` <!-- i18n-keep: E5 --> (Order list is displayed)
|
|
73
|
+
|
|
74
|
+
## E2E: selector priority
|
|
75
|
+
|
|
76
|
+
- Prefer role/label selectors for accessibility and forms; fall back to `data-testid` for stable elements. Use a **hierarchical naming convention** on page roots and key interactive elements (stack adapter defines the scheme — typically `{parent}__{element}`).
|
|
77
|
+
|
|
78
|
+
## E2E: keep plans and selectors in sync with UI
|
|
79
|
+
|
|
80
|
+
- When changing UI: update selectors in page objects and cross-check with the scenario plan. When adding/changing tests: read the matching plan and sync scenario titles first.
|
|
81
|
+
|
|
82
|
+
## Stack notes
|
|
83
|
+
|
|
84
|
+
- Runner: Vitest (default for SvelteKit).
|
|
85
|
+
- Components: `render` from `@testing-library/svelte` (NOT `@vue/test-utils`, NOT React Testing Library as default).
|
|
86
|
+
- `userEvent` from `@testing-library/user-event` when that is the repo convention.
|
|
87
|
+
- HTTP-client behavior tests next to `src/lib/clients/**` (SvelteKit convention; no `app/`, no `src/app/`).
|
|
88
|
+
- Mock `$lib/api` / stores per neighbor patterns.
|
|
89
|
+
- DTO→domain mappers — unit tests for edge cases.
|
|
90
|
+
- UI placement: sibling `*.spec.ts` in `src/lib/components` (no `__tests__/` inside the component folder).
|
|
91
|
+
- `## Stack notes` content is stripped by `scripts/check-shared-core-drift.sh` before byte-comparing this file against `_shared/core/testing/testing-principles.md`; keep prose above (core content) verbatim against the core file.
|
|
@@ -106,8 +106,6 @@ Prefer **`executing`** for pipeline mode. Legacy: `analysis`, `development`, `re
|
|
|
106
106
|
/technical-retro <slug>
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
-
Legacy: `/feature-start`, `/feature-continue`.
|
|
110
|
-
|
|
111
109
|
## Creating task dirs
|
|
112
110
|
|
|
113
111
|
Bootstrap `<slug>/` by **writing** `pipeline.json` (Write tool). Runtime/hook owns `status.json` lifecycle; parent may only create a minimal bootstrap if missing. Do **not** use Shell `mkdir -p` — Cursor’s default sandbox returns `Operation not permitted` (especially for repos on macOS Desktop/Documents).
|
|
@@ -116,7 +114,6 @@ Bootstrap `<slug>/` by **writing** `pipeline.json` (Write tool). Runtime/hook ow
|
|
|
116
114
|
|
|
117
115
|
Commit task artifacts if you want them to survive `ai-rules clean cursor`. Or copy finished tasks to `docs/agent-workflow/tasks/<slug>/`.
|
|
118
116
|
|
|
119
|
-
|
|
120
117
|
## specMode, applyReadiness, memlog
|
|
121
118
|
|
|
122
119
|
- **`specMode`:** `consume` | `generate` | `none` — primary in `brief.md` `## Spec mode`; optional top-level `pipeline.json` `specMode`. `none` skips INDEX/author mode (spike/research).
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "Single source of truth for embed-mode shared-core stems. Loaded by check-shared-core-drift.sh and sync-shared-core-embeds.sh to keep the two scripts in lockstep.",
|
|
3
|
+
"embed": [
|
|
4
|
+
"quality/code-quality-and-refactoring.md",
|
|
5
|
+
"quality/anti-sycophancy-discipline.md",
|
|
6
|
+
"quality/design-guidance.md",
|
|
7
|
+
"quality/mcp-usage.md",
|
|
8
|
+
"meta/preset-layering.md",
|
|
9
|
+
"meta/preset-twin-sync.md",
|
|
10
|
+
"meta/preset-token-budget.md",
|
|
11
|
+
"meta/preset-pr-checklist.md",
|
|
12
|
+
"meta/preset-no-cross-stack-leakage.md",
|
|
13
|
+
"review/code-review-mr.md",
|
|
14
|
+
"review/technical-retro.md",
|
|
15
|
+
"review/mockup-review.md",
|
|
16
|
+
"review/ux-design.md",
|
|
17
|
+
"agent-team/agent-team-intake.md",
|
|
18
|
+
"architecture/product-specs.md",
|
|
19
|
+
"architecture/product-specs-authoring.md",
|
|
20
|
+
"quality/debug-investigation.md",
|
|
21
|
+
"testing/testing-principles.md"
|
|
22
|
+
],
|
|
23
|
+
"lineage": [
|
|
24
|
+
"architecture/feature-delivery-workflow.md",
|
|
25
|
+
"architecture/reference-features.template.md",
|
|
26
|
+
"agent-team/agent-team-orchestrator.md",
|
|
27
|
+
"quality/verification-before-completion.md",
|
|
28
|
+
"review/receiving-code-review.md",
|
|
29
|
+
"agent-team/task-classification.md"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
@@ -1,9 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Aggregate `metrics.json` ledgers across `.cursor/team/tasks/*` and emit a JSON report.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* node scripts/aggregate-agent-task-metrics.mjs [--team-root <dir>] [--help]
|
|
7
|
+
*
|
|
8
|
+
* Defaults to `<cwd>/.cursor/team` when --team-root is omitted.
|
|
9
|
+
*/
|
|
2
10
|
|
|
3
11
|
import fs from 'node:fs';
|
|
4
12
|
import path from 'node:path';
|
|
5
13
|
|
|
6
14
|
const args = process.argv.slice(2);
|
|
15
|
+
|
|
16
|
+
if (args.includes('-h') || args.includes('--help')) {
|
|
17
|
+
console.log(`Aggregate agent-task metrics ledgers.
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
node scripts/aggregate-agent-task-metrics.mjs [--team-root <dir>]
|
|
21
|
+
|
|
22
|
+
Options:
|
|
23
|
+
--team-root <dir> Directory containing a 'tasks/' subfolder with *.metrics.json ledgers
|
|
24
|
+
(default: <cwd>/.cursor/team)
|
|
25
|
+
|
|
26
|
+
Output: JSON report on stdout (machine-readable).`);
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
|
|
7
30
|
const teamRootIndex = args.indexOf('--team-root');
|
|
8
31
|
const teamRoot =
|
|
9
32
|
teamRootIndex >= 0
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# FAIL when chain-team-phases.sh has an orphaned entry:
|
|
3
|
+
# - DEFAULT_ARTIFACT_OUTPUT_IDS entry without an AGENT_HANDOFF entry, or
|
|
4
|
+
# - AGENT_HANDOFF entry without a DEFAULT_ARTIFACT_OUTPUT_IDS entry.
|
|
5
|
+
#
|
|
6
|
+
# Also FAIL when a stack ships an agent file that the hook ignores entirely
|
|
7
|
+
# (no entry in either map) AND the stack has a pipeline intent that can route
|
|
8
|
+
# to it — for example, intent `openspec-change` requires `openspec-author` to
|
|
9
|
+
# be wired through both maps or the pipeline silently halts in
|
|
10
|
+
# `awaiting_artifact_receipt`. We check the documented intent-to-agent table in
|
|
11
|
+
# each stack's task-router.md against the hook's actual coverage.
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
|
|
15
|
+
export AI_RULES_PRESETS_ROOT="$ROOT/packages/ai-rules/presets"
|
|
16
|
+
|
|
17
|
+
python3 <<'PY'
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import os
|
|
21
|
+
import re
|
|
22
|
+
import sys
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
presets = Path(os.environ["AI_RULES_PRESETS_ROOT"])
|
|
26
|
+
|
|
27
|
+
# Stacks that ship a /task pipeline. mcp-ts ships a Phase-1 chain but not the
|
|
28
|
+
# standard openspec-change intent; do not require openspec-author there.
|
|
29
|
+
STACKS_WITH_OPENSPEC = {
|
|
30
|
+
("cursor", "android-kotlin"),
|
|
31
|
+
("cursor", "go"),
|
|
32
|
+
("cursor", "ios-swift"),
|
|
33
|
+
("cursor", "java"),
|
|
34
|
+
("cursor", "next"),
|
|
35
|
+
("cursor", "nuxt"),
|
|
36
|
+
("cursor", "php-hexagonal"),
|
|
37
|
+
("cursor", "php-laravel"),
|
|
38
|
+
("cursor", "svelte"),
|
|
39
|
+
("claude", "android-kotlin"),
|
|
40
|
+
("claude", "go"),
|
|
41
|
+
("claude", "ios-swift"),
|
|
42
|
+
("claude", "java"),
|
|
43
|
+
("claude", "next"),
|
|
44
|
+
("claude", "nuxt"),
|
|
45
|
+
("claude", "php-hexagonal"),
|
|
46
|
+
("claude", "php-laravel"),
|
|
47
|
+
("claude", "svelte"),
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# Agents used only outside the pipeline (no chain hook entry expected).
|
|
51
|
+
PIPELINE_EXEMPT = {"task-router", "codebase-analyzer"}
|
|
52
|
+
|
|
53
|
+
failures: list[str] = []
|
|
54
|
+
checks = 0
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def parse_block(text: str, header_re: str, line_re: str) -> set[str]:
|
|
58
|
+
m = re.search(header_re, text, re.DOTALL)
|
|
59
|
+
if not m:
|
|
60
|
+
return set()
|
|
61
|
+
return {x.group(1) for x in line_re.finditer(m.group(1))}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
for hook in sorted(presets.glob("*/**/hooks/chain-team-phases.sh")):
|
|
65
|
+
rel = hook.relative_to(presets)
|
|
66
|
+
platform, preset = rel.parts[0], rel.parts[1]
|
|
67
|
+
text = hook.read_text(encoding="utf-8")
|
|
68
|
+
|
|
69
|
+
artifact_ids = parse_block(
|
|
70
|
+
text,
|
|
71
|
+
r"const DEFAULT_ARTIFACT_OUTPUT_IDS = \{(.*?)\};\n",
|
|
72
|
+
re.compile(r"^\s*['\"]([a-z][a-z0-9.\-]*)['\"]\s*:\s*['\"][a-z][a-z0-9.\-]*['\"]\s*,?", re.MULTILINE),
|
|
73
|
+
)
|
|
74
|
+
handoff_keys = parse_block(
|
|
75
|
+
text,
|
|
76
|
+
r"const AGENT_HANDOFF = \{(.*?)\n\};\n",
|
|
77
|
+
re.compile(r"^\s*['\"]([a-z][a-z0-9.\-]*)['\"]\s*:\s*\(s", re.MULTILINE),
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# 1) Symmetric invariant: any entry in either map must appear in the other.
|
|
81
|
+
only_artifact = artifact_ids - handoff_keys
|
|
82
|
+
only_handoff = handoff_keys - artifact_ids
|
|
83
|
+
for agent in sorted(only_artifact - PIPELINE_EXEMPT):
|
|
84
|
+
checks += 1
|
|
85
|
+
failures.append(f"{rel}: DEFAULT_ARTIFACT_OUTPUT_IDS '{agent}' has no AGENT_HANDOFF entry")
|
|
86
|
+
for agent in sorted(only_handoff - PIPELINE_EXEMPT):
|
|
87
|
+
checks += 1
|
|
88
|
+
failures.append(f"{rel}: AGENT_HANDOFF '{agent}' has no DEFAULT_ARTIFACT_OUTPUT_IDS entry")
|
|
89
|
+
|
|
90
|
+
# 2) openspec-author must be in BOTH maps for any stack that ships the
|
|
91
|
+
# agent. The hook without this entry silently breaks the openspec-change
|
|
92
|
+
# intent (the original bug).
|
|
93
|
+
agents_dir = presets / platform / preset / "agents"
|
|
94
|
+
if (platform, preset) in STACKS_WITH_OPENSPEC and (agents_dir / "openspec-author.md").exists():
|
|
95
|
+
checks += 1
|
|
96
|
+
if "openspec-author" not in artifact_ids:
|
|
97
|
+
failures.append(f"{rel}: ships openspec-author.md but hook is missing DEFAULT_ARTIFACT_OUTPUT_IDS['openspec-author'] (openspec-change intent will silently stall in awaiting_artifact_receipt)")
|
|
98
|
+
if "openspec-author" not in handoff_keys:
|
|
99
|
+
failures.append(f"{rel}: ships openspec-author.md but hook is missing AGENT_HANDOFF['openspec-author']")
|
|
100
|
+
|
|
101
|
+
if failures:
|
|
102
|
+
print(f"FAIL: chain-team-phases.sh coverage gap ({len(failures)} issue(s) / {checks} checks):")
|
|
103
|
+
for f in failures:
|
|
104
|
+
print(f" - {f}")
|
|
105
|
+
sys.exit(1)
|
|
106
|
+
|
|
107
|
+
print(f"OK: chain-team-phases.sh hook coverage is consistent ({checks} checks across all hooks)")
|
|
108
|
+
sys.exit(0)
|
|
109
|
+
PY
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Verify that every installable stack ships an `ai-local-overlay` rule on both
|
|
3
|
+
# sides (Cursor `.mdc` and Claude `.md`) and that the body contains the
|
|
4
|
+
# mandatory acknowledgement format.
|
|
5
|
+
#
|
|
6
|
+
# Exit 0 on OK; exit 1 on any FAIL.
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
|
|
10
|
+
export AI_RULES_PRESETS_ROOT="$ROOT/packages/ai-rules/presets"
|
|
11
|
+
|
|
12
|
+
python3 <<'PY'
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
import re
|
|
17
|
+
import sys
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
presets = Path(os.environ["AI_RULES_PRESETS_ROOT"])
|
|
21
|
+
STACKS = (
|
|
22
|
+
"next",
|
|
23
|
+
"nuxt",
|
|
24
|
+
"svelte",
|
|
25
|
+
"ios-swift",
|
|
26
|
+
"android-kotlin",
|
|
27
|
+
"go",
|
|
28
|
+
"java",
|
|
29
|
+
"mcp-ts",
|
|
30
|
+
"php-hexagonal",
|
|
31
|
+
"php-laravel",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
CURSOR_NAME = "ai-local-overlay.mdc"
|
|
35
|
+
CLAUDE_NAME = "ai-local-overlay.md"
|
|
36
|
+
# The body line that the agent MUST emit when it applies the overlay.
|
|
37
|
+
ACK_RE = re.compile(r"Using\s+\.ai\.local:\s+<rule-name>")
|
|
38
|
+
# Sentinel strings that signal the rule is mandatory / explains authoring /
|
|
39
|
+
# points at the consumer guide.
|
|
40
|
+
FRONTMATTER_DESCRIPTION = "MANDATORY"
|
|
41
|
+
POINTER_DOCS = "docs/LOCAL-OVERLAY.md"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def strip_frontmatter(text: str) -> tuple[str, str]:
|
|
45
|
+
if not text.startswith("---\n"):
|
|
46
|
+
return "", text
|
|
47
|
+
end = text.find("\n---\n", 4)
|
|
48
|
+
if end < 0:
|
|
49
|
+
return "", text
|
|
50
|
+
return text[4:end], text[end + 5 :]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
failed = 0
|
|
54
|
+
stack_failed: dict[str, int] = {}
|
|
55
|
+
|
|
56
|
+
print("Local overlay coverage (every stack must ship ai-local-overlay)")
|
|
57
|
+
print(f"Presets: {presets}")
|
|
58
|
+
print()
|
|
59
|
+
|
|
60
|
+
for stack in STACKS:
|
|
61
|
+
print(f"=== {stack} ===")
|
|
62
|
+
cursor_path = presets / "cursor" / stack / "rules" / CURSOR_NAME
|
|
63
|
+
claude_path = presets / "claude" / stack / "rules" / CLAUDE_NAME
|
|
64
|
+
|
|
65
|
+
# Per-stack failure counter — keeps the OK message for healthy stacks
|
|
66
|
+
# even when an earlier stack has failed.
|
|
67
|
+
sf = 0
|
|
68
|
+
|
|
69
|
+
# Cursor must exist + alwaysApply: true + ack format + pointer.
|
|
70
|
+
if not cursor_path.is_file():
|
|
71
|
+
print(f"FAIL: missing {cursor_path}")
|
|
72
|
+
sf += 1
|
|
73
|
+
else:
|
|
74
|
+
text = cursor_path.read_text(encoding="utf-8")
|
|
75
|
+
fm, body = strip_frontmatter(text)
|
|
76
|
+
if "alwaysApply: true" not in fm:
|
|
77
|
+
print(f"FAIL: {cursor_path.name} must have alwaysApply: true")
|
|
78
|
+
sf += 1
|
|
79
|
+
if FRONTMATTER_DESCRIPTION not in fm:
|
|
80
|
+
print(f"FAIL: {cursor_path.name} frontmatter description must include 'MANDATORY'")
|
|
81
|
+
sf += 1
|
|
82
|
+
if not ACK_RE.search(body):
|
|
83
|
+
print(f"FAIL: {cursor_path.name} body missing acknowledgement format `Using .ai.local: <rule-name>`")
|
|
84
|
+
sf += 1
|
|
85
|
+
if POINTER_DOCS not in body:
|
|
86
|
+
print(f"FAIL: {cursor_path.name} body must reference `docs/LOCAL-OVERLAY.md`")
|
|
87
|
+
sf += 1
|
|
88
|
+
if sf == 0:
|
|
89
|
+
print(f" OK: {cursor_path.name} (alwaysApply + MANDATORY + ack + pointer)")
|
|
90
|
+
|
|
91
|
+
# Claude must exist (flat or topic folder) + paths: includes .ai.local + ack format + pointer.
|
|
92
|
+
if not claude_path.is_file():
|
|
93
|
+
# Try to find a topic-folder placement (e.g. tooling-and-review/ai-local-overlay.md).
|
|
94
|
+
candidates = list((presets / "claude" / stack / "rules").rglob(CLAUDE_NAME))
|
|
95
|
+
if candidates:
|
|
96
|
+
claude_path = candidates[0]
|
|
97
|
+
else:
|
|
98
|
+
print(f"FAIL: missing {claude_path}")
|
|
99
|
+
sf += 1
|
|
100
|
+
if claude_path.is_file():
|
|
101
|
+
text = claude_path.read_text(encoding="utf-8")
|
|
102
|
+
fm, body = strip_frontmatter(text)
|
|
103
|
+
if "**/.ai.local/**" not in fm:
|
|
104
|
+
print(f"FAIL: {claude_path.name} frontmatter must include `**/.ai.local/**` in paths")
|
|
105
|
+
sf += 1
|
|
106
|
+
if FRONTMATTER_DESCRIPTION not in fm:
|
|
107
|
+
print(f"FAIL: {claude_path.name} frontmatter description must include 'MANDATORY'")
|
|
108
|
+
sf += 1
|
|
109
|
+
if not ACK_RE.search(body):
|
|
110
|
+
print(f"FAIL: {claude_path.name} body missing acknowledgement format `Using .ai.local: <rule-name>`")
|
|
111
|
+
sf += 1
|
|
112
|
+
if POINTER_DOCS not in body:
|
|
113
|
+
print(f"FAIL: {claude_path.name} body must reference `docs/LOCAL-OVERLAY.md`")
|
|
114
|
+
sf += 1
|
|
115
|
+
if sf == 0:
|
|
116
|
+
print(f" OK: {claude_path.name} (paths + MANDATORY + ack + pointer)")
|
|
117
|
+
|
|
118
|
+
# Twin-map coverage: the Claude twin must be listed in claude/<stack>/rules/README.md.
|
|
119
|
+
claude_readme = presets / "claude" / stack / "rules" / "README.md"
|
|
120
|
+
if claude_readme.is_file():
|
|
121
|
+
readme_text = claude_readme.read_text(encoding="utf-8")
|
|
122
|
+
if CURSOR_NAME not in readme_text:
|
|
123
|
+
print(f"FAIL: {claude_readme} mapping table must include `{CURSOR_NAME}`")
|
|
124
|
+
sf += 1
|
|
125
|
+
|
|
126
|
+
stack_failed[stack] = sf
|
|
127
|
+
failed += sf
|
|
128
|
+
print()
|
|
129
|
+
|
|
130
|
+
if failed:
|
|
131
|
+
print(f"Result: FAIL ({failed} issue(s) across {sum(1 for v in stack_failed.values() if v > 0)} stack(s))")
|
|
132
|
+
sys.exit(1)
|
|
133
|
+
|
|
134
|
+
print("Result: OK")
|
|
135
|
+
sys.exit(0)
|
|
136
|
+
PY
|
|
@@ -54,8 +54,8 @@ if len(violations) > 50:
|
|
|
54
54
|
print(f" ... and {len(violations) - 50} more")
|
|
55
55
|
|
|
56
56
|
if violations and (fail or not soft):
|
|
57
|
-
if fail:
|
|
58
|
-
|
|
57
|
+
print("Result: FAIL (unmarked Cyrillic)" if fail else "Result: WARN (soft)")
|
|
58
|
+
sys.exit(1)
|
|
59
59
|
print("Result:", "WARN (soft)" if violations else "OK")
|
|
60
60
|
sys.exit(0)
|
|
61
61
|
PY
|
|
@@ -278,7 +278,10 @@ def line_is_negation(line: str) -> bool:
|
|
|
278
278
|
|
|
279
279
|
|
|
280
280
|
def is_forbidden_agent(name: str, bad_stems: tuple[str, ...]) -> bool:
|
|
281
|
-
|
|
281
|
+
# Exact match, or kebab-case prefix (so `playwright-test-planner` matches
|
|
282
|
+
# `playwright-test-planner-foo` too — kebab-case is the only naming style in
|
|
283
|
+
# use across all presets, so the naive `startswith` is intentional).
|
|
284
|
+
return name in bad_stems or any(name.startswith(s + "-") or name == s for s in bad_stems)
|
|
282
285
|
|
|
283
286
|
|
|
284
287
|
def collect_step_agents(steps) -> list[str]:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# Orchestrator: twin map + token budget + leakage + hook-only lifecycle + shared-core drift + i18n (hard).
|
|
2
|
+
# Orchestrator: twin map + token budget + leakage + hook-only lifecycle + local-overlay + shared-core drift + i18n (hard).
|
|
3
3
|
# All gates exit non-zero on FAIL.
|
|
4
4
|
set -euo pipefail
|
|
5
5
|
|
|
@@ -33,7 +33,9 @@ run_gate "twin-map" "$SCRIPT_DIR/check-preset-twin-map.sh"
|
|
|
33
33
|
run_gate "token-budget" "$SCRIPT_DIR/check-preset-token-budget.sh"
|
|
34
34
|
run_gate "leakage" "$SCRIPT_DIR/check-preset-leakage.sh"
|
|
35
35
|
run_gate "hook-only-lifecycle" "$SCRIPT_DIR/check-hook-only-lifecycle.sh"
|
|
36
|
+
run_gate "local-overlay" "$SCRIPT_DIR/check-local-overlay.sh"
|
|
36
37
|
run_gate "shared-core-drift" "$SCRIPT_DIR/check-shared-core-drift.sh" AI_RULES_DRIFT_FAIL=1
|
|
38
|
+
run_gate "chain-hook-coverage" "$SCRIPT_DIR/check-chain-hook-coverage.sh"
|
|
37
39
|
run_gate "i18n" "$SCRIPT_DIR/check-preset-i18n.sh" AI_RULES_I18N_FAIL=1 AI_RULES_I18N_SOFT=0
|
|
38
40
|
|
|
39
41
|
echo ">>> cli-mcp-merge"
|
|
@@ -45,6 +47,24 @@ else
|
|
|
45
47
|
fi
|
|
46
48
|
echo
|
|
47
49
|
|
|
50
|
+
echo ">>> chain-team-phases coverage"
|
|
51
|
+
if node "$SCRIPT_DIR/test-chain-team-phases-coverage.mjs"; then
|
|
52
|
+
echo "<<< chain-team-phases coverage: OK"
|
|
53
|
+
else
|
|
54
|
+
echo "<<< chain-team-phases coverage: FAIL"
|
|
55
|
+
status=1
|
|
56
|
+
fi
|
|
57
|
+
echo
|
|
58
|
+
|
|
59
|
+
echo ">>> agent-task-metrics hooks"
|
|
60
|
+
if node "$SCRIPT_DIR/test-agent-task-metrics-hooks.mjs"; then
|
|
61
|
+
echo "<<< agent-task-metrics hooks: OK"
|
|
62
|
+
else
|
|
63
|
+
echo "<<< agent-task-metrics hooks: FAIL"
|
|
64
|
+
status=1
|
|
65
|
+
fi
|
|
66
|
+
echo
|
|
67
|
+
|
|
48
68
|
# Soft WARN: dogfood product-specs (never fails the orchestrator).
|
|
49
69
|
# Default check-product-specs exits 0 even when issues are found unless --strict.
|
|
50
70
|
# Use --strict here only to surface problems as WARN in logs; do not flip status.
|