bmalph 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +217 -0
- package/bin/bmalph.js +14 -0
- package/bmad/bmm/agents/analyst.agent.yaml +36 -0
- package/bmad/bmm/agents/architect.agent.yaml +28 -0
- package/bmad/bmm/agents/dev.agent.yaml +38 -0
- package/bmad/bmm/agents/pm.agent.yaml +46 -0
- package/bmad/bmm/agents/quick-flow-solo-dev.agent.yaml +32 -0
- package/bmad/bmm/agents/sm.agent.yaml +36 -0
- package/bmad/bmm/agents/tea.agent.yaml +63 -0
- package/bmad/bmm/agents/tech-writer/tech-writer-sidecar/documentation-standards.md +224 -0
- package/bmad/bmm/agents/tech-writer/tech-writer.agent.yaml +45 -0
- package/bmad/bmm/agents/ux-designer.agent.yaml +26 -0
- package/bmad/bmm/data/project-context-template.md +26 -0
- package/bmad/bmm/module-help.csv +31 -0
- package/bmad/bmm/module.yaml +44 -0
- package/bmad/bmm/sub-modules/claude-code/config.yaml +4 -0
- package/bmad/bmm/sub-modules/claude-code/injections.yaml +242 -0
- package/bmad/bmm/sub-modules/claude-code/readme.md +87 -0
- package/bmad/bmm/teams/default-party.csv +21 -0
- package/bmad/bmm/teams/team-fullstack.yaml +12 -0
- package/bmad/bmm/testarch/knowledge/adr-quality-readiness-checklist.md +350 -0
- package/bmad/bmm/testarch/knowledge/api-request.md +442 -0
- package/bmad/bmm/testarch/knowledge/api-testing-patterns.md +843 -0
- package/bmad/bmm/testarch/knowledge/auth-session.md +552 -0
- package/bmad/bmm/testarch/knowledge/burn-in.md +273 -0
- package/bmad/bmm/testarch/knowledge/ci-burn-in.md +675 -0
- package/bmad/bmm/testarch/knowledge/component-tdd.md +486 -0
- package/bmad/bmm/testarch/knowledge/contract-testing.md +957 -0
- package/bmad/bmm/testarch/knowledge/data-factories.md +500 -0
- package/bmad/bmm/testarch/knowledge/email-auth.md +721 -0
- package/bmad/bmm/testarch/knowledge/error-handling.md +725 -0
- package/bmad/bmm/testarch/knowledge/feature-flags.md +750 -0
- package/bmad/bmm/testarch/knowledge/file-utils.md +463 -0
- package/bmad/bmm/testarch/knowledge/fixture-architecture.md +401 -0
- package/bmad/bmm/testarch/knowledge/fixtures-composition.md +382 -0
- package/bmad/bmm/testarch/knowledge/intercept-network-call.md +430 -0
- package/bmad/bmm/testarch/knowledge/log.md +429 -0
- package/bmad/bmm/testarch/knowledge/network-error-monitor.md +405 -0
- package/bmad/bmm/testarch/knowledge/network-first.md +486 -0
- package/bmad/bmm/testarch/knowledge/network-recorder.md +527 -0
- package/bmad/bmm/testarch/knowledge/nfr-criteria.md +670 -0
- package/bmad/bmm/testarch/knowledge/overview.md +286 -0
- package/bmad/bmm/testarch/knowledge/playwright-config.md +730 -0
- package/bmad/bmm/testarch/knowledge/probability-impact.md +601 -0
- package/bmad/bmm/testarch/knowledge/recurse.md +421 -0
- package/bmad/bmm/testarch/knowledge/risk-governance.md +615 -0
- package/bmad/bmm/testarch/knowledge/selective-testing.md +732 -0
- package/bmad/bmm/testarch/knowledge/selector-resilience.md +527 -0
- package/bmad/bmm/testarch/knowledge/test-healing-patterns.md +644 -0
- package/bmad/bmm/testarch/knowledge/test-levels-framework.md +473 -0
- package/bmad/bmm/testarch/knowledge/test-priorities-matrix.md +373 -0
- package/bmad/bmm/testarch/knowledge/test-quality.md +664 -0
- package/bmad/bmm/testarch/knowledge/timing-debugging.md +372 -0
- package/bmad/bmm/testarch/knowledge/visual-debugging.md +524 -0
- package/bmad/bmm/testarch/tea-index.csv +35 -0
- package/bmad/bmm/workflows/1-analysis/create-product-brief/product-brief.template.md +10 -0
- package/bmad/bmm/workflows/1-analysis/create-product-brief/steps/step-01-init.md +177 -0
- package/bmad/bmm/workflows/1-analysis/create-product-brief/steps/step-01b-continue.md +161 -0
- package/bmad/bmm/workflows/1-analysis/create-product-brief/steps/step-02-vision.md +199 -0
- package/bmad/bmm/workflows/1-analysis/create-product-brief/steps/step-03-users.md +202 -0
- package/bmad/bmm/workflows/1-analysis/create-product-brief/steps/step-04-metrics.md +205 -0
- package/bmad/bmm/workflows/1-analysis/create-product-brief/steps/step-05-scope.md +219 -0
- package/bmad/bmm/workflows/1-analysis/create-product-brief/steps/step-06-complete.md +162 -0
- package/bmad/bmm/workflows/1-analysis/create-product-brief/workflow.md +58 -0
- package/bmad/bmm/workflows/1-analysis/research/domain-steps/step-01-init.md +137 -0
- package/bmad/bmm/workflows/1-analysis/research/domain-steps/step-02-domain-analysis.md +229 -0
- package/bmad/bmm/workflows/1-analysis/research/domain-steps/step-03-competitive-landscape.md +238 -0
- package/bmad/bmm/workflows/1-analysis/research/domain-steps/step-04-regulatory-focus.md +206 -0
- package/bmad/bmm/workflows/1-analysis/research/domain-steps/step-05-technical-trends.md +234 -0
- package/bmad/bmm/workflows/1-analysis/research/domain-steps/step-06-research-synthesis.md +443 -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-02-customer-insights.md +200 -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 +475 -0
- package/bmad/bmm/workflows/1-analysis/research/research.template.md +29 -0
- package/bmad/bmm/workflows/1-analysis/research/technical-steps/step-01-init.md +137 -0
- package/bmad/bmm/workflows/1-analysis/research/technical-steps/step-02-technical-overview.md +239 -0
- package/bmad/bmm/workflows/1-analysis/research/technical-steps/step-03-integration-patterns.md +248 -0
- package/bmad/bmm/workflows/1-analysis/research/technical-steps/step-04-architectural-patterns.md +202 -0
- package/bmad/bmm/workflows/1-analysis/research/technical-steps/step-05-implementation-research.md +239 -0
- package/bmad/bmm/workflows/1-analysis/research/technical-steps/step-06-research-synthesis.md +486 -0
- package/bmad/bmm/workflows/1-analysis/research/workflow.md +173 -0
- package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-01-init.md +135 -0
- package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-01b-continue.md +127 -0
- package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-02-discovery.md +190 -0
- package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-03-core-experience.md +216 -0
- package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md +219 -0
- package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-05-inspiration.md +234 -0
- package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-06-design-system.md +252 -0
- package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-07-defining-experience.md +254 -0
- package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-08-visual-foundation.md +224 -0
- package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-09-design-directions.md +224 -0
- package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-10-user-journeys.md +241 -0
- package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-11-component-strategy.md +248 -0
- package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-12-ux-patterns.md +237 -0
- package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-13-responsive-accessibility.md +264 -0
- package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-14-complete.md +171 -0
- package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/ux-design-template.md +13 -0
- package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/workflow.md +43 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/data/domain-complexity.csv +13 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/data/prd-purpose.md +197 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/data/project-types.csv +11 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-01-init.md +191 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-01b-continue.md +153 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-02-discovery.md +224 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-03-success.md +226 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-04-journeys.md +213 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-05-domain.md +207 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-06-innovation.md +226 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-07-project-type.md +237 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-08-scoping.md +228 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-09-functional.md +231 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-10-nonfunctional.md +242 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-11-polish.md +217 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-12-complete.md +124 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-e/step-e-01-discovery.md +247 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-e/step-e-01b-legacy-conversion.md +208 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-e/step-e-02-review.md +249 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-e/step-e-03-edit.md +253 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-e/step-e-04-complete.md +168 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-01-discovery.md +218 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-02-format-detection.md +191 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-02b-parity-check.md +209 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-03-density-validation.md +174 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-04-brief-coverage-validation.md +214 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-05-measurability-validation.md +228 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-06-traceability-validation.md +217 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-07-implementation-leakage-validation.md +205 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-08-domain-compliance-validation.md +243 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-09-project-type-validation.md +263 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-10-smart-validation.md +209 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-11-holistic-quality-validation.md +264 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-12-completeness-validation.md +242 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-13-report-complete.md +231 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/templates/prd-template.md +10 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/validation-report-prd-workflow.md +433 -0
- package/bmad/bmm/workflows/2-plan-workflows/prd/workflow.md +150 -0
- package/bmad/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-01-document-discovery.md +190 -0
- package/bmad/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-02-prd-analysis.md +178 -0
- package/bmad/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-03-epic-coverage-validation.md +179 -0
- package/bmad/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-04-ux-alignment.md +139 -0
- package/bmad/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-05-epic-quality-review.md +252 -0
- package/bmad/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-06-final-assessment.md +135 -0
- package/bmad/bmm/workflows/3-solutioning/check-implementation-readiness/templates/readiness-report-template.md +4 -0
- package/bmad/bmm/workflows/3-solutioning/check-implementation-readiness/workflow.md +55 -0
- package/bmad/bmm/workflows/3-solutioning/create-architecture/architecture-decision-template.md +12 -0
- package/bmad/bmm/workflows/3-solutioning/create-architecture/data/domain-complexity.csv +11 -0
- package/bmad/bmm/workflows/3-solutioning/create-architecture/data/project-types.csv +7 -0
- package/bmad/bmm/workflows/3-solutioning/create-architecture/steps/step-01-init.md +153 -0
- package/bmad/bmm/workflows/3-solutioning/create-architecture/steps/step-01b-continue.md +164 -0
- package/bmad/bmm/workflows/3-solutioning/create-architecture/steps/step-02-context.md +224 -0
- package/bmad/bmm/workflows/3-solutioning/create-architecture/steps/step-03-starter.md +331 -0
- package/bmad/bmm/workflows/3-solutioning/create-architecture/steps/step-04-decisions.md +318 -0
- package/bmad/bmm/workflows/3-solutioning/create-architecture/steps/step-05-patterns.md +359 -0
- package/bmad/bmm/workflows/3-solutioning/create-architecture/steps/step-06-structure.md +379 -0
- package/bmad/bmm/workflows/3-solutioning/create-architecture/steps/step-07-validation.md +359 -0
- package/bmad/bmm/workflows/3-solutioning/create-architecture/steps/step-08-complete.md +76 -0
- package/bmad/bmm/workflows/3-solutioning/create-architecture/workflow.md +50 -0
- package/bmad/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-01-validate-prerequisites.md +259 -0
- package/bmad/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-02-design-epics.md +233 -0
- package/bmad/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-03-create-stories.md +272 -0
- package/bmad/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +149 -0
- package/bmad/bmm/workflows/3-solutioning/create-epics-and-stories/templates/epics-template.md +57 -0
- package/bmad/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.md +59 -0
- package/bmad/bmm/workflows/4-implementation/code-review/checklist.md +23 -0
- package/bmad/bmm/workflows/4-implementation/code-review/instructions.xml +227 -0
- package/bmad/bmm/workflows/4-implementation/code-review/workflow.yaml +51 -0
- package/bmad/bmm/workflows/4-implementation/correct-course/checklist.md +288 -0
- package/bmad/bmm/workflows/4-implementation/correct-course/instructions.md +206 -0
- package/bmad/bmm/workflows/4-implementation/correct-course/workflow.yaml +60 -0
- package/bmad/bmm/workflows/4-implementation/create-story/checklist.md +358 -0
- package/bmad/bmm/workflows/4-implementation/create-story/instructions.xml +345 -0
- package/bmad/bmm/workflows/4-implementation/create-story/template.md +49 -0
- package/bmad/bmm/workflows/4-implementation/create-story/workflow.yaml +61 -0
- package/bmad/bmm/workflows/4-implementation/dev-story/checklist.md +80 -0
- package/bmad/bmm/workflows/4-implementation/dev-story/instructions.xml +410 -0
- package/bmad/bmm/workflows/4-implementation/dev-story/workflow.yaml +27 -0
- package/bmad/bmm/workflows/4-implementation/retrospective/instructions.md +1443 -0
- package/bmad/bmm/workflows/4-implementation/retrospective/workflow.yaml +58 -0
- package/bmad/bmm/workflows/4-implementation/sprint-planning/checklist.md +33 -0
- package/bmad/bmm/workflows/4-implementation/sprint-planning/instructions.md +225 -0
- package/bmad/bmm/workflows/4-implementation/sprint-planning/sprint-status-template.yaml +55 -0
- package/bmad/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +54 -0
- package/bmad/bmm/workflows/4-implementation/sprint-status/instructions.md +229 -0
- package/bmad/bmm/workflows/4-implementation/sprint-status/workflow.yaml +36 -0
- package/bmad/bmm/workflows/bmad-quick-flow/quick-dev/data/project-levels.yaml +59 -0
- package/bmad/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-01-mode-detection.md +156 -0
- package/bmad/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-02-context-gathering.md +120 -0
- package/bmad/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-03-execute.md +113 -0
- package/bmad/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-04-self-check.md +113 -0
- package/bmad/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-05-adversarial-review.md +106 -0
- package/bmad/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-06-resolve-findings.md +140 -0
- package/bmad/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +50 -0
- package/bmad/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-01-understand.md +189 -0
- package/bmad/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-02-investigate.md +144 -0
- package/bmad/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-03-generate.md +128 -0
- package/bmad/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-04-review.md +191 -0
- package/bmad/bmm/workflows/bmad-quick-flow/quick-spec/tech-spec-template.md +74 -0
- package/bmad/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +79 -0
- package/bmad/bmm/workflows/document-project/checklist.md +245 -0
- package/bmad/bmm/workflows/document-project/documentation-requirements.csv +12 -0
- package/bmad/bmm/workflows/document-project/instructions.md +221 -0
- package/bmad/bmm/workflows/document-project/templates/deep-dive-template.md +345 -0
- package/bmad/bmm/workflows/document-project/templates/index-template.md +169 -0
- package/bmad/bmm/workflows/document-project/templates/project-overview-template.md +103 -0
- package/bmad/bmm/workflows/document-project/templates/project-scan-report-schema.json +160 -0
- package/bmad/bmm/workflows/document-project/templates/source-tree-template.md +135 -0
- package/bmad/bmm/workflows/document-project/workflow.yaml +30 -0
- package/bmad/bmm/workflows/document-project/workflows/deep-dive-instructions.md +298 -0
- package/bmad/bmm/workflows/document-project/workflows/deep-dive.yaml +31 -0
- package/bmad/bmm/workflows/document-project/workflows/full-scan-instructions.md +1106 -0
- package/bmad/bmm/workflows/document-project/workflows/full-scan.yaml +31 -0
- package/bmad/bmm/workflows/excalidraw-diagrams/_shared/excalidraw-library.json +90 -0
- package/bmad/bmm/workflows/excalidraw-diagrams/_shared/excalidraw-templates.yaml +127 -0
- package/bmad/bmm/workflows/excalidraw-diagrams/create-dataflow/checklist.md +39 -0
- package/bmad/bmm/workflows/excalidraw-diagrams/create-dataflow/instructions.md +130 -0
- package/bmad/bmm/workflows/excalidraw-diagrams/create-dataflow/workflow.yaml +27 -0
- package/bmad/bmm/workflows/excalidraw-diagrams/create-diagram/checklist.md +43 -0
- package/bmad/bmm/workflows/excalidraw-diagrams/create-diagram/instructions.md +141 -0
- package/bmad/bmm/workflows/excalidraw-diagrams/create-diagram/workflow.yaml +27 -0
- package/bmad/bmm/workflows/excalidraw-diagrams/create-flowchart/checklist.md +49 -0
- package/bmad/bmm/workflows/excalidraw-diagrams/create-flowchart/instructions.md +241 -0
- package/bmad/bmm/workflows/excalidraw-diagrams/create-flowchart/workflow.yaml +27 -0
- package/bmad/bmm/workflows/excalidraw-diagrams/create-wireframe/checklist.md +38 -0
- package/bmad/bmm/workflows/excalidraw-diagrams/create-wireframe/instructions.md +133 -0
- package/bmad/bmm/workflows/excalidraw-diagrams/create-wireframe/workflow.yaml +27 -0
- package/bmad/bmm/workflows/testarch/atdd/atdd-checklist-template.md +363 -0
- package/bmad/bmm/workflows/testarch/atdd/checklist.md +374 -0
- package/bmad/bmm/workflows/testarch/atdd/instructions.md +806 -0
- package/bmad/bmm/workflows/testarch/atdd/workflow.yaml +47 -0
- package/bmad/bmm/workflows/testarch/automate/checklist.md +582 -0
- package/bmad/bmm/workflows/testarch/automate/instructions.md +1324 -0
- package/bmad/bmm/workflows/testarch/automate/workflow.yaml +54 -0
- package/bmad/bmm/workflows/testarch/ci/checklist.md +247 -0
- package/bmad/bmm/workflows/testarch/ci/github-actions-template.yaml +198 -0
- package/bmad/bmm/workflows/testarch/ci/gitlab-ci-template.yaml +149 -0
- package/bmad/bmm/workflows/testarch/ci/instructions.md +536 -0
- package/bmad/bmm/workflows/testarch/ci/workflow.yaml +47 -0
- package/bmad/bmm/workflows/testarch/framework/checklist.md +320 -0
- package/bmad/bmm/workflows/testarch/framework/instructions.md +481 -0
- package/bmad/bmm/workflows/testarch/framework/workflow.yaml +49 -0
- package/bmad/bmm/workflows/testarch/nfr-assess/checklist.md +407 -0
- package/bmad/bmm/workflows/testarch/nfr-assess/instructions.md +726 -0
- package/bmad/bmm/workflows/testarch/nfr-assess/nfr-report-template.md +461 -0
- package/bmad/bmm/workflows/testarch/nfr-assess/workflow.yaml +49 -0
- package/bmad/bmm/workflows/testarch/test-design/checklist.md +407 -0
- package/bmad/bmm/workflows/testarch/test-design/instructions.md +1158 -0
- package/bmad/bmm/workflows/testarch/test-design/test-design-architecture-template.md +213 -0
- package/bmad/bmm/workflows/testarch/test-design/test-design-qa-template.md +286 -0
- package/bmad/bmm/workflows/testarch/test-design/test-design-template.md +294 -0
- package/bmad/bmm/workflows/testarch/test-design/workflow.yaml +71 -0
- package/bmad/bmm/workflows/testarch/test-review/checklist.md +472 -0
- package/bmad/bmm/workflows/testarch/test-review/instructions.md +628 -0
- package/bmad/bmm/workflows/testarch/test-review/test-review-template.md +390 -0
- package/bmad/bmm/workflows/testarch/test-review/workflow.yaml +48 -0
- package/bmad/bmm/workflows/testarch/trace/checklist.md +642 -0
- package/bmad/bmm/workflows/testarch/trace/instructions.md +1030 -0
- package/bmad/bmm/workflows/testarch/trace/trace-template.md +675 -0
- package/bmad/bmm/workflows/testarch/trace/workflow.yaml +57 -0
- package/bmad/core/agents/bmad-master.agent.yaml +30 -0
- package/bmad/core/module-help.csv +11 -0
- package/bmad/core/module.yaml +25 -0
- package/bmad/core/resources/excalidraw/README.md +160 -0
- package/bmad/core/resources/excalidraw/excalidraw-helpers.md +127 -0
- package/bmad/core/resources/excalidraw/library-loader.md +50 -0
- package/bmad/core/resources/excalidraw/validate-json-instructions.md +79 -0
- package/bmad/core/tasks/bmad-help.md +62 -0
- package/bmad/core/tasks/editorial-review-prose.xml +91 -0
- package/bmad/core/tasks/editorial-review-structure.xml +198 -0
- package/bmad/core/tasks/index-docs.xml +65 -0
- package/bmad/core/tasks/review-adversarial-general.xml +48 -0
- package/bmad/core/tasks/shard-doc.xml +109 -0
- package/bmad/core/tasks/workflow.xml +235 -0
- package/bmad/core/workflows/advanced-elicitation/methods.csv +51 -0
- package/bmad/core/workflows/advanced-elicitation/workflow.xml +117 -0
- package/bmad/core/workflows/brainstorming/brain-methods.csv +62 -0
- package/bmad/core/workflows/brainstorming/steps/step-01-session-setup.md +197 -0
- package/bmad/core/workflows/brainstorming/steps/step-01b-continue.md +122 -0
- package/bmad/core/workflows/brainstorming/steps/step-02a-user-selected.md +225 -0
- package/bmad/core/workflows/brainstorming/steps/step-02b-ai-recommended.md +237 -0
- package/bmad/core/workflows/brainstorming/steps/step-02c-random-selection.md +209 -0
- package/bmad/core/workflows/brainstorming/steps/step-02d-progressive-flow.md +264 -0
- package/bmad/core/workflows/brainstorming/steps/step-03-technique-execution.md +399 -0
- package/bmad/core/workflows/brainstorming/steps/step-04-idea-organization.md +303 -0
- package/bmad/core/workflows/brainstorming/template.md +15 -0
- package/bmad/core/workflows/brainstorming/workflow.md +58 -0
- package/bmad/core/workflows/party-mode/steps/step-01-agent-loading.md +138 -0
- package/bmad/core/workflows/party-mode/steps/step-02-discussion-orchestration.md +187 -0
- package/bmad/core/workflows/party-mode/steps/step-03-graceful-exit.md +157 -0
- package/bmad/core/workflows/party-mode/workflow.md +194 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +26 -0
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/doctor.js +168 -0
- package/dist/commands/guide.d.ts +1 -0
- package/dist/commands/guide.js +19 -0
- package/dist/commands/implement.d.ts +1 -0
- package/dist/commands/implement.js +83 -0
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.js +67 -0
- package/dist/commands/plan.d.ts +5 -0
- package/dist/commands/plan.js +44 -0
- package/dist/commands/reset.d.ts +5 -0
- package/dist/commands/reset.js +35 -0
- package/dist/commands/resume.d.ts +1 -0
- package/dist/commands/resume.js +44 -0
- package/dist/commands/start.d.ts +5 -0
- package/dist/commands/start.js +54 -0
- package/dist/commands/status.d.ts +1 -0
- package/dist/commands/status.js +53 -0
- package/dist/commands/upgrade.d.ts +1 -0
- package/dist/commands/upgrade.js +34 -0
- package/dist/installer.d.ts +11 -0
- package/dist/installer.js +219 -0
- package/dist/transition.d.ts +52 -0
- package/dist/transition.js +656 -0
- package/dist/utils/config.d.ts +7 -0
- package/dist/utils/config.js +14 -0
- package/dist/utils/json.d.ts +7 -0
- package/dist/utils/json.js +26 -0
- package/dist/utils/logger.d.ts +3 -0
- package/dist/utils/logger.js +13 -0
- package/dist/utils/state.d.ts +29 -0
- package/dist/utils/state.js +78 -0
- package/dist/utils/validate.d.ts +4 -0
- package/dist/utils/validate.js +42 -0
- package/package.json +59 -0
- package/ralph/lib/circuit_breaker.sh +330 -0
- package/ralph/lib/date_utils.sh +53 -0
- package/ralph/lib/response_analyzer.sh +768 -0
- package/ralph/lib/timeout_utils.sh +145 -0
- package/ralph/ralph_loop.sh +1391 -0
- package/ralph/templates/AGENT.md +158 -0
- package/ralph/templates/PROMPT.md +292 -0
- package/ralph/templates/fix_plan.md +27 -0
- package/ralph/templates/specs/.gitkeep +2 -0
- package/slash-commands/advanced-elicitation.md +1 -0
- package/slash-commands/adversarial-review.md +1 -0
- package/slash-commands/analyst.md +1 -0
- package/slash-commands/architect.md +1 -0
- package/slash-commands/atdd.md +1 -0
- package/slash-commands/bmad-help.md +1 -0
- package/slash-commands/bmalph-implement.md +152 -0
- package/slash-commands/bmalph.md +1 -0
- package/slash-commands/brainstorm-project.md +1 -0
- package/slash-commands/brainstorming.md +1 -0
- package/slash-commands/continuous-integration.md +1 -0
- package/slash-commands/correct-course.md +1 -0
- package/slash-commands/create-architecture.md +1 -0
- package/slash-commands/create-brief.md +1 -0
- package/slash-commands/create-dataflow.md +1 -0
- package/slash-commands/create-diagram.md +1 -0
- package/slash-commands/create-epics-stories.md +1 -0
- package/slash-commands/create-flowchart.md +1 -0
- package/slash-commands/create-prd.md +1 -0
- package/slash-commands/create-story.md +1 -0
- package/slash-commands/create-ux.md +1 -0
- package/slash-commands/create-wireframe.md +1 -0
- package/slash-commands/dev.md +1 -0
- package/slash-commands/document-project.md +1 -0
- package/slash-commands/domain-research.md +1 -0
- package/slash-commands/editorial-prose.md +1 -0
- package/slash-commands/editorial-structure.md +1 -0
- package/slash-commands/execute-workflow.md +1 -0
- package/slash-commands/implementation-readiness.md +1 -0
- package/slash-commands/index-docs.md +1 -0
- package/slash-commands/market-research.md +1 -0
- package/slash-commands/nfr-assess.md +1 -0
- package/slash-commands/party-mode.md +1 -0
- package/slash-commands/pm.md +1 -0
- package/slash-commands/quick-dev.md +1 -0
- package/slash-commands/quick-flow-solo-dev.md +1 -0
- package/slash-commands/retrospective.md +1 -0
- package/slash-commands/shard-doc.md +1 -0
- package/slash-commands/sm.md +1 -0
- package/slash-commands/sprint-planning.md +1 -0
- package/slash-commands/sprint-status.md +1 -0
- package/slash-commands/tea.md +1 -0
- package/slash-commands/tech-spec.md +1 -0
- package/slash-commands/technical-research.md +1 -0
- package/slash-commands/test-automate.md +1 -0
- package/slash-commands/test-design.md +1 -0
- package/slash-commands/test-framework.md +1 -0
- package/slash-commands/test-review.md +1 -0
- package/slash-commands/test-trace.md +1 -0
- package/slash-commands/ux-designer.md +1 -0
- package/slash-commands/validate-architecture.md +1 -0
- package/slash-commands/validate-brief.md +1 -0
- package/slash-commands/validate-epics-stories.md +1 -0
- package/slash-commands/validate-prd.md +1 -0
- package/slash-commands/validate-story.md +1 -0
- package/slash-commands/validate-test-design.md +1 -0
- package/slash-commands/validate-ux.md +1 -0
|
@@ -0,0 +1,768 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Response Analyzer Component for Ralph
|
|
3
|
+
# Analyzes Claude Code output to detect completion signals, test-only loops, and progress
|
|
4
|
+
|
|
5
|
+
# Source date utilities for cross-platform compatibility
|
|
6
|
+
source "$(dirname "${BASH_SOURCE[0]}")/date_utils.sh"
|
|
7
|
+
|
|
8
|
+
# Response Analysis Functions
|
|
9
|
+
# Based on expert recommendations from Martin Fowler, Michael Nygard, Sam Newman
|
|
10
|
+
|
|
11
|
+
# Colors for output
|
|
12
|
+
RED='\033[0;31m'
|
|
13
|
+
GREEN='\033[0;32m'
|
|
14
|
+
YELLOW='\033[1;33m'
|
|
15
|
+
BLUE='\033[0;34m'
|
|
16
|
+
NC='\033[0m'
|
|
17
|
+
|
|
18
|
+
# Use RALPH_DIR if set by main script, otherwise default to .ralph
|
|
19
|
+
RALPH_DIR="${RALPH_DIR:-.ralph}"
|
|
20
|
+
|
|
21
|
+
# Analysis configuration
|
|
22
|
+
COMPLETION_KEYWORDS=("done" "complete" "finished" "all tasks complete" "project complete" "ready for review")
|
|
23
|
+
TEST_ONLY_PATTERNS=("npm test" "bats" "pytest" "jest" "cargo test" "go test" "running tests")
|
|
24
|
+
NO_WORK_PATTERNS=("nothing to do" "no changes" "already implemented" "up to date")
|
|
25
|
+
|
|
26
|
+
# =============================================================================
|
|
27
|
+
# JSON OUTPUT FORMAT DETECTION AND PARSING
|
|
28
|
+
# =============================================================================
|
|
29
|
+
|
|
30
|
+
# Detect output format (json or text)
|
|
31
|
+
# Returns: "json" if valid JSON, "text" otherwise
|
|
32
|
+
detect_output_format() {
|
|
33
|
+
local output_file=$1
|
|
34
|
+
|
|
35
|
+
if [[ ! -f "$output_file" ]] || [[ ! -s "$output_file" ]]; then
|
|
36
|
+
echo "text"
|
|
37
|
+
return
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Check if file starts with { or [ (JSON indicators)
|
|
41
|
+
local first_char=$(head -c 1 "$output_file" 2>/dev/null | tr -d '[:space:]')
|
|
42
|
+
|
|
43
|
+
if [[ "$first_char" != "{" && "$first_char" != "[" ]]; then
|
|
44
|
+
echo "text"
|
|
45
|
+
return
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# Validate as JSON using jq
|
|
49
|
+
if jq empty "$output_file" 2>/dev/null; then
|
|
50
|
+
echo "json"
|
|
51
|
+
else
|
|
52
|
+
echo "text"
|
|
53
|
+
fi
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# Parse JSON response and extract structured fields
|
|
57
|
+
# Creates .ralph/.json_parse_result with normalized analysis data
|
|
58
|
+
# Supports THREE JSON formats:
|
|
59
|
+
# 1. Flat format: { status, exit_signal, work_type, files_modified, ... }
|
|
60
|
+
# 2. Claude CLI object format: { result, sessionId, metadata: { files_changed, has_errors, completion_status, ... } }
|
|
61
|
+
# 3. Claude CLI array format: [ {type: "system", ...}, {type: "assistant", ...}, {type: "result", ...} ]
|
|
62
|
+
parse_json_response() {
|
|
63
|
+
local output_file=$1
|
|
64
|
+
local result_file="${2:-$RALPH_DIR/.json_parse_result}"
|
|
65
|
+
local normalized_file=""
|
|
66
|
+
|
|
67
|
+
if [[ ! -f "$output_file" ]]; then
|
|
68
|
+
echo "ERROR: Output file not found: $output_file" >&2
|
|
69
|
+
return 1
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# Validate JSON first
|
|
73
|
+
if ! jq empty "$output_file" 2>/dev/null; then
|
|
74
|
+
echo "ERROR: Invalid JSON in output file" >&2
|
|
75
|
+
return 1
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# Check if JSON is an array (Claude CLI array format)
|
|
79
|
+
# Claude CLI outputs: [{type: "system", ...}, {type: "assistant", ...}, {type: "result", ...}]
|
|
80
|
+
if jq -e 'type == "array"' "$output_file" >/dev/null 2>&1; then
|
|
81
|
+
normalized_file=$(mktemp)
|
|
82
|
+
|
|
83
|
+
# Extract the "result" type message from the array (usually the last entry)
|
|
84
|
+
# This contains: result, session_id, is_error, duration_ms, etc.
|
|
85
|
+
local result_obj=$(jq '[.[] | select(.type == "result")] | .[-1] // {}' "$output_file" 2>/dev/null)
|
|
86
|
+
|
|
87
|
+
# Guard against empty result_obj if jq fails (review fix: Macroscope)
|
|
88
|
+
[[ -z "$result_obj" ]] && result_obj="{}"
|
|
89
|
+
|
|
90
|
+
# Extract session_id from init message as fallback
|
|
91
|
+
local init_session_id=$(jq -r '.[] | select(.type == "system" and .subtype == "init") | .session_id // empty' "$output_file" 2>/dev/null | head -1)
|
|
92
|
+
|
|
93
|
+
# Prioritize result object's own session_id, then fall back to init message (review fix: CodeRabbit)
|
|
94
|
+
# This prevents session ID loss when arrays lack an init message with session_id
|
|
95
|
+
local effective_session_id
|
|
96
|
+
effective_session_id=$(echo "$result_obj" | jq -r '.sessionId // .session_id // empty' 2>/dev/null)
|
|
97
|
+
if [[ -z "$effective_session_id" || "$effective_session_id" == "null" ]]; then
|
|
98
|
+
effective_session_id="$init_session_id"
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# Build normalized object merging result with effective session_id
|
|
102
|
+
if [[ -n "$effective_session_id" && "$effective_session_id" != "null" ]]; then
|
|
103
|
+
echo "$result_obj" | jq --arg sid "$effective_session_id" '. + {sessionId: $sid} | del(.session_id)' > "$normalized_file"
|
|
104
|
+
else
|
|
105
|
+
echo "$result_obj" | jq 'del(.session_id)' > "$normalized_file"
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
# Use normalized file for subsequent parsing
|
|
109
|
+
output_file="$normalized_file"
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# Detect JSON format by checking for Claude CLI fields
|
|
113
|
+
local has_result_field=$(jq -r 'has("result")' "$output_file" 2>/dev/null)
|
|
114
|
+
|
|
115
|
+
# Extract fields - support both flat format and Claude CLI format
|
|
116
|
+
# Priority: Claude CLI fields first, then flat format fields
|
|
117
|
+
|
|
118
|
+
# Status: from flat format OR derived from metadata.completion_status
|
|
119
|
+
local status=$(jq -r '.status // "UNKNOWN"' "$output_file" 2>/dev/null)
|
|
120
|
+
local completion_status=$(jq -r '.metadata.completion_status // ""' "$output_file" 2>/dev/null)
|
|
121
|
+
if [[ "$completion_status" == "complete" || "$completion_status" == "COMPLETE" ]]; then
|
|
122
|
+
status="COMPLETE"
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
# Exit signal: from flat format OR derived from completion_status
|
|
126
|
+
local exit_signal=$(jq -r '.exit_signal // false' "$output_file" 2>/dev/null)
|
|
127
|
+
|
|
128
|
+
# Bug #1 Fix: If exit_signal is still false, check for RALPH_STATUS block in .result field
|
|
129
|
+
# Claude CLI JSON format embeds the RALPH_STATUS block within the .result text field
|
|
130
|
+
if [[ "$exit_signal" == "false" && "$has_result_field" == "true" ]]; then
|
|
131
|
+
local result_text=$(jq -r '.result // ""' "$output_file" 2>/dev/null)
|
|
132
|
+
if [[ -n "$result_text" ]] && echo "$result_text" | grep -q -- "---RALPH_STATUS---"; then
|
|
133
|
+
# Extract EXIT_SIGNAL value from RALPH_STATUS block within result text
|
|
134
|
+
local embedded_exit_sig=$(echo "$result_text" | grep "EXIT_SIGNAL:" | cut -d: -f2 | xargs)
|
|
135
|
+
if [[ "$embedded_exit_sig" == "true" ]]; then
|
|
136
|
+
exit_signal="true"
|
|
137
|
+
[[ "${VERBOSE_PROGRESS:-}" == "true" ]] && echo "DEBUG: Extracted EXIT_SIGNAL=true from .result RALPH_STATUS block" >&2
|
|
138
|
+
fi
|
|
139
|
+
# Also check STATUS field as fallback
|
|
140
|
+
local embedded_status=$(echo "$result_text" | grep "STATUS:" | cut -d: -f2 | xargs)
|
|
141
|
+
if [[ "$embedded_status" == "COMPLETE" && "$exit_signal" != "true" ]]; then
|
|
142
|
+
# STATUS: COMPLETE without explicit EXIT_SIGNAL implies completion
|
|
143
|
+
exit_signal="true"
|
|
144
|
+
[[ "${VERBOSE_PROGRESS:-}" == "true" ]] && echo "DEBUG: Inferred EXIT_SIGNAL=true from .result STATUS=COMPLETE" >&2
|
|
145
|
+
fi
|
|
146
|
+
fi
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
# Work type: from flat format
|
|
150
|
+
local work_type=$(jq -r '.work_type // "UNKNOWN"' "$output_file" 2>/dev/null)
|
|
151
|
+
|
|
152
|
+
# Files modified: from flat format OR from metadata.files_changed
|
|
153
|
+
local files_modified=$(jq -r '.metadata.files_changed // .files_modified // 0' "$output_file" 2>/dev/null)
|
|
154
|
+
|
|
155
|
+
# Error count: from flat format OR derived from metadata.has_errors
|
|
156
|
+
# Note: When only has_errors=true is present (without explicit error_count),
|
|
157
|
+
# we set error_count=1 as a minimum. This is defensive programming since
|
|
158
|
+
# the stuck detection threshold is >5 errors, so 1 error won't trigger it.
|
|
159
|
+
# Actual error count may be higher, but precise count isn't critical for our logic.
|
|
160
|
+
local error_count=$(jq -r '.error_count // 0' "$output_file" 2>/dev/null)
|
|
161
|
+
local has_errors=$(jq -r '.metadata.has_errors // false' "$output_file" 2>/dev/null)
|
|
162
|
+
if [[ "$has_errors" == "true" && "$error_count" == "0" ]]; then
|
|
163
|
+
error_count=1 # At least one error if has_errors is true
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
# Summary: from flat format OR from result field (Claude CLI format)
|
|
167
|
+
local summary=$(jq -r '.result // .summary // ""' "$output_file" 2>/dev/null)
|
|
168
|
+
|
|
169
|
+
# Session ID: from Claude CLI format (sessionId) OR from metadata.session_id
|
|
170
|
+
local session_id=$(jq -r '.sessionId // .metadata.session_id // ""' "$output_file" 2>/dev/null)
|
|
171
|
+
|
|
172
|
+
# Loop number: from metadata
|
|
173
|
+
local loop_number=$(jq -r '.metadata.loop_number // .loop_number // 0' "$output_file" 2>/dev/null)
|
|
174
|
+
|
|
175
|
+
# Confidence: from flat format
|
|
176
|
+
local confidence=$(jq -r '.confidence // 0' "$output_file" 2>/dev/null)
|
|
177
|
+
|
|
178
|
+
# Progress indicators: from Claude CLI metadata (optional)
|
|
179
|
+
local progress_count=$(jq -r '.metadata.progress_indicators | if . then length else 0 end' "$output_file" 2>/dev/null)
|
|
180
|
+
|
|
181
|
+
# Normalize values
|
|
182
|
+
# Convert exit_signal to boolean string
|
|
183
|
+
if [[ "$exit_signal" == "true" || "$status" == "COMPLETE" || "$completion_status" == "complete" || "$completion_status" == "COMPLETE" ]]; then
|
|
184
|
+
exit_signal="true"
|
|
185
|
+
else
|
|
186
|
+
exit_signal="false"
|
|
187
|
+
fi
|
|
188
|
+
|
|
189
|
+
# Determine is_test_only from work_type
|
|
190
|
+
local is_test_only="false"
|
|
191
|
+
if [[ "$work_type" == "TEST_ONLY" ]]; then
|
|
192
|
+
is_test_only="true"
|
|
193
|
+
fi
|
|
194
|
+
|
|
195
|
+
# Determine is_stuck from error_count (threshold >5)
|
|
196
|
+
local is_stuck="false"
|
|
197
|
+
error_count=$((error_count + 0)) # Ensure integer
|
|
198
|
+
if [[ $error_count -gt 5 ]]; then
|
|
199
|
+
is_stuck="true"
|
|
200
|
+
fi
|
|
201
|
+
|
|
202
|
+
# Ensure files_modified is integer
|
|
203
|
+
files_modified=$((files_modified + 0))
|
|
204
|
+
|
|
205
|
+
# Ensure progress_count is integer
|
|
206
|
+
progress_count=$((progress_count + 0))
|
|
207
|
+
|
|
208
|
+
# Calculate has_completion_signal
|
|
209
|
+
local has_completion_signal="false"
|
|
210
|
+
if [[ "$status" == "COMPLETE" || "$exit_signal" == "true" ]]; then
|
|
211
|
+
has_completion_signal="true"
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
# Boost confidence based on structured data availability
|
|
215
|
+
if [[ "$has_result_field" == "true" ]]; then
|
|
216
|
+
confidence=$((confidence + 20)) # Structured response boost
|
|
217
|
+
fi
|
|
218
|
+
if [[ $progress_count -gt 0 ]]; then
|
|
219
|
+
confidence=$((confidence + progress_count * 5)) # Progress indicators boost
|
|
220
|
+
fi
|
|
221
|
+
|
|
222
|
+
# Write normalized result using jq for safe JSON construction
|
|
223
|
+
# String fields use --arg (auto-escapes), numeric/boolean use --argjson
|
|
224
|
+
jq -n \
|
|
225
|
+
--arg status "$status" \
|
|
226
|
+
--argjson exit_signal "$exit_signal" \
|
|
227
|
+
--argjson is_test_only "$is_test_only" \
|
|
228
|
+
--argjson is_stuck "$is_stuck" \
|
|
229
|
+
--argjson has_completion_signal "$has_completion_signal" \
|
|
230
|
+
--argjson files_modified "$files_modified" \
|
|
231
|
+
--argjson error_count "$error_count" \
|
|
232
|
+
--arg summary "$summary" \
|
|
233
|
+
--argjson loop_number "$loop_number" \
|
|
234
|
+
--arg session_id "$session_id" \
|
|
235
|
+
--argjson confidence "$confidence" \
|
|
236
|
+
'{
|
|
237
|
+
status: $status,
|
|
238
|
+
exit_signal: $exit_signal,
|
|
239
|
+
is_test_only: $is_test_only,
|
|
240
|
+
is_stuck: $is_stuck,
|
|
241
|
+
has_completion_signal: $has_completion_signal,
|
|
242
|
+
files_modified: $files_modified,
|
|
243
|
+
error_count: $error_count,
|
|
244
|
+
summary: $summary,
|
|
245
|
+
loop_number: $loop_number,
|
|
246
|
+
session_id: $session_id,
|
|
247
|
+
confidence: $confidence,
|
|
248
|
+
metadata: {
|
|
249
|
+
loop_number: $loop_number,
|
|
250
|
+
session_id: $session_id
|
|
251
|
+
}
|
|
252
|
+
}' > "$result_file"
|
|
253
|
+
|
|
254
|
+
# Cleanup temporary normalized file if created (for array format handling)
|
|
255
|
+
if [[ -n "$normalized_file" && -f "$normalized_file" ]]; then
|
|
256
|
+
rm -f "$normalized_file"
|
|
257
|
+
fi
|
|
258
|
+
|
|
259
|
+
return 0
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
# Analyze Claude Code response and extract signals
|
|
263
|
+
analyze_response() {
|
|
264
|
+
local output_file=$1
|
|
265
|
+
local loop_number=$2
|
|
266
|
+
local analysis_result_file=${3:-"$RALPH_DIR/.response_analysis"}
|
|
267
|
+
|
|
268
|
+
# Initialize analysis result
|
|
269
|
+
local has_completion_signal=false
|
|
270
|
+
local is_test_only=false
|
|
271
|
+
local is_stuck=false
|
|
272
|
+
local has_progress=false
|
|
273
|
+
local confidence_score=0
|
|
274
|
+
local exit_signal=false
|
|
275
|
+
local work_summary=""
|
|
276
|
+
local files_modified=0
|
|
277
|
+
|
|
278
|
+
# Read output file
|
|
279
|
+
if [[ ! -f "$output_file" ]]; then
|
|
280
|
+
echo "ERROR: Output file not found: $output_file"
|
|
281
|
+
return 1
|
|
282
|
+
fi
|
|
283
|
+
|
|
284
|
+
local output_content=$(cat "$output_file")
|
|
285
|
+
local output_length=${#output_content}
|
|
286
|
+
|
|
287
|
+
# Detect output format and try JSON parsing first
|
|
288
|
+
local output_format=$(detect_output_format "$output_file")
|
|
289
|
+
|
|
290
|
+
if [[ "$output_format" == "json" ]]; then
|
|
291
|
+
# Try JSON parsing
|
|
292
|
+
if parse_json_response "$output_file" "$RALPH_DIR/.json_parse_result" 2>/dev/null; then
|
|
293
|
+
# Extract values from JSON parse result
|
|
294
|
+
has_completion_signal=$(jq -r '.has_completion_signal' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "false")
|
|
295
|
+
exit_signal=$(jq -r '.exit_signal' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "false")
|
|
296
|
+
is_test_only=$(jq -r '.is_test_only' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "false")
|
|
297
|
+
is_stuck=$(jq -r '.is_stuck' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "false")
|
|
298
|
+
work_summary=$(jq -r '.summary' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "")
|
|
299
|
+
files_modified=$(jq -r '.files_modified' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "0")
|
|
300
|
+
local json_confidence=$(jq -r '.confidence' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "0")
|
|
301
|
+
local session_id=$(jq -r '.session_id' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "")
|
|
302
|
+
|
|
303
|
+
# Persist session ID if present (for session continuity across loop iterations)
|
|
304
|
+
if [[ -n "$session_id" && "$session_id" != "null" ]]; then
|
|
305
|
+
store_session_id "$session_id"
|
|
306
|
+
[[ "${VERBOSE_PROGRESS:-}" == "true" ]] && echo "DEBUG: Persisted session ID: $session_id" >&2
|
|
307
|
+
fi
|
|
308
|
+
|
|
309
|
+
# JSON parsing provides high confidence
|
|
310
|
+
if [[ "$exit_signal" == "true" ]]; then
|
|
311
|
+
confidence_score=100
|
|
312
|
+
else
|
|
313
|
+
confidence_score=$((json_confidence + 50))
|
|
314
|
+
fi
|
|
315
|
+
|
|
316
|
+
# Check for file changes via git (supplements JSON data)
|
|
317
|
+
if command -v git &>/dev/null && git rev-parse --git-dir >/dev/null 2>&1; then
|
|
318
|
+
local git_files=$(git diff --name-only 2>/dev/null | wc -l)
|
|
319
|
+
if [[ $git_files -gt 0 ]]; then
|
|
320
|
+
has_progress=true
|
|
321
|
+
files_modified=$git_files
|
|
322
|
+
fi
|
|
323
|
+
fi
|
|
324
|
+
|
|
325
|
+
# Write analysis results for JSON path using jq for safe construction
|
|
326
|
+
jq -n \
|
|
327
|
+
--argjson loop_number "$loop_number" \
|
|
328
|
+
--arg timestamp "$(get_iso_timestamp)" \
|
|
329
|
+
--arg output_file "$output_file" \
|
|
330
|
+
--arg output_format "json" \
|
|
331
|
+
--argjson has_completion_signal "$has_completion_signal" \
|
|
332
|
+
--argjson is_test_only "$is_test_only" \
|
|
333
|
+
--argjson is_stuck "$is_stuck" \
|
|
334
|
+
--argjson has_progress "$has_progress" \
|
|
335
|
+
--argjson files_modified "$files_modified" \
|
|
336
|
+
--argjson confidence_score "$confidence_score" \
|
|
337
|
+
--argjson exit_signal "$exit_signal" \
|
|
338
|
+
--arg work_summary "$work_summary" \
|
|
339
|
+
--argjson output_length "$output_length" \
|
|
340
|
+
'{
|
|
341
|
+
loop_number: $loop_number,
|
|
342
|
+
timestamp: $timestamp,
|
|
343
|
+
output_file: $output_file,
|
|
344
|
+
output_format: $output_format,
|
|
345
|
+
analysis: {
|
|
346
|
+
has_completion_signal: $has_completion_signal,
|
|
347
|
+
is_test_only: $is_test_only,
|
|
348
|
+
is_stuck: $is_stuck,
|
|
349
|
+
has_progress: $has_progress,
|
|
350
|
+
files_modified: $files_modified,
|
|
351
|
+
confidence_score: $confidence_score,
|
|
352
|
+
exit_signal: $exit_signal,
|
|
353
|
+
work_summary: $work_summary,
|
|
354
|
+
output_length: $output_length
|
|
355
|
+
}
|
|
356
|
+
}' > "$analysis_result_file"
|
|
357
|
+
rm -f "$RALPH_DIR/.json_parse_result"
|
|
358
|
+
return 0
|
|
359
|
+
fi
|
|
360
|
+
# If JSON parsing failed, fall through to text parsing
|
|
361
|
+
fi
|
|
362
|
+
|
|
363
|
+
# Text parsing fallback (original logic)
|
|
364
|
+
|
|
365
|
+
# Track whether an explicit EXIT_SIGNAL was found in RALPH_STATUS block
|
|
366
|
+
# If explicit signal found, heuristics should NOT override Claude's intent
|
|
367
|
+
local explicit_exit_signal_found=false
|
|
368
|
+
|
|
369
|
+
# 1. Check for explicit structured output (if Claude follows schema)
|
|
370
|
+
if grep -q -- "---RALPH_STATUS---" "$output_file"; then
|
|
371
|
+
# Parse structured output
|
|
372
|
+
local status=$(grep "STATUS:" "$output_file" | cut -d: -f2 | xargs)
|
|
373
|
+
local exit_sig=$(grep "EXIT_SIGNAL:" "$output_file" | cut -d: -f2 | xargs)
|
|
374
|
+
|
|
375
|
+
# If EXIT_SIGNAL is explicitly provided, respect it
|
|
376
|
+
if [[ -n "$exit_sig" ]]; then
|
|
377
|
+
explicit_exit_signal_found=true
|
|
378
|
+
if [[ "$exit_sig" == "true" ]]; then
|
|
379
|
+
has_completion_signal=true
|
|
380
|
+
exit_signal=true
|
|
381
|
+
confidence_score=100
|
|
382
|
+
else
|
|
383
|
+
# Explicit EXIT_SIGNAL: false - Claude says to continue
|
|
384
|
+
exit_signal=false
|
|
385
|
+
fi
|
|
386
|
+
elif [[ "$status" == "COMPLETE" ]]; then
|
|
387
|
+
# No explicit EXIT_SIGNAL but STATUS is COMPLETE
|
|
388
|
+
has_completion_signal=true
|
|
389
|
+
exit_signal=true
|
|
390
|
+
confidence_score=100
|
|
391
|
+
fi
|
|
392
|
+
fi
|
|
393
|
+
|
|
394
|
+
# 2. Detect completion keywords in natural language output
|
|
395
|
+
for keyword in "${COMPLETION_KEYWORDS[@]}"; do
|
|
396
|
+
if grep -qi "$keyword" "$output_file"; then
|
|
397
|
+
has_completion_signal=true
|
|
398
|
+
((confidence_score+=10))
|
|
399
|
+
break
|
|
400
|
+
fi
|
|
401
|
+
done
|
|
402
|
+
|
|
403
|
+
# 3. Detect test-only loops
|
|
404
|
+
local test_command_count=0
|
|
405
|
+
local implementation_count=0
|
|
406
|
+
local error_count=0
|
|
407
|
+
|
|
408
|
+
test_command_count=$(grep -c -i "running tests\|npm test\|bats\|pytest\|jest" "$output_file" 2>/dev/null | head -1 || echo "0")
|
|
409
|
+
implementation_count=$(grep -c -i "implementing\|creating\|writing\|adding\|function\|class" "$output_file" 2>/dev/null | head -1 || echo "0")
|
|
410
|
+
|
|
411
|
+
# Strip whitespace and ensure it's a number
|
|
412
|
+
test_command_count=$(echo "$test_command_count" | tr -d '[:space:]')
|
|
413
|
+
implementation_count=$(echo "$implementation_count" | tr -d '[:space:]')
|
|
414
|
+
|
|
415
|
+
# Convert to integers with default fallback
|
|
416
|
+
test_command_count=${test_command_count:-0}
|
|
417
|
+
implementation_count=${implementation_count:-0}
|
|
418
|
+
test_command_count=$((test_command_count + 0))
|
|
419
|
+
implementation_count=$((implementation_count + 0))
|
|
420
|
+
|
|
421
|
+
if [[ $test_command_count -gt 0 ]] && [[ $implementation_count -eq 0 ]]; then
|
|
422
|
+
is_test_only=true
|
|
423
|
+
work_summary="Test execution only, no implementation"
|
|
424
|
+
fi
|
|
425
|
+
|
|
426
|
+
# 4. Detect stuck/error loops
|
|
427
|
+
# Use two-stage filtering to avoid counting JSON field names as errors
|
|
428
|
+
# Stage 1: Filter out JSON field patterns like "is_error": false
|
|
429
|
+
# Stage 2: Count actual error messages in specific contexts
|
|
430
|
+
# Pattern aligned with ralph_loop.sh to ensure consistent behavior
|
|
431
|
+
error_count=$(grep -v '"[^"]*error[^"]*":' "$output_file" 2>/dev/null | \
|
|
432
|
+
grep -cE '(^Error:|^ERROR:|^error:|\]: error|Link: error|Error occurred|failed with error|[Ee]xception|Fatal|FATAL)' \
|
|
433
|
+
2>/dev/null || echo "0")
|
|
434
|
+
error_count=$(echo "$error_count" | tr -d '[:space:]')
|
|
435
|
+
error_count=${error_count:-0}
|
|
436
|
+
error_count=$((error_count + 0))
|
|
437
|
+
|
|
438
|
+
if [[ $error_count -gt 5 ]]; then
|
|
439
|
+
is_stuck=true
|
|
440
|
+
fi
|
|
441
|
+
|
|
442
|
+
# 5. Detect "nothing to do" patterns
|
|
443
|
+
for pattern in "${NO_WORK_PATTERNS[@]}"; do
|
|
444
|
+
if grep -qi "$pattern" "$output_file"; then
|
|
445
|
+
has_completion_signal=true
|
|
446
|
+
((confidence_score+=15))
|
|
447
|
+
work_summary="No work remaining"
|
|
448
|
+
break
|
|
449
|
+
fi
|
|
450
|
+
done
|
|
451
|
+
|
|
452
|
+
# 6. Check for file changes (git integration)
|
|
453
|
+
if command -v git &>/dev/null && git rev-parse --git-dir >/dev/null 2>&1; then
|
|
454
|
+
files_modified=$(git diff --name-only 2>/dev/null | wc -l)
|
|
455
|
+
if [[ $files_modified -gt 0 ]]; then
|
|
456
|
+
has_progress=true
|
|
457
|
+
((confidence_score+=20))
|
|
458
|
+
fi
|
|
459
|
+
fi
|
|
460
|
+
|
|
461
|
+
# 7. Analyze output length trends (detect declining engagement)
|
|
462
|
+
if [[ -f "$RALPH_DIR/.last_output_length" ]]; then
|
|
463
|
+
local last_length=$(cat "$RALPH_DIR/.last_output_length")
|
|
464
|
+
local length_ratio=$((output_length * 100 / last_length))
|
|
465
|
+
|
|
466
|
+
if [[ $length_ratio -lt 50 ]]; then
|
|
467
|
+
# Output is less than 50% of previous - possible completion
|
|
468
|
+
((confidence_score+=10))
|
|
469
|
+
fi
|
|
470
|
+
fi
|
|
471
|
+
echo "$output_length" > "$RALPH_DIR/.last_output_length"
|
|
472
|
+
|
|
473
|
+
# 8. Extract work summary from output
|
|
474
|
+
if [[ -z "$work_summary" ]]; then
|
|
475
|
+
# Try to find summary in output
|
|
476
|
+
work_summary=$(grep -i "summary\|completed\|implemented" "$output_file" | head -1 | cut -c 1-100)
|
|
477
|
+
if [[ -z "$work_summary" ]]; then
|
|
478
|
+
work_summary="Output analyzed, no explicit summary found"
|
|
479
|
+
fi
|
|
480
|
+
fi
|
|
481
|
+
|
|
482
|
+
# 9. Determine exit signal based on confidence (heuristic)
|
|
483
|
+
# IMPORTANT: Only apply heuristics if no explicit EXIT_SIGNAL was found in RALPH_STATUS
|
|
484
|
+
# Claude's explicit intent takes precedence over natural language pattern matching
|
|
485
|
+
if [[ "$explicit_exit_signal_found" != "true" ]]; then
|
|
486
|
+
if [[ $confidence_score -ge 40 || "$has_completion_signal" == "true" ]]; then
|
|
487
|
+
exit_signal=true
|
|
488
|
+
fi
|
|
489
|
+
fi
|
|
490
|
+
|
|
491
|
+
# Write analysis results to file (text parsing path) using jq for safe construction
|
|
492
|
+
jq -n \
|
|
493
|
+
--argjson loop_number "$loop_number" \
|
|
494
|
+
--arg timestamp "$(get_iso_timestamp)" \
|
|
495
|
+
--arg output_file "$output_file" \
|
|
496
|
+
--arg output_format "text" \
|
|
497
|
+
--argjson has_completion_signal "$has_completion_signal" \
|
|
498
|
+
--argjson is_test_only "$is_test_only" \
|
|
499
|
+
--argjson is_stuck "$is_stuck" \
|
|
500
|
+
--argjson has_progress "$has_progress" \
|
|
501
|
+
--argjson files_modified "$files_modified" \
|
|
502
|
+
--argjson confidence_score "$confidence_score" \
|
|
503
|
+
--argjson exit_signal "$exit_signal" \
|
|
504
|
+
--arg work_summary "$work_summary" \
|
|
505
|
+
--argjson output_length "$output_length" \
|
|
506
|
+
'{
|
|
507
|
+
loop_number: $loop_number,
|
|
508
|
+
timestamp: $timestamp,
|
|
509
|
+
output_file: $output_file,
|
|
510
|
+
output_format: $output_format,
|
|
511
|
+
analysis: {
|
|
512
|
+
has_completion_signal: $has_completion_signal,
|
|
513
|
+
is_test_only: $is_test_only,
|
|
514
|
+
is_stuck: $is_stuck,
|
|
515
|
+
has_progress: $has_progress,
|
|
516
|
+
files_modified: $files_modified,
|
|
517
|
+
confidence_score: $confidence_score,
|
|
518
|
+
exit_signal: $exit_signal,
|
|
519
|
+
work_summary: $work_summary,
|
|
520
|
+
output_length: $output_length
|
|
521
|
+
}
|
|
522
|
+
}' > "$analysis_result_file"
|
|
523
|
+
|
|
524
|
+
# Always return 0 (success) - callers should check the JSON result file
|
|
525
|
+
# Returning non-zero would cause issues with set -e and test frameworks
|
|
526
|
+
return 0
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
# Update exit signals file based on analysis
|
|
530
|
+
update_exit_signals() {
|
|
531
|
+
local analysis_file=${1:-"$RALPH_DIR/.response_analysis"}
|
|
532
|
+
local exit_signals_file=${2:-"$RALPH_DIR/.exit_signals"}
|
|
533
|
+
|
|
534
|
+
if [[ ! -f "$analysis_file" ]]; then
|
|
535
|
+
echo "ERROR: Analysis file not found: $analysis_file"
|
|
536
|
+
return 1
|
|
537
|
+
fi
|
|
538
|
+
|
|
539
|
+
# Read analysis results
|
|
540
|
+
local is_test_only=$(jq -r '.analysis.is_test_only' "$analysis_file")
|
|
541
|
+
local has_completion_signal=$(jq -r '.analysis.has_completion_signal' "$analysis_file")
|
|
542
|
+
local loop_number=$(jq -r '.loop_number' "$analysis_file")
|
|
543
|
+
local has_progress=$(jq -r '.analysis.has_progress' "$analysis_file")
|
|
544
|
+
|
|
545
|
+
# Read current exit signals
|
|
546
|
+
local signals=$(cat "$exit_signals_file" 2>/dev/null || echo '{"test_only_loops": [], "done_signals": [], "completion_indicators": []}')
|
|
547
|
+
|
|
548
|
+
# Update test_only_loops array
|
|
549
|
+
if [[ "$is_test_only" == "true" ]]; then
|
|
550
|
+
signals=$(echo "$signals" | jq ".test_only_loops += [$loop_number]")
|
|
551
|
+
else
|
|
552
|
+
# Clear test_only_loops if we had implementation
|
|
553
|
+
if [[ "$has_progress" == "true" ]]; then
|
|
554
|
+
signals=$(echo "$signals" | jq '.test_only_loops = []')
|
|
555
|
+
fi
|
|
556
|
+
fi
|
|
557
|
+
|
|
558
|
+
# Update done_signals array
|
|
559
|
+
if [[ "$has_completion_signal" == "true" ]]; then
|
|
560
|
+
signals=$(echo "$signals" | jq ".done_signals += [$loop_number]")
|
|
561
|
+
fi
|
|
562
|
+
|
|
563
|
+
# Update completion_indicators array (strong signals)
|
|
564
|
+
local confidence=$(jq -r '.analysis.confidence_score' "$analysis_file")
|
|
565
|
+
if [[ $confidence -ge 60 ]]; then
|
|
566
|
+
signals=$(echo "$signals" | jq ".completion_indicators += [$loop_number]")
|
|
567
|
+
fi
|
|
568
|
+
|
|
569
|
+
# Keep only last 5 signals (rolling window)
|
|
570
|
+
signals=$(echo "$signals" | jq '.test_only_loops = .test_only_loops[-5:]')
|
|
571
|
+
signals=$(echo "$signals" | jq '.done_signals = .done_signals[-5:]')
|
|
572
|
+
signals=$(echo "$signals" | jq '.completion_indicators = .completion_indicators[-5:]')
|
|
573
|
+
|
|
574
|
+
# Write updated signals
|
|
575
|
+
echo "$signals" > "$exit_signals_file"
|
|
576
|
+
|
|
577
|
+
return 0
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
# Log analysis results in human-readable format
|
|
581
|
+
log_analysis_summary() {
|
|
582
|
+
local analysis_file=${1:-"$RALPH_DIR/.response_analysis"}
|
|
583
|
+
|
|
584
|
+
if [[ ! -f "$analysis_file" ]]; then
|
|
585
|
+
return 1
|
|
586
|
+
fi
|
|
587
|
+
|
|
588
|
+
local loop=$(jq -r '.loop_number' "$analysis_file")
|
|
589
|
+
local exit_sig=$(jq -r '.analysis.exit_signal' "$analysis_file")
|
|
590
|
+
local confidence=$(jq -r '.analysis.confidence_score' "$analysis_file")
|
|
591
|
+
local test_only=$(jq -r '.analysis.is_test_only' "$analysis_file")
|
|
592
|
+
local files_changed=$(jq -r '.analysis.files_modified' "$analysis_file")
|
|
593
|
+
local summary=$(jq -r '.analysis.work_summary' "$analysis_file")
|
|
594
|
+
|
|
595
|
+
echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}"
|
|
596
|
+
echo -e "${BLUE}║ Response Analysis - Loop #$loop ║${NC}"
|
|
597
|
+
echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}"
|
|
598
|
+
echo -e "${YELLOW}Exit Signal:${NC} $exit_sig"
|
|
599
|
+
echo -e "${YELLOW}Confidence:${NC} $confidence%"
|
|
600
|
+
echo -e "${YELLOW}Test Only:${NC} $test_only"
|
|
601
|
+
echo -e "${YELLOW}Files Changed:${NC} $files_changed"
|
|
602
|
+
echo -e "${YELLOW}Summary:${NC} $summary"
|
|
603
|
+
echo ""
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
# Detect if Claude is stuck (repeating same errors)
|
|
607
|
+
detect_stuck_loop() {
|
|
608
|
+
local current_output=$1
|
|
609
|
+
local history_dir=${2:-"$RALPH_DIR/logs"}
|
|
610
|
+
|
|
611
|
+
# Get last 3 output files
|
|
612
|
+
local recent_outputs=$(ls -t "$history_dir"/claude_output_*.log 2>/dev/null | head -3)
|
|
613
|
+
|
|
614
|
+
if [[ -z "$recent_outputs" ]]; then
|
|
615
|
+
return 1 # Not enough history
|
|
616
|
+
fi
|
|
617
|
+
|
|
618
|
+
# Extract key errors from current output using two-stage filtering
|
|
619
|
+
# Stage 1: Filter out JSON field patterns to avoid false positives
|
|
620
|
+
# Stage 2: Extract actual error messages
|
|
621
|
+
local current_errors=$(grep -v '"[^"]*error[^"]*":' "$current_output" 2>/dev/null | \
|
|
622
|
+
grep -E '(^Error:|^ERROR:|^error:|\]: error|Link: error|Error occurred|failed with error|[Ee]xception|Fatal|FATAL)' 2>/dev/null | \
|
|
623
|
+
sort | uniq)
|
|
624
|
+
|
|
625
|
+
if [[ -z "$current_errors" ]]; then
|
|
626
|
+
return 1 # No errors
|
|
627
|
+
fi
|
|
628
|
+
|
|
629
|
+
# Check if same errors appear in all recent outputs
|
|
630
|
+
# For multi-line errors, verify ALL error lines appear in ALL history files
|
|
631
|
+
local all_files_match=true
|
|
632
|
+
while IFS= read -r output_file; do
|
|
633
|
+
local file_matches_all=true
|
|
634
|
+
while IFS= read -r error_line; do
|
|
635
|
+
# Use -F for literal fixed-string matching (not regex)
|
|
636
|
+
if ! grep -qF "$error_line" "$output_file" 2>/dev/null; then
|
|
637
|
+
file_matches_all=false
|
|
638
|
+
break
|
|
639
|
+
fi
|
|
640
|
+
done <<< "$current_errors"
|
|
641
|
+
|
|
642
|
+
if [[ "$file_matches_all" != "true" ]]; then
|
|
643
|
+
all_files_match=false
|
|
644
|
+
break
|
|
645
|
+
fi
|
|
646
|
+
done <<< "$recent_outputs"
|
|
647
|
+
|
|
648
|
+
if [[ "$all_files_match" == "true" ]]; then
|
|
649
|
+
return 0 # Stuck on same error(s)
|
|
650
|
+
else
|
|
651
|
+
return 1 # Making progress or different errors
|
|
652
|
+
fi
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
# =============================================================================
|
|
656
|
+
# SESSION MANAGEMENT FUNCTIONS
|
|
657
|
+
# =============================================================================
|
|
658
|
+
|
|
659
|
+
# Session file location - standardized across ralph_loop.sh and response_analyzer.sh
|
|
660
|
+
SESSION_FILE="$RALPH_DIR/.claude_session_id"
|
|
661
|
+
# Session expiration time in seconds (24 hours)
|
|
662
|
+
SESSION_EXPIRATION_SECONDS=86400
|
|
663
|
+
|
|
664
|
+
# Store session ID to file with timestamp
|
|
665
|
+
# Usage: store_session_id "session-uuid-123"
|
|
666
|
+
store_session_id() {
|
|
667
|
+
local session_id=$1
|
|
668
|
+
|
|
669
|
+
if [[ -z "$session_id" ]]; then
|
|
670
|
+
return 1
|
|
671
|
+
fi
|
|
672
|
+
|
|
673
|
+
# Write session with timestamp using jq for safe JSON construction
|
|
674
|
+
jq -n \
|
|
675
|
+
--arg session_id "$session_id" \
|
|
676
|
+
--arg timestamp "$(get_iso_timestamp)" \
|
|
677
|
+
'{
|
|
678
|
+
session_id: $session_id,
|
|
679
|
+
timestamp: $timestamp
|
|
680
|
+
}' > "$SESSION_FILE"
|
|
681
|
+
|
|
682
|
+
return 0
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
# Get the last stored session ID
|
|
686
|
+
# Returns: session ID string or empty if not found
|
|
687
|
+
get_last_session_id() {
|
|
688
|
+
if [[ ! -f "$SESSION_FILE" ]]; then
|
|
689
|
+
echo ""
|
|
690
|
+
return 0
|
|
691
|
+
fi
|
|
692
|
+
|
|
693
|
+
# Extract session_id from JSON file
|
|
694
|
+
local session_id=$(jq -r '.session_id // ""' "$SESSION_FILE" 2>/dev/null)
|
|
695
|
+
echo "$session_id"
|
|
696
|
+
return 0
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
# Check if the stored session should be resumed
|
|
700
|
+
# Returns: 0 (true) if session is valid and recent, 1 (false) otherwise
|
|
701
|
+
should_resume_session() {
|
|
702
|
+
if [[ ! -f "$SESSION_FILE" ]]; then
|
|
703
|
+
echo "false"
|
|
704
|
+
return 1
|
|
705
|
+
fi
|
|
706
|
+
|
|
707
|
+
# Get session timestamp
|
|
708
|
+
local timestamp=$(jq -r '.timestamp // ""' "$SESSION_FILE" 2>/dev/null)
|
|
709
|
+
|
|
710
|
+
if [[ -z "$timestamp" ]]; then
|
|
711
|
+
echo "false"
|
|
712
|
+
return 1
|
|
713
|
+
fi
|
|
714
|
+
|
|
715
|
+
# Calculate session age using date utilities
|
|
716
|
+
local now=$(get_epoch_seconds)
|
|
717
|
+
local session_time
|
|
718
|
+
|
|
719
|
+
# Parse ISO timestamp to epoch - try multiple formats for cross-platform compatibility
|
|
720
|
+
# Strip milliseconds if present (e.g., 2026-01-09T10:30:00.123+00:00 → 2026-01-09T10:30:00+00:00)
|
|
721
|
+
local clean_timestamp="${timestamp}"
|
|
722
|
+
if [[ "$timestamp" =~ \.[0-9]+[+-Z] ]]; then
|
|
723
|
+
clean_timestamp=$(echo "$timestamp" | sed 's/\.[0-9]*\([+-Z]\)/\1/')
|
|
724
|
+
fi
|
|
725
|
+
|
|
726
|
+
if command -v gdate &>/dev/null; then
|
|
727
|
+
# macOS with coreutils
|
|
728
|
+
session_time=$(gdate -d "$clean_timestamp" +%s 2>/dev/null)
|
|
729
|
+
elif date --version 2>&1 | grep -q GNU; then
|
|
730
|
+
# GNU date (Linux)
|
|
731
|
+
session_time=$(date -d "$clean_timestamp" +%s 2>/dev/null)
|
|
732
|
+
else
|
|
733
|
+
# BSD date (macOS without coreutils) - try parsing ISO format
|
|
734
|
+
# Format: 2026-01-09T10:30:00+00:00 or 2026-01-09T10:30:00Z
|
|
735
|
+
# Strip timezone suffix for BSD date parsing
|
|
736
|
+
local date_only="${clean_timestamp%[+-Z]*}"
|
|
737
|
+
session_time=$(date -j -f "%Y-%m-%dT%H:%M:%S" "$date_only" +%s 2>/dev/null)
|
|
738
|
+
fi
|
|
739
|
+
|
|
740
|
+
# If we couldn't parse the timestamp, consider session expired
|
|
741
|
+
if [[ -z "$session_time" || ! "$session_time" =~ ^[0-9]+$ ]]; then
|
|
742
|
+
echo "false"
|
|
743
|
+
return 1
|
|
744
|
+
fi
|
|
745
|
+
|
|
746
|
+
# Calculate age in seconds
|
|
747
|
+
local age=$((now - session_time))
|
|
748
|
+
|
|
749
|
+
# Check if session is still valid (less than expiration time)
|
|
750
|
+
if [[ $age -lt $SESSION_EXPIRATION_SECONDS ]]; then
|
|
751
|
+
echo "true"
|
|
752
|
+
return 0
|
|
753
|
+
else
|
|
754
|
+
echo "false"
|
|
755
|
+
return 1
|
|
756
|
+
fi
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
# Export functions for use in ralph_loop.sh
|
|
760
|
+
export -f detect_output_format
|
|
761
|
+
export -f parse_json_response
|
|
762
|
+
export -f analyze_response
|
|
763
|
+
export -f update_exit_signals
|
|
764
|
+
export -f log_analysis_summary
|
|
765
|
+
export -f detect_stuck_loop
|
|
766
|
+
export -f store_session_id
|
|
767
|
+
export -f get_last_session_id
|
|
768
|
+
export -f should_resume_session
|