frappe-builder 1.1.0-dev.8
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/.fb/state.db +0 -0
- package/AGENTS.md +167 -0
- package/README.md +89 -0
- package/_bmad/_config/agent-manifest.csv +10 -0
- package/_bmad/_config/agents/bmm-analyst.customize.yaml +41 -0
- package/_bmad/_config/agents/bmm-architect.customize.yaml +41 -0
- package/_bmad/_config/agents/bmm-dev.customize.yaml +41 -0
- package/_bmad/_config/agents/bmm-pm.customize.yaml +41 -0
- package/_bmad/_config/agents/bmm-qa.customize.yaml +41 -0
- package/_bmad/_config/agents/bmm-quick-flow-solo-dev.customize.yaml +41 -0
- package/_bmad/_config/agents/bmm-sm.customize.yaml +41 -0
- package/_bmad/_config/agents/bmm-tech-writer.customize.yaml +41 -0
- package/_bmad/_config/agents/bmm-ux-designer.customize.yaml +41 -0
- package/_bmad/_config/bmad-help.csv +47 -0
- package/_bmad/_config/files-manifest.csv +369 -0
- package/_bmad/_config/ides/claude-code.yaml +5 -0
- package/_bmad/_config/manifest.yaml +28 -0
- package/_bmad/_config/skill-manifest.csv +41 -0
- package/_bmad/_config/task-manifest.csv +1 -0
- package/_bmad/_config/tool-manifest.csv +1 -0
- package/_bmad/_config/workflow-manifest.csv +1 -0
- package/_bmad/_memory/config.yaml +11 -0
- package/_bmad/_memory/tech-writer-sidecar/documentation-standards.md +224 -0
- package/_bmad/bmm/agents/analyst.md +69 -0
- package/_bmad/bmm/agents/architect.md +59 -0
- package/_bmad/bmm/agents/bmad-skill-manifest.yaml +39 -0
- package/_bmad/bmm/agents/dev.md +66 -0
- package/_bmad/bmm/agents/pm.md +63 -0
- package/_bmad/bmm/agents/qa.md +89 -0
- package/_bmad/bmm/agents/quick-flow-solo-dev.md +61 -0
- package/_bmad/bmm/agents/sm.md +67 -0
- package/_bmad/bmm/agents/tech-writer/bmad-skill-manifest.yaml +3 -0
- package/_bmad/bmm/agents/tech-writer/tech-writer.md +67 -0
- package/_bmad/bmm/agents/ux-designer.md +58 -0
- package/_bmad/bmm/config.yaml +16 -0
- package/_bmad/bmm/data/project-context-template.md +26 -0
- package/_bmad/bmm/module-help.csv +32 -0
- package/_bmad/bmm/teams/default-party.csv +20 -0
- package/_bmad/bmm/teams/team-fullstack.yaml +12 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-create-product-brief/SKILL.md +6 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-create-product-brief/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-create-product-brief/product-brief.template.md +10 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-create-product-brief/steps/step-01-init.md +170 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-create-product-brief/steps/step-01b-continue.md +158 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-create-product-brief/steps/step-02-vision.md +193 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-create-product-brief/steps/step-03-users.md +196 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-create-product-brief/steps/step-04-metrics.md +199 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-create-product-brief/steps/step-05-scope.md +213 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-create-product-brief/steps/step-06-complete.md +159 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-create-product-brief/workflow.md +55 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-product-brief-preview/SKILL.md +88 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-product-brief-preview/agents/artifact-analyzer.md +60 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-product-brief-preview/agents/opportunity-reviewer.md +44 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-product-brief-preview/agents/skeptic-reviewer.md +44 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-product-brief-preview/agents/web-researcher.md +49 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-product-brief-preview/bmad-manifest.json +17 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-product-brief-preview/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-product-brief-preview/prompts/contextual-discovery.md +57 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-product-brief-preview/prompts/draft-and-review.md +86 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-product-brief-preview/prompts/finalize.md +75 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-product-brief-preview/prompts/guided-elicitation.md +70 -0
- package/_bmad/bmm/workflows/1-analysis/bmad-product-brief-preview/resources/brief-template.md +60 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-domain-research/SKILL.md +6 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-domain-research/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-domain-research/domain-steps/step-01-init.md +137 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-domain-research/domain-steps/step-02-domain-analysis.md +229 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-domain-research/domain-steps/step-03-competitive-landscape.md +238 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-domain-research/domain-steps/step-04-regulatory-focus.md +206 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-domain-research/domain-steps/step-05-technical-trends.md +234 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-domain-research/domain-steps/step-06-research-synthesis.md +444 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-domain-research/research.template.md +29 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-domain-research/workflow.md +49 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-market-research/SKILL.md +6 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-market-research/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-market-research/research.template.md +29 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-market-research/steps/step-01-init.md +184 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-market-research/steps/step-02-customer-behavior.md +239 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-market-research/steps/step-03-customer-pain-points.md +251 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-market-research/steps/step-04-customer-decisions.md +261 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-market-research/steps/step-05-competitive-analysis.md +173 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-market-research/steps/step-06-research-completion.md +478 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-market-research/workflow.md +49 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-technical-research/SKILL.md +6 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-technical-research/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-technical-research/research.template.md +29 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-technical-research/technical-steps/step-01-init.md +137 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-technical-research/technical-steps/step-02-technical-overview.md +239 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-technical-research/technical-steps/step-03-integration-patterns.md +248 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-technical-research/technical-steps/step-04-architectural-patterns.md +202 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-technical-research/technical-steps/step-05-implementation-research.md +233 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-technical-research/technical-steps/step-06-research-synthesis.md +487 -0
- package/_bmad/bmm/workflows/1-analysis/research/bmad-technical-research/workflow.md +50 -0
- package/_bmad/bmm/workflows/1-analysis/research/market-steps/step-01-init.md +182 -0
- package/_bmad/bmm/workflows/1-analysis/research/market-steps/step-02-customer-behavior.md +237 -0
- package/_bmad/bmm/workflows/1-analysis/research/market-steps/step-03-customer-pain-points.md +249 -0
- package/_bmad/bmm/workflows/1-analysis/research/market-steps/step-04-customer-decisions.md +259 -0
- package/_bmad/bmm/workflows/1-analysis/research/market-steps/step-05-competitive-analysis.md +177 -0
- package/_bmad/bmm/workflows/1-analysis/research/market-steps/step-06-research-completion.md +476 -0
- package/_bmad/bmm/workflows/1-analysis/research/research.template.md +29 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/SKILL.md +6 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/steps/step-01-init.md +135 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/steps/step-01b-continue.md +127 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/steps/step-02-discovery.md +190 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/steps/step-03-core-experience.md +217 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/steps/step-04-emotional-response.md +220 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/steps/step-05-inspiration.md +235 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/steps/step-06-design-system.md +253 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/steps/step-07-defining-experience.md +255 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/steps/step-08-visual-foundation.md +225 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/steps/step-09-design-directions.md +225 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/steps/step-10-user-journeys.md +242 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/steps/step-11-component-strategy.md +249 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/steps/step-12-ux-patterns.md +238 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/steps/step-13-responsive-accessibility.md +265 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/steps/step-14-complete.md +171 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/ux-design-template.md +13 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-create-ux-design/workflow.md +36 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-edit-prd/SKILL.md +6 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-edit-prd/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-edit-prd/steps-e/step-e-01-discovery.md +242 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-edit-prd/steps-e/step-e-01b-legacy-conversion.md +204 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-edit-prd/steps-e/step-e-02-review.md +245 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-edit-prd/steps-e/step-e-03-edit.md +250 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-edit-prd/steps-e/step-e-04-complete.md +165 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-edit-prd/workflow.md +63 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/SKILL.md +6 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/data/domain-complexity.csv +15 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/data/prd-purpose.md +197 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/data/project-types.csv +11 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/steps-v/step-v-01-discovery.md +221 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/steps-v/step-v-02-format-detection.md +188 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/steps-v/step-v-02b-parity-check.md +206 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/steps-v/step-v-03-density-validation.md +171 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/steps-v/step-v-04-brief-coverage-validation.md +211 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/steps-v/step-v-05-measurability-validation.md +225 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/steps-v/step-v-06-traceability-validation.md +214 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/steps-v/step-v-07-implementation-leakage-validation.md +202 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/steps-v/step-v-08-domain-compliance-validation.md +240 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/steps-v/step-v-09-project-type-validation.md +260 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/steps-v/step-v-10-smart-validation.md +206 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/steps-v/step-v-11-holistic-quality-validation.md +261 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/steps-v/step-v-12-completeness-validation.md +239 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/steps-v/step-v-13-report-complete.md +229 -0
- package/_bmad/bmm/workflows/2-plan-workflows/bmad-validate-prd/workflow.md +62 -0
- package/_bmad/bmm/workflows/2-plan-workflows/create-prd/data/domain-complexity.csv +15 -0
- package/_bmad/bmm/workflows/2-plan-workflows/create-prd/data/prd-purpose.md +197 -0
- package/_bmad/bmm/workflows/2-plan-workflows/create-prd/data/project-types.csv +11 -0
- package/_bmad/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md +224 -0
- package/_bmad/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02-format-detection.md +191 -0
- package/_bmad/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02b-parity-check.md +209 -0
- package/_bmad/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-03-density-validation.md +174 -0
- package/_bmad/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-04-brief-coverage-validation.md +214 -0
- package/_bmad/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-05-measurability-validation.md +228 -0
- package/_bmad/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-06-traceability-validation.md +217 -0
- package/_bmad/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-07-implementation-leakage-validation.md +205 -0
- package/_bmad/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-08-domain-compliance-validation.md +243 -0
- package/_bmad/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-09-project-type-validation.md +263 -0
- package/_bmad/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-10-smart-validation.md +209 -0
- package/_bmad/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-11-holistic-quality-validation.md +264 -0
- package/_bmad/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-12-completeness-validation.md +242 -0
- package/_bmad/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-13-report-complete.md +232 -0
- package/_bmad/bmm/workflows/2-plan-workflows/create-prd/workflow-validate-prd.md +65 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-check-implementation-readiness/SKILL.md +6 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-check-implementation-readiness/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-check-implementation-readiness/steps/step-01-document-discovery.md +179 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-check-implementation-readiness/steps/step-02-prd-analysis.md +168 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-check-implementation-readiness/steps/step-03-epic-coverage-validation.md +169 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-check-implementation-readiness/steps/step-04-ux-alignment.md +129 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-check-implementation-readiness/steps/step-05-epic-quality-review.md +241 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-check-implementation-readiness/steps/step-06-final-assessment.md +126 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-check-implementation-readiness/templates/readiness-report-template.md +4 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-check-implementation-readiness/workflow.md +49 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-architecture/SKILL.md +6 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-architecture/architecture-decision-template.md +12 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-architecture/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-architecture/data/domain-complexity.csv +13 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-architecture/data/project-types.csv +7 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-architecture/steps/step-01-init.md +153 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-architecture/steps/step-01b-continue.md +173 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-architecture/steps/step-02-context.md +224 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-architecture/steps/step-03-starter.md +329 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-architecture/steps/step-04-decisions.md +318 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-architecture/steps/step-05-patterns.md +359 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-architecture/steps/step-06-structure.md +379 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-architecture/steps/step-07-validation.md +359 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-architecture/steps/step-08-complete.md +76 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-architecture/workflow.md +38 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-epics-and-stories/SKILL.md +6 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-epics-and-stories/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-epics-and-stories/steps/step-01-validate-prerequisites.md +255 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-epics-and-stories/steps/step-02-design-epics.md +212 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-epics-and-stories/steps/step-03-create-stories.md +255 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-epics-and-stories/steps/step-04-final-validation.md +131 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-epics-and-stories/templates/epics-template.md +61 -0
- package/_bmad/bmm/workflows/3-solutioning/bmad-create-epics-and-stories/workflow.md +53 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-code-review/SKILL.md +6 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-code-review/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-code-review/steps/step-01-gather-context.md +61 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-code-review/steps/step-02-review.md +41 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-code-review/steps/step-03-triage.md +50 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-code-review/steps/step-04-present.md +38 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-code-review/workflow.md +54 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-correct-course/SKILL.md +6 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-correct-course/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-correct-course/checklist.md +288 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-correct-course/workflow.md +267 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-create-story/SKILL.md +6 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-create-story/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-create-story/checklist.md +357 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-create-story/discover-inputs.md +88 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-create-story/template.md +49 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-create-story/workflow.md +380 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-dev-story/SKILL.md +6 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-dev-story/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-dev-story/checklist.md +80 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-dev-story/workflow.md +450 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-retrospective/SKILL.md +6 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-retrospective/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-retrospective/workflow.md +1479 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-sprint-planning/SKILL.md +6 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-sprint-planning/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-sprint-planning/checklist.md +33 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-sprint-planning/sprint-status-template.yaml +56 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-sprint-planning/workflow.md +263 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-sprint-status/SKILL.md +6 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-sprint-status/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/4-implementation/bmad-sprint-status/workflow.md +261 -0
- package/_bmad/bmm/workflows/bmad-document-project/SKILL.md +6 -0
- package/_bmad/bmm/workflows/bmad-document-project/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/bmad-document-project/checklist.md +245 -0
- package/_bmad/bmm/workflows/bmad-document-project/documentation-requirements.csv +12 -0
- package/_bmad/bmm/workflows/bmad-document-project/instructions.md +128 -0
- package/_bmad/bmm/workflows/bmad-document-project/templates/deep-dive-template.md +345 -0
- package/_bmad/bmm/workflows/bmad-document-project/templates/index-template.md +169 -0
- package/_bmad/bmm/workflows/bmad-document-project/templates/project-overview-template.md +103 -0
- package/_bmad/bmm/workflows/bmad-document-project/templates/project-scan-report-schema.json +160 -0
- package/_bmad/bmm/workflows/bmad-document-project/templates/source-tree-template.md +135 -0
- package/_bmad/bmm/workflows/bmad-document-project/workflow.md +27 -0
- package/_bmad/bmm/workflows/bmad-document-project/workflows/deep-dive-instructions.md +299 -0
- package/_bmad/bmm/workflows/bmad-document-project/workflows/deep-dive-workflow.md +34 -0
- package/_bmad/bmm/workflows/bmad-document-project/workflows/full-scan-instructions.md +1107 -0
- package/_bmad/bmm/workflows/bmad-document-project/workflows/full-scan-workflow.md +34 -0
- package/_bmad/bmm/workflows/bmad-generate-project-context/SKILL.md +6 -0
- package/_bmad/bmm/workflows/bmad-generate-project-context/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/bmad-generate-project-context/project-context-template.md +21 -0
- package/_bmad/bmm/workflows/bmad-generate-project-context/steps/step-01-discover.md +186 -0
- package/_bmad/bmm/workflows/bmad-generate-project-context/steps/step-02-generate.md +321 -0
- package/_bmad/bmm/workflows/bmad-generate-project-context/steps/step-03-complete.md +278 -0
- package/_bmad/bmm/workflows/bmad-generate-project-context/workflow.md +43 -0
- package/_bmad/bmm/workflows/bmad-qa-generate-e2e-tests/SKILL.md +6 -0
- package/_bmad/bmm/workflows/bmad-qa-generate-e2e-tests/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/bmad-qa-generate-e2e-tests/checklist.md +33 -0
- package/_bmad/bmm/workflows/bmad-qa-generate-e2e-tests/workflow.md +136 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev/SKILL.md +6 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev/steps/step-01-mode-detection.md +169 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev/steps/step-02-context-gathering.md +114 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev/steps/step-03-execute.md +107 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev/steps/step-04-self-check.md +107 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev/steps/step-05-adversarial-review.md +94 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev/steps/step-06-resolve-findings.md +144 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev/workflow.md +38 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/SKILL.md +6 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/steps/step-01-clarify-and-route.md +51 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/steps/step-02-plan.md +35 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/steps/step-03-implement.md +33 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/steps/step-04-review.md +50 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/steps/step-05-present.md +17 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/tech-spec-template.md +90 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/workflow.md +79 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-spec/SKILL.md +6 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-spec/bmad-skill-manifest.yaml +1 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-spec/steps/step-01-understand.md +185 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-spec/steps/step-02-investigate.md +140 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-spec/steps/step-03-generate.md +123 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-spec/steps/step-04-review.md +195 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-spec/tech-spec-template.md +74 -0
- package/_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-spec/workflow.md +73 -0
- package/_bmad/cis/config.yaml +12 -0
- package/_bmad/cis/module-help.csv +6 -0
- package/_bmad/cis/skills/bmad-cis-agent-brainstorming-coach/SKILL.md +51 -0
- package/_bmad/cis/skills/bmad-cis-agent-brainstorming-coach/bmad-skill-manifest.yaml +11 -0
- package/_bmad/cis/skills/bmad-cis-agent-creative-problem-solver/SKILL.md +51 -0
- package/_bmad/cis/skills/bmad-cis-agent-creative-problem-solver/bmad-skill-manifest.yaml +11 -0
- package/_bmad/cis/skills/bmad-cis-agent-design-thinking-coach/SKILL.md +52 -0
- package/_bmad/cis/skills/bmad-cis-agent-design-thinking-coach/bmad-skill-manifest.yaml +11 -0
- package/_bmad/cis/skills/bmad-cis-agent-innovation-strategist/SKILL.md +51 -0
- package/_bmad/cis/skills/bmad-cis-agent-innovation-strategist/bmad-skill-manifest.yaml +11 -0
- package/_bmad/cis/skills/bmad-cis-agent-presentation-master/SKILL.md +62 -0
- package/_bmad/cis/skills/bmad-cis-agent-presentation-master/bmad-skill-manifest.yaml +11 -0
- package/_bmad/cis/skills/bmad-cis-agent-storyteller/SKILL.md +56 -0
- package/_bmad/cis/skills/bmad-cis-agent-storyteller/bmad-skill-manifest.yaml +11 -0
- package/_bmad/cis/skills/bmad-cis-agent-storyteller/stories-told.md +7 -0
- package/_bmad/cis/skills/bmad-cis-agent-storyteller/story-preferences.md +7 -0
- package/_bmad/cis/skills/bmad-cis-design-thinking/SKILL.md +6 -0
- package/_bmad/cis/skills/bmad-cis-design-thinking/bmad-skill-manifest.yaml +1 -0
- package/_bmad/cis/skills/bmad-cis-design-thinking/design-methods.csv +31 -0
- package/_bmad/cis/skills/bmad-cis-design-thinking/template.md +111 -0
- package/_bmad/cis/skills/bmad-cis-design-thinking/workflow.md +242 -0
- package/_bmad/cis/skills/bmad-cis-innovation-strategy/SKILL.md +6 -0
- package/_bmad/cis/skills/bmad-cis-innovation-strategy/bmad-skill-manifest.yaml +1 -0
- package/_bmad/cis/skills/bmad-cis-innovation-strategy/innovation-frameworks.csv +31 -0
- package/_bmad/cis/skills/bmad-cis-innovation-strategy/template.md +189 -0
- package/_bmad/cis/skills/bmad-cis-innovation-strategy/workflow.md +315 -0
- package/_bmad/cis/skills/bmad-cis-problem-solving/SKILL.md +6 -0
- package/_bmad/cis/skills/bmad-cis-problem-solving/bmad-skill-manifest.yaml +1 -0
- package/_bmad/cis/skills/bmad-cis-problem-solving/solving-methods.csv +31 -0
- package/_bmad/cis/skills/bmad-cis-problem-solving/template.md +165 -0
- package/_bmad/cis/skills/bmad-cis-problem-solving/workflow.md +291 -0
- package/_bmad/cis/skills/bmad-cis-storytelling/SKILL.md +6 -0
- package/_bmad/cis/skills/bmad-cis-storytelling/bmad-skill-manifest.yaml +1 -0
- package/_bmad/cis/skills/bmad-cis-storytelling/story-types.csv +26 -0
- package/_bmad/cis/skills/bmad-cis-storytelling/template.md +113 -0
- package/_bmad/cis/skills/bmad-cis-storytelling/workflow.md +321 -0
- package/_bmad/core/config.yaml +9 -0
- package/_bmad/core/module-help.csv +11 -0
- package/_bmad/core/skills/bmad-advanced-elicitation/SKILL.md +6 -0
- package/_bmad/core/skills/bmad-advanced-elicitation/bmad-skill-manifest.yaml +1 -0
- package/_bmad/core/skills/bmad-advanced-elicitation/methods.csv +51 -0
- package/_bmad/core/skills/bmad-advanced-elicitation/workflow.md +135 -0
- package/_bmad/core/skills/bmad-brainstorming/SKILL.md +6 -0
- package/_bmad/core/skills/bmad-brainstorming/bmad-skill-manifest.yaml +1 -0
- package/_bmad/core/skills/bmad-brainstorming/brain-methods.csv +62 -0
- package/_bmad/core/skills/bmad-brainstorming/steps/step-01-session-setup.md +214 -0
- package/_bmad/core/skills/bmad-brainstorming/steps/step-01b-continue.md +124 -0
- package/_bmad/core/skills/bmad-brainstorming/steps/step-02a-user-selected.md +229 -0
- package/_bmad/core/skills/bmad-brainstorming/steps/step-02b-ai-recommended.md +239 -0
- package/_bmad/core/skills/bmad-brainstorming/steps/step-02c-random-selection.md +211 -0
- package/_bmad/core/skills/bmad-brainstorming/steps/step-02d-progressive-flow.md +266 -0
- package/_bmad/core/skills/bmad-brainstorming/steps/step-03-technique-execution.md +401 -0
- package/_bmad/core/skills/bmad-brainstorming/steps/step-04-idea-organization.md +305 -0
- package/_bmad/core/skills/bmad-brainstorming/template.md +15 -0
- package/_bmad/core/skills/bmad-brainstorming/workflow.md +53 -0
- package/_bmad/core/skills/bmad-distillator/SKILL.md +178 -0
- package/_bmad/core/skills/bmad-distillator/agents/distillate-compressor.md +116 -0
- package/_bmad/core/skills/bmad-distillator/agents/round-trip-reconstructor.md +68 -0
- package/_bmad/core/skills/bmad-distillator/bmad-skill-manifest.yaml +15 -0
- package/_bmad/core/skills/bmad-distillator/resources/compression-rules.md +51 -0
- package/_bmad/core/skills/bmad-distillator/resources/distillate-format-reference.md +227 -0
- package/_bmad/core/skills/bmad-distillator/resources/splitting-strategy.md +78 -0
- package/_bmad/core/skills/bmad-editorial-review-prose/SKILL.md +6 -0
- package/_bmad/core/skills/bmad-editorial-review-prose/bmad-skill-manifest.yaml +1 -0
- package/_bmad/core/skills/bmad-editorial-review-prose/workflow.md +81 -0
- package/_bmad/core/skills/bmad-editorial-review-structure/SKILL.md +6 -0
- package/_bmad/core/skills/bmad-editorial-review-structure/bmad-skill-manifest.yaml +1 -0
- package/_bmad/core/skills/bmad-editorial-review-structure/workflow.md +174 -0
- package/_bmad/core/skills/bmad-help/SKILL.md +6 -0
- package/_bmad/core/skills/bmad-help/bmad-skill-manifest.yaml +1 -0
- package/_bmad/core/skills/bmad-help/workflow.md +88 -0
- package/_bmad/core/skills/bmad-index-docs/SKILL.md +6 -0
- package/_bmad/core/skills/bmad-index-docs/bmad-skill-manifest.yaml +1 -0
- package/_bmad/core/skills/bmad-index-docs/workflow.md +61 -0
- package/_bmad/core/skills/bmad-party-mode/SKILL.md +6 -0
- package/_bmad/core/skills/bmad-party-mode/bmad-skill-manifest.yaml +1 -0
- package/_bmad/core/skills/bmad-party-mode/steps/step-01-agent-loading.md +138 -0
- package/_bmad/core/skills/bmad-party-mode/steps/step-02-discussion-orchestration.md +187 -0
- package/_bmad/core/skills/bmad-party-mode/steps/step-03-graceful-exit.md +167 -0
- package/_bmad/core/skills/bmad-party-mode/workflow.md +190 -0
- package/_bmad/core/skills/bmad-review-adversarial-general/SKILL.md +6 -0
- package/_bmad/core/skills/bmad-review-adversarial-general/bmad-skill-manifest.yaml +1 -0
- package/_bmad/core/skills/bmad-review-adversarial-general/workflow.md +32 -0
- package/_bmad/core/skills/bmad-review-edge-case-hunter/SKILL.md +6 -0
- package/_bmad/core/skills/bmad-review-edge-case-hunter/bmad-skill-manifest.yaml +1 -0
- package/_bmad/core/skills/bmad-review-edge-case-hunter/workflow.md +62 -0
- package/_bmad/core/skills/bmad-shard-doc/SKILL.md +6 -0
- package/_bmad/core/skills/bmad-shard-doc/bmad-skill-manifest.yaml +1 -0
- package/_bmad/core/skills/bmad-shard-doc/workflow.md +100 -0
- package/_bmad/core/tasks/bmad-create-prd/SKILL.md +6 -0
- package/_bmad/core/tasks/bmad-create-prd/bmad-skill-manifest.yaml +1 -0
- package/_bmad/core/tasks/bmad-create-prd/data/domain-complexity.csv +15 -0
- package/_bmad/core/tasks/bmad-create-prd/data/prd-purpose.md +197 -0
- package/_bmad/core/tasks/bmad-create-prd/data/project-types.csv +11 -0
- package/_bmad/core/tasks/bmad-create-prd/steps-c/step-01-init.md +178 -0
- package/_bmad/core/tasks/bmad-create-prd/steps-c/step-01b-continue.md +161 -0
- package/_bmad/core/tasks/bmad-create-prd/steps-c/step-02-discovery.md +208 -0
- package/_bmad/core/tasks/bmad-create-prd/steps-c/step-02b-vision.md +142 -0
- package/_bmad/core/tasks/bmad-create-prd/steps-c/step-02c-executive-summary.md +158 -0
- package/_bmad/core/tasks/bmad-create-prd/steps-c/step-03-success.md +214 -0
- package/_bmad/core/tasks/bmad-create-prd/steps-c/step-04-journeys.md +201 -0
- package/_bmad/core/tasks/bmad-create-prd/steps-c/step-05-domain.md +194 -0
- package/_bmad/core/tasks/bmad-create-prd/steps-c/step-06-innovation.md +211 -0
- package/_bmad/core/tasks/bmad-create-prd/steps-c/step-07-project-type.md +222 -0
- package/_bmad/core/tasks/bmad-create-prd/steps-c/step-08-scoping.md +216 -0
- package/_bmad/core/tasks/bmad-create-prd/steps-c/step-09-functional.md +219 -0
- package/_bmad/core/tasks/bmad-create-prd/steps-c/step-10-nonfunctional.md +230 -0
- package/_bmad/core/tasks/bmad-create-prd/steps-c/step-11-polish.md +221 -0
- package/_bmad/core/tasks/bmad-create-prd/steps-c/step-12-complete.md +115 -0
- package/_bmad/core/tasks/bmad-create-prd/templates/prd-template.md +10 -0
- package/_bmad/core/tasks/bmad-create-prd/workflow.md +62 -0
- package/config/allowed-commands.ts +39 -0
- package/config/defaults.ts +19 -0
- package/config/loader.ts +105 -0
- package/extensions/frappe-gates.ts +160 -0
- package/extensions/frappe-session.ts +324 -0
- package/extensions/frappe-state.ts +235 -0
- package/extensions/frappe-tools.ts +278 -0
- package/extensions/frappe-ui.ts +119 -0
- package/extensions/frappe-workflow.ts +85 -0
- package/gates/coverage-check.ts +37 -0
- package/gates/frappe-native-check.ts +65 -0
- package/gates/permission-check.ts +65 -0
- package/gates/query-check.ts +40 -0
- package/gates/server-side-check.ts +67 -0
- package/gates/style-check.ts +92 -0
- package/gates/types.ts +13 -0
- package/package.json +43 -0
- package/project-context.md +146 -0
- package/state/db.ts +85 -0
- package/state/fsm.ts +68 -0
- package/state/journal.ts +164 -0
- package/state/schema.ts +41 -0
- package/tools/agent-tools.ts +60 -0
- package/tools/bench-tools.ts +63 -0
- package/tools/context-sandbox.ts +31 -0
- package/tools/debug-tools.ts +12 -0
- package/tools/feature-tools.ts +126 -0
- package/tools/frappe-context7.ts +70 -0
- package/tools/frappe-query-tools.ts +47 -0
- package/tools/project-tools.ts +107 -0
- package/tsdown.config.ts +6 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { startFeature, completeComponent } from "../tools/feature-tools.js";
|
|
3
|
+
import { setActiveProject, getProjectStatus } from "../tools/project-tools.js";
|
|
4
|
+
import { getAuditLog } from "../state/journal.js";
|
|
5
|
+
import { invokeDebugger, endDebug } from "../tools/debug-tools.js";
|
|
6
|
+
import { spawnAgent } from "../tools/agent-tools.js";
|
|
7
|
+
import { scaffoldDoctype, benchExecute, runTests } from "../tools/bench-tools.js";
|
|
8
|
+
import { frappeQuery } from "../tools/frappe-query-tools.js";
|
|
9
|
+
import { getFrappeDocs } from "../tools/frappe-context7.js";
|
|
10
|
+
|
|
11
|
+
// pi.registerTool's execute callback is untyped (pi is `any`); params are
|
|
12
|
+
// enforced at runtime via TypeBox schemas. One explicit-any alias avoids
|
|
13
|
+
// noImplicitAny errors across all callbacks without per-line suppressions.
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15
|
+
type ToolParams = any;
|
|
16
|
+
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
18
|
+
export default function (pi: any) {
|
|
19
|
+
pi.registerTool({
|
|
20
|
+
name: "start_feature",
|
|
21
|
+
label: "Start Feature",
|
|
22
|
+
description:
|
|
23
|
+
"Creates and names a new feature within the active project, initialising its state in state.db. Valid only in the 'idle' phase.",
|
|
24
|
+
parameters: Type.Object({
|
|
25
|
+
name: Type.String({ description: "Feature name (e.g. 'PO Approval')" }),
|
|
26
|
+
mode: Type.Union([Type.Literal("full"), Type.Literal("quick")], {
|
|
27
|
+
description: "Workflow mode: 'full' for all phases, 'quick' for rapid delivery",
|
|
28
|
+
}),
|
|
29
|
+
}),
|
|
30
|
+
execute: async (_toolCallId: string, params: ToolParams) => {
|
|
31
|
+
const result = startFeature(params);
|
|
32
|
+
return {
|
|
33
|
+
content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
|
|
34
|
+
details: result,
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
pi.registerTool({
|
|
40
|
+
name: "complete_component",
|
|
41
|
+
label: "Complete Component",
|
|
42
|
+
description:
|
|
43
|
+
"Marks a feature component as complete in state.db and creates an automatic git checkpoint commit. Valid only in the 'implementation' phase.",
|
|
44
|
+
parameters: Type.Object({
|
|
45
|
+
featureId: Type.String({ description: "Feature ID (kebab-case slug, e.g. 'po-approval')" }),
|
|
46
|
+
componentId: Type.String({ description: "Component ID (e.g. 'auth-module')" }),
|
|
47
|
+
}),
|
|
48
|
+
execute: async (_toolCallId: string, params: ToolParams) => {
|
|
49
|
+
const result = await completeComponent(params);
|
|
50
|
+
return {
|
|
51
|
+
content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
|
|
52
|
+
details: result,
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
pi.registerTool({
|
|
58
|
+
name: "set_active_project",
|
|
59
|
+
label: "Set Active Project",
|
|
60
|
+
description:
|
|
61
|
+
"Switches the active Frappe project and site. Flushes current session state, creates a new session for the target project (restoring prior phase if known), and reloads the system prompt context. Available in any phase.",
|
|
62
|
+
parameters: Type.Object({
|
|
63
|
+
projectId: Type.String({ description: "Project identifier (e.g. 'my-frappe-site')" }),
|
|
64
|
+
sitePath: Type.String({ description: "Absolute path to the Frappe bench site (e.g. '/home/user/frappe-bench/sites/site1.local')" }),
|
|
65
|
+
}),
|
|
66
|
+
execute: async (_toolCallId: string, params: ToolParams) => {
|
|
67
|
+
const result = await setActiveProject(params);
|
|
68
|
+
return {
|
|
69
|
+
content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
|
|
70
|
+
details: result,
|
|
71
|
+
};
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
pi.registerTool({
|
|
76
|
+
name: "invoke_debugger",
|
|
77
|
+
label: "Invoke Debugger",
|
|
78
|
+
description:
|
|
79
|
+
"Loads the frappe-debugger specialist without triggering a phase transition. Valid in any phase (FR34).",
|
|
80
|
+
parameters: Type.Object({}),
|
|
81
|
+
execute: async (_toolCallId: string, _params: ToolParams) => {
|
|
82
|
+
const result = invokeDebugger();
|
|
83
|
+
return {
|
|
84
|
+
content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
|
|
85
|
+
details: result,
|
|
86
|
+
};
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
pi.registerTool({
|
|
91
|
+
name: "end_debug",
|
|
92
|
+
label: "End Debug",
|
|
93
|
+
description:
|
|
94
|
+
"Exits the debugger session and restores the specialist for the preserved phase. Valid in any phase.",
|
|
95
|
+
parameters: Type.Object({}),
|
|
96
|
+
execute: async (_toolCallId: string, _params: ToolParams) => {
|
|
97
|
+
const result = endDebug();
|
|
98
|
+
return {
|
|
99
|
+
content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
|
|
100
|
+
details: result,
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
pi.registerTool({
|
|
106
|
+
name: "spawn_agent",
|
|
107
|
+
label: "Spawn Agent",
|
|
108
|
+
description:
|
|
109
|
+
"Spawns a sub-agent for parallel work. Requires explicit user approval when requirePermission is true in config. Valid in any phase.",
|
|
110
|
+
parameters: Type.Object({
|
|
111
|
+
skill: Type.String({ description: "Sub-agent skill name (e.g. 'dev-agent')" }),
|
|
112
|
+
trigger: Type.String({ description: "Trigger reason (e.g. 'scaffold')" }),
|
|
113
|
+
reason: Type.String({ description: "Human-readable reason for spawning" }),
|
|
114
|
+
approved: Type.Optional(Type.Boolean({ description: "User approval decision (set after permission prompt)" })),
|
|
115
|
+
}),
|
|
116
|
+
execute: async (_toolCallId: string, params: ToolParams) => {
|
|
117
|
+
const result = await spawnAgent(params);
|
|
118
|
+
return {
|
|
119
|
+
content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
|
|
120
|
+
details: result,
|
|
121
|
+
};
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
pi.registerTool({
|
|
126
|
+
name: "scaffold_doctype",
|
|
127
|
+
label: "Scaffold DocType",
|
|
128
|
+
description:
|
|
129
|
+
"Creates a new Frappe DocType via bench. Valid only in the 'implementation' phase. (Story 4.2 deferred)",
|
|
130
|
+
parameters: Type.Object({
|
|
131
|
+
name: Type.String({ description: "DocType name in PascalCase (e.g. 'Purchase Order')" }),
|
|
132
|
+
module: Type.String({ description: "Frappe module name (e.g. 'Buying')" }),
|
|
133
|
+
}),
|
|
134
|
+
execute: async (_toolCallId: string, params: ToolParams) => {
|
|
135
|
+
const result = scaffoldDoctype(params);
|
|
136
|
+
return {
|
|
137
|
+
content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
|
|
138
|
+
details: result,
|
|
139
|
+
};
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
pi.registerTool({
|
|
144
|
+
name: "run_tests",
|
|
145
|
+
label: "Run Tests",
|
|
146
|
+
description:
|
|
147
|
+
"Runs the Frappe test suite for the active feature via bench. Valid only in the 'testing' phase. (Epic 6)",
|
|
148
|
+
parameters: Type.Object({
|
|
149
|
+
featureId: Type.Optional(Type.String({ description: "Feature ID to scope tests (optional)" })),
|
|
150
|
+
}),
|
|
151
|
+
execute: async (_toolCallId: string, params: ToolParams) => {
|
|
152
|
+
const result = runTests(params);
|
|
153
|
+
return {
|
|
154
|
+
content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
|
|
155
|
+
details: result,
|
|
156
|
+
};
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
pi.registerTool({
|
|
161
|
+
name: "get_project_status",
|
|
162
|
+
label: "Get Project Status",
|
|
163
|
+
description:
|
|
164
|
+
"Returns a dashboard summary of the active project: features, components, phase, and progress. Available in any phase. (Story 5.2)",
|
|
165
|
+
parameters: Type.Object({}),
|
|
166
|
+
execute: async (_toolCallId: string, _params: ToolParams) => {
|
|
167
|
+
const result = getProjectStatus();
|
|
168
|
+
return {
|
|
169
|
+
content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
|
|
170
|
+
details: result,
|
|
171
|
+
};
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
pi.registerTool({
|
|
176
|
+
name: "frappe_query",
|
|
177
|
+
label: "Frappe Query",
|
|
178
|
+
description:
|
|
179
|
+
"Queries Frappe data via mcp2cli subprocess. Output is routed through the context-mode sandbox — raw payloads never enter the LLM context. Available in any phase.",
|
|
180
|
+
parameters: Type.Object({
|
|
181
|
+
doctype: Type.String({ description: "Frappe DocType to query (e.g. 'Sales Order')" }),
|
|
182
|
+
filters: Type.Optional(Type.Record(Type.String(), Type.Unknown(), {
|
|
183
|
+
description: "Filter key-value pairs (e.g. { status: 'Draft' })",
|
|
184
|
+
})),
|
|
185
|
+
}),
|
|
186
|
+
execute: async (_toolCallId: string, params: ToolParams) => {
|
|
187
|
+
const result = await frappeQuery(params);
|
|
188
|
+
return {
|
|
189
|
+
content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
|
|
190
|
+
details: result,
|
|
191
|
+
};
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// 9th tool — outside the 8 core Frappe-semantic tools; bypasses phase guard via ALWAYS_ALLOWED_TOOLS
|
|
196
|
+
pi.registerTool({
|
|
197
|
+
name: "get_frappe_docs",
|
|
198
|
+
label: "Get Frappe Docs",
|
|
199
|
+
description:
|
|
200
|
+
"Retrieves compressed Frappe/ERPNext documentation via context7 MCP. Raw web content never enters the LLM context (~90% token reduction). Valid in any phase. (Story 4.4)",
|
|
201
|
+
parameters: Type.Object({
|
|
202
|
+
topic: Type.String({ description: "Documentation topic (e.g. 'DocType', 'hooks', 'frappe.db')" }),
|
|
203
|
+
version: Type.Optional(Type.String({ description: "Frappe version to scope docs (e.g. 'v15')" })),
|
|
204
|
+
}),
|
|
205
|
+
execute: async (_toolCallId: string, params: ToolParams) => {
|
|
206
|
+
const result = await getFrappeDocs(params);
|
|
207
|
+
return {
|
|
208
|
+
content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
|
|
209
|
+
details: result,
|
|
210
|
+
};
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
pi.registerTool({
|
|
215
|
+
name: "get_audit_log",
|
|
216
|
+
label: "Get Audit Log",
|
|
217
|
+
description:
|
|
218
|
+
"Queries JSONL audit log entries from session files. Supports filtering by sessionId, featureId, and limit. Available in any phase. (Story 5.3)",
|
|
219
|
+
parameters: Type.Object({
|
|
220
|
+
sessionId: Type.Optional(Type.String({ description: "Session ID to query (omit for all sessions)" })),
|
|
221
|
+
featureId: Type.Optional(Type.String({ description: "Feature ID to filter entries by payload.feature" })),
|
|
222
|
+
limit: Type.Optional(Type.Number({ description: "Maximum number of entries to return (default: all)" })),
|
|
223
|
+
}),
|
|
224
|
+
execute: async (_toolCallId: string, params: ToolParams) => {
|
|
225
|
+
const result = getAuditLog(params);
|
|
226
|
+
return {
|
|
227
|
+
content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
|
|
228
|
+
details: result,
|
|
229
|
+
};
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// /status slash command — displays project dashboard (FR21, Story 5.2)
|
|
234
|
+
// Defensive: pi.registerCommand may not be available in all pi-mono versions
|
|
235
|
+
if (typeof pi.registerCommand === "function") {
|
|
236
|
+
pi.registerCommand("status", {
|
|
237
|
+
description: "Show project dashboard: features, components, phase, and progress",
|
|
238
|
+
handler: async (_args: string, ctx: Record<string, unknown>) => {
|
|
239
|
+
const status = getProjectStatus();
|
|
240
|
+
const lines: string[] = [];
|
|
241
|
+
if (status.message) {
|
|
242
|
+
lines.push(status.message);
|
|
243
|
+
} else {
|
|
244
|
+
for (const f of status.features) {
|
|
245
|
+
lines.push(`[${f.phase}] ${f.name} (${f.componentsDone}/${f.componentsTotal} done)`);
|
|
246
|
+
for (const c of f.components) {
|
|
247
|
+
const mark = c.status === "complete" ? "✓" : "·";
|
|
248
|
+
lines.push(` ${mark} ${c.componentId}`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const output = lines.join("\n") || "No project data";
|
|
253
|
+
if (ctx.hasUI && ctx.ui && typeof (ctx.ui as Record<string, unknown>).notify === "function") {
|
|
254
|
+
(ctx.ui as { notify: (msg: string, sev: string) => void }).notify(output, "info");
|
|
255
|
+
}
|
|
256
|
+
return output;
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
pi.registerTool({
|
|
262
|
+
name: "bench_execute",
|
|
263
|
+
label: "Bench Execute",
|
|
264
|
+
description:
|
|
265
|
+
"Runs a whitelisted bench command via subprocess. Output sandboxed through context-mode. Valid only in the 'implementation' phase. (Story 4.3)",
|
|
266
|
+
parameters: Type.Object({
|
|
267
|
+
command: Type.String({ description: "Bench command (e.g. 'migrate')" }),
|
|
268
|
+
args: Type.Optional(Type.Array(Type.String(), { description: "Additional arguments" })),
|
|
269
|
+
}),
|
|
270
|
+
execute: async (_toolCallId: string, params: ToolParams) => {
|
|
271
|
+
const result = benchExecute(params);
|
|
272
|
+
return {
|
|
273
|
+
content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
|
|
274
|
+
details: result,
|
|
275
|
+
};
|
|
276
|
+
},
|
|
277
|
+
});
|
|
278
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { AfterToolCallContext, AfterToolCallResult } from "@mariozechner/pi-agent-core";
|
|
2
|
+
import { db, getCurrentPhase } from "../state/db.js";
|
|
3
|
+
|
|
4
|
+
interface FooterState {
|
|
5
|
+
projectId: string | null;
|
|
6
|
+
featureName: string | null;
|
|
7
|
+
phase: string;
|
|
8
|
+
tokenCount: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function readFooterState(): FooterState {
|
|
12
|
+
try {
|
|
13
|
+
const session = db
|
|
14
|
+
.prepare(
|
|
15
|
+
`SELECT s.project_id, f.name AS feature_name, s.current_phase
|
|
16
|
+
FROM sessions s
|
|
17
|
+
LEFT JOIN features f ON f.feature_id = s.feature_id
|
|
18
|
+
WHERE s.is_active = 1 LIMIT 1`
|
|
19
|
+
)
|
|
20
|
+
.get() as
|
|
21
|
+
| { project_id: string | null; feature_name: string | null; current_phase: string }
|
|
22
|
+
| undefined;
|
|
23
|
+
|
|
24
|
+
// Token count: count journal_entries for active session; table may not exist yet
|
|
25
|
+
let tokenCount = 0;
|
|
26
|
+
try {
|
|
27
|
+
const tokenRow = db
|
|
28
|
+
.prepare(
|
|
29
|
+
`SELECT COUNT(*) as count FROM journal_entries
|
|
30
|
+
WHERE session_id = (SELECT session_id FROM sessions WHERE is_active = 1 LIMIT 1)`
|
|
31
|
+
)
|
|
32
|
+
.get() as { count: number } | undefined;
|
|
33
|
+
tokenCount = tokenRow?.count ?? 0;
|
|
34
|
+
} catch {
|
|
35
|
+
// journal_entries table not yet created — default to 0
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
projectId: session?.project_id ?? null,
|
|
40
|
+
featureName: session?.feature_name ?? null,
|
|
41
|
+
phase: session?.current_phase ?? "idle",
|
|
42
|
+
tokenCount,
|
|
43
|
+
};
|
|
44
|
+
} catch {
|
|
45
|
+
return { projectId: null, featureName: null, phase: "idle", tokenCount: 0 };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Pure formatting function — no I/O, no side effects.
|
|
51
|
+
* Exported for unit testing.
|
|
52
|
+
*/
|
|
53
|
+
export function formatFooter(state: FooterState): string {
|
|
54
|
+
if (!state.projectId) {
|
|
55
|
+
return `No active project | Phase: ${state.phase}`;
|
|
56
|
+
}
|
|
57
|
+
if (!state.featureName) {
|
|
58
|
+
return `Project: ${state.projectId} | No active feature | Phase: ${state.phase}`;
|
|
59
|
+
}
|
|
60
|
+
return `Project: ${state.projectId} | Feature: ${state.featureName} | Phase: ${state.phase} | Tokens: ${state.tokenCount}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function renderFooter(): void {
|
|
64
|
+
try {
|
|
65
|
+
const state = readFooterState();
|
|
66
|
+
const line = formatFooter(state);
|
|
67
|
+
process.stderr.write(`\r\x1b[2K[frappe-builder] ${line}\n`);
|
|
68
|
+
} catch {
|
|
69
|
+
// Silently swallow all rendering errors — footer is non-critical
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* beforeToolCall announcement hook — writes "→ Calling {tool} [{phase}]" to stderr.
|
|
75
|
+
* Always returns undefined — this hook only announces, never blocks.
|
|
76
|
+
* Wrap in try/catch so announcement failure never crashes the session.
|
|
77
|
+
*
|
|
78
|
+
* Load order note: frappe-ui must load before frappe-workflow so this fires
|
|
79
|
+
* before the FSM guard. Load order is controlled by the pi extension list;
|
|
80
|
+
* package.json "pi" field is currently empty so order is determined by the
|
|
81
|
+
* pi CLI -e flags at startup.
|
|
82
|
+
*/
|
|
83
|
+
export function handleBeforeToolCall(toolName: string): undefined {
|
|
84
|
+
try {
|
|
85
|
+
const phase = getCurrentPhase();
|
|
86
|
+
process.stderr.write(`→ Calling ${toolName} [${phase}]\n`);
|
|
87
|
+
} catch {
|
|
88
|
+
// Swallow — announcement is non-critical, must never block or crash
|
|
89
|
+
}
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* afterToolCall hook — renders the footer and returns undefined so the
|
|
95
|
+
* original tool result passes through unmodified.
|
|
96
|
+
*/
|
|
97
|
+
export async function handleAfterToolCall(
|
|
98
|
+
_context: AfterToolCallContext,
|
|
99
|
+
_signal?: AbortSignal
|
|
100
|
+
): Promise<AfterToolCallResult | undefined> {
|
|
101
|
+
renderFooter();
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
106
|
+
export default function (pi: any) {
|
|
107
|
+
pi.on("session_start", () => {
|
|
108
|
+
renderFooter();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Announcement hook — fires before FSM guard in frappe-workflow.ts (FR25)
|
|
112
|
+
pi.on("tool_call", (event: { toolName?: string }) => {
|
|
113
|
+
return handleBeforeToolCall(event.toolName ?? "");
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
pi.on("after_tool_call", async (context: AfterToolCallContext) => {
|
|
117
|
+
return await handleAfterToolCall(context);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { getCurrentPhase, db } from "../state/db.js";
|
|
2
|
+
import { isToolAllowedInPhase, getValidPhase, type Phase } from "../state/fsm.js";
|
|
3
|
+
import { appendEntry } from "../state/journal.js";
|
|
4
|
+
|
|
5
|
+
interface BlockedResponse {
|
|
6
|
+
blocked: true;
|
|
7
|
+
tool: string;
|
|
8
|
+
current_phase: Phase;
|
|
9
|
+
valid_phase: Phase | "any";
|
|
10
|
+
message: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function buildBlockedResponse(
|
|
14
|
+
tool: string,
|
|
15
|
+
currentPhase: Phase,
|
|
16
|
+
validPhase: Phase | "any"
|
|
17
|
+
): BlockedResponse {
|
|
18
|
+
return {
|
|
19
|
+
blocked: true,
|
|
20
|
+
tool,
|
|
21
|
+
current_phase: currentPhase,
|
|
22
|
+
valid_phase: validPhase,
|
|
23
|
+
message: `${tool} is not available in ${currentPhase} phase. Available in: ${validPhase}`,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Phase guard logic for beforeToolCall. Returns a blocked response if the tool
|
|
29
|
+
* is not valid in the current phase, undefined to allow.
|
|
30
|
+
*
|
|
31
|
+
* Override: if args.override === true, writes a JSONL entry and allows the tool
|
|
32
|
+
* regardless of phase. Does NOT disable quality gates (frappe-gates.ts).
|
|
33
|
+
*
|
|
34
|
+
* Never throws — always returns a value or undefined.
|
|
35
|
+
*/
|
|
36
|
+
// Tools valid in all phases — never blocked by the phase guard (FR34)
|
|
37
|
+
const ALWAYS_ALLOWED_TOOLS = ["invoke_debugger", "end_debug", "spawn_agent", "get_frappe_docs", "get_audit_log"];
|
|
38
|
+
|
|
39
|
+
export function beforeToolCall(
|
|
40
|
+
toolName: string,
|
|
41
|
+
args: Record<string, unknown>
|
|
42
|
+
): BlockedResponse | undefined {
|
|
43
|
+
// Always-allowed bypass — checked before everything else
|
|
44
|
+
if (ALWAYS_ALLOWED_TOOLS.includes(toolName)) return undefined;
|
|
45
|
+
|
|
46
|
+
const currentPhase = getCurrentPhase() as Phase;
|
|
47
|
+
|
|
48
|
+
// Override bypass — checked BEFORE phase guard (FR10 escape hatch)
|
|
49
|
+
if (args.override === true) {
|
|
50
|
+
const session = db
|
|
51
|
+
.prepare("SELECT session_id FROM sessions WHERE is_active = 1 LIMIT 1")
|
|
52
|
+
.get() as { session_id: string } | undefined;
|
|
53
|
+
|
|
54
|
+
appendEntry({
|
|
55
|
+
ts: new Date().toISOString(),
|
|
56
|
+
sessionId: session?.session_id ?? "unknown",
|
|
57
|
+
type: "tool_call",
|
|
58
|
+
payload: {
|
|
59
|
+
override: true,
|
|
60
|
+
reason: (args.reason as string) ?? "unspecified",
|
|
61
|
+
tool: toolName,
|
|
62
|
+
phase: currentPhase,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
return undefined; // allow
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Phase guard
|
|
69
|
+
if (!isToolAllowedInPhase(toolName, currentPhase)) {
|
|
70
|
+
return buildBlockedResponse(toolName, currentPhase, getValidPhase(toolName));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return undefined; // allow
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
77
|
+
export default function (pi: any) {
|
|
78
|
+
pi.on("tool_call", (event: { toolName?: string; input?: Record<string, unknown> }) => {
|
|
79
|
+
const result = beforeToolCall(event.toolName ?? "", event.input ?? {});
|
|
80
|
+
if (result) {
|
|
81
|
+
return { block: true, reason: result.message };
|
|
82
|
+
}
|
|
83
|
+
return undefined;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gates/coverage-check.ts — Async coverage gate (NOT a pure function).
|
|
3
|
+
* Runs `bench run-tests --coverage` via execa and parses the result.
|
|
4
|
+
*
|
|
5
|
+
* NOT wired via frappe-gates.ts — integrated directly in completeComponent().
|
|
6
|
+
* Triggers when the final component is completed in `testing` phase. (FR29)
|
|
7
|
+
*/
|
|
8
|
+
import { execa } from "execa";
|
|
9
|
+
import type { GateContext } from "./types.js";
|
|
10
|
+
|
|
11
|
+
export type CoverageResult =
|
|
12
|
+
| { passed: true; coverage: number }
|
|
13
|
+
| { passed: false; coverage: number; required: string; error?: string };
|
|
14
|
+
|
|
15
|
+
function parseCoverage(stdout: string): number {
|
|
16
|
+
const match = stdout.match(/^TOTAL\s+\d+\s+\d+\s+(\d+)%/m);
|
|
17
|
+
return match ? parseInt(match[1], 10) : 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function coverageCheck(_context: GateContext): Promise<CoverageResult> {
|
|
21
|
+
try {
|
|
22
|
+
const { stdout } = await execa("bench", ["run-tests", "--coverage"], {
|
|
23
|
+
cwd: process.env.FRAPPE_BENCH_PATH ?? process.cwd(),
|
|
24
|
+
reject: false, // don't throw on non-zero exit — coverage data may still be in stdout
|
|
25
|
+
timeout: 120_000, // 2 minute timeout
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const coverage = parseCoverage(stdout ?? "");
|
|
29
|
+
|
|
30
|
+
if (coverage < 70) {
|
|
31
|
+
return { passed: false, coverage, required: "70%" };
|
|
32
|
+
}
|
|
33
|
+
return { passed: true, coverage };
|
|
34
|
+
} catch (err) {
|
|
35
|
+
return { passed: false, coverage: 0, required: "70%", error: (err as Error).message };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gates/frappe-native-check.ts — pure gate function, no side effects.
|
|
3
|
+
* No imports from state/, extensions/, or config/.
|
|
4
|
+
* No async, no db, no I/O. Same input always produces same output.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export type NativeCheckResult =
|
|
8
|
+
| { passed: true }
|
|
9
|
+
| { passed: true; result: "override"; justification: string; detectedPatterns: string[] }
|
|
10
|
+
| { passed: false; requiresJustification: true; message: string; detectedPatterns: string[] };
|
|
11
|
+
|
|
12
|
+
export const NON_NATIVE_PATTERNS: { pattern: RegExp; label: string }[] = [
|
|
13
|
+
// HTTP clients — use frappe.call() or frappe.db instead
|
|
14
|
+
{ pattern: /import\s+axios/, label: "axios (use frappe.call)" },
|
|
15
|
+
{ pattern: /require\(['"]axios['"]\)/, label: "axios (use frappe.call)" },
|
|
16
|
+
{ pattern: /import\s+requests/, label: "requests (use frappe.call)" },
|
|
17
|
+
{ pattern: /from\s+requests\s+import/, label: "requests (use frappe.call)" },
|
|
18
|
+
|
|
19
|
+
// Raw database access — use Frappe ORM
|
|
20
|
+
{ pattern: /cursor\.execute\s*\(/, label: "raw SQL cursor (use frappe.db.sql or ORM)" },
|
|
21
|
+
{ pattern: /pymysql|psycopg2|sqlite3\.connect/, label: "direct DB driver (use Frappe ORM)" },
|
|
22
|
+
{ pattern: /mongoose|sequelize|typeorm/i, label: "external ORM (use Frappe DocType)" },
|
|
23
|
+
|
|
24
|
+
// Custom auth — use frappe.whitelist()
|
|
25
|
+
{ pattern: /jwt\.sign|jsonwebtoken/, label: "JWT auth (use frappe.whitelist + session)" },
|
|
26
|
+
{ pattern: /passport\.authenticate/, label: "passport auth (use Frappe auth)" },
|
|
27
|
+
|
|
28
|
+
// External data processing — use Frappe reports/scripts
|
|
29
|
+
{ pattern: /import\s+pandas/, label: "pandas (use Frappe Script Report)" },
|
|
30
|
+
{ pattern: /import\s+numpy/, label: "numpy (use Frappe computation)" },
|
|
31
|
+
|
|
32
|
+
// File system — use Frappe file manager
|
|
33
|
+
{ pattern: /fs\.writeFileSync|fs\.readFileSync/, label: "raw fs (use frappe.get_file_url or File DocType)" },
|
|
34
|
+
|
|
35
|
+
// HTTP server — use Frappe whitelisted methods
|
|
36
|
+
{ pattern: /express\(\)|fastapi|flask\.Flask/, label: "external web framework (use Frappe whitelist)" },
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Scans `content` for non-Frappe-native patterns.
|
|
41
|
+
*
|
|
42
|
+
* - No detected patterns → { passed: true }
|
|
43
|
+
* - Detected + no justification → { passed: false, requiresJustification: true, ... }
|
|
44
|
+
* - Detected + justification provided → { passed: true, result: "override", ... }
|
|
45
|
+
*/
|
|
46
|
+
export function checkFrappeNative(content: string, justification?: string): NativeCheckResult {
|
|
47
|
+
const detectedPatterns = NON_NATIVE_PATTERNS
|
|
48
|
+
.filter(({ pattern }) => pattern.test(content))
|
|
49
|
+
.map(({ label }) => label);
|
|
50
|
+
|
|
51
|
+
if (detectedPatterns.length === 0) {
|
|
52
|
+
return { passed: true };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (justification) {
|
|
56
|
+
return { passed: true, result: "override", justification, detectedPatterns };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
passed: false,
|
|
61
|
+
requiresJustification: true,
|
|
62
|
+
message: "This uses a non-Frappe-native approach. Justification required to proceed.",
|
|
63
|
+
detectedPatterns,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gates/permission-check.ts — Pure gate function, no side effects.
|
|
3
|
+
* No imports from state/, extensions/, or config/.
|
|
4
|
+
* No async, no db, no I/O. Same input always produces same output.
|
|
5
|
+
*
|
|
6
|
+
* Scans Python code for @frappe.whitelist() decorated methods that lack
|
|
7
|
+
* a permission check inside their function body. (FR26)
|
|
8
|
+
*/
|
|
9
|
+
import type { GateContext, GateResult } from "./types.js";
|
|
10
|
+
|
|
11
|
+
const PERMISSION_PATTERNS = [
|
|
12
|
+
/frappe\.has_permission\s*\(/,
|
|
13
|
+
/frappe\.only_for\s*\(/,
|
|
14
|
+
/frappe\.check_permission\s*\(/,
|
|
15
|
+
/frappe\.has_role\s*\(/,
|
|
16
|
+
/frappe\.session\.user/,
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
function getLineNumber(code: string, offset: number): number {
|
|
20
|
+
return code.slice(0, offset).split("\n").length;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function extractFunctionBody(code: string, defStart: number): string {
|
|
24
|
+
const bodyStart = code.indexOf("\n", defStart) + 1;
|
|
25
|
+
// Find next top-level def/class/decorator (at column 0)
|
|
26
|
+
const nextTopLevel = /\n(?=def |class |@)/g;
|
|
27
|
+
nextTopLevel.lastIndex = bodyStart;
|
|
28
|
+
const match = nextTopLevel.exec(code);
|
|
29
|
+
return match ? code.slice(bodyStart, match.index) : code.slice(bodyStart);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function hasPermissionCheck(body: string): boolean {
|
|
33
|
+
return PERMISSION_PATTERNS.some((p) => p.test(body));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function permissionCheck(code: string, context: GateContext): GateResult {
|
|
37
|
+
// Only scan Python files
|
|
38
|
+
if (!context.file.endsWith(".py")) return { passed: true };
|
|
39
|
+
|
|
40
|
+
// Find all @frappe.whitelist(...) followed by a def
|
|
41
|
+
const WHITELIST_DECORATOR = /@frappe\.whitelist\([^)]*\)\s*\ndef\s+(\w+)/g;
|
|
42
|
+
|
|
43
|
+
const violations: Array<{ method: string; line: number; reason: string }> = [];
|
|
44
|
+
let match: RegExpExecArray | null;
|
|
45
|
+
|
|
46
|
+
while ((match = WHITELIST_DECORATOR.exec(code)) !== null) {
|
|
47
|
+
const decoratorOffset = match.index;
|
|
48
|
+
const methodName = match[1];
|
|
49
|
+
const line = getLineNumber(code, decoratorOffset);
|
|
50
|
+
|
|
51
|
+
// defStart: position of "def " within the full match
|
|
52
|
+
const defStart = code.indexOf("\ndef ", decoratorOffset) + 1;
|
|
53
|
+
const body = extractFunctionBody(code, defStart);
|
|
54
|
+
|
|
55
|
+
if (!hasPermissionCheck(body)) {
|
|
56
|
+
violations.push({ method: methodName, line, reason: "missing permission check" });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (violations.length > 0) {
|
|
61
|
+
return { passed: false, violations };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return { passed: true };
|
|
65
|
+
}
|