@williambeto/ai-workflow 1.19.0 → 2.1.0
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 +56 -837
- package/PUBLISH_MANIFEST.json +34 -0
- package/README.md +70 -149
- package/{packages/ai-workflow/bin → bin}/ai-workflow.js +0 -0
- package/dist-assets/AGENTS.md +27 -0
- package/dist-assets/agents/astra.md +63 -0
- package/dist-assets/agents/atlas.md +169 -0
- package/dist-assets/agents/nexus.md +42 -0
- package/dist-assets/agents/orion.md +44 -0
- package/dist-assets/agents/phoenix.md +42 -0
- package/dist-assets/agents/sage.md +54 -0
- package/dist-assets/commands/README.md +14 -0
- package/dist-assets/commands/atlas.md +12 -0
- package/dist-assets/commands/audit.md +10 -0
- package/dist-assets/commands/deploy.md +12 -0
- package/dist-assets/commands/discover.md +10 -0
- package/dist-assets/commands/implement.md +28 -0
- package/dist-assets/commands/optimize-tokens.md +10 -0
- package/dist-assets/commands/plan.md +10 -0
- package/dist-assets/commands/release.md +12 -0
- package/dist-assets/commands/run.md +26 -0
- package/dist-assets/commands/spec-create.md +10 -0
- package/dist-assets/commands/spec-implement.md +10 -0
- package/dist-assets/commands/spec-review.md +10 -0
- package/dist-assets/commands/update-memory.md +10 -0
- package/dist-assets/commands/validate.md +12 -0
- package/dist-assets/docs/INDEX.md +21 -0
- package/dist-assets/docs/QUICKSTART.md +23 -0
- package/dist-assets/docs/adr/ADR-0000.md +19 -0
- package/dist-assets/docs/adr/ADR-0001.md +45 -0
- package/dist-assets/docs/adr/ADR-0002.md +62 -0
- package/dist-assets/docs/adr/ADR-0003.md +60 -0
- package/dist-assets/docs/adr/ADR-0004.md +71 -0
- package/dist-assets/docs/adr/ADR-0005.md +22 -0
- package/dist-assets/docs/adr/ADR-0006.md +82 -0
- package/dist-assets/docs/adr/ADR-0007.md +78 -0
- package/dist-assets/docs/api-engine-reference.md +7 -0
- package/{docs → dist-assets/docs}/architecture-policy.md +1 -1
- package/dist-assets/docs/cli-reference.md +27 -0
- package/dist-assets/docs/compatibility/provider-usage.md +38 -0
- package/dist-assets/docs/compatibility/runtime-matrix.md +30 -0
- package/dist-assets/docs/consumer-onboarding.md +17 -0
- package/dist-assets/docs/contributing-guide.md +11 -0
- package/{docs → dist-assets/docs}/design-patterns-policy.md +2 -2
- package/dist-assets/docs/full-documentation.md +113 -0
- package/{docs → dist-assets/docs}/npm-consumer-quickstart.md +18 -46
- package/dist-assets/docs/opencode-readme.md +8 -0
- package/dist-assets/docs/policies/01-BRANCH_GATE.md +63 -0
- package/dist-assets/docs/policies/02-SDD_METHODOLOGY.md +95 -0
- package/dist-assets/docs/policies/03-QUALITY_GATE.md +22 -0
- package/dist-assets/docs/policies/05-AGENT_CONTRACT.md +7 -0
- package/dist-assets/docs/policies/06-FINAL_EVIDENCE_CONTRACT.md +31 -0
- package/dist-assets/docs/policies/07-RELEASE_GATE.md +47 -0
- package/dist-assets/docs/policies/08-PRODUCT_TRUTHFULNESS_AND_PROJECT_DOCS.md +18 -0
- package/dist-assets/docs/policies/09-SPEC_VISIBILITY_AND_PUBLICATION.md +28 -0
- package/dist-assets/docs/policies/10-BEHAVIORAL_CONTRACT_HARDENING.md +9 -0
- package/dist-assets/docs/policies/11-EXECUTABLE_DELEGATION_AND_TRUTHFULNESS.md +7 -0
- package/dist-assets/docs/policies/ORCHESTRATION_PROTOCOL.md +15 -0
- package/dist-assets/docs/policies/PROCEDURE_DELIVERY_ARTIFACTS.md +21 -0
- package/dist-assets/docs/policies/PROCEDURE_DOCUMENTATION_CHECKLIST.md +24 -0
- package/dist-assets/docs/policies/PROCEDURE_UI_CHECKLIST.md +54 -0
- package/dist-assets/docs/profiles/README.md +19 -0
- package/dist-assets/docs/profiles/backend-api.md +5 -0
- package/dist-assets/docs/profiles/documentation.md +3 -0
- package/dist-assets/docs/profiles/frontend-product.md +19 -0
- package/dist-assets/docs/profiles/frontend-utility.md +19 -0
- package/dist-assets/docs/profiles/refactor.md +3 -0
- package/dist-assets/docs/profiles/security-review.md +3 -0
- package/dist-assets/docs/references/frontend-quality/landing-page-quality-checklist.md +11 -0
- package/dist-assets/docs/references/frontend-quality/product-copy-truthfulness.md +7 -0
- package/dist-assets/docs/references/frontend-quality/quality-failure-examples.md +20 -0
- package/dist-assets/docs/references/frontend-quality/visual-composition-patterns.md +10 -0
- package/dist-assets/docs/specs/runtime-operational-contract.md +39 -0
- package/dist-assets/docs/troubleshooting-guide.md +21 -0
- package/dist-assets/examples/README.md +10 -0
- package/dist-assets/examples/autopilot-cycle/00-CONTEXT.md +3 -0
- package/dist-assets/examples/autopilot-cycle/01-requirement.md +16 -0
- package/dist-assets/examples/autopilot-cycle/02-gate-a-check.md +23 -0
- package/dist-assets/examples/autopilot-cycle/03-orion-planning.md +20 -0
- package/dist-assets/examples/autopilot-cycle/04-astra-implementation.md +17 -0
- package/dist-assets/examples/autopilot-cycle/05-sage-validation.md +15 -0
- package/dist-assets/examples/autopilot-cycle/06-phoenix-healing.md +12 -0
- package/dist-assets/examples/autopilot-cycle/07-orchestration-report.md +18 -0
- package/dist-assets/examples/backend-api/00-CONTEXT.md +12 -0
- package/dist-assets/examples/backend-api/01-requirement.md +19 -0
- package/dist-assets/examples/backend-api/02-functional-spec.md +20 -0
- package/dist-assets/examples/backend-api/03-technical-plan.md +15 -0
- package/dist-assets/examples/backend-api/04-pr-breakdown.md +10 -0
- package/dist-assets/examples/backend-api/05-execution-handoff.md +13 -0
- package/dist-assets/examples/backend-api/06-validation-report.md +11 -0
- package/dist-assets/examples/backend-api/07-orchestration-report.md +7 -0
- package/dist-assets/examples/blocked-scenarios/00-CONTEXT.md +9 -0
- package/dist-assets/examples/blocked-scenarios/01-branch-gate-block.md +12 -0
- package/dist-assets/examples/blocked-scenarios/02-quality-gate-block.md +13 -0
- package/dist-assets/examples/blocked-scenarios/03-scope-creep-block.md +13 -0
- package/dist-assets/examples/blocked-scenarios/04-unblock-resolution.md +9 -0
- package/dist-assets/examples/blocked-scenarios/05-orchestration-decision-log.md +11 -0
- package/dist-assets/examples/bugfix-critical/00-CONTEXT.md +12 -0
- package/dist-assets/examples/bugfix-critical/01-bug-report.md +11 -0
- package/dist-assets/examples/bugfix-critical/02-diagnosis-hypothesis.md +11 -0
- package/dist-assets/examples/bugfix-critical/03-technical-plan.md +12 -0
- package/dist-assets/examples/bugfix-critical/04-implementation-handoff.md +8 -0
- package/dist-assets/examples/bugfix-critical/05-validation-report.md +10 -0
- package/dist-assets/examples/bugfix-critical/06-orchestration-report.md +7 -0
- package/dist-assets/examples/cli-package/00-CONTEXT.md +9 -0
- package/dist-assets/examples/cli-package/01-requirement.md +14 -0
- package/dist-assets/examples/cli-package/02-technical-spec.md +16 -0
- package/dist-assets/examples/cli-package/03-technical-plan.md +12 -0
- package/dist-assets/examples/cli-package/04-pr-breakdown.md +9 -0
- package/dist-assets/examples/cli-package/05-release-report.md +15 -0
- package/dist-assets/examples/docs-only-repo/01-requirement.md +31 -0
- package/dist-assets/examples/docs-only-repo/02-functional-spec.md +25 -0
- package/dist-assets/examples/docs-only-repo/03-technical-plan.md +21 -0
- package/dist-assets/examples/docs-only-repo/04-pr-breakdown.md +13 -0
- package/dist-assets/examples/docs-only-repo/05-execution-handoff.md +17 -0
- package/dist-assets/examples/docs-only-repo/06-validation-report.md +16 -0
- package/dist-assets/examples/docs-only-repo/README.md +26 -0
- package/dist-assets/examples/full-stack-checkout/00-CONTEXT.md +9 -0
- package/dist-assets/examples/full-stack-checkout/01-requirement.md +12 -0
- package/dist-assets/examples/full-stack-checkout/02-functional-spec.md +15 -0
- package/dist-assets/examples/full-stack-checkout/03-technical-plan.md +15 -0
- package/dist-assets/examples/full-stack-checkout/04-pr-breakdown.md +8 -0
- package/dist-assets/examples/full-stack-checkout/05-execution-handoff.md +14 -0
- package/dist-assets/examples/full-stack-checkout/06-validation-report.md +12 -0
- package/dist-assets/examples/healing-cycle/00-CONTEXT.md +15 -0
- package/dist-assets/examples/healing-cycle/01-broken-implementation.md +10 -0
- package/dist-assets/examples/healing-cycle/02-sage-fails.md +14 -0
- package/dist-assets/examples/healing-cycle/03-phoenix-diagnosis.md +17 -0
- package/dist-assets/examples/healing-cycle/04-phoenix-fix.md +18 -0
- package/dist-assets/examples/healing-cycle/05-sage-revalidation.md +12 -0
- package/dist-assets/examples/healing-cycle/06-orchestration-log.md +14 -0
- package/dist-assets/examples/infra-deploy/00-CONTEXT.md +9 -0
- package/dist-assets/examples/infra-deploy/01-operational-goal.md +12 -0
- package/dist-assets/examples/infra-deploy/02-architecture-specs.md +15 -0
- package/dist-assets/examples/infra-deploy/03-implementation-plan.md +14 -0
- package/dist-assets/examples/infra-deploy/04-step-breakdown.md +9 -0
- package/dist-assets/examples/infra-deploy/05-execution-handoff.md +13 -0
- package/dist-assets/examples/infra-deploy/06-operational-report.md +11 -0
- package/dist-assets/examples/multi-pr-release/00-CONTEXT.md +9 -0
- package/dist-assets/examples/multi-pr-release/01-requirement.md +13 -0
- package/dist-assets/examples/multi-pr-release/02-strategic-plan.md +13 -0
- package/dist-assets/examples/multi-pr-release/03-pr-breakdown.md +14 -0
- package/dist-assets/examples/multi-pr-release/04-release-plan.md +12 -0
- package/dist-assets/examples/multi-pr-release/05-orchestration-report.md +7 -0
- package/dist-assets/examples/nuxt-dashboard/01-requirement.md +81 -0
- package/dist-assets/examples/nuxt-dashboard/02-functional-spec.md +88 -0
- package/dist-assets/examples/nuxt-dashboard/03-technical-plan.md +76 -0
- package/dist-assets/examples/nuxt-dashboard/04-pr-breakdown.md +219 -0
- package/dist-assets/examples/nuxt-dashboard/05-execution-handoff.md +88 -0
- package/dist-assets/examples/nuxt-dashboard/06-validation-report.md +56 -0
- package/dist-assets/examples/nuxt-dashboard/07-orchestration-report.md +79 -0
- package/dist-assets/examples/nuxt-dashboard/README.md +52 -0
- package/dist-assets/examples/react-dashboard/01-requirement.md +84 -0
- package/dist-assets/examples/react-dashboard/02-functional-spec.md +88 -0
- package/dist-assets/examples/react-dashboard/03-technical-plan.md +76 -0
- package/dist-assets/examples/react-dashboard/04-pr-breakdown.md +218 -0
- package/dist-assets/examples/react-dashboard/05-execution-handoff.md +13 -0
- package/dist-assets/examples/react-dashboard/06-validation-report.md +12 -0
- package/dist-assets/examples/react-dashboard/07-orchestration-report.md +7 -0
- package/dist-assets/examples/react-dashboard/README.md +70 -0
- package/dist-assets/examples/refactoring-service/00-CONTEXT.md +9 -0
- package/dist-assets/examples/refactoring-service/01-debt-report.md +12 -0
- package/dist-assets/examples/refactoring-service/02-behavior-spec.md +11 -0
- package/dist-assets/examples/refactoring-service/03-technical-plan.md +13 -0
- package/dist-assets/examples/refactoring-service/04-pr-breakdown.md +9 -0
- package/dist-assets/examples/refactoring-service/05-execution-handoff.md +14 -0
- package/dist-assets/examples/refactoring-service/06-stability-report.md +12 -0
- package/dist-assets/examples/sdd-cycle/00-CONTEXT.md +12 -0
- package/dist-assets/examples/sdd-cycle/01-raw-request.md +13 -0
- package/dist-assets/examples/sdd-cycle/02-spec-creation.md +18 -0
- package/dist-assets/examples/sdd-cycle/03-spec-review.md +12 -0
- package/dist-assets/examples/sdd-cycle/04-technical-plan.md +16 -0
- package/dist-assets/examples/sdd-cycle/05-pr-breakdown.md +9 -0
- package/dist-assets/examples/sdd-cycle/06-spec-implement.md +13 -0
- package/dist-assets/examples/sdd-cycle/07-validation-against-spec.md +13 -0
- package/dist-assets/examples/wordpress-theme/01-requirement.md +29 -0
- package/dist-assets/examples/wordpress-theme/02-functional-spec.md +22 -0
- package/dist-assets/examples/wordpress-theme/03-technical-plan.md +22 -0
- package/dist-assets/examples/wordpress-theme/04-pr-breakdown.md +14 -0
- package/dist-assets/examples/wordpress-theme/05-execution-handoff.md +17 -0
- package/dist-assets/examples/wordpress-theme/06-validation-report.md +16 -0
- package/dist-assets/examples/wordpress-theme/README.md +32 -0
- package/{harness → dist-assets/harness}/handoffs/HANDOFF.template.md +2 -2
- package/{harness → dist-assets/harness}/workflows/agent-evaluation-checklist.md +5 -5
- package/{harness → dist-assets/harness}/workflows/implement-review-validate.md +24 -0
- package/{harness → dist-assets/harness}/workflows/multi-agent-handoff.md +4 -4
- package/{harness → dist-assets/harness}/workflows/planner-executor-workflow.md +5 -5
- package/{harness → dist-assets/harness}/workflows/requirement-to-pr.md +1 -1
- package/dist-assets/runbooks/agent-delegation-workflow.md +50 -0
- package/dist-assets/runbooks/apply-starter-to-real-project.md +45 -0
- package/dist-assets/runbooks/commands-cheatsheet.md +44 -0
- package/dist-assets/runbooks/how-to-use-skills.md +44 -0
- package/dist-assets/runbooks/private-spec-publication-safety.md +35 -0
- package/{runbooks → dist-assets/runbooks}/spec-driven-development.md +3 -6
- package/dist-assets/runbooks/tutorial-walkthroughs.md +23 -0
- package/dist-assets/runbooks/use-linear-for-operational-planning.md +45 -0
- package/dist-assets/runbooks/use-napkin-project-memory.md +33 -0
- package/dist-assets/skills/architecture/SKILL.md +166 -0
- package/dist-assets/skills/backend-development/SKILL.md +166 -0
- package/dist-assets/skills/deployment/SKILL.md +166 -0
- package/dist-assets/skills/design-principles/SKILL.md +166 -0
- package/dist-assets/skills/documentation/SKILL.md +171 -0
- package/dist-assets/skills/frontend-development/SKILL.md +225 -0
- package/dist-assets/skills/full-stack-development/SKILL.md +166 -0
- package/dist-assets/skills/optimize-tokens/SKILL.md +166 -0
- package/dist-assets/skills/pr-workflow/SKILL.md +166 -0
- package/dist-assets/skills/product-discovery/SKILL.md +166 -0
- package/dist-assets/skills/product-planning/SKILL.md +166 -0
- package/dist-assets/skills/project-memory/SKILL.md +166 -0
- package/dist-assets/skills/prompt-engineer/SKILL.md +166 -0
- package/dist-assets/skills/qa-workflow/SKILL.md +186 -0
- package/dist-assets/skills/refactoring/SKILL.md +166 -0
- package/dist-assets/skills/release-workflow/SKILL.md +166 -0
- package/dist-assets/skills/spec-driven-development/SKILL.md +166 -0
- package/dist-assets/skills/technical-leadership/SKILL.md +166 -0
- package/dist-assets/skills/ui-ux-design/SKILL.md +202 -0
- package/dist-assets/templates/.geminiignore.template +8 -0
- package/dist-assets/templates/CLAUDE.md.template +20 -0
- package/dist-assets/templates/CODEX.md.template +20 -0
- package/dist-assets/templates/GEMINI.md.template +20 -0
- package/dist-assets/templates/HANDOFF.template.md +45 -0
- package/dist-assets/templates/SPEC.template.md +38 -0
- package/dist-assets/templates/change-proposal.template.md +14 -0
- package/dist-assets/templates/owner-evidence/astra-implementation.json +10 -0
- package/dist-assets/templates/owner-evidence/phoenix-remediation.json +8 -0
- package/dist-assets/templates/owner-evidence/sage-revalidation.json +8 -0
- package/dist-assets/templates/owner-evidence/sage-validation.json +8 -0
- package/dist-assets/templates/specs/deep.md +48 -0
- package/dist-assets/templates/specs/standard.md +38 -0
- package/dist-assets/templates/specs/tiny.md +19 -0
- package/package.json +42 -47
- package/src/adapters/index.js +3 -0
- package/src/adapters/platforms/claude.js +126 -0
- package/src/adapters/platforms/codex.js +100 -0
- package/src/adapters/platforms/gemini.js +232 -0
- package/src/cli.js +96 -0
- package/src/commands/collect-evidence.js +61 -0
- package/src/commands/doctor.js +186 -0
- package/{packages/ai-workflow/src → src}/commands/init.js +119 -20
- package/src/commands/run.js +111 -0
- package/src/core/completion-contract.js +35 -0
- package/src/core/gates/branch-gate.js +113 -0
- package/src/core/handoff/handoff-engine.js +78 -0
- package/src/core/healing/cli-remediation-executor.js +151 -0
- package/src/core/healing/healer-engine.js +179 -0
- package/src/core/identity.js +43 -0
- package/{packages/ai-workflow/src → src}/core/install-plan.js +3 -3
- package/src/core/opencode-merge.js +149 -0
- package/{packages/ai-workflow/src → src}/core/package-assets.js +29 -10
- package/src/core/sdd/validator.js +67 -0
- package/src/core/statuses.js +29 -0
- package/src/core/symlink-layout.js +93 -0
- package/src/core/templates.js +218 -0
- package/src/core/validation/canonical-finalization.js +43 -0
- package/src/core/validation/evidence-collector.js +109 -0
- package/src/core/validation/quality-guard.js +243 -0
- package/src/core/workflow-profiles.js +107 -0
- package/.agents/napkin.md +0 -89
- package/.agents/skills/backend-implementer/SKILL.md +0 -490
- package/.agents/skills/build-and-validate/SKILL.md +0 -442
- package/.agents/skills/deploy-engineer/SKILL.md +0 -541
- package/.agents/skills/docs-writer/SKILL.md +0 -430
- package/.agents/skills/frontend-implementer/SKILL.md +0 -488
- package/.agents/skills/interface-design/SKILL.md +0 -428
- package/.agents/skills/interface-design/references/critique.md +0 -67
- package/.agents/skills/interface-design/references/example.md +0 -86
- package/.agents/skills/interface-design/references/principles.md +0 -235
- package/.agents/skills/interface-design/references/validation.md +0 -48
- package/.agents/skills/minimal-context/SKILL.md +0 -177
- package/.agents/skills/napkin/SKILL.md +0 -84
- package/.agents/skills/opencode-agent-design/SKILL.md +0 -77
- package/.agents/skills/playwright-cli/SKILL.md +0 -62
- package/.agents/skills/pr-orchestrator/SKILL.md +0 -366
- package/.agents/skills/product-manager/SKILL.md +0 -519
- package/.agents/skills/seo-audit/SKILL.md +0 -176
- package/.agents/skills/stack-variant-creator/SKILL.md +0 -265
- package/.agents/skills/tech-lead/SKILL.md +0 -453
- package/.agents/skills/tester/SKILL.md +0 -399
- package/.agents/skills/token-economy/SKILL.md +0 -137
- package/.agents/skills/vue-nuxt/SKILL.md +0 -102
- package/.agents/skills/wordpress-engineer/SKILL.md +0 -75
- package/.codex/prompts/README.md +0 -44
- package/.codex/prompts/autopilot.md +0 -50
- package/.codex/prompts/deploy.md +0 -33
- package/.codex/prompts/execute-selected-pr.md +0 -35
- package/.codex/prompts/fix-issue.md +0 -34
- package/.codex/prompts/minimal-context-mode.md +0 -55
- package/.codex/prompts/orchestrate-next.md +0 -33
- package/.codex/prompts/plan-from-requirement.md +0 -37
- package/.codex/prompts/review-implementation.md +0 -33
- package/.codex/prompts/roadmap-audit.md +0 -22
- package/.codex/prompts/specs/create-spec-from-requirement.md +0 -26
- package/.codex/prompts/specs/review-spec.md +0 -29
- package/.codex/prompts/specs/spec-to-pr-breakdown.md +0 -23
- package/.codex/prompts/specs/spec-to-technical-plan.md +0 -28
- package/.codex/prompts/start-project.md +0 -29
- package/.codex/prompts/token-economy-mode.md +0 -48
- package/.codex/prompts/validate-work.md +0 -28
- package/checklists/change-spec-readiness-checklist.md +0 -34
- package/docs/full-documentation.md +0 -661
- package/docs/setup-codex-opencode.md +0 -313
- package/harness/README.md +0 -106
- package/opencode/README.md +0 -84
- package/opencode/agents/README.md +0 -113
- package/opencode/agents/atlas.md +0 -127
- package/opencode/agents/discovery.md +0 -61
- package/opencode/agents/fixer.md +0 -51
- package/opencode/agents/implementer.md +0 -61
- package/opencode/agents/orchestrator.md +0 -145
- package/opencode/agents/planner.md +0 -60
- package/opencode/agents/prompt-engineer.md +0 -50
- package/opencode/agents/release-manager.md +0 -50
- package/opencode/agents/reviewer.md +0 -51
- package/opencode/agents/spec-engineer.md +0 -85
- package/opencode/agents/validator.md +0 -50
- package/opencode/agents/wordpress-engineer.md +0 -49
- package/opencode/commands/README.md +0 -48
- package/opencode/commands/autopilot.md +0 -50
- package/opencode/commands/deploy.md +0 -35
- package/opencode/commands/execute.md +0 -47
- package/opencode/commands/orchestrate.md +0 -37
- package/opencode/commands/plan.md +0 -39
- package/opencode/commands/review.md +0 -33
- package/opencode/commands/roadmap-audit.md +0 -30
- package/opencode/commands/ship.md +0 -48
- package/opencode/commands/specs/create-spec-from-request.md +0 -27
- package/opencode/commands/specs/create-spec-from-requirement.md +0 -25
- package/opencode/commands/specs/review-spec.md +0 -26
- package/opencode/commands/specs/spec-to-pr-breakdown.md +0 -19
- package/opencode/commands/specs/spec-to-tasks.md +0 -26
- package/opencode/commands/specs/spec-to-technical-plan.md +0 -27
- package/opencode/commands/start.md +0 -45
- package/opencode/commands/token-economy.md +0 -29
- package/opencode/commands/validate.md +0 -33
- package/opencode.jsonc +0 -235
- package/packages/ai-workflow/README.md +0 -82
- package/packages/ai-workflow/src/cli.js +0 -70
- package/packages/ai-workflow/src/commands/codex.js +0 -37
- package/packages/ai-workflow/src/commands/doctor.js +0 -168
- package/packages/ai-workflow/src/commands/guide.js +0 -194
- package/packages/ai-workflow/src/core/opencode-merge.js +0 -172
- package/packages/ai-workflow/src/core/symlink-layout.js +0 -54
- package/packages/ai-workflow/src/core/templates.js +0 -275
- package/runbooks/agent-delegation-workflow.md +0 -111
- package/runbooks/apply-starter-to-real-project.md +0 -445
- package/runbooks/commands-cheatsheet.md +0 -71
- package/runbooks/how-to-use-skills.md +0 -713
- package/runbooks/quick-start-guide.md +0 -213
- package/runbooks/tutorial-walkthroughs.md +0 -416
- package/runbooks/use-linear-for-operational-planning.md +0 -185
- package/runbooks/use-napkin-project-memory.md +0 -77
- package/templates/AGENTS.template.md +0 -397
- package/templates/DESIGN.template.md +0 -484
- package/templates/PR-PLAN.template.md +0 -172
- package/templates/README.template.md +0 -293
- package/templates/REQUIREMENT.template.md +0 -165
- package/templates/SPEC.template.md +0 -397
- package/templates/TECH-PLAN.template.md +0 -244
- package/templates/change-proposal.template.md +0 -97
- /package/{checklists/spec-readiness-checklist.md → dist-assets/docs/policies/SPEC_READINESS.md} +0 -0
- /package/{prompts → dist-assets/prompts}/00-bootstrap-project.md +0 -0
- /package/{prompts → dist-assets/prompts}/01-create-requirement.md +0 -0
- /package/{prompts → dist-assets/prompts}/02-create-spec.md +0 -0
- /package/{prompts → dist-assets/prompts}/03-create-tech-plan.md +0 -0
- /package/{prompts → dist-assets/prompts}/04-breakdown-prs.md +0 -0
- /package/{prompts → dist-assets/prompts}/05-implement-pr.md +0 -0
- /package/{prompts → dist-assets/prompts}/06-review-and-fix.md +0 -0
- /package/{prompts → dist-assets/prompts}/07-apply-design.md +0 -0
- /package/{prompts → dist-assets/prompts}/08-validate.md +0 -0
- /package/{prompts → dist-assets/prompts}/09-deploy.md +0 -0
- /package/{prompts → dist-assets/prompts}/commands/implement.md +0 -0
- /package/{prompts → dist-assets/prompts}/commands/requirement.md +0 -0
- /package/{prompts → dist-assets/prompts}/commands/spec.md +0 -0
- /package/{prompts → dist-assets/prompts}/commands/tech-plan.md +0 -0
- /package/{prompts → dist-assets/prompts}/commands/validate.md +0 -0
- /package/{runbooks → dist-assets/runbooks}/branch-cleanup.md +0 -0
- /package/{runbooks → dist-assets/runbooks}/deploy-checklist.md +0 -0
- /package/{runbooks → dist-assets/runbooks}/publication-readiness-checklist.md +0 -0
- /package/{runbooks → dist-assets/runbooks}/publish-package-checklist.md +0 -0
- /package/{runbooks → dist-assets/runbooks}/team-governance-pr-readiness.md +0 -0
- /package/{runbooks → dist-assets/runbooks}/validate-starter-in-real-project.md +0 -0
- /package/{runbooks → dist-assets/runbooks}/validation-checklist.md +0 -0
- /package/{schemas → dist-assets/schemas}/README.md +0 -0
- /package/{schemas → dist-assets/schemas}/functional-spec.schema.json +0 -0
- /package/{schemas → dist-assets/schemas}/handoff.schema.json +0 -0
- /package/{schemas → dist-assets/schemas}/pr-breakdown.schema.json +0 -0
- /package/{schemas → dist-assets/schemas}/requirement.schema.json +0 -0
- /package/{schemas → dist-assets/schemas}/technical-plan.schema.json +0 -0
- /package/{schemas → dist-assets/schemas}/validation-report.schema.json +0 -0
- /package/{packages/ai-workflow/src → src}/core/backup.js +0 -0
- /package/{packages/ai-workflow/src → src}/core/filesystem.js +0 -0
|
@@ -2,10 +2,11 @@ import fs from "node:fs/promises";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { createInstallPlan } from "../core/install-plan.js";
|
|
4
4
|
import { buildAiWorkflowConfig, getTemplateFiles, isValidProfile } from "../core/templates.js";
|
|
5
|
-
import { exists, writeFileSafe } from "../core/filesystem.js";
|
|
5
|
+
import { exists, writeFileSafe, readJson } from "../core/filesystem.js";
|
|
6
6
|
import { createManagedBackup, createManagedPathBackup } from "../core/backup.js";
|
|
7
7
|
import { mergeOpencodeConfig } from "../core/opencode-merge.js";
|
|
8
|
-
import { buildSymlinkEntries, isSymlinkTo } from "../core/symlink-layout.js";
|
|
8
|
+
import { buildSymlinkEntries, isSymlinkTo, setupInternalSymlinks } from "../core/symlink-layout.js";
|
|
9
|
+
import { GeminiAdapter, ClaudeAdapter, CodexAdapter } from "../adapters/index.js";
|
|
9
10
|
|
|
10
11
|
function summarize(actions) {
|
|
11
12
|
const createCount = actions.filter((a) => a.type === "create").length;
|
|
@@ -79,16 +80,63 @@ async function upsertGitignoreBlock(cwd, entries) {
|
|
|
79
80
|
return "updated";
|
|
80
81
|
}
|
|
81
82
|
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
|
|
83
|
+
async function injectScripts(cwd) {
|
|
84
|
+
const pkgPath = path.join(cwd, "package.json");
|
|
85
|
+
if (!(await exists(pkgPath))) return;
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const pkg = await readJson(pkgPath);
|
|
89
|
+
if (!pkg.scripts) pkg.scripts = {};
|
|
90
|
+
|
|
91
|
+
if (!pkg.scripts.validate) {
|
|
92
|
+
pkg.scripts.validate = "ai-workflow collect-evidence";
|
|
93
|
+
await writeFileSafe(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
} catch {
|
|
97
|
+
// Ignore invalid package.json
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function runInit({
|
|
103
|
+
cwd, yes, force, dryRun, noInstall, noOverwrite, gemini, claude, codex, "dev-mode": devMode, profile }) {
|
|
104
|
+
// Self-execution guard
|
|
105
|
+
if (!devMode) {
|
|
106
|
+
try {
|
|
107
|
+
const pkgPath = path.join(cwd, "package.json");
|
|
108
|
+
if (await exists(pkgPath)) {
|
|
109
|
+
const pkg = await readJson(pkgPath);
|
|
110
|
+
if (pkg.name === "@williambeto/ai-workflow") {
|
|
111
|
+
console.error("\nFATAL: Cannot run 'ai-workflow init' inside its own development repository.");
|
|
112
|
+
console.error("This would corrupt the development environment. Aborting.");
|
|
113
|
+
console.error("Use the --dev-mode flag if you are developing the kit itself and need to test the init command.\n");
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} catch {
|
|
118
|
+
// Ignore if package.json is unreadable. The guard is a safety net.
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const selectedProfile = profile || "standard";
|
|
85
123
|
|
|
86
124
|
if (!isValidProfile(selectedProfile)) {
|
|
87
|
-
|
|
125
|
+
console.error(`Invalid profile: "${selectedProfile}". Valid profiles: standard, full`);
|
|
126
|
+
process.exit(1);
|
|
88
127
|
}
|
|
128
|
+
const installRoot = ".ai-workflow";
|
|
129
|
+
|
|
130
|
+
const platforms = [];
|
|
131
|
+
if (gemini) platforms.push("gemini");
|
|
132
|
+
if (claude) platforms.push("claude");
|
|
133
|
+
if (codex) platforms.push("codex");
|
|
89
134
|
|
|
90
135
|
console.log(`ai-workflow: initializing in ${cwd}`);
|
|
91
136
|
console.log(`Profile: ${selectedProfile}`);
|
|
137
|
+
if (platforms.length > 0) {
|
|
138
|
+
console.log(`Platforms: ${platforms.join(", ")}`);
|
|
139
|
+
}
|
|
92
140
|
|
|
93
141
|
const actions = await createInstallPlan({ cwd, exists, profile: selectedProfile });
|
|
94
142
|
const linkEntries = buildSymlinkEntries({ templateFiles: getTemplateFiles(selectedProfile), installRoot });
|
|
@@ -105,6 +153,9 @@ export async function runInit({ cwd, yes, force, dryRun, noInstall, noOverwrite,
|
|
|
105
153
|
|
|
106
154
|
if (dryRun) {
|
|
107
155
|
console.log("Dry-run enabled. No files were written.");
|
|
156
|
+
if (platforms.length > 0) {
|
|
157
|
+
console.log("ai-workflow: (dry-run) platform migration would be executed after file writing.");
|
|
158
|
+
}
|
|
108
159
|
return;
|
|
109
160
|
}
|
|
110
161
|
|
|
@@ -128,17 +179,10 @@ export async function runInit({ cwd, yes, force, dryRun, noInstall, noOverwrite,
|
|
|
128
179
|
}
|
|
129
180
|
|
|
130
181
|
const content =
|
|
131
|
-
action.relativePath === ".ai-workflow.json"
|
|
182
|
+
action.relativePath === ".ai-workflow/config.json"
|
|
132
183
|
? `${JSON.stringify(
|
|
133
184
|
buildAiWorkflowConfig({
|
|
134
|
-
profile: selectedProfile
|
|
135
|
-
managedFiles: Array.from(
|
|
136
|
-
new Set([
|
|
137
|
-
...Object.keys(getTemplateFiles(selectedProfile)).map((p) => path.join(installRoot, p)),
|
|
138
|
-
".ai-workflow.json"
|
|
139
|
-
])
|
|
140
|
-
),
|
|
141
|
-
managedLinks: linkEntries.map((entry) => entry.linkPath)
|
|
185
|
+
profile: selectedProfile
|
|
142
186
|
}),
|
|
143
187
|
null,
|
|
144
188
|
2
|
|
@@ -175,6 +219,8 @@ export async function runInit({ cwd, yes, force, dryRun, noInstall, noOverwrite,
|
|
|
175
219
|
maxPerFile: 20
|
|
176
220
|
});
|
|
177
221
|
linkBackups.push(backupPath);
|
|
222
|
+
// Ensure we remove the old path before symlinking if it's not already handled by backup
|
|
223
|
+
await fs.rm(absoluteLinkPath, { recursive: true, force: true });
|
|
178
224
|
}
|
|
179
225
|
|
|
180
226
|
const stat = await fs.lstat(absoluteTargetPath);
|
|
@@ -182,6 +228,7 @@ export async function runInit({ cwd, yes, force, dryRun, noInstall, noOverwrite,
|
|
|
182
228
|
const linkTarget = process.platform === "win32" ? absoluteTargetPath : path.relative(path.dirname(absoluteLinkPath), absoluteTargetPath);
|
|
183
229
|
|
|
184
230
|
try {
|
|
231
|
+
await fs.mkdir(path.dirname(absoluteLinkPath), { recursive: true });
|
|
185
232
|
await fs.symlink(linkTarget, absoluteLinkPath, type);
|
|
186
233
|
} catch (error) {
|
|
187
234
|
throw new Error(
|
|
@@ -193,25 +240,77 @@ export async function runInit({ cwd, yes, force, dryRun, noInstall, noOverwrite,
|
|
|
193
240
|
linkCreated.push(linkPath);
|
|
194
241
|
}
|
|
195
242
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
: await mergeOpencodeConfig(cwd, { force, backupRoot, profile: selectedProfile });
|
|
243
|
+
await setupInternalSymlinks(cwd, installRoot);
|
|
244
|
+
|
|
245
|
+
const opencodeResult = await mergeOpencodeConfig(cwd, { force, backupRoot });
|
|
200
246
|
|
|
201
247
|
const generatedIgnoreEntries = [
|
|
202
248
|
".ai-workflow/",
|
|
203
|
-
".ai-workflow.json",
|
|
204
249
|
".ai-workflow-backups/",
|
|
250
|
+
"opencode.jsonc.backup.*",
|
|
205
251
|
...linkEntries.flatMap((entry) => toIgnoreEntries(entry.linkPath))
|
|
206
252
|
];
|
|
207
253
|
|
|
254
|
+
if (gemini) {
|
|
255
|
+
generatedIgnoreEntries.push(".gemini/");
|
|
256
|
+
}
|
|
257
|
+
if (codex) {
|
|
258
|
+
generatedIgnoreEntries.push(".agents/", ".codex/");
|
|
259
|
+
}
|
|
260
|
+
if (claude) {
|
|
261
|
+
generatedIgnoreEntries.push(".claude/");
|
|
262
|
+
}
|
|
263
|
+
|
|
208
264
|
const gitignoreResult = await upsertGitignoreBlock(cwd, generatedIgnoreEntries);
|
|
265
|
+
const scriptInjected = await injectScripts(cwd);
|
|
266
|
+
|
|
267
|
+
if (platforms.length > 0) {
|
|
268
|
+
console.log("ai-workflow: migrating to native platforms...");
|
|
269
|
+
const agentsDir = path.join(cwd, installRoot, "opencode/agents");
|
|
270
|
+
const skillsDir = path.join(cwd, installRoot, "opencode/skills");
|
|
271
|
+
|
|
272
|
+
const agentFiles = (await fs.readdir(agentsDir).catch(() => []))
|
|
273
|
+
.filter((f) => f.endsWith(".md"))
|
|
274
|
+
.map((f) => path.join(agentsDir, f));
|
|
275
|
+
|
|
276
|
+
if (gemini) {
|
|
277
|
+
const adapter = new GeminiAdapter({ cwd });
|
|
278
|
+
|
|
279
|
+
// Collect specialized skills from the new opencode/skills path
|
|
280
|
+
const skillFolders = await fs.readdir(skillsDir).catch(() => []);
|
|
281
|
+
const skillFiles = [];
|
|
282
|
+
for (const folder of skillFolders) {
|
|
283
|
+
const skillPath = path.join(skillsDir, folder, "SKILL.md");
|
|
284
|
+
if (await exists(skillPath)) {
|
|
285
|
+
skillFiles.push(skillPath);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const allFiles = [...agentFiles, ...skillFiles];
|
|
290
|
+
const transformed = await Promise.all(allFiles.map((f) => adapter.transform(f)));
|
|
291
|
+
await adapter.deploy(transformed, installRoot);
|
|
292
|
+
console.log(`- gemini: deployed AI Workflow Kit agents to .gemini/ (native discovery enabled)`);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (claude) {
|
|
296
|
+
const adapter = new ClaudeAdapter({ cwd });
|
|
297
|
+
await adapter.deploy(installRoot);
|
|
298
|
+
console.log("- claude: deployed AI Workflow Kit agents to CLAUDE.md and .claude/rules/ (native discovery enabled)");
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (codex) {
|
|
302
|
+
const adapter = new CodexAdapter({ cwd });
|
|
303
|
+
await adapter.deploy(installRoot);
|
|
304
|
+
console.log("- codex: deployed AI Workflow Kit agents to .agents/, .codex/, and .github/ (native discovery enabled)");
|
|
305
|
+
}
|
|
306
|
+
}
|
|
209
307
|
|
|
210
308
|
console.log("Installation complete.");
|
|
211
309
|
console.log(`- profile: ${selectedProfile}`);
|
|
212
310
|
|
|
213
311
|
console.log(`- opencode.jsonc: ${opencodeResult.reason}`);
|
|
214
312
|
console.log(`- .gitignore: ${gitignoreResult}`);
|
|
313
|
+
console.log(`- scripts: ${scriptInjected ? "injected 'validate'" : "already-up-to-date"}`);
|
|
215
314
|
console.log(`- symlink layout: ${linkCreated.length > 0 ? `created ${linkCreated.length}` : "already-up-to-date"}`);
|
|
216
315
|
if (backups.length > 0) {
|
|
217
316
|
console.log(`- backups created: ${backups.length}`);
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { BranchGate } from "../core/gates/branch-gate.js";
|
|
2
|
+
import { SpecValidator } from "../core/sdd/validator.js";
|
|
3
|
+
import { HandoffEngine } from "../core/handoff/handoff-engine.js";
|
|
4
|
+
import { runCollectEvidence } from "./collect-evidence.js";
|
|
5
|
+
import { QualityGuard } from "../core/validation/quality-guard.js";
|
|
6
|
+
import { HealerEngine } from "../core/healing/healer-engine.js";
|
|
7
|
+
import { createCliRemediationExecutor } from "../core/healing/cli-remediation-executor.js";
|
|
8
|
+
import { isRecoverableGateFailure, isTerminalFailure } from "../core/statuses.js";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import fs from "node:fs/promises";
|
|
11
|
+
import { getWorkflowProfile, resolveWorkflowProfile } from "../core/workflow-profiles.js";
|
|
12
|
+
|
|
13
|
+
function normalizeTaskSlugFromSpec(specPath) {
|
|
14
|
+
const normalized = String(specPath).replaceAll("\\", "/");
|
|
15
|
+
const marker = "/docs/workflows/";
|
|
16
|
+
const index = normalized.includes(marker)
|
|
17
|
+
? normalized.indexOf(marker) + marker.length
|
|
18
|
+
: normalized.startsWith("docs/workflows/") ? "docs/workflows/".length : -1;
|
|
19
|
+
if (index >= 0) {
|
|
20
|
+
const slug = normalized.slice(index).split("/")[0];
|
|
21
|
+
if (slug) return slug;
|
|
22
|
+
}
|
|
23
|
+
return path.basename(specPath, path.extname(specPath));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function combineValidation(evidence, quality) {
|
|
27
|
+
const statuses = [evidence.internalStatus, quality.overallStatus];
|
|
28
|
+
let overallStatus = "PASS";
|
|
29
|
+
if (statuses.includes("BLOCKED")) overallStatus = "BLOCKED";
|
|
30
|
+
else if (statuses.includes("FAIL")) overallStatus = "FAIL";
|
|
31
|
+
else if (statuses.includes("FAIL_DELEGATION_GATE")) overallStatus = "FAIL_DELEGATION_GATE";
|
|
32
|
+
else if (statuses.includes("FAIL_QUALITY_GATE")) overallStatus = "FAIL_QUALITY_GATE";
|
|
33
|
+
else if (statuses.includes("PASS_WITH_NOTES")) overallStatus = "PASS_WITH_NOTES";
|
|
34
|
+
return { overallStatus, evidence, quality };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Coordinates branch safety, specification validation, observed validation, bounded remediation, and handoff.
|
|
39
|
+
* Failed required validation can never be promoted to success.
|
|
40
|
+
*/
|
|
41
|
+
export async function runMasterOrchestrator({ cwd, specPath, override, remediationExecutor = null }) {
|
|
42
|
+
console.log("\n[AI WORKFLOW] Starting evidence-backed orchestration...\n");
|
|
43
|
+
|
|
44
|
+
const branchGate = new BranchGate({ memoryDir: path.join(cwd, ".ai-workflow"), cwd });
|
|
45
|
+
const taskSlug = specPath ? normalizeTaskSlugFromSpec(specPath) : "implementation";
|
|
46
|
+
const gateResult = branchGate.check(override, { autoRecover: true, taskSlug });
|
|
47
|
+
if (gateResult.blocked) throw new Error(`[GATE BLOCKED] ${gateResult.reason}`);
|
|
48
|
+
console.log(`[PASS] Branch Gate: ${gateResult.recovered ? `${gateResult.branchBefore} -> ${gateResult.branch}` : `${gateResult.branch} is authorized`}.`);
|
|
49
|
+
|
|
50
|
+
if (!specPath) throw new Error("[SDD BLOCKED] Missing --spec-path. An approved specification is required.");
|
|
51
|
+
|
|
52
|
+
const validator = new SpecValidator();
|
|
53
|
+
const absoluteSpecPath = path.isAbsolute(specPath) ? specPath : path.join(cwd, specPath);
|
|
54
|
+
const validation = await validator.validate(absoluteSpecPath);
|
|
55
|
+
if (!validation.valid) throw new Error(`[SDD BLOCKED] Specification is not ready: ${validation.reason}`);
|
|
56
|
+
|
|
57
|
+
const executionMode = validation.tier === "deep" ? "full" : validation.tier === "tiny" ? "quick" : "standard";
|
|
58
|
+
const specContent = await fs.readFile(absoluteSpecPath, "utf8");
|
|
59
|
+
const workflowProfile = resolveWorkflowProfile({ request: specContent });
|
|
60
|
+
const profileDefinition = getWorkflowProfile(workflowProfile);
|
|
61
|
+
console.log(`[PASS] Specification: ${validation.tier.toUpperCase()} spec is APPROVED.`);
|
|
62
|
+
console.log(`[PROFILE] ${workflowProfile} -> ${profileDefinition.owner}; skills: ${profileDefinition.skills.join(", ") || "none"}.`);
|
|
63
|
+
|
|
64
|
+
const validateWorkflow = async () => {
|
|
65
|
+
const evidence = await runCollectEvidence({
|
|
66
|
+
cwd,
|
|
67
|
+
exitOnError: false,
|
|
68
|
+
taskSlug,
|
|
69
|
+
mode: executionMode,
|
|
70
|
+
profile: workflowProfile,
|
|
71
|
+
branchRecovery: gateResult.recovered ? `${gateResult.branchBefore} -> ${gateResult.branch}` : "NOT_REQUIRED"
|
|
72
|
+
});
|
|
73
|
+
const quality = await new QualityGuard({ cwd, taskSlug, mode: executionMode }).verify();
|
|
74
|
+
return combineValidation(evidence, quality);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
let result = await validateWorkflow();
|
|
78
|
+
if (isRecoverableGateFailure(result.overallStatus)) {
|
|
79
|
+
console.log(`\n[REMEDIATION REQUIRED] ${result.overallStatus}. Starting bounded ${executionMode} remediation.`);
|
|
80
|
+
// Use the provided executor (programmatic API) or fall back to the default CLI executor.
|
|
81
|
+
// The CLI executor re-runs failed npm scripts; it does not modify source code.
|
|
82
|
+
const executor = typeof remediationExecutor === "function"
|
|
83
|
+
? remediationExecutor
|
|
84
|
+
: createCliRemediationExecutor(cwd);
|
|
85
|
+
const healer = new HealerEngine({ cwd, mode: executionMode, taskSlug });
|
|
86
|
+
result = await healer.run({ initialResult: result, validate: validateWorkflow, remediate: executor });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (isTerminalFailure(result.overallStatus)) {
|
|
90
|
+
throw new Error(`[WORKFLOW BLOCKED] ${result.overallStatus}: ${result.reason || "Validation could not be resolved safely."}`);
|
|
91
|
+
}
|
|
92
|
+
if (isRecoverableGateFailure(result.overallStatus)) {
|
|
93
|
+
throw new Error(`[WORKFLOW BLOCKED] Unresolved gate status after remediation: ${result.overallStatus}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
console.log("\n--- Final Handoff ---");
|
|
97
|
+
const handoffEngine = new HandoffEngine({ cwd });
|
|
98
|
+
const handoffPath = await handoffEngine.generate({
|
|
99
|
+
taskId: path.basename(specPath, ".md"),
|
|
100
|
+
status: result.overallStatus,
|
|
101
|
+
specPaths: [specPath],
|
|
102
|
+
nextActions: `Profile ${workflowProfile}. Observed validation completed. Ready for review or explicitly approved release actions.`
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
console.log(`\n[AI WORKFLOW COMPLETE] ${result.overallStatus}`);
|
|
106
|
+
if (result.remediation?.attempts) console.log(`Remediation attempts: ${result.remediation.attempts}`);
|
|
107
|
+
console.log(`Handoff Packet: ${path.relative(cwd, handoffPath)}\n`);
|
|
108
|
+
return { ...result, workflowProfile };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { combineValidation };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Evaluates objective owner-output completeness. It does not judge visual taste.
|
|
3
|
+
* A caller may resume the same owner once; a second incomplete result must block.
|
|
4
|
+
*/
|
|
5
|
+
export function evaluateOwnerCompletion({
|
|
6
|
+
expectedFiles = [],
|
|
7
|
+
existingFiles = [],
|
|
8
|
+
validation = {},
|
|
9
|
+
ownerReportComplete = false,
|
|
10
|
+
resumeCount = 0
|
|
11
|
+
} = {}) {
|
|
12
|
+
const existing = new Set(existingFiles);
|
|
13
|
+
const missingFiles = expectedFiles.filter((file) => !existing.has(file));
|
|
14
|
+
const missingValidation = Object.entries(validation)
|
|
15
|
+
.filter(([, value]) => value === "REQUIRED" || value === false)
|
|
16
|
+
.map(([key]) => key);
|
|
17
|
+
const missing = [
|
|
18
|
+
...missingFiles.map((file) => `file:${file}`),
|
|
19
|
+
...missingValidation.map((check) => `validation:${check}`),
|
|
20
|
+
...(!ownerReportComplete ? ["owner-report"] : [])
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
if (missing.length === 0) {
|
|
24
|
+
return { status: "PASS", action: "continue", missing: [] };
|
|
25
|
+
}
|
|
26
|
+
if (resumeCount < 1) {
|
|
27
|
+
return { status: "INCOMPLETE", action: "resume-same-owner", missing };
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
status: "BLOCKED",
|
|
31
|
+
action: "stop",
|
|
32
|
+
reason: "Owner output remained incomplete after one resume",
|
|
33
|
+
missing
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
function slugify(value = "task") {
|
|
6
|
+
return String(value)
|
|
7
|
+
.toLowerCase()
|
|
8
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
9
|
+
.replace(/^-+|-+$/g, "")
|
|
10
|
+
.slice(0, 48) || "task";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* BranchGate - Protects main/master and can recover safely onto a scoped branch.
|
|
15
|
+
*/
|
|
16
|
+
export class BranchGate {
|
|
17
|
+
constructor({ protectedBranches = ["main", "master"], memoryDir, cwd = process.cwd() } = {}) {
|
|
18
|
+
this.protectedBranches = protectedBranches;
|
|
19
|
+
this.logPath = memoryDir ? path.join(memoryDir, "GATE_ALERTS.log") : null;
|
|
20
|
+
this.cwd = cwd;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
run(command) {
|
|
24
|
+
return execSync(command, {
|
|
25
|
+
cwd: this.cwd,
|
|
26
|
+
encoding: "utf8",
|
|
27
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
28
|
+
}).trim();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
log(event) {
|
|
32
|
+
if (!this.logPath) return;
|
|
33
|
+
const timestamp = new Date().toISOString();
|
|
34
|
+
const logEntry = `[${timestamp}] ${event}\n`;
|
|
35
|
+
try {
|
|
36
|
+
if (!fs.existsSync(path.dirname(this.logPath))) fs.mkdirSync(path.dirname(this.logPath), { recursive: true });
|
|
37
|
+
fs.appendFileSync(this.logPath, logEntry);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error(`Failed to write to gate log: ${error.message}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
getDirtyState() {
|
|
44
|
+
const lines = this.run("git status --short").split("\n").filter(Boolean);
|
|
45
|
+
const tracked = lines.filter((line) => !line.startsWith("??"));
|
|
46
|
+
const untracked = lines.filter((line) => line.startsWith("??"));
|
|
47
|
+
return { clean: lines.length === 0, tracked, untracked, lines };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
createScopedBranch(taskSlug) {
|
|
51
|
+
const base = `feat/${slugify(taskSlug)}`;
|
|
52
|
+
let candidate = base;
|
|
53
|
+
let suffix = 2;
|
|
54
|
+
while (true) {
|
|
55
|
+
try {
|
|
56
|
+
this.run(`git show-ref --verify --quiet refs/heads/${candidate}`);
|
|
57
|
+
candidate = `${base}-${suffix++}`;
|
|
58
|
+
} catch {
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
this.run(`git switch -c ${candidate}`);
|
|
63
|
+
return candidate;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @param {string} override
|
|
68
|
+
* @param {{autoRecover?: boolean, taskSlug?: string}} options
|
|
69
|
+
*/
|
|
70
|
+
check(override = "", { autoRecover = false, taskSlug = "implementation" } = {}) {
|
|
71
|
+
try {
|
|
72
|
+
const currentBranch = this.run("git rev-parse --abbrev-ref HEAD");
|
|
73
|
+
const isProtected = this.protectedBranches.includes(currentBranch);
|
|
74
|
+
if (!isProtected) return { blocked: false, branch: currentBranch, recovered: false };
|
|
75
|
+
|
|
76
|
+
if (override && override.trim().length >= 20) {
|
|
77
|
+
this.log(`AUTHORIZED BYPASS on '${currentBranch}': ${override.trim()}`);
|
|
78
|
+
return { blocked: false, branch: currentBranch, authorized: true, recovered: false };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (autoRecover) {
|
|
82
|
+
const dirty = this.getDirtyState();
|
|
83
|
+
if (dirty.tracked.length > 0) {
|
|
84
|
+
const reason = `Unsafe tracked changes prevent Branch Gate Auto-Recovery: ${dirty.tracked.join(", ")}`;
|
|
85
|
+
this.log(`BLOCKED AUTO-RECOVERY on '${currentBranch}': ${reason}`);
|
|
86
|
+
return { blocked: true, branch: currentBranch, reason, dirtyState: dirty };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const recoveredBranch = this.createScopedBranch(taskSlug);
|
|
90
|
+
this.log(`AUTO-RECOVERED '${currentBranch}' -> '${recoveredBranch}'`);
|
|
91
|
+
return {
|
|
92
|
+
blocked: false,
|
|
93
|
+
branch: recoveredBranch,
|
|
94
|
+
branchBefore: currentBranch,
|
|
95
|
+
recovered: true,
|
|
96
|
+
dirtyState: dirty
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const reason = override && override.trim().length < 20
|
|
101
|
+
? "Override justification too short (min 20 chars)."
|
|
102
|
+
: `Direct commits to '${currentBranch}' are prohibited.`;
|
|
103
|
+
this.log(`BLOCKED ATTEMPT on '${currentBranch}': ${reason}`);
|
|
104
|
+
return {
|
|
105
|
+
blocked: true,
|
|
106
|
+
branch: currentBranch,
|
|
107
|
+
reason: `${reason} Enable safe auto-recovery or use AI_OVERRIDE with a concrete justification.`
|
|
108
|
+
};
|
|
109
|
+
} catch (error) {
|
|
110
|
+
return { blocked: false, branch: "unknown", error: error.message, recovered: false };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* HandoffEngine - Bundles project context into a single Markdown packet.
|
|
7
|
+
*/
|
|
8
|
+
export class HandoffEngine {
|
|
9
|
+
constructor({ cwd }) {
|
|
10
|
+
this.cwd = cwd;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Generates a handoff packet.
|
|
15
|
+
* @param {Object} data - Context data.
|
|
16
|
+
* @returns {Promise<string>} The generated packet content.
|
|
17
|
+
*/
|
|
18
|
+
async generate({ taskId, author, status, specPaths = [], nextActions }) {
|
|
19
|
+
const timestamp = new Date().toISOString();
|
|
20
|
+
|
|
21
|
+
// 1. Collect Specs content
|
|
22
|
+
let specsContent = "";
|
|
23
|
+
for (const specPath of specPaths) {
|
|
24
|
+
const absolutePath = path.isAbsolute(specPath) ? specPath : path.join(this.cwd, specPath);
|
|
25
|
+
try {
|
|
26
|
+
const content = await fs.readFile(absolutePath, "utf8");
|
|
27
|
+
specsContent += `### File: ${specPath}\n\n${content}\n\n`;
|
|
28
|
+
} catch (err) {
|
|
29
|
+
specsContent += `### File: ${specPath}\n\n[Error reading file: ${err.message}]\n\n`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 2. Capture Git Diff
|
|
34
|
+
let gitDiff = "No changes detected.";
|
|
35
|
+
try {
|
|
36
|
+
gitDiff = execSync("git diff HEAD", { cwd: this.cwd, encoding: "utf8" }).trim() || "No changes detected.";
|
|
37
|
+
} catch (err) {
|
|
38
|
+
gitDiff = `[Error capturing diff: ${err.message}]`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 3. Read EVIDENCE.json
|
|
42
|
+
let evidenceJson = "{}";
|
|
43
|
+
let evidenceSummary = "No evidence found.";
|
|
44
|
+
const evidencePath = path.join(this.cwd, "EVIDENCE.json");
|
|
45
|
+
try {
|
|
46
|
+
const content = await fs.readFile(evidencePath, "utf8");
|
|
47
|
+
const data = JSON.parse(content);
|
|
48
|
+
evidenceJson = JSON.stringify(data, null, 2);
|
|
49
|
+
evidenceSummary = `Status: ${data.status}, Commands: ${data.commands?.length || 0}`;
|
|
50
|
+
} catch (err) {
|
|
51
|
+
// Optional: don't fail if evidence is missing
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 4. Populate Template
|
|
55
|
+
const templatePath = path.join(import.meta.dirname, "../../../dist-assets/templates/HANDOFF.template.md");
|
|
56
|
+
let template = await fs.readFile(templatePath, "utf8");
|
|
57
|
+
|
|
58
|
+
const packet = template
|
|
59
|
+
.replace("${TASK_ID}", taskId || "unknown")
|
|
60
|
+
.replace("${TIMESTAMP}", timestamp)
|
|
61
|
+
.replace("${AUTHOR}", author || "AI Workflow Kit")
|
|
62
|
+
.replace("${STATUS}", status || "IN_PROGRESS")
|
|
63
|
+
.replace("${SPECS_CONTENT}", specsContent || "No specs provided.")
|
|
64
|
+
.replace("${EVIDENCE_SUMMARY}", evidenceSummary)
|
|
65
|
+
.replace("${EVIDENCE_JSON}", evidenceJson)
|
|
66
|
+
.replace("${GIT_DIFF}", gitDiff)
|
|
67
|
+
.replace("${NEXT_ACTIONS}", nextActions || "Awaiting manager assignment.");
|
|
68
|
+
|
|
69
|
+
const handoffDir = path.join(this.cwd, ".ai-workflow/handoffs");
|
|
70
|
+
await fs.mkdir(handoffDir, { recursive: true });
|
|
71
|
+
|
|
72
|
+
const packetName = `HANDOFF-${taskId || "TMP"}-${Date.now()}.md`;
|
|
73
|
+
const packetPath = path.join(handoffDir, packetName);
|
|
74
|
+
await fs.writeFile(packetPath, packet);
|
|
75
|
+
|
|
76
|
+
return packetPath;
|
|
77
|
+
}
|
|
78
|
+
}
|