@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
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SpecValidator - Enforces "No Spec, No Code" rule.
|
|
5
|
+
* Validates existence, structure, and approval status of specifications.
|
|
6
|
+
*/
|
|
7
|
+
export class SpecValidator {
|
|
8
|
+
/**
|
|
9
|
+
* Validates a specification file.
|
|
10
|
+
* @param {string} filePath - Path to the .md specification file.
|
|
11
|
+
* @returns {Promise<{valid: boolean, reason?: string, tier?: string}>}
|
|
12
|
+
*/
|
|
13
|
+
async validate(filePath) {
|
|
14
|
+
try {
|
|
15
|
+
const content = await fs.readFile(filePath, "utf8");
|
|
16
|
+
|
|
17
|
+
// Check for tiered tier identification
|
|
18
|
+
let tier = "unknown";
|
|
19
|
+
if (content.includes("[DEEP]")) tier = "deep";
|
|
20
|
+
else if (content.includes("[STANDARD]")) tier = "standard";
|
|
21
|
+
else if (content.includes("[TINY]")) tier = "tiny";
|
|
22
|
+
|
|
23
|
+
if (tier === "unknown") {
|
|
24
|
+
return { valid: false, reason: "Specification tier [DEEP|STANDARD|TINY] not identified in title." };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Check for Metadata section
|
|
28
|
+
if (!content.includes("## Metadata")) {
|
|
29
|
+
return { valid: false, reason: "Missing '## Metadata' section.", tier };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Check for Acceptance Criteria section
|
|
33
|
+
if (!content.includes("## Acceptance Criteria")) {
|
|
34
|
+
return { valid: false, reason: "Missing '## Acceptance Criteria' section.", tier };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Check for Approved status
|
|
38
|
+
const lines = content.split("\n");
|
|
39
|
+
const statusLine = lines.find(l => l.includes("Status:"));
|
|
40
|
+
|
|
41
|
+
if (!statusLine) {
|
|
42
|
+
return { valid: false, reason: "Missing Status field in Metadata section.", tier };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const statusPart = statusLine.split(":")[1]
|
|
46
|
+
.replace(/[\*_]/g, "") // Remove bold/italic markers
|
|
47
|
+
.trim()
|
|
48
|
+
.toUpperCase();
|
|
49
|
+
|
|
50
|
+
// If it contains multiple options separated by |, it's not approved yet
|
|
51
|
+
if (statusPart.includes("|")) {
|
|
52
|
+
return { valid: false, reason: "Specification status is a template list. Must be explicitly set to 'APPROVED'.", tier };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (statusPart !== "APPROVED") {
|
|
56
|
+
return { valid: false, reason: `Specification status is '${statusPart}', but must be 'APPROVED' to proceed.`, tier };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return { valid: true, tier };
|
|
60
|
+
} catch (error) {
|
|
61
|
+
if (error.code === "ENOENT") {
|
|
62
|
+
return { valid: false, reason: `Specification file not found: ${filePath}` };
|
|
63
|
+
}
|
|
64
|
+
return { valid: false, reason: `Error reading specification: ${error.message}` };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const COMPLETION_STATUSES = Object.freeze([
|
|
2
|
+
"PASS",
|
|
3
|
+
"PASS_WITH_NOTES",
|
|
4
|
+
"FAIL_DELEGATION_GATE",
|
|
5
|
+
"FAIL_QUALITY_GATE",
|
|
6
|
+
"FAIL",
|
|
7
|
+
"BLOCKED",
|
|
8
|
+
"NOT_RUN"
|
|
9
|
+
]);
|
|
10
|
+
|
|
11
|
+
export const RECOVERABLE_GATE_STATUSES = Object.freeze([
|
|
12
|
+
"FAIL_DELEGATION_GATE",
|
|
13
|
+
"FAIL_QUALITY_GATE"
|
|
14
|
+
]);
|
|
15
|
+
|
|
16
|
+
export const TERMINAL_FAILURE_STATUSES = Object.freeze([
|
|
17
|
+
"FAIL",
|
|
18
|
+
"BLOCKED"
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
export function isRecoverableGateFailure(status) {
|
|
22
|
+
return RECOVERABLE_GATE_STATUSES.includes(status);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function isTerminalFailure(status) {
|
|
26
|
+
return TERMINAL_FAILURE_STATUSES.includes(status);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const COMPLETION_STATUS_TEXT = COMPLETION_STATUSES.join(" | ");
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
function normalize(p) {
|
|
5
|
+
return p.split(path.sep).join("/");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* For v3.0.0 "Elite Governance", we want an ULTRA-CLEAN root.
|
|
10
|
+
* Only "opencode" is symlinked to the root (required for OpenCode discovery).
|
|
11
|
+
* All other assets stay inside .ai-workflow/.
|
|
12
|
+
*/
|
|
13
|
+
const LINKABLE_ROOTS = new Set([
|
|
14
|
+
"opencode",
|
|
15
|
+
".agents"
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
const LINKABLE_FILES = new Set([]);
|
|
19
|
+
|
|
20
|
+
export function buildSymlinkEntries({ templateFiles, installRoot = ".ai-workflow" }) {
|
|
21
|
+
const entries = new Map();
|
|
22
|
+
|
|
23
|
+
for (const relativePath of Object.keys(templateFiles)) {
|
|
24
|
+
if (relativePath === "opencode.jsonc") continue;
|
|
25
|
+
|
|
26
|
+
const normalized = normalize(relativePath);
|
|
27
|
+
|
|
28
|
+
if (LINKABLE_FILES.has(normalized)) {
|
|
29
|
+
entries.set(normalized, `${installRoot}/${normalized}`);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Match composite paths in LINKABLE_ROOTS (e.g., "docs/policies")
|
|
34
|
+
for (const rootPath of LINKABLE_ROOTS) {
|
|
35
|
+
if (normalized === rootPath || normalized.startsWith(`${rootPath}/`)) {
|
|
36
|
+
entries.set(rootPath, `${installRoot}/${rootPath}`);
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return Array.from(entries.entries()).map(([linkPath, targetPath]) => ({ linkPath, targetPath }));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function isSymlinkTo(absoluteLinkPath, absoluteTargetPath) {
|
|
46
|
+
try {
|
|
47
|
+
const stat = await fs.lstat(absoluteLinkPath);
|
|
48
|
+
if (!stat.isSymbolicLink()) return false;
|
|
49
|
+
const currentTarget = await fs.readlink(absoluteLinkPath);
|
|
50
|
+
const resolved = path.resolve(path.dirname(absoluteLinkPath), currentTarget);
|
|
51
|
+
return resolved === absoluteTargetPath;
|
|
52
|
+
} catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Internal symlink to satisfy opencode.jsonc paths without polluting the root.
|
|
59
|
+
* Creates .ai-workflow/opencode/skills -> ../.agents/skills
|
|
60
|
+
*/
|
|
61
|
+
export async function setupInternalSymlinks(cwd, installRoot = ".ai-workflow") {
|
|
62
|
+
const skillsLink = path.join(cwd, installRoot, "opencode/skills");
|
|
63
|
+
const skillsTarget = path.join(cwd, installRoot, ".agents/skills");
|
|
64
|
+
|
|
65
|
+
if (!(await exists(skillsTarget))) return;
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const stat = await fs.lstat(skillsLink).catch(() => null);
|
|
69
|
+
if (stat) {
|
|
70
|
+
if (stat.isSymbolicLink()) {
|
|
71
|
+
const current = await fs.readlink(skillsLink);
|
|
72
|
+
if (current === "../.agents/skills") return;
|
|
73
|
+
await fs.unlink(skillsLink);
|
|
74
|
+
} else {
|
|
75
|
+
return; // File exists, skip
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const type = process.platform === "win32" ? "junction" : "dir";
|
|
80
|
+
await fs.symlink("../.agents/skills", skillsLink, type);
|
|
81
|
+
} catch {
|
|
82
|
+
// Silent fail for internal symlink
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function exists(p) {
|
|
87
|
+
try {
|
|
88
|
+
await fs.access(p);
|
|
89
|
+
return true;
|
|
90
|
+
} catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { getFullAgentContent, getFullSkillFiles, discoverPackageFiles, readPackageFile, getPackageVersion } from "./package-assets.js";
|
|
2
|
+
import { getCanonicalAgentName } from "./identity.js";
|
|
3
|
+
|
|
4
|
+
const COMMON_FILES = {
|
|
5
|
+
"opencode/README.md": `# OpenCode Setup\n\nThis directory is managed by \`ai-workflow\` init.\nAdd agent and command files required by your project workflow.\n`
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const FULL_PRIMARY_AGENTS = [
|
|
9
|
+
"atlas",
|
|
10
|
+
"nexus",
|
|
11
|
+
"orion",
|
|
12
|
+
"astra",
|
|
13
|
+
"sage",
|
|
14
|
+
"phoenix"
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const FULL_SKILLS = [
|
|
18
|
+
"project-memory",
|
|
19
|
+
"optimize-tokens",
|
|
20
|
+
"documentation",
|
|
21
|
+
"architecture",
|
|
22
|
+
"technical-leadership",
|
|
23
|
+
"product-discovery",
|
|
24
|
+
"product-planning",
|
|
25
|
+
"spec-driven-development",
|
|
26
|
+
"pr-workflow",
|
|
27
|
+
"qa-workflow",
|
|
28
|
+
"release-workflow",
|
|
29
|
+
"deployment",
|
|
30
|
+
"ui-ux-design",
|
|
31
|
+
"design-principles",
|
|
32
|
+
"frontend-development",
|
|
33
|
+
"backend-development",
|
|
34
|
+
"full-stack-development",
|
|
35
|
+
"refactoring",
|
|
36
|
+
"prompt-engineer"
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const KIT_VERSION = getPackageVersion() ?? "unknown";
|
|
40
|
+
|
|
41
|
+
function buildRuntimeFiles({ includeFormalEvidence = false } = {}) {
|
|
42
|
+
const files = {};
|
|
43
|
+
|
|
44
|
+
for (const agent of FULL_PRIMARY_AGENTS) {
|
|
45
|
+
const content = getFullAgentContent(agent);
|
|
46
|
+
if (content === null) {
|
|
47
|
+
throw new Error(`CRITICAL FAILURE: Missing required agent asset: dist-assets/agents/${agent}.md`);
|
|
48
|
+
}
|
|
49
|
+
files[`opencode/agents/${agent}.md`] = content;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
for (const skill of FULL_SKILLS) {
|
|
53
|
+
const skillFiles = getFullSkillFiles(skill);
|
|
54
|
+
if (Object.keys(skillFiles).length === 0) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
for (const [relPath, content] of Object.entries(skillFiles)) {
|
|
58
|
+
const targetPath = relPath.replace(/^dist-assets\//, "opencode/");
|
|
59
|
+
if (!files[targetPath]) {
|
|
60
|
+
files[targetPath] = content;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const commandFiles = discoverPackageFiles("dist-assets/commands");
|
|
66
|
+
for (const [relPath, content] of Object.entries(commandFiles)) {
|
|
67
|
+
const targetPath = relPath.replace(/^dist-assets\//, "opencode/");
|
|
68
|
+
if (!files[targetPath]) {
|
|
69
|
+
files[targetPath] = content;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const opencodeSkillFiles = discoverPackageFiles("dist-assets/skills");
|
|
74
|
+
for (const [relPath, content] of Object.entries(opencodeSkillFiles)) {
|
|
75
|
+
const targetPath = relPath.replace(/^dist-assets\//, "opencode/");
|
|
76
|
+
if (!files[targetPath]) {
|
|
77
|
+
files[targetPath] = content;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const harnessWorkflowFiles = discoverPackageFiles("dist-assets/harness/workflows");
|
|
82
|
+
for (const [relPath, content] of Object.entries(harnessWorkflowFiles)) {
|
|
83
|
+
const targetPath = relPath.replace(/^dist-assets\//, "");
|
|
84
|
+
files[targetPath] = content;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const harnessHandoffFiles = discoverPackageFiles("dist-assets/harness/handoffs");
|
|
88
|
+
for (const [relPath, content] of Object.entries(harnessHandoffFiles)) {
|
|
89
|
+
const targetPath = relPath.replace(/^dist-assets\//, "");
|
|
90
|
+
files[targetPath] = content;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const agentsContent = readPackageFile("dist-assets/AGENTS.md");
|
|
94
|
+
if (agentsContent !== null) files["AGENTS.md"] = agentsContent;
|
|
95
|
+
|
|
96
|
+
const consumerQuickstart = readPackageFile("dist-assets/docs/QUICKSTART.md");
|
|
97
|
+
if (consumerQuickstart !== null) files["QUICKSTART.md"] = consumerQuickstart;
|
|
98
|
+
|
|
99
|
+
const policyContent = readPackageFile("dist-assets/docs/architecture-policy.md");
|
|
100
|
+
if (policyContent !== null) files["docs/architecture-policy.md"] = policyContent;
|
|
101
|
+
|
|
102
|
+
const dpContent = readPackageFile("dist-assets/docs/design-patterns-policy.md");
|
|
103
|
+
if (dpContent !== null) files["docs/design-patterns-policy.md"] = dpContent;
|
|
104
|
+
|
|
105
|
+
const governancePolicies = discoverPackageFiles("dist-assets/docs/policies");
|
|
106
|
+
for (const [relPath, content] of Object.entries(governancePolicies)) {
|
|
107
|
+
const targetPath = relPath.replace(/^dist-assets\//, "");
|
|
108
|
+
files[targetPath] = content;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const compatibilityDocs = discoverPackageFiles("dist-assets/docs/compatibility");
|
|
112
|
+
for (const [relPath, content] of Object.entries(compatibilityDocs)) {
|
|
113
|
+
const targetPath = relPath.replace(/^dist-assets\//, "");
|
|
114
|
+
files[targetPath] = content;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const qualityReferenceFiles = discoverPackageFiles("dist-assets/docs/references");
|
|
118
|
+
for (const [relPath, content] of Object.entries(qualityReferenceFiles)) {
|
|
119
|
+
const targetPath = relPath.replace(/^dist-assets\//, "");
|
|
120
|
+
files[targetPath] = content;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const workflowProfileFiles = discoverPackageFiles("dist-assets/docs/profiles");
|
|
124
|
+
for (const [relPath, content] of Object.entries(workflowProfileFiles)) {
|
|
125
|
+
const targetPath = relPath.replace(/^dist-assets\//, "");
|
|
126
|
+
files[targetPath] = content;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const templateFiles = discoverPackageFiles("dist-assets/templates");
|
|
130
|
+
for (const [relPath, content] of Object.entries(templateFiles)) {
|
|
131
|
+
if (!includeFormalEvidence && relPath.includes("/owner-evidence/")) continue;
|
|
132
|
+
const targetPath = relPath.replace(/^dist-assets\//, "");
|
|
133
|
+
files[targetPath] = content;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const schemaFiles = discoverPackageFiles("dist-assets/schemas");
|
|
137
|
+
for (const [relPath, content] of Object.entries(schemaFiles)) {
|
|
138
|
+
const targetPath = relPath.replace(/^dist-assets\//, "");
|
|
139
|
+
files[targetPath] = content;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return files;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function buildExtraFiles() {
|
|
146
|
+
const files = {};
|
|
147
|
+
const exampleFiles = discoverPackageFiles("dist-assets/examples");
|
|
148
|
+
for (const [relPath, content] of Object.entries(exampleFiles)) {
|
|
149
|
+
const targetPath = relPath.replace(/^dist-assets\//, "");
|
|
150
|
+
files[targetPath] = content;
|
|
151
|
+
}
|
|
152
|
+
return files;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const STANDARD_FILES = buildRuntimeFiles();
|
|
156
|
+
const FULL_FILES = { ...buildRuntimeFiles({ includeFormalEvidence: true }), ...buildExtraFiles() };
|
|
157
|
+
|
|
158
|
+
export const PROFILE_FILES = {
|
|
159
|
+
standard: {
|
|
160
|
+
...COMMON_FILES,
|
|
161
|
+
...STANDARD_FILES
|
|
162
|
+
},
|
|
163
|
+
full: {
|
|
164
|
+
...COMMON_FILES,
|
|
165
|
+
...FULL_FILES
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
export function isValidProfile(profile) {
|
|
170
|
+
return profile === "standard" || profile === "full";
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function getTemplateFiles(profile = "standard") {
|
|
174
|
+
return PROFILE_FILES[profile] ?? PROFILE_FILES.standard;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function getManagedBlocks() {
|
|
178
|
+
return [
|
|
179
|
+
...FULL_PRIMARY_AGENTS.map((agent) => `opencode.jsonc:agent.${getCanonicalAgentName(agent)}`),
|
|
180
|
+
...FULL_SKILLS.map((skill) => `opencode.jsonc:agent.${getCanonicalAgentName(skill)}`),
|
|
181
|
+
"opencode.jsonc:command.atlas",
|
|
182
|
+
"opencode.jsonc:command.run",
|
|
183
|
+
"opencode.jsonc:command.discover",
|
|
184
|
+
"opencode.jsonc:command.spec-create",
|
|
185
|
+
"opencode.jsonc:command.spec-review",
|
|
186
|
+
"opencode.jsonc:command.spec-implement",
|
|
187
|
+
"opencode.jsonc:command.plan",
|
|
188
|
+
"opencode.jsonc:command.implement",
|
|
189
|
+
"opencode.jsonc:command.validate",
|
|
190
|
+
"opencode.jsonc:command.audit",
|
|
191
|
+
"opencode.jsonc:command.optimize-tokens",
|
|
192
|
+
"opencode.jsonc:command.update-memory",
|
|
193
|
+
"opencode.jsonc:command.release",
|
|
194
|
+
"opencode.jsonc:command.deploy"
|
|
195
|
+
];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export function buildAiWorkflowConfig({ profile, managedFiles, managedLinks = [] }) {
|
|
199
|
+
const version = getPackageVersion();
|
|
200
|
+
const now = new Date().toISOString();
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
package: "@williambeto/ai-workflow",
|
|
204
|
+
version,
|
|
205
|
+
runtime: "opencode",
|
|
206
|
+
profile,
|
|
207
|
+
installMode: "project-local",
|
|
208
|
+
generatedAt: now,
|
|
209
|
+
paths: {
|
|
210
|
+
agents: ".ai-workflow/opencode/agents",
|
|
211
|
+
commands: ".ai-workflow/opencode/commands",
|
|
212
|
+
skills: ".ai-workflow/opencode/skills",
|
|
213
|
+
policies: ".ai-workflow/docs/policies",
|
|
214
|
+
harness: ".ai-workflow/harness",
|
|
215
|
+
schemas: ".ai-workflow/schemas"
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export const DELIVERY_SUMMARY_FIELDS = Object.freeze([
|
|
2
|
+
"Status",
|
|
3
|
+
"Branch",
|
|
4
|
+
"Changes",
|
|
5
|
+
"Validation",
|
|
6
|
+
"Known limitations"
|
|
7
|
+
]);
|
|
8
|
+
|
|
9
|
+
export function buildDeliverySummary({ evidence }) {
|
|
10
|
+
const commands = (evidence?.commands || []).map((item) => `${item.command || item.name}: ${item.status}`).join("; ") || "No validation commands recorded";
|
|
11
|
+
return {
|
|
12
|
+
Status: evidence?.status || "BLOCKED",
|
|
13
|
+
Branch: evidence?.branch || "unknown",
|
|
14
|
+
Changes: (evidence?.changedFiles || []).join(", ") || "No changed files recorded",
|
|
15
|
+
Validation: commands,
|
|
16
|
+
"Known limitations": (evidence?.limitations || []).join("; ") || "None recorded"
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function validateDeliverySummary(summary) {
|
|
21
|
+
const missing = DELIVERY_SUMMARY_FIELDS.filter((field) => !String(summary?.[field] || "").trim());
|
|
22
|
+
const status = String(summary?.Status || "").trim();
|
|
23
|
+
const invalid = [];
|
|
24
|
+
if (!["COMPLETED", "COMPLETED_WITH_NOTES", "BLOCKED"].includes(status)) invalid.push("Status");
|
|
25
|
+
if (status !== "BLOCKED" && /FAIL|BLOCKED/.test(String(summary?.Validation || ""))) invalid.push("successful status with failed validation");
|
|
26
|
+
return { status: missing.length || invalid.length ? "FAIL" : "PASS", missing, invalid };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function formatDeliverySummary(summary) {
|
|
30
|
+
return DELIVERY_SUMMARY_FIELDS.map((field) => `${field}: ${summary?.[field] || "NOT_RECORDED"}`).join("\n");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Backward-compatible aliases for integrations that imported the previous API.
|
|
34
|
+
export const CANONICAL_FINALIZATION_FIELDS = DELIVERY_SUMMARY_FIELDS;
|
|
35
|
+
export const buildCanonicalFinalization = ({ collectorStatus = "BLOCKED", branchRecovery = "unknown" } = {}) => ({
|
|
36
|
+
Status: collectorStatus === "PASS" ? "COMPLETED" : collectorStatus === "PASS_WITH_NOTES" ? "COMPLETED_WITH_NOTES" : "BLOCKED",
|
|
37
|
+
Branch: branchRecovery,
|
|
38
|
+
Changes: "See observed diff",
|
|
39
|
+
Validation: collectorStatus,
|
|
40
|
+
"Known limitations": "See evidence"
|
|
41
|
+
});
|
|
42
|
+
export const validateCanonicalFinalization = validateDeliverySummary;
|
|
43
|
+
export const formatCanonicalFinalization = formatDeliverySummary;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { QualityGuard } from "./quality-guard.js";
|
|
5
|
+
|
|
6
|
+
const VALIDATION_KINDS = new Set(["test", "build", "typecheck", "lint", "security", "smoke", "validate", "other"]);
|
|
7
|
+
|
|
8
|
+
function publicStatus(status) {
|
|
9
|
+
if (status === "PASS") return "COMPLETED";
|
|
10
|
+
if (status === "PASS_WITH_NOTES") return "COMPLETED_WITH_NOTES";
|
|
11
|
+
return "BLOCKED";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function inferTaskKind(task = {}) {
|
|
15
|
+
const explicit = String(task.kind || "").trim().toLowerCase();
|
|
16
|
+
if (VALIDATION_KINDS.has(explicit)) return explicit;
|
|
17
|
+
|
|
18
|
+
const value = `${task.name || ""} ${task.command || ""}`.toLowerCase();
|
|
19
|
+
if (/\b(test|tests|vitest|jest|mocha|ava|tap|pytest|phpunit|rspec|cypress|playwright)\b/.test(value)) return "test";
|
|
20
|
+
if (/\b(typecheck|tsc\b|mypy|pyright)\b/.test(value)) return "typecheck";
|
|
21
|
+
if (/\b(lint|eslint|stylelint|ruff|flake8|pylint)\b/.test(value)) return "lint";
|
|
22
|
+
if (/\b(build|bundle|compile)\b/.test(value)) return "build";
|
|
23
|
+
if (/\b(audit|security|sast|scan)\b/.test(value)) return "security";
|
|
24
|
+
if (/\b(smoke|curl|preview|serve)\b/.test(value)) return "smoke";
|
|
25
|
+
if (/\bvalidate\b/.test(value)) return "validate";
|
|
26
|
+
return "other";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class EvidenceCollector {
|
|
30
|
+
constructor({ cwd, maxLogLength = 2000, timeout = 60000, taskSlug = null, mode = null, profile = "generic", branchRecovery = "NOT_RECORDED" } = {}) {
|
|
31
|
+
this.cwd = cwd;
|
|
32
|
+
this.maxLogLength = maxLogLength;
|
|
33
|
+
this.timeout = timeout;
|
|
34
|
+
this.taskSlug = taskSlug;
|
|
35
|
+
this.mode = mode;
|
|
36
|
+
this.profile = profile;
|
|
37
|
+
this.branchRecovery = branchRecovery;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
runTask(task) {
|
|
41
|
+
const kind = inferTaskKind(task);
|
|
42
|
+
if (task.presetStatus) {
|
|
43
|
+
return { name: task.name, command: task.command, kind, status: task.presetStatus, exitCode: null, summary: task.summary, output: "" };
|
|
44
|
+
}
|
|
45
|
+
const result = spawnSync(task.command, {
|
|
46
|
+
cwd: this.cwd,
|
|
47
|
+
shell: true,
|
|
48
|
+
encoding: "utf8",
|
|
49
|
+
timeout: this.timeout
|
|
50
|
+
});
|
|
51
|
+
let status = result.status === 0 ? "PASS" : "FAIL";
|
|
52
|
+
let summary = status === "PASS" ? "Command completed successfully." : "Command failed.";
|
|
53
|
+
if (result.error?.code === "ETIMEDOUT") {
|
|
54
|
+
status = "BLOCKED";
|
|
55
|
+
summary = `Command timed out after ${this.timeout / 1000}s.`;
|
|
56
|
+
}
|
|
57
|
+
const rawOutput = `${result.stdout || ""}${result.stderr || ""}`.trim();
|
|
58
|
+
const output = rawOutput.length > this.maxLogLength ? `${rawOutput.slice(0, this.maxLogLength)}\n... [TRUNCATED]` : rawOutput;
|
|
59
|
+
return { name: task.name, command: task.command, kind, status, exitCode: result.status, signal: result.signal, summary, output };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async collect(tasks, { writeArtifact = false } = {}) {
|
|
63
|
+
const qualityGuard = new QualityGuard({ cwd: this.cwd, taskSlug: this.taskSlug, mode: this.mode, evidenceWillBePersisted: writeArtifact });
|
|
64
|
+
const implementation = qualityGuard.isImplementationTask();
|
|
65
|
+
const executableBehavior = await qualityGuard.hasExecutableBehaviorChanges();
|
|
66
|
+
const results = tasks.map((task) => this.runTask(task));
|
|
67
|
+
const policyValidation = await qualityGuard.verify();
|
|
68
|
+
const behaviorTests = results.filter((result) => result.kind === "test");
|
|
69
|
+
const passingBehaviorTest = behaviorTests.some((result) => result.status === "PASS");
|
|
70
|
+
|
|
71
|
+
let overallStatus = "PASS";
|
|
72
|
+
if (implementation && executableBehavior && tasks.length === 0) overallStatus = "BLOCKED";
|
|
73
|
+
else if (results.some((result) => ["FAIL", "BLOCKED", "FAIL_QUALITY_GATE"].includes(result.status))) overallStatus = "FAIL_QUALITY_GATE";
|
|
74
|
+
else if (executableBehavior && !passingBehaviorTest) overallStatus = "BLOCKED";
|
|
75
|
+
else if (["FAIL", "BLOCKED", "FAIL_QUALITY_GATE"].includes(policyValidation.overallStatus)) overallStatus = "FAIL_QUALITY_GATE";
|
|
76
|
+
else if (results.some((result) => result.status === "PASS_WITH_NOTES") || policyValidation.overallStatus === "PASS_WITH_NOTES") overallStatus = "PASS_WITH_NOTES";
|
|
77
|
+
|
|
78
|
+
const limitations = [];
|
|
79
|
+
if (implementation && executableBehavior && tasks.length === 0) limitations.push("No meaningful validation command was available for executable implementation work.");
|
|
80
|
+
if (executableBehavior && behaviorTests.length === 0) {
|
|
81
|
+
limitations.push("Executable behavior changed without a proportional automated behavior test. Build, lint, typecheck, smoke, screenshots, and manual review do not replace behavior tests.");
|
|
82
|
+
}
|
|
83
|
+
for (const [name, check] of Object.entries(policyValidation.checks || {})) {
|
|
84
|
+
if (check.status === "PASS_WITH_NOTES" && check.reason) limitations.push(`${name}: ${check.reason}`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const evidence = {
|
|
88
|
+
timestamp: new Date().toISOString(),
|
|
89
|
+
taskSlug: this.taskSlug,
|
|
90
|
+
executionMode: this.mode,
|
|
91
|
+
workflowProfile: this.profile,
|
|
92
|
+
branchRecovery: this.branchRecovery,
|
|
93
|
+
branch: policyValidation.git?.branch || "unknown",
|
|
94
|
+
changedFiles: policyValidation.git?.changedFiles || [],
|
|
95
|
+
status: publicStatus(overallStatus),
|
|
96
|
+
internalStatus: overallStatus,
|
|
97
|
+
commands: results,
|
|
98
|
+
checks: policyValidation.checks,
|
|
99
|
+
limitations
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
if (writeArtifact) {
|
|
103
|
+
await fs.writeFile(path.join(this.cwd, "EVIDENCE.json"), JSON.stringify(evidence, null, 2));
|
|
104
|
+
}
|
|
105
|
+
return evidence;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export { inferTaskKind };
|