@pennyfarthing/core 9.0.0 → 9.1.2
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/README.md +16 -7
- package/package.json +1 -1
- package/packages/core/dist/cli/commands/doctor.d.ts +5 -2
- package/packages/core/dist/cli/commands/doctor.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/doctor.js +327 -17
- package/packages/core/dist/cli/commands/doctor.js.map +1 -1
- package/packages/core/dist/cli/commands/init.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/init.js +3 -246
- package/packages/core/dist/cli/commands/init.js.map +1 -1
- package/packages/core/dist/cli/commands/update.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/update.js +4 -140
- package/packages/core/dist/cli/commands/update.js.map +1 -1
- package/packages/core/dist/cli/utils/constants.d.ts +7 -1
- package/packages/core/dist/cli/utils/constants.d.ts.map +1 -1
- package/packages/core/dist/cli/utils/constants.js +2 -0
- package/packages/core/dist/cli/utils/constants.js.map +1 -1
- package/packages/core/dist/cli/utils/settings.d.ts +22 -0
- package/packages/core/dist/cli/utils/settings.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/settings.js +300 -0
- package/packages/core/dist/cli/utils/settings.js.map +1 -0
- package/pennyfarthing-dist/commands/chore.md +18 -17
- package/pennyfarthing-dist/commands/continue-session.md +41 -7
- package/pennyfarthing-dist/commands/fix-blocker.md +22 -0
- package/pennyfarthing-dist/commands/git-cleanup.md +25 -19
- package/pennyfarthing-dist/commands/patch.md +210 -0
- package/pennyfarthing-dist/commands/setup.md +65 -0
- package/pennyfarthing-dist/guides/session-schema.md +346 -0
- package/pennyfarthing-dist/guides/skill-schema.md +412 -0
- package/pennyfarthing-dist/guides/workflow-step-schema.md +512 -0
- package/pennyfarthing-dist/guides/xml-tags.md +292 -0
- package/pennyfarthing-dist/scripts/hooks/__pycache__/question_reflector_check.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +43 -8
- package/pennyfarthing-dist/scripts/hooks/schema-validation.sh +30 -0
- package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +78 -0
- package/pennyfarthing-dist/scripts/lib/find-root.sh +32 -7
- package/pennyfarthing-dist/scripts/misc/generate-skill-docs.sh +13 -2
- package/pennyfarthing-dist/scripts/sprint/validate-sprint-yaml.sh +139 -0
- package/pennyfarthing-dist/skills/agentic-patterns/SKILL.md +4 -0
- package/pennyfarthing-dist/skills/changelog/SKILL.md +18 -0
- package/pennyfarthing-dist/skills/code-review/SKILL.md +5 -1
- package/pennyfarthing-dist/skills/context-engineering/SKILL.md +3 -0
- package/pennyfarthing-dist/skills/cyclist/SKILL.md +2 -2
- package/pennyfarthing-dist/skills/dev-patterns/SKILL.md +24 -0
- package/pennyfarthing-dist/skills/finalize-run/SKILL.md +3 -0
- package/pennyfarthing-dist/skills/judge/SKILL.md +8 -0
- package/pennyfarthing-dist/skills/just/SKILL.md +11 -0
- package/pennyfarthing-dist/skills/mermaid/SKILL.md +16 -0
- package/pennyfarthing-dist/skills/otel/skill.md +4 -0
- package/pennyfarthing-dist/skills/permissions/skill.md +3 -0
- package/pennyfarthing-dist/skills/persona-benchmark/SKILL.md +9 -0
- package/pennyfarthing-dist/skills/story/skill.md +16 -16
- package/pennyfarthing-dist/skills/systematic-debugging/SKILL.md +56 -0
- package/pennyfarthing-dist/skills/testing/SKILL.md +22 -0
- package/pennyfarthing-dist/skills/theme/skill.md +12 -0
- package/pennyfarthing-dist/skills/theme-creation/SKILL.md +4 -0
- package/pennyfarthing-dist/skills/workflow/skill.md +22 -14
- package/pennyfarthing-dist/skills/yq/SKILL.md +8 -0
- package/pennyfarthing-dist/templates/settings.local.json.template +9 -0
- package/pennyfarthing-dist/workflows/architecture/steps/step-01-initialize.md +12 -0
- package/pennyfarthing-dist/workflows/architecture/steps/step-01b-continue.md +12 -0
- package/pennyfarthing-dist/workflows/architecture/steps/step-02-context.md +12 -0
- package/pennyfarthing-dist/workflows/architecture/steps/step-03-patterns.md +12 -0
- package/pennyfarthing-dist/workflows/architecture/steps/step-04-components.md +12 -0
- package/pennyfarthing-dist/workflows/architecture/steps/step-05-interfaces.md +12 -0
- package/pennyfarthing-dist/workflows/architecture/steps/step-06-risks.md +12 -0
- package/pennyfarthing-dist/workflows/architecture/steps/step-07-document.md +12 -0
- package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-01-validate-prerequisites.md +25 -0
- package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-02-design-epics.md +23 -0
- package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-03-create-stories.md +26 -0
- package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-04-final-validation.md +24 -0
- package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-05-import-to-future.md +23 -0
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-01-analyze.md +43 -41
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-02-categorize.md +50 -19
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-03-execute.md +102 -111
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-04-verify.md +48 -39
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-05-complete.md +30 -31
- package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-01-document-discovery.md +21 -0
- package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-02-prd-analysis.md +21 -0
- package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-03-epic-coverage-validation.md +23 -0
- package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-04-ux-alignment.md +23 -0
- package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-05-epic-quality-review.md +28 -0
- package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-06-final-assessment.md +25 -0
- package/pennyfarthing-dist/workflows/interactive-debug/steps/step-01-connect.md +257 -0
- package/pennyfarthing-dist/workflows/interactive-debug/steps/step-02-explore.md +107 -0
- package/pennyfarthing-dist/workflows/interactive-debug/steps/step-03-fix.md +127 -0
- package/pennyfarthing-dist/workflows/interactive-debug/steps/step-04-commit.md +122 -0
- package/pennyfarthing-dist/workflows/interactive-debug/workflow.yaml +51 -0
- package/pennyfarthing-dist/workflows/patch.yaml +2 -3
- package/pennyfarthing-dist/workflows/prd/steps-c/step-01-init.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-01b-continue.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-02-discovery.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-03-success.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-04-journeys.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-05-domain.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-06-innovation.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-07-project-type.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-08-scoping.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-09-functional.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-10-nonfunctional.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-11-polish.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-12-complete.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-e/step-e-01-discovery.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-e/step-e-01b-legacy-conversion.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-e/step-e-02-review.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-e/step-e-03-edit.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-e/step-e-04-complete.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-01-discovery.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-02-format-detection.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-02b-parity-check.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-03-density-validation.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-04-brief-coverage-validation.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-05-measurability-validation.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-06-traceability-validation.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-07-implementation-leakage-validation.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-08-domain-compliance-validation.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-09-project-type-validation.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-10-smart-validation.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-11-holistic-quality-validation.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-12-completeness-validation.md +6 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-13-report-complete.md +6 -0
- package/pennyfarthing-dist/workflows/product-brief/steps/step-01-init.md +18 -0
- package/pennyfarthing-dist/workflows/product-brief/steps/step-01b-continue.md +19 -0
- package/pennyfarthing-dist/workflows/product-brief/steps/step-02-vision.md +22 -0
- package/pennyfarthing-dist/workflows/product-brief/steps/step-03-users.md +22 -0
- package/pennyfarthing-dist/workflows/product-brief/steps/step-04-metrics.md +23 -0
- package/pennyfarthing-dist/workflows/product-brief/steps/step-05-scope.md +24 -0
- package/pennyfarthing-dist/workflows/product-brief/steps/step-06-complete.md +22 -0
- package/pennyfarthing-dist/workflows/project-context/steps/step-01-discover.md +22 -0
- package/pennyfarthing-dist/workflows/project-context/steps/step-02-generate.md +31 -0
- package/pennyfarthing-dist/workflows/project-context/steps/step-03-complete.md +28 -0
- package/pennyfarthing-dist/workflows/project-setup/steps/step-01-discover.md +157 -0
- package/pennyfarthing-dist/workflows/project-setup/steps/step-02-clone-repos.md +217 -0
- package/pennyfarthing-dist/workflows/project-setup/steps/step-03-repos-yaml.md +159 -0
- package/pennyfarthing-dist/workflows/project-setup/steps/step-04-claude-md.md +186 -0
- package/pennyfarthing-dist/workflows/project-setup/steps/step-05-shared-context.md +185 -0
- package/pennyfarthing-dist/workflows/project-setup/steps/step-06-task-runner.md +279 -0
- package/pennyfarthing-dist/workflows/project-setup/steps/step-07-theme.md +200 -0
- package/pennyfarthing-dist/workflows/project-setup/steps/step-08-cyclist.md +245 -0
- package/pennyfarthing-dist/workflows/project-setup/steps/step-09-complete.md +203 -0
- package/pennyfarthing-dist/workflows/project-setup/workflow.yaml +41 -0
- package/pennyfarthing-dist/workflows/quick-dev/steps/step-01-mode-detection.md +21 -0
- package/pennyfarthing-dist/workflows/quick-dev/steps/step-02-context-gathering.md +23 -0
- package/pennyfarthing-dist/workflows/quick-dev/steps/step-03-execute.md +25 -0
- package/pennyfarthing-dist/workflows/quick-dev/steps/step-04-self-check.md +22 -0
- package/pennyfarthing-dist/workflows/quick-dev/steps/step-05-adversarial-review.md +23 -0
- package/pennyfarthing-dist/workflows/quick-dev/steps/step-06-resolve-findings.md +23 -0
- package/pennyfarthing-dist/workflows/quick-spec/steps/step-01-understand.md +12 -0
- package/pennyfarthing-dist/workflows/quick-spec/steps/step-02-investigate.md +12 -0
- package/pennyfarthing-dist/workflows/quick-spec/steps/step-03-generate.md +12 -0
- package/pennyfarthing-dist/workflows/quick-spec/steps/step-04-review.md +12 -0
- package/pennyfarthing-dist/workflows/research/steps-domain/step-01-init.md +22 -0
- package/pennyfarthing-dist/workflows/research/steps-domain/step-02-domain-analysis.md +24 -0
- package/pennyfarthing-dist/workflows/research/steps-domain/step-03-competitive-landscape.md +25 -0
- package/pennyfarthing-dist/workflows/research/steps-domain/step-04-regulatory-focus.md +26 -0
- package/pennyfarthing-dist/workflows/research/steps-domain/step-05-technical-trends.md +26 -0
- package/pennyfarthing-dist/workflows/research/steps-domain/step-06-research-synthesis.md +34 -0
- package/pennyfarthing-dist/workflows/research/steps-market/step-01-init.md +23 -0
- package/pennyfarthing-dist/workflows/research/steps-market/step-02-customer-behavior.md +25 -0
- package/pennyfarthing-dist/workflows/research/steps-market/step-02-customer-insights.md +27 -0
- package/pennyfarthing-dist/workflows/research/steps-market/step-03-customer-pain-points.md +26 -0
- package/pennyfarthing-dist/workflows/research/steps-market/step-04-customer-decisions.md +27 -0
- package/pennyfarthing-dist/workflows/research/steps-market/step-05-competitive-analysis.md +26 -0
- package/pennyfarthing-dist/workflows/research/steps-market/step-06-research-completion.md +35 -0
- package/pennyfarthing-dist/workflows/research/steps-technical/step-01-init.md +22 -0
- package/pennyfarthing-dist/workflows/research/steps-technical/step-02-technical-overview.md +25 -0
- package/pennyfarthing-dist/workflows/research/steps-technical/step-03-integration-patterns.md +26 -0
- package/pennyfarthing-dist/workflows/research/steps-technical/step-04-architectural-patterns.md +26 -0
- package/pennyfarthing-dist/workflows/research/steps-technical/step-05-implementation-research.md +29 -1
- package/pennyfarthing-dist/workflows/research/steps-technical/step-06-research-synthesis.md +37 -1
- package/pennyfarthing-dist/workflows/sprint-planning/steps/step-01-parse-epic-files.md +15 -0
- package/pennyfarthing-dist/workflows/sprint-planning/steps/step-02-build-sprint-status.md +17 -0
- package/pennyfarthing-dist/workflows/sprint-planning/steps/step-03-status-detection.md +16 -0
- package/pennyfarthing-dist/workflows/sprint-planning/steps/step-04-generate-status-file.md +17 -0
- package/pennyfarthing-dist/workflows/sprint-planning/steps/step-05-validate-and-report.md +22 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-01-init.md +6 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-01b-continue.md +6 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-02-discovery.md +6 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-03-core-experience.md +6 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-04-emotional-response.md +6 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-05-inspiration.md +6 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-06-design-system.md +6 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-07-defining-experience.md +6 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-08-visual-foundation.md +6 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-09-design-directions.md +6 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-10-user-journeys.md +6 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-11-component-strategy.md +6 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-12-ux-patterns.md +6 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-13-responsive-accessibility.md +6 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-14-complete.md +6 -0
- package/pennyfarthing_scripts/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/config.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/hooks.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira_bidirectional_sync.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira_epic_creation.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira_sync.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira_sync_story.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/output.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/patch_mode.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/schema_validation_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/sprint.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/workflow.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/discover.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/output.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/create_branches.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/status_all.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/bidirectional.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/claim.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/client.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/compat.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/epic.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/mappings.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/story.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/sync.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__init__.py +39 -0
- package/pennyfarthing_scripts/migration/__main__.py +10 -0
- package/pennyfarthing_scripts/migration/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/session.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/skill.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/step.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/validate.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/cli.py +304 -0
- package/pennyfarthing_scripts/migration/session.py +384 -0
- package/pennyfarthing_scripts/migration/skill.py +188 -0
- package/pennyfarthing_scripts/migration/step.py +229 -0
- package/pennyfarthing_scripts/migration/validate.py +282 -0
- package/pennyfarthing_scripts/preflight/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/preflight/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/preflight/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/preflight/__pycache__/finish.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/loader.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/persona.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/session.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/tiers.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/schema_validation_hook.py +306 -0
- package/pennyfarthing_scripts/sprint/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/archive_epic.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/status.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/archive_epic.py +399 -0
- package/pennyfarthing_scripts/sprint/cli.py +100 -0
- package/pennyfarthing_scripts/sprint/import_epic.py +431 -0
- package/pennyfarthing_scripts/story/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/create.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/size.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/template.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_brownfield.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_cli_modules.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_common.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_git_utils.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_jira_package.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_package_structure.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_patch_mode.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_prime.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_sprint_package.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_sprint_validator.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_story_package.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_tiers.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_token_counting.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_workflow_check.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_workflow_cli.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing-dist/scripts/sprint/import-epic-to-future.sh +0 -10
- package/pennyfarthing-dist/scripts/sprint/import_epic_to_future.py +0 -270
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Workflow step file auditing tools.
|
|
3
|
+
|
|
4
|
+
Audits workflow step files for conformance to guides/workflow-step-schema.md.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import re
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Tag requirements
|
|
15
|
+
REQUIRED_TAGS = ["step-meta", "purpose", "instructions", "output"]
|
|
16
|
+
RECOMMENDED_TAGS = ["prerequisites", "actions", "collaboration-menu", "next-step"]
|
|
17
|
+
OPTIONAL_TAGS = ["gate"]
|
|
18
|
+
|
|
19
|
+
# step-meta required fields
|
|
20
|
+
STEP_META_FIELDS = ["number", "name", "gate"]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class StepAuditResult:
|
|
25
|
+
"""Result of auditing a workflow step file."""
|
|
26
|
+
|
|
27
|
+
workflow_name: str
|
|
28
|
+
step_name: str
|
|
29
|
+
file_path: Path
|
|
30
|
+
missing_required: list[str] = field(default_factory=list)
|
|
31
|
+
missing_recommended: list[str] = field(default_factory=list)
|
|
32
|
+
missing_meta_fields: list[str] = field(default_factory=list)
|
|
33
|
+
present_tags: list[str] = field(default_factory=list)
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def is_valid(self) -> bool:
|
|
37
|
+
"""Check if step passes validation (has all required)."""
|
|
38
|
+
return len(self.missing_required) == 0 and len(self.missing_meta_fields) == 0
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def status(self) -> str:
|
|
42
|
+
"""Get status string."""
|
|
43
|
+
if not self.is_valid:
|
|
44
|
+
return "NEEDS UPDATE"
|
|
45
|
+
if self.missing_recommended:
|
|
46
|
+
return "PARTIAL"
|
|
47
|
+
return "OK"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _has_tag(content: str, tag: str) -> bool:
|
|
51
|
+
"""Check if content contains a specific XML tag."""
|
|
52
|
+
return f"<{tag}>" in content or f"<{tag} " in content
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _check_step_meta_fields(content: str) -> list[str]:
|
|
56
|
+
"""Check which step-meta fields are missing."""
|
|
57
|
+
# Extract step-meta section
|
|
58
|
+
meta_match = re.search(r"<step-meta>(.+?)</step-meta>", content, re.DOTALL)
|
|
59
|
+
if not meta_match:
|
|
60
|
+
return STEP_META_FIELDS.copy()
|
|
61
|
+
|
|
62
|
+
meta_content = meta_match.group(1)
|
|
63
|
+
missing = []
|
|
64
|
+
|
|
65
|
+
for field_name in STEP_META_FIELDS:
|
|
66
|
+
if f"{field_name}:" not in meta_content:
|
|
67
|
+
missing.append(field_name)
|
|
68
|
+
|
|
69
|
+
return missing
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def audit_step_file(file_path: Path) -> StepAuditResult:
|
|
73
|
+
"""Audit a single workflow step file.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
file_path: Path to step-*.md file
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
StepAuditResult with findings
|
|
80
|
+
"""
|
|
81
|
+
# Determine workflow name from path
|
|
82
|
+
# Could be workflows/{name}/steps/step-*.md
|
|
83
|
+
# or workflows/{name}/steps-{mode}/step-*.md
|
|
84
|
+
steps_dir = file_path.parent
|
|
85
|
+
workflow_dir = steps_dir.parent
|
|
86
|
+
workflow_name = workflow_dir.name
|
|
87
|
+
step_name = file_path.stem
|
|
88
|
+
|
|
89
|
+
content = file_path.read_text()
|
|
90
|
+
|
|
91
|
+
result = StepAuditResult(
|
|
92
|
+
workflow_name=workflow_name, step_name=step_name, file_path=file_path
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Check required tags
|
|
96
|
+
for tag in REQUIRED_TAGS:
|
|
97
|
+
if _has_tag(content, tag):
|
|
98
|
+
result.present_tags.append(tag)
|
|
99
|
+
else:
|
|
100
|
+
result.missing_required.append(tag)
|
|
101
|
+
|
|
102
|
+
# Check step-meta fields if tag exists
|
|
103
|
+
if "step-meta" in result.present_tags:
|
|
104
|
+
result.missing_meta_fields = _check_step_meta_fields(content)
|
|
105
|
+
if result.missing_meta_fields:
|
|
106
|
+
# Add to required as "step-meta fields: x, y"
|
|
107
|
+
missing_str = ", ".join(result.missing_meta_fields)
|
|
108
|
+
result.missing_required.append(f"step-meta fields ({missing_str})")
|
|
109
|
+
|
|
110
|
+
# Check recommended tags
|
|
111
|
+
for tag in RECOMMENDED_TAGS:
|
|
112
|
+
if _has_tag(content, tag):
|
|
113
|
+
result.present_tags.append(tag)
|
|
114
|
+
else:
|
|
115
|
+
result.missing_recommended.append(tag)
|
|
116
|
+
|
|
117
|
+
# Check optional tags (just track presence)
|
|
118
|
+
for tag in OPTIONAL_TAGS:
|
|
119
|
+
if _has_tag(content, tag):
|
|
120
|
+
result.present_tags.append(tag)
|
|
121
|
+
|
|
122
|
+
return result
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def find_step_files(root: Path) -> list[Path]:
|
|
126
|
+
"""Find all workflow step files in a project.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
root: Project root directory
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
List of step-*.md file paths
|
|
133
|
+
"""
|
|
134
|
+
# Try multiple locations
|
|
135
|
+
workflow_dirs = [
|
|
136
|
+
root / ".pennyfarthing" / "workflows",
|
|
137
|
+
root / "pennyfarthing" / "pennyfarthing-dist" / "workflows",
|
|
138
|
+
root / "pennyfarthing-dist" / "workflows",
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
step_files = []
|
|
142
|
+
|
|
143
|
+
for workflows_dir in workflow_dirs:
|
|
144
|
+
if workflows_dir.exists():
|
|
145
|
+
# Find step files in steps/ and steps-*/ directories
|
|
146
|
+
for workflow_dir in workflows_dir.iterdir():
|
|
147
|
+
if not workflow_dir.is_dir():
|
|
148
|
+
continue
|
|
149
|
+
|
|
150
|
+
for steps_dir in workflow_dir.iterdir():
|
|
151
|
+
if steps_dir.is_dir() and steps_dir.name.startswith("steps"):
|
|
152
|
+
step_files.extend(steps_dir.glob("step-*.md"))
|
|
153
|
+
|
|
154
|
+
break # Only use first found workflows dir
|
|
155
|
+
|
|
156
|
+
return sorted(step_files)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@dataclass
|
|
160
|
+
class WorkflowAuditResult:
|
|
161
|
+
"""Result of auditing a workflow's step files."""
|
|
162
|
+
|
|
163
|
+
workflow_name: str
|
|
164
|
+
step_results: list[StepAuditResult] = field(default_factory=list)
|
|
165
|
+
|
|
166
|
+
@property
|
|
167
|
+
def total_steps(self) -> int:
|
|
168
|
+
return len(self.step_results)
|
|
169
|
+
|
|
170
|
+
@property
|
|
171
|
+
def valid_steps(self) -> int:
|
|
172
|
+
return sum(1 for r in self.step_results if r.is_valid)
|
|
173
|
+
|
|
174
|
+
@property
|
|
175
|
+
def needs_update(self) -> int:
|
|
176
|
+
return sum(1 for r in self.step_results if not r.is_valid)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def audit_workflow_steps(
|
|
180
|
+
root: Path, *, workflow_name: str | None = None
|
|
181
|
+
) -> dict[str, list | dict]:
|
|
182
|
+
"""Audit workflow step files in a project.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
root: Project root directory
|
|
186
|
+
workflow_name: Optional specific workflow to audit
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
Dict with 'workflows', 'summary' keys
|
|
190
|
+
"""
|
|
191
|
+
step_files = find_step_files(root)
|
|
192
|
+
|
|
193
|
+
# Group by workflow
|
|
194
|
+
workflows: dict[str, WorkflowAuditResult] = {}
|
|
195
|
+
|
|
196
|
+
for file_path in step_files:
|
|
197
|
+
result = audit_step_file(file_path)
|
|
198
|
+
|
|
199
|
+
if workflow_name and result.workflow_name != workflow_name:
|
|
200
|
+
continue
|
|
201
|
+
|
|
202
|
+
if result.workflow_name not in workflows:
|
|
203
|
+
workflows[result.workflow_name] = WorkflowAuditResult(
|
|
204
|
+
workflow_name=result.workflow_name
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
workflows[result.workflow_name].step_results.append(result)
|
|
208
|
+
|
|
209
|
+
# Calculate summary
|
|
210
|
+
workflow_list = list(workflows.values())
|
|
211
|
+
total_files = sum(w.total_steps for w in workflow_list)
|
|
212
|
+
total_valid = sum(w.valid_steps for w in workflow_list)
|
|
213
|
+
total_needs_update = sum(w.needs_update for w in workflow_list)
|
|
214
|
+
|
|
215
|
+
all_results = [r for w in workflow_list for r in w.step_results]
|
|
216
|
+
total_missing_required = sum(len(r.missing_required) for r in all_results)
|
|
217
|
+
total_missing_recommended = sum(len(r.missing_recommended) for r in all_results)
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
"workflows": workflow_list,
|
|
221
|
+
"summary": {
|
|
222
|
+
"total_workflows": len(workflow_list),
|
|
223
|
+
"total_files": total_files,
|
|
224
|
+
"valid": total_valid,
|
|
225
|
+
"needs_update": total_needs_update,
|
|
226
|
+
"missing_required": total_missing_required,
|
|
227
|
+
"missing_recommended": total_missing_recommended,
|
|
228
|
+
},
|
|
229
|
+
}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
"""
|
|
2
|
+
XML schema validation for Pennyfarthing files.
|
|
3
|
+
|
|
4
|
+
Validates files against their respective schemas:
|
|
5
|
+
- Session files -> guides/session-schema.md
|
|
6
|
+
- Skill files -> guides/skill-schema.md
|
|
7
|
+
- Workflow step files -> guides/workflow-step-schema.md
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import re
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Literal
|
|
16
|
+
|
|
17
|
+
from pennyfarthing_scripts.migration.session import (
|
|
18
|
+
find_session_files,
|
|
19
|
+
is_xml_format,
|
|
20
|
+
)
|
|
21
|
+
from pennyfarthing_scripts.migration.skill import (
|
|
22
|
+
RECOMMENDED_TAGS as SKILL_RECOMMENDED,
|
|
23
|
+
REQUIRED_TAGS as SKILL_REQUIRED,
|
|
24
|
+
find_skill_files,
|
|
25
|
+
)
|
|
26
|
+
from pennyfarthing_scripts.migration.step import (
|
|
27
|
+
RECOMMENDED_TAGS as STEP_RECOMMENDED,
|
|
28
|
+
REQUIRED_TAGS as STEP_REQUIRED,
|
|
29
|
+
STEP_META_FIELDS,
|
|
30
|
+
find_step_files,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class ValidationResult:
|
|
36
|
+
"""Result of validating a single file."""
|
|
37
|
+
|
|
38
|
+
file_path: Path
|
|
39
|
+
file_type: Literal["session", "skill", "step"]
|
|
40
|
+
errors: list[str] = field(default_factory=list)
|
|
41
|
+
warnings: list[str] = field(default_factory=list)
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def is_valid(self) -> bool:
|
|
45
|
+
return len(self.errors) == 0
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def status(self) -> str:
|
|
49
|
+
if self.errors:
|
|
50
|
+
return "ERROR"
|
|
51
|
+
if self.warnings:
|
|
52
|
+
return "WARN"
|
|
53
|
+
return "PASS"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _has_tag(content: str, tag: str) -> bool:
|
|
57
|
+
"""Check if content contains a specific XML tag."""
|
|
58
|
+
return f"<{tag}>" in content or f"<{tag} " in content
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def validate_session_file(file_path: Path) -> ValidationResult:
|
|
62
|
+
"""Validate a session file against the schema.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
file_path: Path to session file
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
ValidationResult with errors/warnings
|
|
69
|
+
"""
|
|
70
|
+
result = ValidationResult(file_path=file_path, file_type="session")
|
|
71
|
+
content = file_path.read_text()
|
|
72
|
+
|
|
73
|
+
# Check for XML format
|
|
74
|
+
if not is_xml_format(content):
|
|
75
|
+
result.errors.append("Not in XML format - needs migration")
|
|
76
|
+
return result
|
|
77
|
+
|
|
78
|
+
# Validate <session> root with attributes
|
|
79
|
+
if not re.search(r'<session\s+story="[^"]+"', content):
|
|
80
|
+
result.errors.append("Missing story attribute on <session>")
|
|
81
|
+
|
|
82
|
+
if not re.search(r'<session[^>]+workflow="[^"]+"', content):
|
|
83
|
+
result.errors.append("Missing workflow attribute on <session>")
|
|
84
|
+
|
|
85
|
+
# Validate <meta> section
|
|
86
|
+
if not _has_tag(content, "meta"):
|
|
87
|
+
result.errors.append("Missing <meta> section")
|
|
88
|
+
else:
|
|
89
|
+
if "<jira>" not in content:
|
|
90
|
+
result.errors.append("Missing <jira> in <meta>")
|
|
91
|
+
if "<started>" not in content:
|
|
92
|
+
result.errors.append("Missing <started> in <meta>")
|
|
93
|
+
|
|
94
|
+
# Validate <status> element
|
|
95
|
+
if not _has_tag(content, "status"):
|
|
96
|
+
result.errors.append("Missing <status> element")
|
|
97
|
+
else:
|
|
98
|
+
if 'phase="' not in content:
|
|
99
|
+
result.errors.append("Missing phase attribute on <status>")
|
|
100
|
+
if 'next-agent="' not in content:
|
|
101
|
+
result.warnings.append("Missing next-agent attribute on <status>")
|
|
102
|
+
|
|
103
|
+
# Validate optional sections
|
|
104
|
+
if not _has_tag(content, "acceptance-criteria"):
|
|
105
|
+
result.warnings.append("Missing <acceptance-criteria> section")
|
|
106
|
+
|
|
107
|
+
if not _has_tag(content, "work-log"):
|
|
108
|
+
result.warnings.append("Missing <work-log> section")
|
|
109
|
+
|
|
110
|
+
return result
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def validate_skill_file(file_path: Path) -> ValidationResult:
|
|
114
|
+
"""Validate a skill file against the schema.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
file_path: Path to SKILL.md file
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
ValidationResult with errors/warnings
|
|
121
|
+
"""
|
|
122
|
+
skill_name = file_path.parent.name
|
|
123
|
+
result = ValidationResult(file_path=file_path, file_type="skill")
|
|
124
|
+
content = file_path.read_text()
|
|
125
|
+
|
|
126
|
+
# Check YAML frontmatter
|
|
127
|
+
if not content.startswith("---\n"):
|
|
128
|
+
result.errors.append("Missing YAML frontmatter")
|
|
129
|
+
else:
|
|
130
|
+
if "name:" not in content.split("---")[1]:
|
|
131
|
+
result.errors.append("Missing 'name' in frontmatter")
|
|
132
|
+
if "description:" not in content.split("---")[1]:
|
|
133
|
+
result.errors.append("Missing 'description' in frontmatter")
|
|
134
|
+
|
|
135
|
+
# Check required tags
|
|
136
|
+
for tag in SKILL_REQUIRED:
|
|
137
|
+
if not _has_tag(content, tag):
|
|
138
|
+
result.errors.append(f"Missing <{tag}> tag (required)")
|
|
139
|
+
|
|
140
|
+
# Check recommended tags
|
|
141
|
+
for tag in SKILL_RECOMMENDED:
|
|
142
|
+
if not _has_tag(content, tag):
|
|
143
|
+
result.warnings.append(f"Missing <{tag}> tag (recommended)")
|
|
144
|
+
|
|
145
|
+
return result
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def validate_step_file(file_path: Path) -> ValidationResult:
|
|
149
|
+
"""Validate a workflow step file against the schema.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
file_path: Path to step-*.md file
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
ValidationResult with errors/warnings
|
|
156
|
+
"""
|
|
157
|
+
result = ValidationResult(file_path=file_path, file_type="step")
|
|
158
|
+
content = file_path.read_text()
|
|
159
|
+
|
|
160
|
+
# Determine workflow/step names from path
|
|
161
|
+
workflow_name = file_path.parent.parent.name
|
|
162
|
+
step_name = file_path.stem
|
|
163
|
+
|
|
164
|
+
# Check required tags
|
|
165
|
+
for tag in STEP_REQUIRED:
|
|
166
|
+
if not _has_tag(content, tag):
|
|
167
|
+
result.errors.append(f"Missing <{tag}> tag")
|
|
168
|
+
|
|
169
|
+
# Check step-meta fields if tag exists
|
|
170
|
+
if _has_tag(content, "step-meta"):
|
|
171
|
+
meta_match = re.search(r"<step-meta>(.+?)</step-meta>", content, re.DOTALL)
|
|
172
|
+
if meta_match:
|
|
173
|
+
meta_content = meta_match.group(1)
|
|
174
|
+
for field_name in STEP_META_FIELDS:
|
|
175
|
+
if f"{field_name}:" not in meta_content:
|
|
176
|
+
result.errors.append(f"Missing '{field_name}' in step-meta")
|
|
177
|
+
|
|
178
|
+
# Check recommended tags
|
|
179
|
+
for tag in STEP_RECOMMENDED:
|
|
180
|
+
if not _has_tag(content, tag):
|
|
181
|
+
result.warnings.append(f"Missing <{tag}> tag")
|
|
182
|
+
|
|
183
|
+
return result
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def validate_file(file_path: Path) -> ValidationResult:
|
|
187
|
+
"""Validate a file, auto-detecting its type.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
file_path: Path to file
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
ValidationResult
|
|
194
|
+
"""
|
|
195
|
+
name = file_path.name
|
|
196
|
+
|
|
197
|
+
if name.endswith("-session.md"):
|
|
198
|
+
return validate_session_file(file_path)
|
|
199
|
+
elif name == "SKILL.md":
|
|
200
|
+
return validate_skill_file(file_path)
|
|
201
|
+
elif name.startswith("step-") and name.endswith(".md"):
|
|
202
|
+
return validate_step_file(file_path)
|
|
203
|
+
else:
|
|
204
|
+
result = ValidationResult(file_path=file_path, file_type="session")
|
|
205
|
+
result.errors.append(f"Unknown file type: {name}")
|
|
206
|
+
return result
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
@dataclass
|
|
210
|
+
class ValidationSummary:
|
|
211
|
+
"""Summary of validation results."""
|
|
212
|
+
|
|
213
|
+
results: list[ValidationResult] = field(default_factory=list)
|
|
214
|
+
passed: int = 0
|
|
215
|
+
warnings: int = 0
|
|
216
|
+
errors: int = 0
|
|
217
|
+
|
|
218
|
+
def add(self, result: ValidationResult) -> None:
|
|
219
|
+
"""Add a result to the summary."""
|
|
220
|
+
self.results.append(result)
|
|
221
|
+
if result.status == "PASS":
|
|
222
|
+
self.passed += 1
|
|
223
|
+
elif result.status == "WARN":
|
|
224
|
+
self.warnings += 1
|
|
225
|
+
else:
|
|
226
|
+
self.errors += 1
|
|
227
|
+
|
|
228
|
+
@property
|
|
229
|
+
def total(self) -> int:
|
|
230
|
+
return len(self.results)
|
|
231
|
+
|
|
232
|
+
@property
|
|
233
|
+
def success(self) -> bool:
|
|
234
|
+
return self.errors == 0
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def validate_all(
|
|
238
|
+
root: Path,
|
|
239
|
+
*,
|
|
240
|
+
file_type: Literal["session", "skill", "step", "all"] = "all",
|
|
241
|
+
strict: bool = False,
|
|
242
|
+
) -> ValidationSummary:
|
|
243
|
+
"""Validate all files of specified type(s).
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
root: Project root directory
|
|
247
|
+
file_type: Type to validate (session, skill, step, or all)
|
|
248
|
+
strict: If True, treat warnings as errors
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
ValidationSummary with all results
|
|
252
|
+
"""
|
|
253
|
+
summary = ValidationSummary()
|
|
254
|
+
|
|
255
|
+
# Validate sessions
|
|
256
|
+
if file_type in ("session", "all"):
|
|
257
|
+
for file_path in find_session_files(root):
|
|
258
|
+
result = validate_session_file(file_path)
|
|
259
|
+
if strict and result.warnings:
|
|
260
|
+
result.errors.extend(result.warnings)
|
|
261
|
+
result.warnings = []
|
|
262
|
+
summary.add(result)
|
|
263
|
+
|
|
264
|
+
# Validate skills
|
|
265
|
+
if file_type in ("skill", "all"):
|
|
266
|
+
for file_path in find_skill_files(root):
|
|
267
|
+
result = validate_skill_file(file_path)
|
|
268
|
+
if strict and result.warnings:
|
|
269
|
+
result.errors.extend(result.warnings)
|
|
270
|
+
result.warnings = []
|
|
271
|
+
summary.add(result)
|
|
272
|
+
|
|
273
|
+
# Validate steps
|
|
274
|
+
if file_type in ("step", "all"):
|
|
275
|
+
for file_path in find_step_files(root):
|
|
276
|
+
result = validate_step_file(file_path)
|
|
277
|
+
if strict and result.warnings:
|
|
278
|
+
result.errors.extend(result.warnings)
|
|
279
|
+
result.warnings = []
|
|
280
|
+
summary.add(result)
|
|
281
|
+
|
|
282
|
+
return summary
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|