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