@bonesofspring/ai-rules 0.2.11 → 0.2.13
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 +42 -0
- package/README.md +5 -1
- package/bin/cli.js +4 -0
- package/package.json +1 -1
- package/presets/_shared/README.md +1 -1
- package/presets/_shared/core/agent-team/agent-artifact-contracts.md +114 -0
- package/presets/_shared/core/agent-team/agent-task-metrics.md +30 -0
- package/presets/_shared/core/agent-team/agent-team-orchestrator.md +71 -4
- package/presets/_shared/core/meta/preset-layering.md +1 -1
- package/presets/_shared/core/meta/preset-no-cross-stack-leakage.md +5 -5
- package/presets/_shared/core/meta/preset-pr-checklist.md +1 -1
- package/presets/_shared/core/meta/preset-twin-sync.md +4 -0
- package/presets/_shared/core/review/technical-retro.md +2 -0
- package/presets/claude/go/agents/build-verifier.md +11 -4
- package/presets/claude/go/agents/code-reviewer.md +8 -1
- package/presets/claude/go/agents/feature-developer.md +8 -1
- package/presets/claude/go/agents/task-analyst.md +8 -1
- package/presets/claude/go/agents/task-router.md +35 -3
- package/presets/claude/go/commands/task-continue.md +17 -16
- package/presets/claude/go/commands/task.md +11 -5
- package/presets/claude/go/commands/technical-retro.md +4 -0
- package/presets/claude/go/hooks/chain-team-phases.sh +411 -69
- package/presets/claude/go/rules/README.md +6 -0
- package/presets/claude/go/rules/tooling-and-review/agent-team-orchestrator.md +33 -4
- package/presets/claude/go/rules/tooling-and-review/preset-layering.md +1 -1
- package/presets/claude/go/rules/tooling-and-review/preset-no-cross-stack-leakage.md +5 -5
- package/presets/claude/go/rules/tooling-and-review/preset-pr-checklist.md +1 -1
- package/presets/claude/go/rules/tooling-and-review/preset-twin-sync.md +4 -0
- package/presets/claude/go/rules/tooling-and-review/technical-retro.md +2 -0
- package/presets/claude/go/team/README.md +19 -0
- package/presets/claude/ios-swift/agents/build-verifier.md +11 -4
- package/presets/claude/ios-swift/agents/code-reviewer.md +9 -14
- package/presets/claude/ios-swift/agents/feature-developer.md +8 -1
- package/presets/claude/ios-swift/agents/task-analyst.md +8 -1
- package/presets/claude/ios-swift/agents/task-router.md +33 -1
- package/presets/claude/ios-swift/commands/task-continue.md +17 -16
- package/presets/claude/ios-swift/commands/task.md +11 -5
- package/presets/claude/ios-swift/commands/technical-retro.md +4 -0
- package/presets/claude/ios-swift/hooks/chain-team-phases.sh +393 -70
- package/presets/claude/ios-swift/rules/README.md +6 -0
- package/presets/claude/ios-swift/rules/tooling-and-review/agent-team-orchestrator.md +36 -1
- package/presets/claude/ios-swift/rules/tooling-and-review/preset-layering.md +1 -1
- package/presets/claude/ios-swift/rules/tooling-and-review/preset-no-cross-stack-leakage.md +5 -5
- package/presets/claude/ios-swift/rules/tooling-and-review/preset-pr-checklist.md +1 -1
- package/presets/claude/ios-swift/rules/tooling-and-review/preset-twin-sync.md +4 -0
- package/presets/claude/ios-swift/rules/tooling-and-review/technical-retro.md +2 -0
- package/presets/claude/ios-swift/team/README.md +19 -0
- package/presets/claude/java/agents/build-verifier.md +11 -4
- package/presets/claude/java/agents/code-reviewer.md +8 -1
- package/presets/claude/java/agents/feature-developer.md +8 -1
- package/presets/claude/java/agents/task-analyst.md +8 -1
- package/presets/claude/java/agents/task-router.md +33 -1
- package/presets/claude/java/commands/task-continue.md +17 -16
- package/presets/claude/java/commands/task.md +11 -5
- package/presets/claude/java/commands/technical-retro.md +4 -0
- package/presets/claude/java/hooks/chain-team-phases.sh +411 -69
- package/presets/claude/java/rules/README.md +6 -0
- package/presets/claude/java/rules/tooling-and-review/agent-team-orchestrator.md +33 -4
- package/presets/claude/java/rules/tooling-and-review/preset-layering.md +1 -1
- package/presets/claude/java/rules/tooling-and-review/preset-no-cross-stack-leakage.md +5 -5
- package/presets/claude/java/rules/tooling-and-review/preset-pr-checklist.md +1 -1
- package/presets/claude/java/rules/tooling-and-review/preset-twin-sync.md +4 -0
- package/presets/claude/java/rules/tooling-and-review/technical-retro.md +2 -0
- package/presets/claude/java/team/README.md +19 -0
- package/presets/claude/mcp-ts/agents/build-verifier.md +11 -4
- package/presets/claude/mcp-ts/agents/feature-developer.md +7 -1
- package/presets/claude/mcp-ts/agents/task-analyst.md +8 -1
- package/presets/claude/mcp-ts/agents/task-router.md +35 -3
- package/presets/claude/mcp-ts/commands/task-continue.md +21 -20
- package/presets/claude/mcp-ts/commands/task.md +11 -5
- package/presets/claude/mcp-ts/commands/technical-retro.md +4 -0
- package/presets/claude/mcp-ts/hooks/chain-team-phases.sh +397 -55
- package/presets/claude/mcp-ts/rules/README.md +6 -0
- package/presets/claude/mcp-ts/rules/tooling-and-review/agent-team-orchestrator.md +33 -4
- package/presets/claude/mcp-ts/rules/tooling-and-review/preset-layering.md +1 -1
- package/presets/claude/mcp-ts/rules/tooling-and-review/preset-no-cross-stack-leakage.md +5 -5
- package/presets/claude/mcp-ts/rules/tooling-and-review/preset-pr-checklist.md +1 -1
- package/presets/claude/mcp-ts/rules/tooling-and-review/preset-twin-sync.md +4 -0
- package/presets/claude/mcp-ts/rules/tooling-and-review/technical-retro.md +2 -4
- package/presets/claude/mcp-ts/team/README.md +19 -0
- package/presets/claude/next/agents/accessibility-reviewer.md +6 -12
- package/presets/claude/next/agents/api-contract-reviewer.md +6 -12
- package/presets/claude/next/agents/build-verifier.md +10 -14
- package/presets/claude/next/agents/ci-investigator.md +7 -13
- package/presets/claude/next/agents/code-reviewer.md +9 -14
- package/presets/claude/next/agents/debugger.md +6 -12
- package/presets/claude/next/agents/feature-developer.md +8 -1
- package/presets/claude/next/agents/migration-specialist.md +6 -12
- package/presets/claude/next/agents/performance-auditor.md +5 -11
- package/presets/claude/next/agents/qa-tester.md +6 -12
- package/presets/claude/next/agents/security-reviewer.md +6 -12
- package/presets/claude/next/agents/solution-architect.md +6 -12
- package/presets/claude/next/agents/task-analyst.md +10 -16
- package/presets/claude/next/agents/task-router.md +33 -1
- package/presets/claude/next/agents/tech-writer.md +6 -13
- package/presets/claude/next/agents/unit-test-generator.md +6 -10
- package/presets/claude/next/agents/unit-test-healer.md +6 -10
- package/presets/claude/next/agents/unit-test-planner.md +5 -11
- package/presets/claude/next/commands/task-continue.md +17 -16
- package/presets/claude/next/commands/task.md +11 -5
- package/presets/claude/next/commands/technical-retro.md +4 -0
- package/presets/claude/next/hooks/chain-team-phases.sh +413 -70
- package/presets/claude/next/rules/README.md +6 -0
- package/presets/claude/next/rules/tooling-and-review/agent-team-orchestrator.md +32 -3
- package/presets/claude/next/rules/tooling-and-review/preset-layering.md +1 -1
- package/presets/claude/next/rules/tooling-and-review/preset-no-cross-stack-leakage.md +5 -5
- package/presets/claude/next/rules/tooling-and-review/preset-pr-checklist.md +1 -1
- package/presets/claude/next/rules/tooling-and-review/preset-twin-sync.md +4 -0
- package/presets/claude/next/rules/tooling-and-review/technical-retro.md +2 -0
- package/presets/claude/next/team/README.md +32 -1
- package/presets/claude/next/team/fixtures/artifact-manifest.example.json +61 -0
- package/presets/claude/next/team/fixtures/bugfix-standard.json +10 -0
- package/presets/claude/next/team/fixtures/feature-full.json +10 -0
- package/presets/claude/next/team/fixtures/feature-light.json +10 -0
- package/presets/claude/php-hexagonal/CLAUDE.md +31 -0
- package/presets/claude/php-hexagonal/MCP.md +15 -0
- package/presets/claude/php-hexagonal/README.md +26 -0
- package/presets/claude/php-hexagonal/REPO_AGENTS.md +46 -0
- package/presets/claude/php-hexagonal/agents/README.md +32 -0
- package/presets/claude/php-hexagonal/agents/api-contract-reviewer.md +23 -0
- package/presets/claude/php-hexagonal/agents/build-verifier.md +52 -0
- package/presets/claude/php-hexagonal/agents/ci-investigator.md +21 -0
- package/presets/claude/php-hexagonal/agents/code-reviewer.md +47 -0
- package/presets/claude/php-hexagonal/agents/codebase-analyzer.md +28 -0
- package/presets/claude/php-hexagonal/agents/debugger.md +29 -0
- package/presets/claude/php-hexagonal/agents/feature-developer.md +54 -0
- package/presets/claude/php-hexagonal/agents/integration-test-generator.md +22 -0
- package/presets/claude/php-hexagonal/agents/integration-test-healer.md +22 -0
- package/presets/claude/php-hexagonal/agents/integration-test-planner.md +22 -0
- package/presets/claude/php-hexagonal/agents/migration-specialist.md +31 -0
- package/presets/claude/php-hexagonal/agents/performance-auditor.md +22 -0
- package/presets/claude/php-hexagonal/agents/qa-tester.md +24 -0
- package/presets/claude/php-hexagonal/agents/security-reviewer.md +20 -0
- package/presets/claude/php-hexagonal/agents/solution-architect.md +28 -0
- package/presets/claude/php-hexagonal/agents/task-analyst.md +32 -0
- package/presets/claude/php-hexagonal/agents/task-router.md +101 -0
- package/presets/claude/php-hexagonal/agents/tech-writer.md +15 -0
- package/presets/claude/php-hexagonal/agents/unit-test-generator.md +21 -0
- package/presets/claude/php-hexagonal/agents/unit-test-healer.md +13 -0
- package/presets/claude/php-hexagonal/agents/unit-test-planner.md +26 -0
- package/presets/claude/php-hexagonal/commands/README.md +13 -0
- package/presets/claude/php-hexagonal/commands/feature-continue.md +51 -0
- package/presets/claude/php-hexagonal/commands/feature-start.md +30 -0
- package/presets/claude/php-hexagonal/commands/task-continue.md +50 -0
- package/presets/claude/php-hexagonal/commands/task.md +55 -0
- package/presets/claude/php-hexagonal/commands/technical-retro.md +62 -0
- package/presets/claude/php-hexagonal/hooks/README.md +16 -0
- package/presets/claude/php-hexagonal/hooks/chain-team-phases.sh +724 -0
- package/presets/claude/php-hexagonal/hooks/examples/README.md +18 -0
- package/presets/claude/php-hexagonal/hooks/examples/format-edited.example.sh +11 -0
- package/presets/claude/php-hexagonal/hooks/examples/secret-guard.example.sh +10 -0
- package/presets/claude/php-hexagonal/hooks/examples/test-on-save.example.sh +19 -0
- package/presets/claude/php-hexagonal/hooks/guard-shell-command.sh +80 -0
- package/presets/claude/php-hexagonal/mcp.json +11 -0
- package/presets/claude/php-hexagonal/rules/README.md +67 -0
- package/presets/claude/php-hexagonal/rules/api-and-data/README.md +14 -0
- package/presets/claude/php-hexagonal/rules/api-and-data/adapters-driven.md +38 -0
- package/presets/claude/php-hexagonal/rules/api-and-data/adapters-driving.md +38 -0
- package/presets/claude/php-hexagonal/rules/api-and-data/api-grpc.md +29 -0
- package/presets/claude/php-hexagonal/rules/api-and-data/api-http.md +36 -0
- package/presets/claude/php-hexagonal/rules/api-and-data/messaging-adapters.md +37 -0
- package/presets/claude/php-hexagonal/rules/api-and-data/persistence-adapters.md +33 -0
- package/presets/claude/php-hexagonal/rules/architecture/README.md +16 -0
- package/presets/claude/php-hexagonal/rules/architecture/application-usecases.md +31 -0
- package/presets/claude/php-hexagonal/rules/architecture/boundaries.md +34 -0
- package/presets/claude/php-hexagonal/rules/architecture/composition-root.md +33 -0
- package/presets/claude/php-hexagonal/rules/architecture/domain-layer.md +37 -0
- package/presets/claude/php-hexagonal/rules/architecture/feature-delivery.md +53 -0
- package/presets/claude/php-hexagonal/rules/architecture/module-public-api.md +31 -0
- package/presets/claude/php-hexagonal/rules/architecture/ports-interfaces.md +34 -0
- package/presets/claude/php-hexagonal/rules/architecture/reference-features.md +39 -0
- package/presets/claude/php-hexagonal/rules/stack/README.md +10 -0
- package/presets/claude/php-hexagonal/rules/stack/php-app-core.md +35 -0
- package/presets/claude/php-hexagonal/rules/stack/php-conventions.md +51 -0
- package/presets/claude/php-hexagonal/rules/testing/README.md +11 -0
- package/presets/claude/php-hexagonal/rules/testing/e2e.md +35 -0
- package/presets/claude/php-hexagonal/rules/testing/integration.md +31 -0
- package/presets/claude/php-hexagonal/rules/testing/unit.md +32 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/README.md +21 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/agent-team-intake.md +26 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/agent-team-orchestrator.md +208 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/anti-sycophancy-discipline.md +29 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/code-quality.md +53 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/code-review.md +60 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/design-guidance.md +111 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/php-tooling.md +39 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/post-change-test.md +31 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-layering.md +36 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-no-cross-stack-leakage.md +69 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-pr-checklist.md +39 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-token-budget.md +41 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-twin-sync.md +50 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/security-php.md +29 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/technical-retro.md +22 -0
- package/presets/claude/php-hexagonal/rules/ui-and-accessibility/README.md +5 -0
- package/presets/claude/php-hexagonal/skills/README.md +5 -0
- package/presets/claude/php-hexagonal/skills/ci-investigation/SKILL.md +11 -0
- package/presets/claude/php-hexagonal/skills/code-review/SKILL.md +25 -0
- package/presets/claude/php-hexagonal/skills/debug-investigation/SKILL.md +15 -0
- package/presets/claude/php-hexagonal/skills/feature-delivery/SKILL.md +30 -0
- package/presets/claude/php-hexagonal/skills/integration-testing/SKILL.md +15 -0
- package/presets/claude/php-hexagonal/skills/technical-retro/SKILL.md +54 -0
- package/presets/claude/php-hexagonal/skills/unit-testing/SKILL.md +14 -0
- package/presets/claude/php-hexagonal/skills/write-adr/SKILL.md +41 -0
- package/presets/claude/php-hexagonal/team/README.md +48 -0
- package/presets/claude/php-hexagonal/team/conventions.md +21 -0
- package/presets/claude/php-hexagonal/team/fixtures/bugfix-standard.json +37 -0
- package/presets/claude/php-hexagonal/team/fixtures/feature-full.json +25 -0
- package/presets/claude/php-hexagonal/team/fixtures/feature-light.json +17 -0
- package/presets/claude/php-laravel/CLAUDE.md +20 -0
- package/presets/claude/php-laravel/MCP.md +5 -0
- package/presets/claude/php-laravel/README.md +30 -0
- package/presets/claude/php-laravel/REPO_AGENTS.md +47 -0
- package/presets/claude/php-laravel/agents/README.md +32 -0
- package/presets/claude/php-laravel/agents/api-contract-reviewer.md +23 -0
- package/presets/claude/php-laravel/agents/build-verifier.md +52 -0
- package/presets/claude/php-laravel/agents/ci-investigator.md +21 -0
- package/presets/claude/php-laravel/agents/code-reviewer.md +47 -0
- package/presets/claude/php-laravel/agents/codebase-analyzer.md +28 -0
- package/presets/claude/php-laravel/agents/debugger.md +29 -0
- package/presets/claude/php-laravel/agents/feature-developer.md +54 -0
- package/presets/claude/php-laravel/agents/integration-test-generator.md +22 -0
- package/presets/claude/php-laravel/agents/integration-test-healer.md +22 -0
- package/presets/claude/php-laravel/agents/integration-test-planner.md +22 -0
- package/presets/claude/php-laravel/agents/migration-specialist.md +31 -0
- package/presets/claude/php-laravel/agents/performance-auditor.md +22 -0
- package/presets/claude/php-laravel/agents/qa-tester.md +30 -0
- package/presets/claude/php-laravel/agents/security-reviewer.md +32 -0
- package/presets/claude/php-laravel/agents/solution-architect.md +29 -0
- package/presets/claude/php-laravel/agents/task-analyst.md +32 -0
- package/presets/claude/php-laravel/agents/task-router.md +120 -0
- package/presets/claude/php-laravel/agents/tech-writer.md +15 -0
- package/presets/claude/php-laravel/agents/unit-test-generator.md +21 -0
- package/presets/claude/php-laravel/agents/unit-test-healer.md +13 -0
- package/presets/claude/php-laravel/agents/unit-test-planner.md +26 -0
- package/presets/claude/php-laravel/commands/README.md +13 -0
- package/presets/claude/php-laravel/commands/feature-continue.md +51 -0
- package/presets/claude/php-laravel/commands/feature-start.md +30 -0
- package/presets/claude/php-laravel/commands/task-continue.md +50 -0
- package/presets/claude/php-laravel/commands/task.md +55 -0
- package/presets/claude/php-laravel/commands/technical-retro.md +62 -0
- package/presets/claude/php-laravel/hooks/README.md +16 -0
- package/presets/claude/php-laravel/hooks/chain-team-phases.sh +724 -0
- package/presets/claude/php-laravel/hooks/examples/README.md +18 -0
- package/presets/claude/php-laravel/hooks/examples/format-edited.example.sh +11 -0
- package/presets/claude/php-laravel/hooks/examples/secret-guard.example.sh +10 -0
- package/presets/claude/php-laravel/hooks/examples/test-on-save.example.sh +19 -0
- package/presets/claude/php-laravel/hooks/guard-shell-command.sh +80 -0
- package/presets/claude/php-laravel/mcp.json +11 -0
- package/presets/claude/php-laravel/rules/README.md +67 -0
- package/presets/claude/php-laravel/rules/api-and-data/README.md +3 -0
- package/presets/claude/php-laravel/rules/api-and-data/eloquent-persistence.md +31 -0
- package/presets/claude/php-laravel/rules/api-and-data/events-listeners.md +31 -0
- package/presets/claude/php-laravel/rules/api-and-data/form-requests.md +29 -0
- package/presets/claude/php-laravel/rules/api-and-data/http-layer.md +32 -0
- package/presets/claude/php-laravel/rules/api-and-data/jobs-queues.md +41 -0
- package/presets/claude/php-laravel/rules/api-and-data/policies-authorization.md +29 -0
- package/presets/claude/php-laravel/rules/api-and-data/routes-api.md +29 -0
- package/presets/claude/php-laravel/rules/architecture/README.md +3 -0
- package/presets/claude/php-laravel/rules/architecture/actions-services.md +30 -0
- package/presets/claude/php-laravel/rules/architecture/boundaries.md +34 -0
- package/presets/claude/php-laravel/rules/architecture/domain-layer.md +24 -0
- package/presets/claude/php-laravel/rules/architecture/feature-delivery.md +51 -0
- package/presets/claude/php-laravel/rules/architecture/module-public-api.md +29 -0
- package/presets/claude/php-laravel/rules/architecture/reference-features.md +40 -0
- package/presets/claude/php-laravel/rules/architecture/service-providers.md +28 -0
- package/presets/claude/php-laravel/rules/stack/README.md +3 -0
- package/presets/claude/php-laravel/rules/stack/laravel-app-core.md +32 -0
- package/presets/claude/php-laravel/rules/stack/laravel-conventions.md +38 -0
- package/presets/claude/php-laravel/rules/testing/README.md +3 -0
- package/presets/claude/php-laravel/rules/testing/e2e.md +34 -0
- package/presets/claude/php-laravel/rules/testing/integration.md +30 -0
- package/presets/claude/php-laravel/rules/testing/unit.md +30 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/README.md +3 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/agent-team-intake.md +21 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/agent-team-orchestrator.md +205 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/anti-sycophancy-discipline.md +29 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/code-quality.md +52 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/code-review.md +58 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/design-guidance.md +111 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/php-tooling.md +37 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/post-change-test.md +29 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/preset-layering.md +33 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/preset-no-cross-stack-leakage.md +66 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/preset-pr-checklist.md +36 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/preset-token-budget.md +38 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/preset-twin-sync.md +47 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/security-php.md +58 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/technical-retro.md +17 -0
- package/presets/claude/php-laravel/rules/ui-and-accessibility/README.md +3 -0
- package/presets/claude/php-laravel/skills/README.md +5 -0
- package/presets/claude/php-laravel/skills/ci-investigation/SKILL.md +11 -0
- package/presets/claude/php-laravel/skills/code-review/SKILL.md +25 -0
- package/presets/claude/php-laravel/skills/debug-investigation/SKILL.md +15 -0
- package/presets/claude/php-laravel/skills/feature-delivery/SKILL.md +30 -0
- package/presets/claude/php-laravel/skills/integration-testing/SKILL.md +15 -0
- package/presets/claude/php-laravel/skills/technical-retro/SKILL.md +54 -0
- package/presets/claude/php-laravel/skills/unit-testing/SKILL.md +14 -0
- package/presets/claude/php-laravel/skills/write-adr/SKILL.md +41 -0
- package/presets/claude/php-laravel/team/README.md +28 -0
- package/presets/claude/php-laravel/team/conventions.md +21 -0
- package/presets/claude/php-laravel/team/fixtures/bugfix-standard.json +12 -0
- package/presets/claude/php-laravel/team/fixtures/feature-full.json +15 -0
- package/presets/claude/php-laravel/team/fixtures/feature-light.json +8 -0
- package/presets/cursor/go/agents/build-verifier.md +10 -3
- package/presets/cursor/go/agents/code-reviewer.md +8 -1
- package/presets/cursor/go/agents/feature-developer.md +8 -1
- package/presets/cursor/go/agents/task-analyst.md +8 -1
- package/presets/cursor/go/agents/task-router.md +33 -1
- package/presets/cursor/go/commands/task-continue.md +17 -16
- package/presets/cursor/go/commands/task.md +11 -5
- package/presets/cursor/go/commands/technical-retro.md +4 -0
- package/presets/cursor/go/hooks/chain-team-phases.sh +411 -69
- package/presets/cursor/go/rules/README.md +6 -0
- package/presets/cursor/go/rules/agent-team-orchestrator.mdc +33 -4
- package/presets/cursor/go/rules/preset-layering.mdc +1 -1
- package/presets/cursor/go/rules/preset-no-cross-stack-leakage.mdc +5 -5
- package/presets/cursor/go/rules/preset-pr-checklist.mdc +1 -1
- package/presets/cursor/go/rules/preset-twin-sync.mdc +4 -0
- package/presets/cursor/go/rules/technical-retro.mdc +2 -0
- package/presets/cursor/go/team/README.md +19 -0
- package/presets/cursor/ios-swift/agents/build-verifier.md +11 -4
- package/presets/cursor/ios-swift/agents/code-reviewer.md +9 -14
- package/presets/cursor/ios-swift/agents/feature-developer.md +8 -1
- package/presets/cursor/ios-swift/agents/task-analyst.md +8 -1
- package/presets/cursor/ios-swift/agents/task-router.md +33 -1
- package/presets/cursor/ios-swift/commands/task-continue.md +17 -16
- package/presets/cursor/ios-swift/commands/task.md +11 -5
- package/presets/cursor/ios-swift/commands/technical-retro.md +4 -0
- package/presets/cursor/ios-swift/hooks/chain-team-phases.sh +411 -70
- package/presets/cursor/ios-swift/rules/README.md +6 -0
- package/presets/cursor/ios-swift/rules/agent-team-orchestrator.mdc +26 -1
- package/presets/cursor/ios-swift/rules/preset-layering.mdc +1 -1
- package/presets/cursor/ios-swift/rules/preset-no-cross-stack-leakage.mdc +5 -5
- package/presets/cursor/ios-swift/rules/preset-pr-checklist.mdc +1 -1
- package/presets/cursor/ios-swift/rules/preset-twin-sync.mdc +4 -0
- package/presets/cursor/ios-swift/rules/technical-retro.mdc +2 -0
- package/presets/cursor/ios-swift/team/README.md +19 -0
- package/presets/cursor/java/agents/build-verifier.md +11 -4
- package/presets/cursor/java/agents/code-reviewer.md +8 -1
- package/presets/cursor/java/agents/feature-developer.md +8 -1
- package/presets/cursor/java/agents/task-analyst.md +8 -1
- package/presets/cursor/java/agents/task-router.md +33 -1
- package/presets/cursor/java/commands/task-continue.md +17 -16
- package/presets/cursor/java/commands/task.md +11 -5
- package/presets/cursor/java/commands/technical-retro.md +4 -0
- package/presets/cursor/java/hooks/chain-team-phases.sh +411 -69
- package/presets/cursor/java/rules/README.md +6 -0
- package/presets/cursor/java/rules/agent-team-orchestrator.mdc +33 -4
- package/presets/cursor/java/rules/preset-layering.mdc +1 -1
- package/presets/cursor/java/rules/preset-no-cross-stack-leakage.mdc +5 -5
- package/presets/cursor/java/rules/preset-pr-checklist.mdc +1 -1
- package/presets/cursor/java/rules/preset-twin-sync.mdc +4 -0
- package/presets/cursor/java/rules/technical-retro.mdc +2 -0
- package/presets/cursor/java/team/README.md +19 -0
- package/presets/cursor/mcp-ts/agents/build-verifier.md +10 -3
- package/presets/cursor/mcp-ts/agents/feature-developer.md +7 -1
- package/presets/cursor/mcp-ts/agents/task-analyst.md +8 -1
- package/presets/cursor/mcp-ts/agents/task-router.md +33 -1
- package/presets/cursor/mcp-ts/commands/task-continue.md +19 -18
- package/presets/cursor/mcp-ts/commands/task.md +11 -5
- package/presets/cursor/mcp-ts/commands/technical-retro.md +4 -0
- package/presets/cursor/mcp-ts/hooks/chain-team-phases.sh +397 -55
- package/presets/cursor/mcp-ts/rules/README.md +6 -0
- package/presets/cursor/mcp-ts/rules/agent-team-orchestrator.mdc +33 -4
- package/presets/cursor/mcp-ts/rules/preset-layering.mdc +1 -1
- package/presets/cursor/mcp-ts/rules/preset-no-cross-stack-leakage.mdc +5 -5
- package/presets/cursor/mcp-ts/rules/preset-pr-checklist.mdc +1 -1
- package/presets/cursor/mcp-ts/rules/preset-twin-sync.mdc +4 -0
- package/presets/cursor/mcp-ts/rules/technical-retro.mdc +2 -4
- package/presets/cursor/mcp-ts/team/README.md +19 -0
- package/presets/cursor/next/agents/accessibility-reviewer.md +7 -14
- package/presets/cursor/next/agents/api-contract-reviewer.md +7 -14
- package/presets/cursor/next/agents/build-verifier.md +10 -15
- package/presets/cursor/next/agents/ci-investigator.md +7 -14
- package/presets/cursor/next/agents/code-reviewer.md +9 -14
- package/presets/cursor/next/agents/debugger.md +6 -12
- package/presets/cursor/next/agents/feature-developer.md +8 -1
- package/presets/cursor/next/agents/migration-specialist.md +7 -14
- package/presets/cursor/next/agents/performance-auditor.md +6 -13
- package/presets/cursor/next/agents/qa-tester.md +6 -13
- package/presets/cursor/next/agents/security-reviewer.md +7 -14
- package/presets/cursor/next/agents/solution-architect.md +6 -12
- package/presets/cursor/next/agents/task-analyst.md +10 -16
- package/presets/cursor/next/agents/task-router.md +33 -1
- package/presets/cursor/next/agents/tech-writer.md +6 -13
- package/presets/cursor/next/agents/unit-test-generator.md +6 -11
- package/presets/cursor/next/agents/unit-test-healer.md +6 -11
- package/presets/cursor/next/agents/unit-test-planner.md +6 -13
- package/presets/cursor/next/commands/task-continue.md +17 -16
- package/presets/cursor/next/commands/task.md +11 -5
- package/presets/cursor/next/commands/technical-retro.md +4 -0
- package/presets/cursor/next/hooks/chain-team-phases.sh +417 -70
- package/presets/cursor/next/rules/README.md +6 -0
- package/presets/cursor/next/rules/agent-team-orchestrator.mdc +33 -4
- package/presets/cursor/next/rules/preset-layering.mdc +1 -1
- package/presets/cursor/next/rules/preset-no-cross-stack-leakage.mdc +5 -5
- package/presets/cursor/next/rules/preset-pr-checklist.mdc +1 -1
- package/presets/cursor/next/rules/preset-twin-sync.mdc +4 -0
- package/presets/cursor/next/rules/technical-retro.mdc +2 -0
- package/presets/cursor/next/team/README.md +33 -2
- package/presets/cursor/next/team/fixtures/artifact-manifest.example.json +61 -0
- package/presets/cursor/next/team/fixtures/bugfix-standard.json +10 -0
- package/presets/cursor/next/team/fixtures/feature-full.json +10 -0
- package/presets/cursor/next/team/fixtures/feature-light.json +10 -0
- package/presets/cursor/next/team/fixtures/metrics-scenarios/tasks/human-gate/metrics.json +69 -0
- package/presets/cursor/next/team/fixtures/metrics-scenarios/tasks/missing-ledger/status.json +5 -0
- package/presets/cursor/next/team/fixtures/metrics-scenarios/tasks/parallel-receipts/metrics.json +79 -0
- package/presets/cursor/next/team/fixtures/metrics-scenarios/tasks/serial-retry/metrics.json +124 -0
- package/presets/cursor/next/team/fixtures/metrics-scenarios/tasks/validation-failed/metrics.json +124 -0
- package/presets/cursor/next/team/fixtures/metrics.example.json +54 -0
- package/presets/cursor/php-hexagonal/AGENTS.md +39 -0
- package/presets/cursor/php-hexagonal/BUGBOT.md +11 -0
- package/presets/cursor/php-hexagonal/MCP.md +15 -0
- package/presets/cursor/php-hexagonal/README.md +26 -0
- package/presets/cursor/php-hexagonal/REPO_AGENTS.md +46 -0
- package/presets/cursor/php-hexagonal/agents/README.md +36 -0
- package/presets/cursor/php-hexagonal/agents/api-contract-reviewer.md +23 -0
- package/presets/cursor/php-hexagonal/agents/build-verifier.md +52 -0
- package/presets/cursor/php-hexagonal/agents/ci-investigator.md +21 -0
- package/presets/cursor/php-hexagonal/agents/code-reviewer.md +47 -0
- package/presets/cursor/php-hexagonal/agents/codebase-analyzer.md +28 -0
- package/presets/cursor/php-hexagonal/agents/debugger.md +29 -0
- package/presets/cursor/php-hexagonal/agents/feature-developer.md +54 -0
- package/presets/cursor/php-hexagonal/agents/integration-test-generator.md +22 -0
- package/presets/cursor/php-hexagonal/agents/integration-test-healer.md +22 -0
- package/presets/cursor/php-hexagonal/agents/integration-test-planner.md +22 -0
- package/presets/cursor/php-hexagonal/agents/migration-specialist.md +31 -0
- package/presets/cursor/php-hexagonal/agents/performance-auditor.md +22 -0
- package/presets/cursor/php-hexagonal/agents/qa-tester.md +24 -0
- package/presets/cursor/php-hexagonal/agents/security-reviewer.md +20 -0
- package/presets/cursor/php-hexagonal/agents/solution-architect.md +28 -0
- package/presets/cursor/php-hexagonal/agents/task-analyst.md +32 -0
- package/presets/cursor/php-hexagonal/agents/task-router.md +101 -0
- package/presets/cursor/php-hexagonal/agents/tech-writer.md +15 -0
- package/presets/cursor/php-hexagonal/agents/unit-test-generator.md +21 -0
- package/presets/cursor/php-hexagonal/agents/unit-test-healer.md +13 -0
- package/presets/cursor/php-hexagonal/agents/unit-test-planner.md +26 -0
- package/presets/cursor/php-hexagonal/commands/README.md +54 -0
- package/presets/cursor/php-hexagonal/commands/feature-continue.md +19 -0
- package/presets/cursor/php-hexagonal/commands/feature-start.md +33 -0
- package/presets/cursor/php-hexagonal/commands/task-continue.md +50 -0
- package/presets/cursor/php-hexagonal/commands/task.md +55 -0
- package/presets/cursor/php-hexagonal/commands/technical-retro.md +85 -0
- package/presets/cursor/php-hexagonal/hooks/README.md +12 -0
- package/presets/cursor/php-hexagonal/hooks/chain-team-phases.sh +724 -0
- package/presets/cursor/php-hexagonal/hooks/examples/README.md +18 -0
- package/presets/cursor/php-hexagonal/hooks/examples/format-edited.example.sh +11 -0
- package/presets/cursor/php-hexagonal/hooks/examples/secret-guard.example.sh +10 -0
- package/presets/cursor/php-hexagonal/hooks/examples/test-on-save.example.sh +19 -0
- package/presets/cursor/php-hexagonal/hooks/guard-shell-command.sh +80 -0
- package/presets/cursor/php-hexagonal/hooks.json +17 -0
- package/presets/cursor/php-hexagonal/mcp.json +11 -0
- package/presets/cursor/php-hexagonal/rules/README.md +106 -0
- package/presets/cursor/php-hexagonal/rules/adapters-driven.mdc +41 -0
- package/presets/cursor/php-hexagonal/rules/adapters-driving.mdc +42 -0
- package/presets/cursor/php-hexagonal/rules/agent-team-intake.mdc +20 -0
- package/presets/cursor/php-hexagonal/rules/agent-team-orchestrator.mdc +202 -0
- package/presets/cursor/php-hexagonal/rules/anti-sycophancy-discipline.mdc +30 -0
- package/presets/cursor/php-hexagonal/rules/api-grpc.mdc +31 -0
- package/presets/cursor/php-hexagonal/rules/api-http.mdc +40 -0
- package/presets/cursor/php-hexagonal/rules/application-usecases.mdc +33 -0
- package/presets/cursor/php-hexagonal/rules/architecture-boundaries.mdc +36 -0
- package/presets/cursor/php-hexagonal/rules/code-quality-and-refactoring.mdc +54 -0
- package/presets/cursor/php-hexagonal/rules/code-review-mr.mdc +54 -0
- package/presets/cursor/php-hexagonal/rules/composition-root.mdc +37 -0
- package/presets/cursor/php-hexagonal/rules/design-guidance.mdc +112 -0
- package/presets/cursor/php-hexagonal/rules/domain-layer.mdc +39 -0
- package/presets/cursor/php-hexagonal/rules/feature-delivery-workflow.mdc +47 -0
- package/presets/cursor/php-hexagonal/rules/messaging-adapters.mdc +38 -0
- package/presets/cursor/php-hexagonal/rules/module-public-api.mdc +32 -0
- package/presets/cursor/php-hexagonal/rules/persistence-adapters.mdc +35 -0
- package/presets/cursor/php-hexagonal/rules/php-app-core.mdc +37 -0
- package/presets/cursor/php-hexagonal/rules/php-conventions.mdc +53 -0
- package/presets/cursor/php-hexagonal/rules/php-tooling.mdc +38 -0
- package/presets/cursor/php-hexagonal/rules/ports-interfaces.mdc +37 -0
- package/presets/cursor/php-hexagonal/rules/post-change-test.mdc +30 -0
- package/presets/cursor/php-hexagonal/rules/preset-layering.mdc +36 -0
- package/presets/cursor/php-hexagonal/rules/preset-no-cross-stack-leakage.mdc +69 -0
- package/presets/cursor/php-hexagonal/rules/preset-pr-checklist.mdc +39 -0
- package/presets/cursor/php-hexagonal/rules/preset-token-budget.mdc +41 -0
- package/presets/cursor/php-hexagonal/rules/preset-twin-sync.mdc +50 -0
- package/presets/cursor/php-hexagonal/rules/reference-features.mdc +40 -0
- package/presets/cursor/php-hexagonal/rules/security-php.mdc +33 -0
- package/presets/cursor/php-hexagonal/rules/technical-retro.mdc +16 -0
- package/presets/cursor/php-hexagonal/rules/tests-e2e.mdc +36 -0
- package/presets/cursor/php-hexagonal/rules/tests-integration.mdc +33 -0
- package/presets/cursor/php-hexagonal/rules/tests-unit.mdc +35 -0
- package/presets/cursor/php-hexagonal/skills/README.md +5 -0
- package/presets/cursor/php-hexagonal/skills/ci-investigation/SKILL.md +11 -0
- package/presets/cursor/php-hexagonal/skills/code-review/SKILL.md +25 -0
- package/presets/cursor/php-hexagonal/skills/debug-investigation/SKILL.md +15 -0
- package/presets/cursor/php-hexagonal/skills/feature-delivery/SKILL.md +30 -0
- package/presets/cursor/php-hexagonal/skills/integration-testing/SKILL.md +15 -0
- package/presets/cursor/php-hexagonal/skills/technical-retro/SKILL.md +54 -0
- package/presets/cursor/php-hexagonal/skills/unit-testing/SKILL.md +14 -0
- package/presets/cursor/php-hexagonal/skills/write-adr/SKILL.md +41 -0
- package/presets/cursor/php-hexagonal/team/README.md +52 -0
- package/presets/cursor/php-hexagonal/team/conventions.md +21 -0
- package/presets/cursor/php-hexagonal/team/fixtures/bugfix-standard.json +37 -0
- package/presets/cursor/php-hexagonal/team/fixtures/feature-full.json +25 -0
- package/presets/cursor/php-hexagonal/team/fixtures/feature-light.json +17 -0
- package/presets/cursor/php-laravel/AGENTS.md +39 -0
- package/presets/cursor/php-laravel/BUGBOT.md +9 -0
- package/presets/cursor/php-laravel/MCP.md +5 -0
- package/presets/cursor/php-laravel/README.md +33 -0
- package/presets/cursor/php-laravel/REPO_AGENTS.md +47 -0
- package/presets/cursor/php-laravel/agents/README.md +36 -0
- package/presets/cursor/php-laravel/agents/api-contract-reviewer.md +23 -0
- package/presets/cursor/php-laravel/agents/build-verifier.md +52 -0
- package/presets/cursor/php-laravel/agents/ci-investigator.md +21 -0
- package/presets/cursor/php-laravel/agents/code-reviewer.md +47 -0
- package/presets/cursor/php-laravel/agents/codebase-analyzer.md +28 -0
- package/presets/cursor/php-laravel/agents/debugger.md +29 -0
- package/presets/cursor/php-laravel/agents/feature-developer.md +54 -0
- package/presets/cursor/php-laravel/agents/integration-test-generator.md +22 -0
- package/presets/cursor/php-laravel/agents/integration-test-healer.md +22 -0
- package/presets/cursor/php-laravel/agents/integration-test-planner.md +22 -0
- package/presets/cursor/php-laravel/agents/migration-specialist.md +31 -0
- package/presets/cursor/php-laravel/agents/performance-auditor.md +22 -0
- package/presets/cursor/php-laravel/agents/qa-tester.md +30 -0
- package/presets/cursor/php-laravel/agents/security-reviewer.md +32 -0
- package/presets/cursor/php-laravel/agents/solution-architect.md +29 -0
- package/presets/cursor/php-laravel/agents/task-analyst.md +32 -0
- package/presets/cursor/php-laravel/agents/task-router.md +120 -0
- package/presets/cursor/php-laravel/agents/tech-writer.md +15 -0
- package/presets/cursor/php-laravel/agents/unit-test-generator.md +21 -0
- package/presets/cursor/php-laravel/agents/unit-test-healer.md +13 -0
- package/presets/cursor/php-laravel/agents/unit-test-planner.md +26 -0
- package/presets/cursor/php-laravel/commands/README.md +54 -0
- package/presets/cursor/php-laravel/commands/feature-continue.md +19 -0
- package/presets/cursor/php-laravel/commands/feature-start.md +33 -0
- package/presets/cursor/php-laravel/commands/task-continue.md +50 -0
- package/presets/cursor/php-laravel/commands/task.md +55 -0
- package/presets/cursor/php-laravel/commands/technical-retro.md +85 -0
- package/presets/cursor/php-laravel/hooks/README.md +12 -0
- package/presets/cursor/php-laravel/hooks/chain-team-phases.sh +724 -0
- package/presets/cursor/php-laravel/hooks/examples/README.md +18 -0
- package/presets/cursor/php-laravel/hooks/examples/format-edited.example.sh +11 -0
- package/presets/cursor/php-laravel/hooks/examples/secret-guard.example.sh +10 -0
- package/presets/cursor/php-laravel/hooks/examples/test-on-save.example.sh +19 -0
- package/presets/cursor/php-laravel/hooks/guard-shell-command.sh +80 -0
- package/presets/cursor/php-laravel/hooks.json +17 -0
- package/presets/cursor/php-laravel/mcp.json +11 -0
- package/presets/cursor/php-laravel/rules/README.md +111 -0
- package/presets/cursor/php-laravel/rules/actions-services.mdc +33 -0
- package/presets/cursor/php-laravel/rules/agent-team-intake.mdc +20 -0
- package/presets/cursor/php-laravel/rules/agent-team-orchestrator.mdc +203 -0
- package/presets/cursor/php-laravel/rules/anti-sycophancy-discipline.mdc +30 -0
- package/presets/cursor/php-laravel/rules/architecture-boundaries.mdc +37 -0
- package/presets/cursor/php-laravel/rules/code-quality-and-refactoring.mdc +54 -0
- package/presets/cursor/php-laravel/rules/code-review-mr.mdc +56 -0
- package/presets/cursor/php-laravel/rules/design-guidance.mdc +112 -0
- package/presets/cursor/php-laravel/rules/domain-layer.mdc +27 -0
- package/presets/cursor/php-laravel/rules/eloquent-persistence.mdc +34 -0
- package/presets/cursor/php-laravel/rules/events-listeners.mdc +34 -0
- package/presets/cursor/php-laravel/rules/feature-delivery-workflow.mdc +50 -0
- package/presets/cursor/php-laravel/rules/form-requests.mdc +32 -0
- package/presets/cursor/php-laravel/rules/http-layer.mdc +35 -0
- package/presets/cursor/php-laravel/rules/jobs-queues.mdc +44 -0
- package/presets/cursor/php-laravel/rules/laravel-app-core.mdc +35 -0
- package/presets/cursor/php-laravel/rules/laravel-conventions.mdc +41 -0
- package/presets/cursor/php-laravel/rules/module-public-api.mdc +31 -0
- package/presets/cursor/php-laravel/rules/php-tooling.mdc +39 -0
- package/presets/cursor/php-laravel/rules/policies-authorization.mdc +32 -0
- package/presets/cursor/php-laravel/rules/post-change-test.mdc +31 -0
- package/presets/cursor/php-laravel/rules/preset-layering.mdc +36 -0
- package/presets/cursor/php-laravel/rules/preset-no-cross-stack-leakage.mdc +69 -0
- package/presets/cursor/php-laravel/rules/preset-pr-checklist.mdc +39 -0
- package/presets/cursor/php-laravel/rules/preset-token-budget.mdc +41 -0
- package/presets/cursor/php-laravel/rules/preset-twin-sync.mdc +50 -0
- package/presets/cursor/php-laravel/rules/reference-features.mdc +42 -0
- package/presets/cursor/php-laravel/rules/routes-api.mdc +32 -0
- package/presets/cursor/php-laravel/rules/security-php.mdc +61 -0
- package/presets/cursor/php-laravel/rules/service-providers.mdc +31 -0
- package/presets/cursor/php-laravel/rules/technical-retro.mdc +16 -0
- package/presets/cursor/php-laravel/rules/tests-e2e.mdc +36 -0
- package/presets/cursor/php-laravel/rules/tests-integration.mdc +33 -0
- package/presets/cursor/php-laravel/rules/tests-unit.mdc +33 -0
- package/presets/cursor/php-laravel/skills/README.md +5 -0
- package/presets/cursor/php-laravel/skills/ci-investigation/SKILL.md +11 -0
- package/presets/cursor/php-laravel/skills/code-review/SKILL.md +25 -0
- package/presets/cursor/php-laravel/skills/debug-investigation/SKILL.md +15 -0
- package/presets/cursor/php-laravel/skills/feature-delivery/SKILL.md +30 -0
- package/presets/cursor/php-laravel/skills/integration-testing/SKILL.md +15 -0
- package/presets/cursor/php-laravel/skills/technical-retro/SKILL.md +54 -0
- package/presets/cursor/php-laravel/skills/unit-testing/SKILL.md +14 -0
- package/presets/cursor/php-laravel/skills/write-adr/SKILL.md +41 -0
- package/presets/cursor/php-laravel/team/README.md +28 -0
- package/presets/cursor/php-laravel/team/conventions.md +21 -0
- package/presets/cursor/php-laravel/team/fixtures/bugfix-standard.json +12 -0
- package/presets/cursor/php-laravel/team/fixtures/feature-full.json +15 -0
- package/presets/cursor/php-laravel/team/fixtures/feature-light.json +8 -0
|
@@ -50,6 +50,8 @@ if (!slug) {
|
|
|
50
50
|
const taskDir = path.join(TEAM_ROOT, 'tasks', slug);
|
|
51
51
|
const statusPath = path.join(taskDir, 'status.json');
|
|
52
52
|
const pipelinePath = path.join(taskDir, 'pipeline.json');
|
|
53
|
+
const METRICS_PATH = path.join(taskDir, 'metrics.json');
|
|
54
|
+
const METRICS_LOCK = `${METRICS_PATH}.lock`;
|
|
53
55
|
|
|
54
56
|
if (!fs.existsSync(statusPath)) {
|
|
55
57
|
process.stdout.write('{}');
|
|
@@ -57,18 +59,192 @@ if (!fs.existsSync(statusPath)) {
|
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
let status;
|
|
62
|
+
const now = new Date().toISOString();
|
|
63
|
+
const STACK = 'next';
|
|
64
|
+
const PLATFORM = 'cursor';
|
|
65
|
+
|
|
66
|
+
function waitForMetricsLock() {
|
|
67
|
+
for (let attempt = 0; attempt < 200; attempt += 1) {
|
|
68
|
+
try { fs.mkdirSync(METRICS_LOCK); return; } catch (error) {
|
|
69
|
+
if (error && error.code !== 'EEXIST') throw error;
|
|
70
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 10);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
throw new Error('metrics lock timeout');
|
|
74
|
+
}
|
|
75
|
+
let taskLockHeld = false;
|
|
76
|
+
function releaseTaskLock() {
|
|
77
|
+
if (!taskLockHeld) return;
|
|
78
|
+
taskLockHeld = false;
|
|
79
|
+
try { fs.rmdirSync(METRICS_LOCK); } catch {}
|
|
80
|
+
}
|
|
81
|
+
waitForMetricsLock();
|
|
82
|
+
taskLockHeld = true;
|
|
83
|
+
process.on('exit', releaseTaskLock);
|
|
60
84
|
try {
|
|
61
85
|
status = JSON.parse(fs.readFileSync(statusPath, 'utf8'));
|
|
62
86
|
} catch {
|
|
87
|
+
releaseTaskLock();
|
|
63
88
|
process.stdout.write('{}');
|
|
64
89
|
process.exit(0);
|
|
65
90
|
}
|
|
91
|
+
function mutateMetrics(mutator) {
|
|
92
|
+
const acquiredHere = !taskLockHeld;
|
|
93
|
+
if (acquiredHere) waitForMetricsLock();
|
|
94
|
+
try {
|
|
95
|
+
let metrics;
|
|
96
|
+
try { metrics = JSON.parse(fs.readFileSync(METRICS_PATH, 'utf8')); } catch {
|
|
97
|
+
const runId = status.metricsRunId || `${slug}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
98
|
+
status.metricsRunId = runId;
|
|
99
|
+
metrics = { schemaVersion: 1, task: { runId, slug, preset: 'ai-rules', stack: STACK, platform: PLATFORM, intent: status.intent || 'unknown', profile: 'unknown' }, events: [] };
|
|
100
|
+
metrics.events.push({ eventId: `${runId}:task_started`, type: 'task_started', at: now, source: 'hook', attributionConfidence: 'high' });
|
|
101
|
+
}
|
|
102
|
+
mutator(metrics);
|
|
103
|
+
const temporary = `${METRICS_PATH}.${process.pid}.${Date.now()}.tmp`;
|
|
104
|
+
fs.writeFileSync(temporary, JSON.stringify(metrics, null, 2) + '\n');
|
|
105
|
+
fs.renameSync(temporary, METRICS_PATH);
|
|
106
|
+
} finally {
|
|
107
|
+
if (acquiredHere) { try { fs.rmdirSync(METRICS_LOCK); } catch {} }
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function appendMetric(event) { mutateMetrics((metrics) => metrics.events.push({ eventId: `${metrics.task.runId}:${Date.now()}:${Math.random().toString(16).slice(2)}`, ...event })); }
|
|
111
|
+
function nextAttemptOrdinal(stepIndex, agent) {
|
|
112
|
+
try {
|
|
113
|
+
const metrics = JSON.parse(fs.readFileSync(METRICS_PATH, 'utf8'));
|
|
114
|
+
return metrics.events.reduce((highest, event) => event.type === 'attempt_started' && event.stepIndex === stepIndex && event.agent === agent ? Math.max(highest, Number(event.attempt) || 0) : highest, 0) + 1;
|
|
115
|
+
} catch { return 1; }
|
|
116
|
+
}
|
|
117
|
+
function roleFor(agent) {
|
|
118
|
+
if (/analyst|architect|router|migration/.test(agent || '')) return 'planning';
|
|
119
|
+
if (/verifier/.test(agent || '')) return 'validation';
|
|
120
|
+
if (/reviewer|auditor/.test(agent || '')) return 'review';
|
|
121
|
+
if (/test|qa/.test(agent || '')) return 'testing';
|
|
122
|
+
if (/writer/.test(agent || '')) return 'docs';
|
|
123
|
+
return 'implementation';
|
|
124
|
+
}
|
|
125
|
+
const DEFAULT_ARTIFACT_OUTPUT_IDS = {
|
|
126
|
+
'task-router': 'routing',
|
|
127
|
+
'task-analyst': 'analysis',
|
|
128
|
+
'solution-architect': 'architecture',
|
|
129
|
+
'migration-specialist': 'migration-plan',
|
|
130
|
+
debugger: 'debug',
|
|
131
|
+
'ci-investigator': 'ci',
|
|
132
|
+
'feature-developer': 'implementation',
|
|
133
|
+
'build-verifier': 'validation',
|
|
134
|
+
'code-reviewer': 'review',
|
|
135
|
+
'security-reviewer': 'security-review',
|
|
136
|
+
'accessibility-reviewer': 'a11y-review',
|
|
137
|
+
'performance-auditor': 'perf-report',
|
|
138
|
+
'api-contract-reviewer': 'api-contract-review',
|
|
139
|
+
'tech-writer': 'documentation',
|
|
140
|
+
};
|
|
141
|
+
function artifactOutputIdFor(step, agent) {
|
|
142
|
+
if (step && typeof step.artifactOutputId === 'string') return step.artifactOutputId;
|
|
143
|
+
if (step?.artifactOutputIds && typeof step.artifactOutputIds[agent] === 'string') return step.artifactOutputIds[agent];
|
|
144
|
+
return DEFAULT_ARTIFACT_OUTPUT_IDS[agent] || agent;
|
|
145
|
+
}
|
|
146
|
+
function activateAttempts(step, stepIndex) {
|
|
147
|
+
const active = { ...(status.activeAttempts || {}) }; const agents = getStepAgents(step);
|
|
148
|
+
const parallelGroupId = step.parallel && agents.length > 1 ? `${status.metricsRunId || slug}:step-${stepIndex}` : null;
|
|
149
|
+
for (const agent of agents) {
|
|
150
|
+
const attempt = nextAttemptOrdinal(stepIndex, agent); const runId = status.metricsRunId || `${slug}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
151
|
+
status.metricsRunId = runId; const attemptId = `${runId}:step-${stepIndex}:${agent}:attempt-${attempt}`;
|
|
152
|
+
if (active[attemptId]) continue;
|
|
153
|
+
active[attemptId] = { agent, stepIndex, attempt, startedAt: now, parallelGroupId };
|
|
154
|
+
appendMetric({ type: 'attempt_started', at: now, attemptId, stepIndex, stepLabel: step.label || null, agent, role: roleFor(agent), attempt, parallelGroupId, source: 'hook', attributionConfidence: 'high' });
|
|
155
|
+
}
|
|
156
|
+
status.activeAttempts = active;
|
|
157
|
+
}
|
|
158
|
+
function resolvedAttempt() {
|
|
159
|
+
const active = status.activeAttempts || {}; const entries = Object.entries(active);
|
|
160
|
+
const stableAttemptId = hookInput.attemptId;
|
|
161
|
+
if (stableAttemptId) {
|
|
162
|
+
return active[stableAttemptId]
|
|
163
|
+
? { attemptId: stableAttemptId, entry: active[stableAttemptId], confidence: 'high' }
|
|
164
|
+
: null;
|
|
165
|
+
}
|
|
166
|
+
if (entries.length === 1) return { attemptId: entries[0][0], entry: entries[0][1], confidence: 'high' };
|
|
167
|
+
try { const receipts = JSON.parse(fs.readFileSync(path.join(taskDir, '.metrics-receipts.json'), 'utf8')); const receipt = Array.isArray(receipts) ? receipts.find((item) => active[item.attemptId]) : null; if (receipt) return { attemptId: receipt.attemptId, entry: active[receipt.attemptId], confidence: 'fallback', source: 'agent' }; } catch {}
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
function readBoundReceiptOutcome(agent, step, resolved) {
|
|
171
|
+
if (!agent || !resolved) return { outcome: null, receiptRequired: false };
|
|
172
|
+
const manifestPath = path.join(taskDir, 'artifact-manifest.json');
|
|
173
|
+
if (!fs.existsSync(manifestPath)) return { outcome: null, receiptRequired: false };
|
|
174
|
+
try {
|
|
175
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
176
|
+
const artifacts = Array.isArray(manifest.artifacts) ? manifest.artifacts : [];
|
|
177
|
+
const expectedOutputId = artifactOutputIdFor(step, agent);
|
|
178
|
+
const attemptStartedAt = Date.parse(resolved.entry.startedAt);
|
|
179
|
+
const owned = artifacts
|
|
180
|
+
.filter((entry) => {
|
|
181
|
+
if (!entry || entry.producer !== agent || !entry.receipt || typeof entry.receipt.outcome !== 'string') return false;
|
|
182
|
+
const boundByAttempt = typeof entry.receipt.attemptId === 'string' && entry.receipt.attemptId === resolved.attemptId;
|
|
183
|
+
const boundByOutput = entry.receipt.attemptId == null && entry.id === expectedOutputId;
|
|
184
|
+
if (!boundByAttempt && !boundByOutput) return false;
|
|
185
|
+
const terminalAt = Date.parse(entry.timestamps?.completedAt || entry.timestamps?.updatedAt || '');
|
|
186
|
+
return Number.isFinite(terminalAt) && (!Number.isFinite(attemptStartedAt) || terminalAt >= attemptStartedAt);
|
|
187
|
+
})
|
|
188
|
+
.sort((a, b) => {
|
|
189
|
+
const ta = Date.parse(a.timestamps?.completedAt || a.timestamps?.updatedAt || 0) || 0;
|
|
190
|
+
const tb = Date.parse(b.timestamps?.completedAt || b.timestamps?.updatedAt || 0) || 0;
|
|
191
|
+
return tb - ta;
|
|
192
|
+
});
|
|
193
|
+
return { outcome: owned[0]?.receipt?.outcome || null, receiptRequired: true };
|
|
194
|
+
} catch {
|
|
195
|
+
return { outcome: null, receiptRequired: false };
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function reconcileStatusFromManifest(agent, step, resolved) {
|
|
199
|
+
const terminal = new Set(['completed', 'blocked', 'changes_requested', 'validation_failed']);
|
|
200
|
+
const { outcome, receiptRequired } = readBoundReceiptOutcome(agent, step, resolved);
|
|
201
|
+
if (terminal.has(outcome)) {
|
|
202
|
+
status.state = outcome;
|
|
203
|
+
return outcome;
|
|
204
|
+
}
|
|
205
|
+
if (receiptRequired) {
|
|
206
|
+
status.state = 'awaiting_artifact_receipt';
|
|
207
|
+
status.phase = 'blocked';
|
|
208
|
+
return status.state;
|
|
209
|
+
}
|
|
210
|
+
if (terminal.has(status.state)) return status.state;
|
|
211
|
+
// Host reported subagent completed and no blocking receipt → treat as completed for metrics/advance.
|
|
212
|
+
if (hookInput.status === 'completed') {
|
|
213
|
+
status.state = 'completed';
|
|
214
|
+
return 'completed';
|
|
215
|
+
}
|
|
216
|
+
return status.state;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function finishActiveAttempt() {
|
|
220
|
+
const resolved = resolvedAttempt(); if (!resolved) return null;
|
|
221
|
+
const durationMs = Date.parse(now) - Date.parse(resolved.entry.startedAt);
|
|
222
|
+
const outcome = ['completed', 'blocked', 'changes_requested', 'validation_failed'].includes(status.state) ? status.state : 'unknown';
|
|
223
|
+
appendMetric({ type: 'attempt_finished', at: now, attemptId: resolved.attemptId, outcome, durationMs: Number.isFinite(durationMs) && durationMs >= 0 ? durationMs : null, retryAfterFix: status.retryAfterFix || null, source: resolved.source || 'hook', attributionConfidence: resolved.confidence });
|
|
224
|
+
const active = { ...(status.activeAttempts || {}) }; delete active[resolved.attemptId]; status.activeAttempts = active; status.lastCompletedAttempt = { attemptId: resolved.attemptId, completedAt: now }; return { ...resolved, outcome };
|
|
225
|
+
}
|
|
226
|
+
function beginHumanGate() { const eventId = `${status.metricsRunId || slug}:gate:${Date.now()}`; appendMetric({ eventId, type: 'human_gate_started', at: now, source: 'hook', attributionConfidence: 'high' }); status.activeHumanGateEventId = eventId; }
|
|
227
|
+
function endHumanGateIfResumed() {
|
|
228
|
+
if (!status.activeHumanGateEventId || status.awaitingHumanGate || status.state === 'awaiting_approval') return;
|
|
229
|
+
appendMetric({ type: 'human_gate_ended', at: now, gateStartedEventId: status.activeHumanGateEventId, source: 'hook', attributionConfidence: 'high' });
|
|
230
|
+
delete status.activeHumanGateEventId;
|
|
231
|
+
}
|
|
232
|
+
function completeTaskMetrics() { appendMetric({ type: 'task_completed', at: now, outcome: status.state === 'completed' ? 'completed' : 'unknown', source: 'hook', attributionConfidence: 'high' }); }
|
|
233
|
+
function recordSkippedStep(step, stepIndex) {
|
|
234
|
+
for (const agent of getStepAgents(step)) {
|
|
235
|
+
const runId = status.metricsRunId || `${slug}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
236
|
+
status.metricsRunId = runId;
|
|
237
|
+
const attempt = nextAttemptOrdinal(stepIndex, agent);
|
|
238
|
+
appendMetric({ type: 'attempt_skipped', at: now, attemptId: `${runId}:step-${stepIndex}:${agent}:attempt-${attempt}`, stepIndex, stepLabel: step.label || null, agent, role: roleFor(agent), attempt, outcome: 'skipped', source: 'hook', attributionConfidence: 'high' });
|
|
239
|
+
}
|
|
240
|
+
}
|
|
66
241
|
|
|
67
|
-
const now = new Date().toISOString();
|
|
68
242
|
|
|
69
243
|
function writeStatus(next) {
|
|
70
244
|
status = { ...status, ...next, slug, updatedAt: now };
|
|
71
|
-
|
|
245
|
+
const temporary = `${statusPath}.${process.pid}.${Date.now()}.tmp`;
|
|
246
|
+
fs.writeFileSync(temporary, JSON.stringify(status, null, 2) + '\n');
|
|
247
|
+
fs.renameSync(temporary, statusPath);
|
|
72
248
|
}
|
|
73
249
|
|
|
74
250
|
function out(message) {
|
|
@@ -105,9 +281,8 @@ function skipIfMatches(skipIf, dir) {
|
|
|
105
281
|
|
|
106
282
|
function findNextExecutableStep(steps, startIdx, dir) {
|
|
107
283
|
for (let i = startIdx; i < steps.length; i++) {
|
|
108
|
-
if (!skipIfMatches(steps[i].skipIf, dir)) {
|
|
109
|
-
|
|
110
|
-
}
|
|
284
|
+
if (!skipIfMatches(steps[i].skipIf, dir)) return { step: steps[i], index: i };
|
|
285
|
+
recordSkippedStep(steps[i], i);
|
|
111
286
|
}
|
|
112
287
|
return null;
|
|
113
288
|
}
|
|
@@ -115,54 +290,54 @@ function findNextExecutableStep(steps, startIdx, dir) {
|
|
|
115
290
|
const AGENT_HANDOFF = {
|
|
116
291
|
'task-analyst': (s) =>
|
|
117
292
|
`Invoke task-analyst for slug "${s}". Write brief.md and decomposition.md under .cursor/team/tasks/${s}/. ` +
|
|
118
|
-
`
|
|
293
|
+
`Upsert the analysis receipt in artifact-manifest.json; do not mutate status.json lifecycle fields. Do not use legacy phase analysis.`,
|
|
119
294
|
debugger: (s) =>
|
|
120
295
|
`Invoke debugger subagent for slug "${s}". Investigate root cause; write debug-report.md with fixApplied: true/false. ` +
|
|
121
|
-
`
|
|
296
|
+
`Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`,
|
|
122
297
|
'solution-architect': (s) =>
|
|
123
|
-
`Invoke solution-architect for slug "${s}". Read brief.md; write architecture.md.
|
|
298
|
+
`Invoke solution-architect for slug "${s}". Read brief.md; write architecture.md. Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`,
|
|
124
299
|
'migration-specialist': (s) =>
|
|
125
|
-
`Invoke migration-specialist for slug "${s}". Read brief.md; write migration-plan.md.
|
|
300
|
+
`Invoke migration-specialist for slug "${s}". Read brief.md; write migration-plan.md. Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`,
|
|
126
301
|
'api-contract-reviewer': (s) =>
|
|
127
|
-
`Invoke api-contract-reviewer (readonly) for slug "${s}". Write api-contract-review.md.
|
|
302
|
+
`Invoke api-contract-reviewer (readonly) for slug "${s}". Write api-contract-review.md. Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`,
|
|
128
303
|
'ci-investigator': (s) =>
|
|
129
304
|
`Invoke ci-investigator for slug "${s}". Diagnose CI failure; write ci-report.md; apply minimal fix. ` +
|
|
130
|
-
`Use ci-investigation skill.
|
|
305
|
+
`Use ci-investigation skill. Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`,
|
|
131
306
|
'feature-developer': (s) =>
|
|
132
307
|
`Invoke feature-developer for slug "${s}". Read brief.md, decomposition.md, validation-report.md, review.md, architecture.md, migration-plan.md, api-contract-review.md, debug-report.md if present. ` +
|
|
133
|
-
`Follow feature-delivery-workflow.mdc and reference-features.mdc. Include unit tests for mappers/logic before handoff.
|
|
308
|
+
`Follow feature-delivery-workflow.mdc and reference-features.mdc. Include unit tests for mappers/logic before handoff. Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`,
|
|
134
309
|
'build-verifier': (s) =>
|
|
135
310
|
`Invoke build-verifier (readonly) for slug "${s}". Run lint:js, lint:css, type-check, and targeted unit tests from app/. ` +
|
|
136
|
-
`Write validation-report.md
|
|
311
|
+
`Write validation-report.md and emit receipt outcome completed or validation_failed. Do not edit production code.`,
|
|
137
312
|
'accessibility-reviewer': (s) =>
|
|
138
|
-
`Invoke accessibility-reviewer (readonly) for slug "${s}". Review UI diff; write a11y-review.md.
|
|
313
|
+
`Invoke accessibility-reviewer (readonly) for slug "${s}". Review UI diff; write a11y-review.md. Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`,
|
|
139
314
|
'performance-auditor': (s) =>
|
|
140
|
-
`Invoke performance-auditor (readonly) for slug "${s}". Write perf-report.md.
|
|
315
|
+
`Invoke performance-auditor (readonly) for slug "${s}". Write perf-report.md. Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`,
|
|
141
316
|
'code-reviewer': (s) =>
|
|
142
317
|
`Invoke code-reviewer subagent (readonly) for slug "${s}". Review git diff vs brief.md per code-review-mr.mdc. ` +
|
|
143
|
-
`
|
|
318
|
+
`Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`,
|
|
144
319
|
'security-reviewer': (s) =>
|
|
145
|
-
`Invoke security-reviewer (readonly) for slug "${s}". Write security-review.md.
|
|
320
|
+
`Invoke security-reviewer (readonly) for slug "${s}". Write security-review.md. Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`,
|
|
146
321
|
'qa-tester': (s, scope) =>
|
|
147
322
|
`Invoke qa-tester for slug "${s}"${scope ? ` (scope: ${scope})` : ''}. ` +
|
|
148
|
-
`Add/update tests per brief. Follow playwright-agents.mdc.
|
|
323
|
+
`Add/update tests per brief. Follow playwright-agents.mdc. Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`,
|
|
149
324
|
'unit-test-planner': (s) =>
|
|
150
|
-
`Invoke unit-test-planner for slug "${s}". Write unit-test-plan.md. Use unit-testing skill.
|
|
325
|
+
`Invoke unit-test-planner for slug "${s}". Write unit-test-plan.md. Use unit-testing skill. Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`,
|
|
151
326
|
'unit-test-generator': (s) =>
|
|
152
|
-
`Invoke unit-test-generator for slug "${s}". Implement specs from unit-test-plan.md. Use unit-testing skill.
|
|
327
|
+
`Invoke unit-test-generator for slug "${s}". Implement specs from unit-test-plan.md. Use unit-testing skill. Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`,
|
|
153
328
|
'unit-test-healer': (s) =>
|
|
154
|
-
`Invoke unit-test-healer for slug "${s}". Fix failing unit tests. Use unit-testing and debug-investigation skills.
|
|
329
|
+
`Invoke unit-test-healer for slug "${s}". Fix failing unit tests. Use unit-testing and debug-investigation skills. Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`,
|
|
155
330
|
'playwright-test-planner': (s) =>
|
|
156
331
|
`Invoke playwright-test-planner for slug "${s}". Create/update app/__tests__/e2e/**/*.cases.md. ` +
|
|
157
|
-
`Follow playwright-agents.mdc and the playwright-e2e skill.
|
|
332
|
+
`Follow playwright-agents.mdc and the playwright-e2e skill. Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`,
|
|
158
333
|
'playwright-test-generator': (s) =>
|
|
159
334
|
`Invoke playwright-test-generator for slug "${s}". Generate/update *.spec.ts from matching *.cases.md. ` +
|
|
160
|
-
`Use playwright MCP when available. Follow playwright-agents.mdc and the playwright-e2e skill.
|
|
335
|
+
`Use playwright MCP when available. Follow playwright-agents.mdc and the playwright-e2e skill. Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`,
|
|
161
336
|
'playwright-test-healer': (s) =>
|
|
162
337
|
`Invoke playwright-test-healer for slug "${s}". Fix failing/flaky e2e while preserving cases.md assertions. ` +
|
|
163
|
-
`Use playwright MCP when available. Follow playwright-agents.mdc and debug-investigation.
|
|
338
|
+
`Use playwright MCP when available. Follow playwright-agents.mdc and debug-investigation. Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`,
|
|
164
339
|
'tech-writer': (s) =>
|
|
165
|
-
`Invoke tech-writer for slug "${s}". Write documentation.md from task artifacts.
|
|
340
|
+
`Invoke tech-writer for slug "${s}". Write documentation.md from task artifacts. Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`,
|
|
166
341
|
};
|
|
167
342
|
|
|
168
343
|
const REVIEW_AGENTS = new Set([
|
|
@@ -172,16 +347,35 @@ const REVIEW_AGENTS = new Set([
|
|
|
172
347
|
'api-contract-reviewer',
|
|
173
348
|
]);
|
|
174
349
|
|
|
175
|
-
function
|
|
350
|
+
function metricsHandoff(agent) {
|
|
351
|
+
const matches = Object.entries(status.activeAttempts || {}).filter(([, entry]) => entry.agent === agent);
|
|
352
|
+
if (matches.length === 1) {
|
|
353
|
+
return ` Metrics attemptId: ${matches[0][0]}; write owned artifact-manifest receipt outcome. If the hook cannot identify a parallel stop, append a minimal { attemptId, outcome } receipt to .metrics-receipts.json; do not mutate status.json or calculate duration.`;
|
|
354
|
+
}
|
|
355
|
+
return ' Metrics: use the supplied attemptId when available; for a parallel completion, write a minimal { attemptId, outcome } receipt to .metrics-receipts.json rather than relying on currentAgent. Do not calculate duration.';
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function artifactHandoff(step, agent) {
|
|
359
|
+
const inputIds = Array.isArray(step?.artifactInputIds) ? step.artifactInputIds.join(', ') : 'manifest defaults';
|
|
360
|
+
return ` Artifact inputs: ${inputIds}; owned output ID: ${artifactOutputIdFor(step, agent)}. Bind the terminal receipt to the supplied attemptId.`;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function handoffForAgent(agent, scope, step = null) {
|
|
176
364
|
const fn = AGENT_HANDOFF[agent];
|
|
177
|
-
|
|
365
|
+
const handoff = fn ? fn(slug, scope) : `Invoke ${agent} subagent for slug "${slug}". Upsert the owned terminal receipt in artifact-manifest.json; do not mutate status.json lifecycle fields.`;
|
|
366
|
+
return handoff + artifactHandoff(step, agent) + metricsHandoff(agent);
|
|
178
367
|
}
|
|
179
368
|
|
|
180
369
|
function handoffForParallelStep(step) {
|
|
181
370
|
const agents = getStepAgents(step);
|
|
371
|
+
const attemptIds = Object.entries(status.activeAttempts || {})
|
|
372
|
+
.filter(([, entry]) => agents.includes(entry.agent))
|
|
373
|
+
.map(([attemptId, entry]) => `${entry.agent}=${attemptId}`);
|
|
182
374
|
return (
|
|
183
375
|
`Invoke IN PARALLEL (one message, multiple Task calls): ${agents.join(' AND ')} for slug "${slug}". ` +
|
|
184
|
-
`Each agent writes its artifact and
|
|
376
|
+
`Each agent writes its artifact and owned receipt; the hook records parallelCompleted from stops. Do not mutate status.json lifecycle fields. ` +
|
|
377
|
+
`Artifact inputs: ${Array.isArray(step.artifactInputIds) ? step.artifactInputIds.join(', ') : 'manifest defaults'}; owned output IDs: ${agents.map((agent) => `${agent}=${artifactOutputIdFor(step, agent)}`).join('; ')}. ` +
|
|
378
|
+
`Metrics attemptIds: ${attemptIds.join('; ')}. If the hook cannot identify a parallel stop, append a minimal { attemptId, outcome } receipt to .metrics-receipts.json; do not calculate duration.`
|
|
185
379
|
);
|
|
186
380
|
}
|
|
187
381
|
|
|
@@ -213,34 +407,42 @@ function legacyFlow() {
|
|
|
213
407
|
out(handoffForAgent('qa-tester'));
|
|
214
408
|
process.exit(0);
|
|
215
409
|
}
|
|
216
|
-
|
|
410
|
+
function scheduleLegacyRetry(agent, retryAfterFix) {
|
|
411
|
+
const stepIndex = typeof status.pipelineIndex === 'number' ? status.pipelineIndex : 0;
|
|
412
|
+
const predecessorAttemptId = status.lastCompletedAttempt?.attemptId || null;
|
|
413
|
+
appendMetric({ type: 'retry_scheduled', at: now, attemptId: predecessorAttemptId, nextAgent: agent, retryAfterFix: retryAfterFix || null, source: 'hook', attributionConfidence: 'unknown' });
|
|
414
|
+
activateAttempts({ agent }, stepIndex);
|
|
415
|
+
}
|
|
416
|
+
if (status.state === 'changes_requested') {
|
|
417
|
+
const reviewer = status.currentAgent;
|
|
418
|
+
if (!reviewer) {
|
|
419
|
+
process.stdout.write('{}');
|
|
420
|
+
process.exit(0);
|
|
421
|
+
}
|
|
422
|
+
scheduleLegacyRetry('feature-developer', reviewer);
|
|
217
423
|
writeStatus({
|
|
218
424
|
currentAgent: 'feature-developer',
|
|
219
425
|
state: 'in_progress',
|
|
220
426
|
phase: 'executing',
|
|
221
|
-
retryAfterFix:
|
|
427
|
+
retryAfterFix: reviewer,
|
|
222
428
|
});
|
|
223
|
-
out(
|
|
224
|
-
handoffForAgent('feature-developer') +
|
|
225
|
-
` After fixes, re-run ${status.currentAgent}.`,
|
|
226
|
-
);
|
|
429
|
+
out(handoffForAgent('feature-developer') + ` After fixes, re-run ${reviewer}.`);
|
|
227
430
|
process.exit(0);
|
|
228
431
|
}
|
|
229
432
|
if (status.state === 'validation_failed' && status.currentAgent === 'build-verifier') {
|
|
433
|
+
scheduleLegacyRetry('feature-developer', 'build-verifier');
|
|
230
434
|
writeStatus({
|
|
231
435
|
currentAgent: 'feature-developer',
|
|
232
436
|
state: 'in_progress',
|
|
233
437
|
phase: 'executing',
|
|
234
438
|
retryAfterFix: 'build-verifier',
|
|
235
439
|
});
|
|
236
|
-
out(
|
|
237
|
-
handoffForAgent('feature-developer') +
|
|
238
|
-
` Read validation-report.md. After fixes, re-run build-verifier.`,
|
|
239
|
-
);
|
|
440
|
+
out(handoffForAgent('feature-developer') + ' Read validation-report.md. After fixes, re-run build-verifier.');
|
|
240
441
|
process.exit(0);
|
|
241
442
|
}
|
|
242
443
|
if (status.state === 'completed' && status.retryAfterFix) {
|
|
243
444
|
const retry = status.retryAfterFix;
|
|
445
|
+
scheduleLegacyRetry(retry, null);
|
|
244
446
|
writeStatus({ currentAgent: retry, state: 'in_progress', retryAfterFix: null });
|
|
245
447
|
out(handoffForAgent(retry));
|
|
246
448
|
process.exit(0);
|
|
@@ -254,6 +456,56 @@ function legacyFlow() {
|
|
|
254
456
|
process.exit(0);
|
|
255
457
|
}
|
|
256
458
|
|
|
459
|
+
|
|
460
|
+
if (hookInput.action === 'end_human_gate') {
|
|
461
|
+
status.awaitingHumanGate = false;
|
|
462
|
+
if (status.state === 'awaiting_approval') {
|
|
463
|
+
status.state = 'in_progress';
|
|
464
|
+
status.phase = status.phase === 'human_gate' ? 'executing' : status.phase;
|
|
465
|
+
}
|
|
466
|
+
if (status.activeHumanGateEventId) {
|
|
467
|
+
appendMetric({
|
|
468
|
+
type: 'human_gate_ended',
|
|
469
|
+
at: now,
|
|
470
|
+
gateStartedEventId: status.activeHumanGateEventId,
|
|
471
|
+
source: 'orchestrator',
|
|
472
|
+
attributionConfidence: 'high',
|
|
473
|
+
});
|
|
474
|
+
delete status.activeHumanGateEventId;
|
|
475
|
+
}
|
|
476
|
+
if (hookInput.activateNext && fs.existsSync(pipelinePath)) {
|
|
477
|
+
let resumePipeline = null;
|
|
478
|
+
try { resumePipeline = JSON.parse(fs.readFileSync(pipelinePath, 'utf8')); } catch {}
|
|
479
|
+
if (resumePipeline) {
|
|
480
|
+
const resumeSteps = resumePipeline.steps || [];
|
|
481
|
+
const resumeStart = (typeof status.pipelineIndex === 'number' ? status.pipelineIndex : 0) + 1;
|
|
482
|
+
const resumeNext = findNextExecutableStep(resumeSteps, resumeStart, taskDir);
|
|
483
|
+
if (resumeNext) {
|
|
484
|
+
const resumeAgents = getStepAgents(resumeNext.step);
|
|
485
|
+
activateAttempts(resumeNext.step, resumeNext.index);
|
|
486
|
+
writeStatus({
|
|
487
|
+
pipelineIndex: resumeNext.index,
|
|
488
|
+
currentAgent: resumeAgents[0],
|
|
489
|
+
phase: 'executing',
|
|
490
|
+
state: 'in_progress',
|
|
491
|
+
awaitingHumanGate: false,
|
|
492
|
+
parallelCompleted: [],
|
|
493
|
+
});
|
|
494
|
+
if (resumeNext.step.parallel && resumeAgents.length > 1) out(handoffForParallelStep(resumeNext.step));
|
|
495
|
+
else out(handoffForAgent(resumeAgents[0], resumeNext.step.scope, resumeNext.step));
|
|
496
|
+
process.exit(0);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
writeStatus({
|
|
501
|
+
awaitingHumanGate: false,
|
|
502
|
+
state: status.state,
|
|
503
|
+
phase: status.phase,
|
|
504
|
+
});
|
|
505
|
+
process.stdout.write(JSON.stringify({ ok: true, action: 'end_human_gate', activeHumanGateEventId: status.activeHumanGateEventId || null }));
|
|
506
|
+
process.exit(0);
|
|
507
|
+
}
|
|
508
|
+
|
|
257
509
|
if (!fs.existsSync(pipelinePath)) {
|
|
258
510
|
legacyFlow();
|
|
259
511
|
}
|
|
@@ -266,7 +518,30 @@ try {
|
|
|
266
518
|
}
|
|
267
519
|
|
|
268
520
|
const steps = pipeline.steps || [];
|
|
521
|
+
const initialIdx = typeof status.pipelineIndex === 'number' ? status.pipelineIndex : 0;
|
|
522
|
+
const initialStep = steps[initialIdx];
|
|
523
|
+
const activeAttemptCountBeforeFinish = Object.keys(status.activeAttempts || {}).length;
|
|
524
|
+
const completingAgentHint = (() => {
|
|
525
|
+
const resolved = resolvedAttempt();
|
|
526
|
+
if (resolved?.entry?.agent) return resolved.entry.agent;
|
|
527
|
+
if (status.currentAgent) return status.currentAgent;
|
|
528
|
+
return getStepAgents(initialStep)[0];
|
|
529
|
+
})();
|
|
530
|
+
const reconcilingAttempt = resolvedAttempt();
|
|
531
|
+
reconcileStatusFromManifest(completingAgentHint, initialStep, reconcilingAttempt);
|
|
532
|
+
if (status.state === 'awaiting_artifact_receipt') {
|
|
533
|
+
writeStatus({});
|
|
534
|
+
process.stdout.write('{}');
|
|
535
|
+
process.exit(0);
|
|
536
|
+
}
|
|
537
|
+
const finishedAttempt = finishActiveAttempt();
|
|
538
|
+
if (!finishedAttempt && (hookInput.attemptId || activeAttemptCountBeforeFinish > 0)) {
|
|
539
|
+
process.stdout.write('{}');
|
|
540
|
+
process.exit(0);
|
|
541
|
+
}
|
|
542
|
+
endHumanGateIfResumed();
|
|
269
543
|
if (steps.length === 0 || pipeline.autoChain === false) {
|
|
544
|
+
writeStatus({});
|
|
270
545
|
process.stdout.write('{}');
|
|
271
546
|
process.exit(0);
|
|
272
547
|
}
|
|
@@ -276,68 +551,138 @@ if (status.awaitingHumanGate || status.state === 'awaiting_approval') {
|
|
|
276
551
|
process.exit(0);
|
|
277
552
|
}
|
|
278
553
|
|
|
279
|
-
|
|
280
|
-
|
|
554
|
+
function nearestPrecedingStepIndex(agent, fromIndex, fallback) {
|
|
555
|
+
for (let index = fromIndex - 1; index >= 0; index -= 1) {
|
|
556
|
+
if (getStepAgents(steps[index]).includes(agent)) return index;
|
|
557
|
+
}
|
|
558
|
+
const match = steps.findIndex((step) => getStepAgents(step).includes(agent));
|
|
559
|
+
return match >= 0 ? match : fallback;
|
|
560
|
+
}
|
|
561
|
+
function scheduleRetry(agent, retryAfterFix, predecessor, explicitStepIndex = null) {
|
|
562
|
+
const currentIndex = typeof status.pipelineIndex === 'number' ? status.pipelineIndex : 0;
|
|
563
|
+
const stepIndex = Number.isInteger(explicitStepIndex)
|
|
564
|
+
? explicitStepIndex
|
|
565
|
+
: nearestPrecedingStepIndex(agent, currentIndex, currentIndex);
|
|
566
|
+
const predecessorAttemptId = predecessor?.attemptId || status.lastCompletedAttempt?.attemptId || null;
|
|
567
|
+
appendMetric({ type: 'retry_scheduled', at: now, attemptId: predecessorAttemptId, nextAgent: agent, retryAfterFix: retryAfterFix || null, source: 'hook', attributionConfidence: predecessor ? predecessor.confidence : 'unknown' });
|
|
568
|
+
activateAttempts(steps[stepIndex] || { agent }, stepIndex);
|
|
569
|
+
return stepIndex;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
const idx = typeof status.pipelineIndex === 'number' ? status.pipelineIndex : 0;
|
|
573
|
+
const currentStep = steps[idx];
|
|
574
|
+
const completedAgent = finishedAttempt?.entry?.agent || status.currentAgent || getStepAgents(currentStep)[0];
|
|
575
|
+
const stepAgents = getStepAgents(currentStep);
|
|
576
|
+
|
|
577
|
+
if (currentStep?.parallel && stepAgents.length > 1) {
|
|
578
|
+
const done = [...(status.parallelCompleted || [])];
|
|
579
|
+
const outcomes = { ...(status.parallelOutcomes || {}) };
|
|
580
|
+
if (finishedAttempt && completedAgent) {
|
|
581
|
+
if (!done.includes(completedAgent)) done.push(completedAgent);
|
|
582
|
+
outcomes[completedAgent] = {
|
|
583
|
+
outcome: finishedAttempt.outcome || status.state,
|
|
584
|
+
attemptId: finishedAttempt.attemptId,
|
|
585
|
+
confidence: finishedAttempt.confidence,
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
writeStatus({ parallelCompleted: done, parallelOutcomes: outcomes });
|
|
589
|
+
const remaining = stepAgents.filter((agent) => !done.includes(agent));
|
|
590
|
+
if (remaining.length > 0) {
|
|
591
|
+
process.stdout.write('{}');
|
|
592
|
+
process.exit(0);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
const blockedProducer = stepAgents.find((agent) => outcomes[agent]?.outcome === 'blocked');
|
|
596
|
+
if (blockedProducer) {
|
|
597
|
+
writeStatus({ parallelCompleted: [], parallelOutcomes: {}, state: 'blocked', phase: 'blocked', currentAgent: blockedProducer });
|
|
598
|
+
process.stdout.write('{}');
|
|
599
|
+
process.exit(0);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
const retryReviewer = stepAgents.find((agent) => outcomes[agent]?.outcome === 'changes_requested');
|
|
603
|
+
if (retryReviewer) {
|
|
604
|
+
const retryAfterFixStepIndex = idx;
|
|
605
|
+
const predecessor = outcomes[retryReviewer]
|
|
606
|
+
? {
|
|
607
|
+
attemptId: outcomes[retryReviewer].attemptId,
|
|
608
|
+
confidence: outcomes[retryReviewer].confidence,
|
|
609
|
+
}
|
|
610
|
+
: finishedAttempt;
|
|
611
|
+
const developerIndex = scheduleRetry('feature-developer', retryReviewer, predecessor);
|
|
612
|
+
writeStatus({
|
|
613
|
+
pipelineIndex: developerIndex,
|
|
614
|
+
currentAgent: 'feature-developer',
|
|
615
|
+
state: 'in_progress',
|
|
616
|
+
phase: 'executing',
|
|
617
|
+
retryAfterFix: retryReviewer,
|
|
618
|
+
retryAfterFixStepIndex,
|
|
619
|
+
parallelCompleted: [],
|
|
620
|
+
parallelOutcomes: {},
|
|
621
|
+
});
|
|
622
|
+
out(handoffForAgent('feature-developer', steps[developerIndex]?.scope, steps[developerIndex]) + ` After fixes, re-run ${retryReviewer}.`);
|
|
623
|
+
process.exit(0);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
writeStatus({ parallelCompleted: [], parallelOutcomes: {}, state: 'completed' });
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
if (status.state === 'blocked') {
|
|
630
|
+
writeStatus({ state: 'blocked', phase: 'blocked', currentAgent: completedAgent });
|
|
631
|
+
process.stdout.write('{}');
|
|
632
|
+
process.exit(0);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
if (status.state === 'changes_requested') {
|
|
636
|
+
const reviewer = status.currentAgent || finishedAttempt?.entry?.agent;
|
|
637
|
+
if (!reviewer) {
|
|
638
|
+
process.stdout.write('{}');
|
|
639
|
+
process.exit(0);
|
|
640
|
+
}
|
|
641
|
+
const retryAfterFixStepIndex = typeof status.pipelineIndex === 'number' ? status.pipelineIndex : 0;
|
|
642
|
+
const developerIndex = scheduleRetry('feature-developer', reviewer, finishedAttempt);
|
|
281
643
|
writeStatus({
|
|
644
|
+
pipelineIndex: developerIndex,
|
|
282
645
|
currentAgent: 'feature-developer',
|
|
283
646
|
state: 'in_progress',
|
|
284
647
|
phase: 'executing',
|
|
285
648
|
retryAfterFix: reviewer,
|
|
649
|
+
retryAfterFixStepIndex,
|
|
286
650
|
});
|
|
287
|
-
out(
|
|
288
|
-
handoffForAgent('feature-developer') +
|
|
289
|
-
` After fixes, re-run ${reviewer}.`,
|
|
290
|
-
);
|
|
651
|
+
out(handoffForAgent('feature-developer', steps[developerIndex]?.scope, steps[developerIndex]) + ` After fixes, re-run ${reviewer}.`);
|
|
291
652
|
process.exit(0);
|
|
292
653
|
}
|
|
293
654
|
|
|
294
655
|
if (status.state === 'validation_failed' && status.currentAgent === 'build-verifier') {
|
|
656
|
+
const retryAfterFixStepIndex = typeof status.pipelineIndex === 'number' ? status.pipelineIndex : 0;
|
|
657
|
+
const developerIndex = scheduleRetry('feature-developer', 'build-verifier', finishedAttempt);
|
|
295
658
|
writeStatus({
|
|
659
|
+
pipelineIndex: developerIndex,
|
|
296
660
|
currentAgent: 'feature-developer',
|
|
297
661
|
state: 'in_progress',
|
|
298
662
|
phase: 'executing',
|
|
299
663
|
retryAfterFix: 'build-verifier',
|
|
664
|
+
retryAfterFixStepIndex,
|
|
300
665
|
});
|
|
301
|
-
out(
|
|
302
|
-
handoffForAgent('feature-developer') +
|
|
303
|
-
` Read validation-report.md. After fixes, re-run build-verifier.`,
|
|
304
|
-
);
|
|
666
|
+
out(handoffForAgent('feature-developer', steps[developerIndex]?.scope, steps[developerIndex]) + ' Read validation-report.md. After fixes, re-run build-verifier.');
|
|
305
667
|
process.exit(0);
|
|
306
668
|
}
|
|
307
669
|
|
|
308
670
|
if (status.state === 'completed' && status.retryAfterFix) {
|
|
309
671
|
const retry = status.retryAfterFix;
|
|
310
|
-
|
|
311
|
-
|
|
672
|
+
const retryIndex = scheduleRetry(retry, null, finishedAttempt, status.retryAfterFixStepIndex);
|
|
673
|
+
writeStatus({ pipelineIndex: retryIndex, currentAgent: retry, state: 'in_progress', retryAfterFix: null, retryAfterFixStepIndex: null });
|
|
674
|
+
out(handoffForAgent(retry, steps[retryIndex]?.scope, steps[retryIndex]));
|
|
312
675
|
process.exit(0);
|
|
313
676
|
}
|
|
314
677
|
|
|
315
|
-
const idx = typeof status.pipelineIndex === 'number' ? status.pipelineIndex : 0;
|
|
316
|
-
const currentStep = steps[idx];
|
|
317
678
|
if (!currentStep) {
|
|
318
679
|
writeStatus({ phase: 'done', state: 'completed', currentAgent: null });
|
|
319
680
|
out(`Pipeline complete for "${slug}". Run /technical-retro ${slug}.`);
|
|
320
681
|
process.exit(0);
|
|
321
682
|
}
|
|
322
683
|
|
|
323
|
-
const completedAgent = status.currentAgent || getStepAgents(currentStep)[0];
|
|
324
|
-
const stepAgents = getStepAgents(currentStep);
|
|
325
|
-
|
|
326
|
-
if (currentStep.parallel && stepAgents.length > 1) {
|
|
327
|
-
const done = [...(status.parallelCompleted || [])];
|
|
328
|
-
if (completedAgent && !done.includes(completedAgent)) {
|
|
329
|
-
done.push(completedAgent);
|
|
330
|
-
}
|
|
331
|
-
writeStatus({ parallelCompleted: done });
|
|
332
|
-
const remaining = stepAgents.filter((a) => !done.includes(a));
|
|
333
|
-
if (remaining.length > 0) {
|
|
334
|
-
process.stdout.write('{}');
|
|
335
|
-
process.exit(0);
|
|
336
|
-
}
|
|
337
|
-
writeStatus({ parallelCompleted: [] });
|
|
338
|
-
}
|
|
339
|
-
|
|
340
684
|
if (hasGateAfterStep(currentStep, pipeline.humanGates)) {
|
|
685
|
+
beginHumanGate();
|
|
341
686
|
writeStatus({
|
|
342
687
|
awaitingHumanGate: true,
|
|
343
688
|
state: 'awaiting_approval',
|
|
@@ -349,6 +694,7 @@ if (hasGateAfterStep(currentStep, pipeline.humanGates)) {
|
|
|
349
694
|
|
|
350
695
|
const next = findNextExecutableStep(steps, idx + 1, taskDir);
|
|
351
696
|
if (!next) {
|
|
697
|
+
completeTaskMetrics();
|
|
352
698
|
writeStatus({
|
|
353
699
|
pipelineIndex: steps.length,
|
|
354
700
|
phase: 'done',
|
|
@@ -363,6 +709,7 @@ if (!next) {
|
|
|
363
709
|
const { step: nextStep, index: nextIdx } = next;
|
|
364
710
|
const nextAgents = getStepAgents(nextStep);
|
|
365
711
|
|
|
712
|
+
activateAttempts(nextStep, nextIdx);
|
|
366
713
|
writeStatus({
|
|
367
714
|
pipelineIndex: nextIdx,
|
|
368
715
|
currentAgent: nextAgents[0],
|
|
@@ -375,6 +722,6 @@ writeStatus({
|
|
|
375
722
|
if (nextStep.parallel && nextAgents.length > 1) {
|
|
376
723
|
out(handoffForParallelStep(nextStep));
|
|
377
724
|
} else {
|
|
378
|
-
out(handoffForAgent(nextAgents[0], nextStep.scope));
|
|
725
|
+
out(handoffForAgent(nextAgents[0], nextStep.scope, nextStep));
|
|
379
726
|
}
|
|
380
727
|
NODE
|