rafcode 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/.claude/settings.local.json +32 -0
- package/CLAUDE.md +187 -0
- package/LICENSE +21 -0
- package/RAF/001-raf-task-improvements/input.md +9 -0
- package/RAF/001-raf-task-improvements/outcomes/001-add-decisions-folder.md +21 -0
- package/RAF/001-raf-task-improvements/outcomes/002-fix-write-error-on-shutdown.md +22 -0
- package/RAF/001-raf-task-improvements/outcomes/003-stash-changes-on-failure.md +34 -0
- package/RAF/001-raf-task-improvements/outcomes/004-add-project-name-to-commits.md +28 -0
- package/RAF/001-raf-task-improvements/outcomes/005-add-running-time-display.md +36 -0
- package/RAF/001-raf-task-improvements/outcomes/006-add-task-name-to-logs.md +22 -0
- package/RAF/001-raf-task-improvements/outcomes/007-show-model-at-task-start.md +52 -0
- package/RAF/001-raf-task-improvements/outcomes/009-remove-editor-placeholder-text.md +20 -0
- package/RAF/001-raf-task-improvements/outcomes/SUMMARY.md +83 -0
- package/RAF/001-raf-task-improvements/plans/001-add-decisions-folder.md +38 -0
- package/RAF/001-raf-task-improvements/plans/002-fix-write-error-on-shutdown.md +33 -0
- package/RAF/001-raf-task-improvements/plans/003-stash-changes-on-failure.md +37 -0
- package/RAF/001-raf-task-improvements/plans/004-add-project-name-to-commits.md +34 -0
- package/RAF/001-raf-task-improvements/plans/005-add-running-time-display.md +39 -0
- package/RAF/001-raf-task-improvements/plans/006-add-task-name-to-logs.md +37 -0
- package/RAF/001-raf-task-improvements/plans/009-remove-editor-placeholder-text.md +34 -0
- package/RAF/002-raf-task-improvements-execution/decisions/DECISIONS.md +13 -0
- package/RAF/002-raf-task-improvements-execution/input.md +3 -0
- package/RAF/002-raf-task-improvements-execution/outcomes/001-commit-show-model-at-task-start.md +17 -0
- package/RAF/002-raf-task-improvements-execution/outcomes/002-delete-skipped-plan.md +23 -0
- package/RAF/002-raf-task-improvements-execution/outcomes/SUMMARY.md +32 -0
- package/RAF/002-raf-task-improvements-execution/plans/001-commit-show-model-at-task-start.md +37 -0
- package/RAF/002-raf-task-improvements-execution/plans/002-delete-skipped-plan.md +23 -0
- package/RAF/003-multi-project-execution/decisions/DECISIONS.md +68 -0
- package/RAF/003-multi-project-execution/input.md +6 -0
- package/RAF/003-multi-project-execution/outcomes/001-remove-state-json.md +52 -0
- package/RAF/003-multi-project-execution/outcomes/002-update-raf-status.md +50 -0
- package/RAF/003-multi-project-execution/outcomes/003-simplify-git-logic.md +35 -0
- package/RAF/003-multi-project-execution/outcomes/004-auto-commit-planning.md +43 -0
- package/RAF/003-multi-project-execution/outcomes/005-rerun-failed-tasks.md +43 -0
- package/RAF/003-multi-project-execution/outcomes/006-multi-project-execution.md +42 -0
- package/RAF/003-multi-project-execution/outcomes/007-verify-timeout.md +54 -0
- package/RAF/003-multi-project-execution/outcomes/008-move-decisions-file.md +38 -0
- package/RAF/003-multi-project-execution/outcomes/SUMMARY.md +79 -0
- package/RAF/003-multi-project-execution/plans/001-remove-state-json.md +71 -0
- package/RAF/003-multi-project-execution/plans/002-update-raf-status.md +65 -0
- package/RAF/003-multi-project-execution/plans/003-simplify-git-logic.md +74 -0
- package/RAF/003-multi-project-execution/plans/004-auto-commit-planning.md +57 -0
- package/RAF/003-multi-project-execution/plans/005-rerun-failed-tasks.md +69 -0
- package/RAF/003-multi-project-execution/plans/006-multi-project-execution.md +81 -0
- package/RAF/003-multi-project-execution/plans/007-verify-timeout.md +63 -0
- package/RAF/003-multi-project-execution/plans/008-move-decisions-file.md +78 -0
- package/RAF/004-task-naming-optimization/decisions.md +22 -0
- package/RAF/004-task-naming-optimization/input.md +6 -0
- package/RAF/004-task-naming-optimization/outcomes/001-remove-summary-file.md +17 -0
- package/RAF/004-task-naming-optimization/outcomes/002-base36-project-numbering.md +32 -0
- package/RAF/004-task-naming-optimization/outcomes/003-improve-haiku-prompt.md +20 -0
- package/RAF/004-task-naming-optimization/outcomes/SUMMARY.md +28 -0
- package/RAF/004-task-naming-optimization/plans/001-remove-summary-file.md +34 -0
- package/RAF/004-task-naming-optimization/plans/002-base36-project-numbering.md +56 -0
- package/RAF/004-task-naming-optimization/plans/003-improve-haiku-prompt.md +50 -0
- package/RAF/005-task-naming-improvements/decisions.md +60 -0
- package/RAF/005-task-naming-improvements/input.md +2 -0
- package/RAF/005-task-naming-improvements/outcomes/001-enhance-identifier-resolution.md +42 -0
- package/RAF/005-task-naming-improvements/outcomes/002-add-identifier-support-to-status.md +38 -0
- package/RAF/005-task-naming-improvements/outcomes/003-update-do-for-full-folder-names.md +44 -0
- package/RAF/005-task-naming-improvements/outcomes/004-implement-amend-flag-for-plan.md +55 -0
- package/RAF/005-task-naming-improvements/outcomes/005-commit-outcomes-on-complete.md +47 -0
- package/RAF/005-task-naming-improvements/outcomes/006-update-execution-prompt-commit-schema.md +40 -0
- package/RAF/005-task-naming-improvements/outcomes/007-allow-pending-task-amendments.md +38 -0
- package/RAF/005-task-naming-improvements/outcomes/008-fix-timeout-label.md +24 -0
- package/RAF/005-task-naming-improvements/plans/001-enhance-identifier-resolution.md +46 -0
- package/RAF/005-task-naming-improvements/plans/002-add-identifier-support-to-status.md +36 -0
- package/RAF/005-task-naming-improvements/plans/003-update-do-for-full-folder-names.md +38 -0
- package/RAF/005-task-naming-improvements/plans/004-implement-amend-flag-for-plan.md +67 -0
- package/RAF/005-task-naming-improvements/plans/005-commit-outcomes-on-complete.md +86 -0
- package/RAF/005-task-naming-improvements/plans/006-update-execution-prompt-commit-schema.md +60 -0
- package/RAF/005-task-naming-improvements/plans/007-allow-pending-task-amendments.md +60 -0
- package/RAF/005-task-naming-improvements/plans/008-fix-timeout-label.md +31 -0
- package/RAF/006-fix-double-summary-headers/decisions.md +28 -0
- package/RAF/006-fix-double-summary-headers/input.md +3 -0
- package/RAF/006-fix-double-summary-headers/outcomes/001-fix-double-summary-headers.md +29 -0
- package/RAF/006-fix-double-summary-headers/outcomes/002-update-readme-for-npm.md +31 -0
- package/RAF/006-fix-double-summary-headers/outcomes/003-npm-publish-instructions.md +30 -0
- package/RAF/006-fix-double-summary-headers/outcomes/004-flexible-project-lookup.md +47 -0
- package/RAF/006-fix-double-summary-headers/plans/001-fix-double-summary-headers.md +42 -0
- package/RAF/006-fix-double-summary-headers/plans/002-update-readme-for-npm.md +44 -0
- package/RAF/006-fix-double-summary-headers/plans/003-npm-publish-instructions.md +45 -0
- package/RAF/006-fix-double-summary-headers/plans/004-flexible-project-lookup.md +40 -0
- package/RAF/007-improve-outcome-format/decisions.md +28 -0
- package/RAF/007-improve-outcome-format/input.md +2 -0
- package/RAF/007-improve-outcome-format/outcomes/001-update-execution-prompt.md +10 -0
- package/RAF/007-improve-outcome-format/outcomes/002-update-state-derivation.md +17 -0
- package/RAF/007-improve-outcome-format/outcomes/003-update-do-command-outcome-handling.md +16 -0
- package/RAF/007-improve-outcome-format/outcomes/004-implement-failure-analysis.md +16 -0
- package/RAF/007-improve-outcome-format/outcomes/005-update-documentation.md +15 -0
- package/RAF/007-improve-outcome-format/plans/001-update-execution-prompt.md +36 -0
- package/RAF/007-improve-outcome-format/plans/002-update-state-derivation.md +35 -0
- package/RAF/007-improve-outcome-format/plans/003-update-do-command-outcome-handling.md +37 -0
- package/RAF/007-improve-outcome-format/plans/004-implement-failure-analysis.md +44 -0
- package/RAF/007-improve-outcome-format/plans/005-update-documentation.md +33 -0
- package/RAF/008-beautiful-do/decisions.md +31 -0
- package/RAF/008-beautiful-do/input.md +1 -0
- package/RAF/008-beautiful-do/outcomes/001-terminal-symbols.md +55 -0
- package/RAF/008-beautiful-do/outcomes/002-refactor-do-output.md +95 -0
- package/RAF/008-beautiful-do/outcomes/003-refactor-status-output.md +71 -0
- package/RAF/008-beautiful-do/outcomes/004-simplify-logger.md +53 -0
- package/RAF/008-beautiful-do/outcomes/005-add-tests.md +41 -0
- package/RAF/008-beautiful-do/plans/001-terminal-symbols.md +41 -0
- package/RAF/008-beautiful-do/plans/002-refactor-do-output.md +44 -0
- package/RAF/008-beautiful-do/plans/003-refactor-status-output.md +37 -0
- package/RAF/008-beautiful-do/plans/004-simplify-logger.md +32 -0
- package/RAF/008-beautiful-do/plans/005-add-tests.md +40 -0
- package/RAF/009-system-promt-ammend/decisions.md +13 -0
- package/RAF/009-system-promt-ammend/input.md +9 -0
- package/RAF/009-system-promt-ammend/outcomes/001-model-override.md +79 -0
- package/RAF/009-system-promt-ammend/outcomes/002-system-prompt-append.md +51 -0
- package/RAF/009-system-promt-ammend/outcomes/003-retry-context.md +60 -0
- package/RAF/009-system-promt-ammend/plans/001-model-override.md +61 -0
- package/RAF/009-system-promt-ammend/plans/002-system-prompt-append.md +56 -0
- package/RAF/009-system-promt-ammend/plans/003-retry-context.md +76 -0
- package/RAF/010-outcome-marker-fallback/decisions.md +19 -0
- package/RAF/010-outcome-marker-fallback/input.md +1 -0
- package/RAF/010-outcome-marker-fallback/outcomes/001-outcome-file-marker-fallback.md +35 -0
- package/RAF/010-outcome-marker-fallback/outcomes/002-creative-project-naming.md +47 -0
- package/RAF/010-outcome-marker-fallback/plans/001-outcome-file-marker-fallback.md +58 -0
- package/RAF/010-outcome-marker-fallback/plans/002-creative-project-naming.md +68 -0
- package/RAF/011-do-task-in-commit/decisions.md +22 -0
- package/RAF/011-do-task-in-commit/input.md +1 -0
- package/RAF/011-do-task-in-commit/outcomes/001-update-execution-prompt.md +54 -0
- package/RAF/011-do-task-in-commit/outcomes/002-update-tests.md +61 -0
- package/RAF/011-do-task-in-commit/outcomes/003-update-documentation.md +51 -0
- package/RAF/011-do-task-in-commit/plans/001-update-execution-prompt.md +46 -0
- package/RAF/011-do-task-in-commit/plans/002-update-tests.md +51 -0
- package/RAF/011-do-task-in-commit/plans/003-update-documentation.md +45 -0
- package/RAF/012-name-picker-buffet/decisions.md +40 -0
- package/RAF/012-name-picker-buffet/input.md +6 -0
- package/RAF/012-name-picker-buffet/outcomes/001-name-picker-for-raf-plan.md +49 -0
- package/RAF/012-name-picker-buffet/outcomes/002-interactive-project-picker-for-raf-do.md +49 -0
- package/RAF/012-name-picker-buffet/outcomes/003-raf-status-truncation.md +55 -0
- package/RAF/012-name-picker-buffet/outcomes/004-failure-reason-details.md +65 -0
- package/RAF/012-name-picker-buffet/outcomes/005-remove-raf-commits.md +57 -0
- package/RAF/012-name-picker-buffet/outcomes/006-update-execution-prompt-for-commits.md +47 -0
- package/RAF/012-name-picker-buffet/outcomes/007-fix-plan-mode-user-prompt.md +83 -0
- package/RAF/012-name-picker-buffet/outcomes/008-add-auto-flag-for-plan-mode.md +77 -0
- package/RAF/012-name-picker-buffet/plans/001-name-picker-for-raf-plan.md +47 -0
- package/RAF/012-name-picker-buffet/plans/002-interactive-project-picker-for-raf-do.md +43 -0
- package/RAF/012-name-picker-buffet/plans/003-raf-status-truncation.md +36 -0
- package/RAF/012-name-picker-buffet/plans/004-failure-reason-details.md +46 -0
- package/RAF/012-name-picker-buffet/plans/005-remove-raf-commits.md +42 -0
- package/RAF/012-name-picker-buffet/plans/006-update-execution-prompt-for-commits.md +47 -0
- package/RAF/012-name-picker-buffet/plans/007-fix-plan-mode-user-prompt.md +55 -0
- package/RAF/012-name-picker-buffet/plans/008-add-auto-flag-for-plan-mode.md +49 -0
- package/RAF/013-dependencies-watchdog/decisions.md +37 -0
- package/RAF/013-dependencies-watchdog/input.md +1 -0
- package/RAF/013-dependencies-watchdog/outcomes/001-define-dependency-syntax.md +56 -0
- package/RAF/013-dependencies-watchdog/outcomes/002-update-planning-prompts.md +60 -0
- package/RAF/013-dependencies-watchdog/outcomes/003-parse-dependencies-update-state.md +81 -0
- package/RAF/013-dependencies-watchdog/outcomes/004-implement-dependency-checking-in-do.md +116 -0
- package/RAF/013-dependencies-watchdog/outcomes/005-update-execution-prompts.md +75 -0
- package/RAF/013-dependencies-watchdog/outcomes/006-add-tests.md +100 -0
- package/RAF/013-dependencies-watchdog/outcomes/007-add-act-alias.md +46 -0
- package/RAF/013-dependencies-watchdog/outcomes/008-add-exit-message.md +52 -0
- package/RAF/013-dependencies-watchdog/plans/001-define-dependency-syntax.md +32 -0
- package/RAF/013-dependencies-watchdog/plans/002-update-planning-prompts.md +38 -0
- package/RAF/013-dependencies-watchdog/plans/003-parse-dependencies-update-state.md +46 -0
- package/RAF/013-dependencies-watchdog/plans/004-implement-dependency-checking-in-do.md +48 -0
- package/RAF/013-dependencies-watchdog/plans/005-update-execution-prompts.md +44 -0
- package/RAF/013-dependencies-watchdog/plans/006-add-tests.md +54 -0
- package/RAF/013-dependencies-watchdog/plans/007-add-act-alias.md +26 -0
- package/RAF/013-dependencies-watchdog/plans/008-add-exit-message.md +31 -0
- package/RAF/014-watchdog/decisions.md +16 -0
- package/RAF/014-watchdog/input.md +2 -0
- package/RAF/014-watchdog/outcomes/001-amend-flag-position.md +50 -0
- package/RAF/014-watchdog/outcomes/002-details-only-on-failure.md +58 -0
- package/RAF/014-watchdog/plans/001-amend-flag-position.md +34 -0
- package/RAF/014-watchdog/plans/002-details-only-on-failure.md +46 -0
- package/RAF/015-name-lottery/decisions.md +14 -0
- package/RAF/015-name-lottery/input.md +3 -0
- package/RAF/015-name-lottery/outcomes/001-auto-pick-project-name.md +31 -0
- package/RAF/015-name-lottery/outcomes/002-mention-plan-files-in-commit.md +23 -0
- package/RAF/015-name-lottery/outcomes/003-fix-input-md-in-amend-flow.md +44 -0
- package/RAF/015-name-lottery/plans/001-auto-pick-project-name.md +38 -0
- package/RAF/015-name-lottery/plans/002-mention-plan-files-in-commit.md +32 -0
- package/RAF/015-name-lottery/plans/003-fix-input-md-in-amend-flow.md +44 -0
- package/README.md +116 -0
- package/dist/commands/do.d.ts +12 -0
- package/dist/commands/do.d.ts.map +1 -0
- package/dist/commands/do.js +684 -0
- package/dist/commands/do.js.map +1 -0
- package/dist/commands/plan.d.ts +3 -0
- package/dist/commands/plan.d.ts.map +1 -0
- package/dist/commands/plan.js +345 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +117 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/core/claude-runner.d.ts +78 -0
- package/dist/core/claude-runner.d.ts.map +1 -0
- package/dist/core/claude-runner.js +297 -0
- package/dist/core/claude-runner.js.map +1 -0
- package/dist/core/editor.d.ts +10 -0
- package/dist/core/editor.d.ts.map +1 -0
- package/dist/core/editor.js +77 -0
- package/dist/core/editor.js.map +1 -0
- package/dist/core/failure-analyzer.d.ts +28 -0
- package/dist/core/failure-analyzer.d.ts.map +1 -0
- package/dist/core/failure-analyzer.js +305 -0
- package/dist/core/failure-analyzer.js.map +1 -0
- package/dist/core/git.d.ts +42 -0
- package/dist/core/git.d.ts.map +1 -0
- package/dist/core/git.js +148 -0
- package/dist/core/git.js.map +1 -0
- package/dist/core/project-manager.d.ts +72 -0
- package/dist/core/project-manager.d.ts.map +1 -0
- package/dist/core/project-manager.js +193 -0
- package/dist/core/project-manager.js.map +1 -0
- package/dist/core/retry-handler.d.ts +19 -0
- package/dist/core/retry-handler.d.ts.map +1 -0
- package/dist/core/retry-handler.js +51 -0
- package/dist/core/retry-handler.js.map +1 -0
- package/dist/core/shutdown-handler.d.ts +30 -0
- package/dist/core/shutdown-handler.d.ts.map +1 -0
- package/dist/core/shutdown-handler.js +79 -0
- package/dist/core/shutdown-handler.js.map +1 -0
- package/dist/core/state-derivation.d.ts +82 -0
- package/dist/core/state-derivation.d.ts.map +1 -0
- package/dist/core/state-derivation.js +271 -0
- package/dist/core/state-derivation.js.map +1 -0
- package/dist/core/state-manager.d.ts +54 -0
- package/dist/core/state-manager.d.ts.map +1 -0
- package/dist/core/state-manager.js +198 -0
- package/dist/core/state-manager.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/output-parser.d.ts +19 -0
- package/dist/parsers/output-parser.d.ts.map +1 -0
- package/dist/parsers/output-parser.js +137 -0
- package/dist/parsers/output-parser.js.map +1 -0
- package/dist/prompts/amend.d.ts +20 -0
- package/dist/prompts/amend.d.ts.map +1 -0
- package/dist/prompts/amend.js +166 -0
- package/dist/prompts/amend.js.map +1 -0
- package/dist/prompts/execution.d.ts +30 -0
- package/dist/prompts/execution.d.ts.map +1 -0
- package/dist/prompts/execution.js +179 -0
- package/dist/prompts/execution.js.map +1 -0
- package/dist/prompts/planning.d.ts +15 -0
- package/dist/prompts/planning.d.ts.map +1 -0
- package/dist/prompts/planning.js +163 -0
- package/dist/prompts/planning.js.map +1 -0
- package/dist/types/config.d.ts +26 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +7 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/state.d.ts +33 -0
- package/dist/types/state.d.ts.map +1 -0
- package/dist/types/state.js +28 -0
- package/dist/types/state.js.map +1 -0
- package/dist/ui/name-picker-subprocess.d.ts +11 -0
- package/dist/ui/name-picker-subprocess.d.ts.map +1 -0
- package/dist/ui/name-picker-subprocess.js +83 -0
- package/dist/ui/name-picker-subprocess.js.map +1 -0
- package/dist/ui/name-picker.d.ts +19 -0
- package/dist/ui/name-picker.d.ts.map +1 -0
- package/dist/ui/name-picker.js +173 -0
- package/dist/ui/name-picker.js.map +1 -0
- package/dist/ui/project-picker.d.ts +27 -0
- package/dist/ui/project-picker.d.ts.map +1 -0
- package/dist/ui/project-picker.js +58 -0
- package/dist/ui/project-picker.js.map +1 -0
- package/dist/utils/config.d.ts +24 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +63 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/logger.d.ts +32 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +60 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/name-generator.d.ts +20 -0
- package/dist/utils/name-generator.d.ts.map +1 -0
- package/dist/utils/name-generator.js +183 -0
- package/dist/utils/name-generator.js.map +1 -0
- package/dist/utils/paths.d.ts +132 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +412 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/status-line.d.ts +14 -0
- package/dist/utils/status-line.d.ts.map +1 -0
- package/dist/utils/status-line.js +36 -0
- package/dist/utils/status-line.js.map +1 -0
- package/dist/utils/terminal-symbols.d.ts +50 -0
- package/dist/utils/terminal-symbols.d.ts.map +1 -0
- package/dist/utils/terminal-symbols.js +97 -0
- package/dist/utils/terminal-symbols.js.map +1 -0
- package/dist/utils/timer.d.ts +17 -0
- package/dist/utils/timer.d.ts.map +1 -0
- package/dist/utils/timer.js +56 -0
- package/dist/utils/timer.js.map +1 -0
- package/dist/utils/validation.d.ts +17 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +106 -0
- package/dist/utils/validation.js.map +1 -0
- package/dist/utils/version.d.ts +2 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +12 -0
- package/dist/utils/version.js.map +1 -0
- package/jest.config.ts +30 -0
- package/package.json +55 -0
- package/src/commands/do.ts +829 -0
- package/src/commands/plan.ts +422 -0
- package/src/commands/status.ts +146 -0
- package/src/core/claude-runner.ts +374 -0
- package/src/core/editor.ts +85 -0
- package/src/core/failure-analyzer.ts +372 -0
- package/src/core/git.ts +166 -0
- package/src/core/project-manager.ts +243 -0
- package/src/core/retry-handler.ts +72 -0
- package/src/core/shutdown-handler.ts +93 -0
- package/src/core/state-derivation.ts +343 -0
- package/src/index.ts +20 -0
- package/src/parsers/output-parser.ts +164 -0
- package/src/prompts/amend.ts +194 -0
- package/src/prompts/execution.ts +223 -0
- package/src/prompts/planning.ts +175 -0
- package/src/types/config.ts +35 -0
- package/src/ui/name-picker-subprocess.ts +96 -0
- package/src/ui/name-picker.ts +198 -0
- package/src/ui/project-picker.ts +80 -0
- package/src/utils/config.ts +69 -0
- package/src/utils/logger.ts +81 -0
- package/src/utils/name-generator.ts +211 -0
- package/src/utils/paths.ts +497 -0
- package/src/utils/status-line.ts +45 -0
- package/src/utils/terminal-symbols.ts +124 -0
- package/src/utils/timer.ts +64 -0
- package/src/utils/validation.ts +132 -0
- package/src/utils/version.ts +12 -0
- package/tests/unit/claude-runner-interactive.test.ts +343 -0
- package/tests/unit/claude-runner.test.ts +629 -0
- package/tests/unit/command-output.test.ts +295 -0
- package/tests/unit/config.test.ts +72 -0
- package/tests/unit/dependency-integration.test.ts +559 -0
- package/tests/unit/do-blocked-tasks.test.ts +323 -0
- package/tests/unit/do-command.test.ts +198 -0
- package/tests/unit/do-multiproject.test.ts +270 -0
- package/tests/unit/do-rerun.test.ts +270 -0
- package/tests/unit/execution-prompt.test.ts +406 -0
- package/tests/unit/failure-analyzer.test.ts +276 -0
- package/tests/unit/failure-history.test.ts +143 -0
- package/tests/unit/git-stash.test.ts +138 -0
- package/tests/unit/git.test.ts +80 -0
- package/tests/unit/logger.test.ts +132 -0
- package/tests/unit/name-generator.test.ts +283 -0
- package/tests/unit/name-picker.test.ts +179 -0
- package/tests/unit/outcome-content.test.ts +166 -0
- package/tests/unit/output-parser.test.ts +178 -0
- package/tests/unit/paths.test.ts +741 -0
- package/tests/unit/plan-command-amend-flag.test.ts +115 -0
- package/tests/unit/plan-command-amend-input.test.ts +156 -0
- package/tests/unit/plan-command-auto-flag.test.ts +112 -0
- package/tests/unit/plan-command.test.ts +580 -0
- package/tests/unit/planning-prompt.test.ts +137 -0
- package/tests/unit/project-manager.test.ts +265 -0
- package/tests/unit/project-picker.test.ts +338 -0
- package/tests/unit/retry-handler.test.ts +89 -0
- package/tests/unit/state-derivation.test.ts +714 -0
- package/tests/unit/status-command.test.ts +271 -0
- package/tests/unit/status-line.test.ts +92 -0
- package/tests/unit/terminal-symbols.test.ts +214 -0
- package/tests/unit/timer.test.ts +102 -0
- package/tests/unit/validation.test.ts +118 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import { getExecutionPrompt, ExecutionPromptParams, summarizeOutcome } from '../../src/prompts/execution.js';
|
|
2
|
+
|
|
3
|
+
describe('Execution Prompt', () => {
|
|
4
|
+
const baseParams: ExecutionPromptParams = {
|
|
5
|
+
projectPath: '/Users/test/RAF/005-task-naming-improvements',
|
|
6
|
+
planPath: '/Users/test/RAF/005-task-naming-improvements/plans/001-enhance-identifier-resolution.md',
|
|
7
|
+
taskId: '001',
|
|
8
|
+
taskNumber: 1,
|
|
9
|
+
totalTasks: 5,
|
|
10
|
+
previousOutcomes: [],
|
|
11
|
+
autoCommit: true,
|
|
12
|
+
projectNumber: '005',
|
|
13
|
+
outcomeFilePath: '/Users/test/RAF/005-task-naming-improvements/outcomes/001-enhance-identifier-resolution.md',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
describe('Commit Message Format', () => {
|
|
17
|
+
it('should include RAF commit schema format with description placeholder in prompt', () => {
|
|
18
|
+
const prompt = getExecutionPrompt(baseParams);
|
|
19
|
+
expect(prompt).toContain('RAF[005:001] <description>');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should instruct to write meaningful description', () => {
|
|
23
|
+
const prompt = getExecutionPrompt(baseParams);
|
|
24
|
+
expect(prompt).toContain('Write a concise description of what was accomplished');
|
|
25
|
+
expect(prompt).toContain('Focus on the actual change, not the task name');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should zero-pad single digit task numbers', () => {
|
|
29
|
+
const params = { ...baseParams, taskNumber: 1 };
|
|
30
|
+
const prompt = getExecutionPrompt(params);
|
|
31
|
+
expect(prompt).toContain('RAF[005:001]');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should zero-pad double digit task numbers', () => {
|
|
35
|
+
const params = { ...baseParams, taskNumber: 12 };
|
|
36
|
+
const prompt = getExecutionPrompt(params);
|
|
37
|
+
expect(prompt).toContain('RAF[005:012]');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should not pad triple digit task numbers', () => {
|
|
41
|
+
const params = { ...baseParams, taskNumber: 123 };
|
|
42
|
+
const prompt = getExecutionPrompt(params);
|
|
43
|
+
expect(prompt).toContain('RAF[005:123]');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should include project number from base36 prefix', () => {
|
|
47
|
+
const params = { ...baseParams, projectNumber: 'a05' };
|
|
48
|
+
const prompt = getExecutionPrompt(params);
|
|
49
|
+
expect(prompt).toContain('RAF[a05:001]');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should not include commit instructions when autoCommit is false', () => {
|
|
53
|
+
const params = { ...baseParams, autoCommit: false };
|
|
54
|
+
const prompt = getExecutionPrompt(params);
|
|
55
|
+
expect(prompt).not.toContain('Git Instructions');
|
|
56
|
+
expect(prompt).not.toContain('RAF[');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should include instruction not to commit on failure', () => {
|
|
60
|
+
const prompt = getExecutionPrompt(baseParams);
|
|
61
|
+
expect(prompt).toContain('On Failure');
|
|
62
|
+
expect(prompt).toContain('do NOT commit');
|
|
63
|
+
expect(prompt).toContain('<promise>FAILED</promise>');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should not include failure commit instruction when autoCommit is false', () => {
|
|
67
|
+
const params = { ...baseParams, autoCommit: false };
|
|
68
|
+
const prompt = getExecutionPrompt(params);
|
|
69
|
+
expect(prompt).not.toContain('On Failure');
|
|
70
|
+
expect(prompt).not.toContain('do NOT commit');
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('Complete Commit Message', () => {
|
|
75
|
+
it('should generate correct commit message format for task 006', () => {
|
|
76
|
+
const params: ExecutionPromptParams = {
|
|
77
|
+
projectPath: '/Users/test/RAF/005-task-naming-improvements',
|
|
78
|
+
planPath: '/Users/test/RAF/005-task-naming-improvements/plans/006-update-execution-prompt.md',
|
|
79
|
+
taskId: '006',
|
|
80
|
+
taskNumber: 6,
|
|
81
|
+
totalTasks: 7,
|
|
82
|
+
previousOutcomes: [],
|
|
83
|
+
autoCommit: true,
|
|
84
|
+
projectNumber: '005',
|
|
85
|
+
outcomeFilePath: '/Users/test/RAF/005-task-naming-improvements/outcomes/006-update-execution-prompt.md',
|
|
86
|
+
};
|
|
87
|
+
const prompt = getExecutionPrompt(params);
|
|
88
|
+
expect(prompt).toContain('RAF[005:006] <description>');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should generate correct commit message format for first task', () => {
|
|
92
|
+
const params: ExecutionPromptParams = {
|
|
93
|
+
projectPath: '/Users/test/RAF/001-fix-bug',
|
|
94
|
+
planPath: '/Users/test/RAF/001-fix-bug/plans/001-identify-issue.md',
|
|
95
|
+
taskId: '001',
|
|
96
|
+
taskNumber: 1,
|
|
97
|
+
totalTasks: 3,
|
|
98
|
+
previousOutcomes: [],
|
|
99
|
+
autoCommit: true,
|
|
100
|
+
projectNumber: '001',
|
|
101
|
+
outcomeFilePath: '/Users/test/RAF/001-fix-bug/outcomes/001-identify-issue.md',
|
|
102
|
+
};
|
|
103
|
+
const prompt = getExecutionPrompt(params);
|
|
104
|
+
expect(prompt).toContain('RAF[001:001] <description>');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should generate correct commit message format for base36 project', () => {
|
|
108
|
+
const params: ExecutionPromptParams = {
|
|
109
|
+
projectPath: '/Users/test/RAF/a0b-feature-branch',
|
|
110
|
+
planPath: '/Users/test/RAF/a0b-feature-branch/plans/002-implement-feature.md',
|
|
111
|
+
taskId: '002',
|
|
112
|
+
taskNumber: 2,
|
|
113
|
+
totalTasks: 4,
|
|
114
|
+
previousOutcomes: [],
|
|
115
|
+
autoCommit: true,
|
|
116
|
+
projectNumber: 'a0b',
|
|
117
|
+
outcomeFilePath: '/Users/test/RAF/a0b-feature-branch/outcomes/002-implement-feature.md',
|
|
118
|
+
};
|
|
119
|
+
const prompt = getExecutionPrompt(params);
|
|
120
|
+
expect(prompt).toContain('RAF[a0b:002] <description>');
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
describe('Task Information', () => {
|
|
125
|
+
it('should include task number and total', () => {
|
|
126
|
+
const prompt = getExecutionPrompt(baseParams);
|
|
127
|
+
expect(prompt).toContain('Task: 1 of 5');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should include task ID', () => {
|
|
131
|
+
const prompt = getExecutionPrompt(baseParams);
|
|
132
|
+
expect(prompt).toContain('Task ID: 001');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('should include project path', () => {
|
|
136
|
+
const prompt = getExecutionPrompt(baseParams);
|
|
137
|
+
expect(prompt).toContain('Project folder: /Users/test/RAF/005-task-naming-improvements');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should include plan path', () => {
|
|
141
|
+
const prompt = getExecutionPrompt(baseParams);
|
|
142
|
+
expect(prompt).toContain('plans/001-enhance-identifier-resolution.md');
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe('Outcome File Instructions', () => {
|
|
147
|
+
it('should include outcome file path in prompt', () => {
|
|
148
|
+
const prompt = getExecutionPrompt(baseParams);
|
|
149
|
+
expect(prompt).toContain('Outcome file path');
|
|
150
|
+
expect(prompt).toContain(baseParams.outcomeFilePath);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should include instructions for writing outcome file', () => {
|
|
154
|
+
const prompt = getExecutionPrompt(baseParams);
|
|
155
|
+
expect(prompt).toContain('You MUST write an outcome file');
|
|
156
|
+
expect(prompt).toContain('summary of what was done');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('should specify that completion marker must be at end of file', () => {
|
|
160
|
+
const prompt = getExecutionPrompt(baseParams);
|
|
161
|
+
expect(prompt).toContain('MUST end with one of these markers');
|
|
162
|
+
expect(prompt).toContain('<promise>COMPLETE</promise>');
|
|
163
|
+
expect(prompt).toContain('<promise>FAILED</promise>');
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should distinguish between code tasks and documentation tasks', () => {
|
|
167
|
+
const prompt = getExecutionPrompt(baseParams);
|
|
168
|
+
expect(prompt).toContain('For code tasks');
|
|
169
|
+
expect(prompt).toContain('For documentation/report tasks');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should instruct that marker is last line in outcome file', () => {
|
|
173
|
+
const prompt = getExecutionPrompt(baseParams);
|
|
174
|
+
expect(prompt).toContain('completion marker MUST be the LAST line in the outcome file');
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
describe('Commit Workflow Rules', () => {
|
|
179
|
+
it('should include rule to commit code and outcome together on success', () => {
|
|
180
|
+
const prompt = getExecutionPrompt(baseParams);
|
|
181
|
+
expect(prompt).toContain('On SUCCESS: Commit code changes AND outcome file together');
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('should include rule not to commit on failure', () => {
|
|
185
|
+
const prompt = getExecutionPrompt(baseParams);
|
|
186
|
+
expect(prompt).toContain('On FAILURE: Do NOT commit');
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should specify that changes are preserved for debugging on failure', () => {
|
|
190
|
+
const prompt = getExecutionPrompt(baseParams);
|
|
191
|
+
expect(prompt).toContain('preserved for debugging');
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
describe('Previous Outcomes', () => {
|
|
196
|
+
it('should include previous outcomes section when outcomes exist', () => {
|
|
197
|
+
const params = {
|
|
198
|
+
...baseParams,
|
|
199
|
+
previousOutcomes: [
|
|
200
|
+
{ taskId: '001', content: '## Status: SUCCESS\n\nTask completed successfully.' },
|
|
201
|
+
],
|
|
202
|
+
};
|
|
203
|
+
const prompt = getExecutionPrompt(params);
|
|
204
|
+
expect(prompt).toContain('Previous Task Outcomes');
|
|
205
|
+
expect(prompt).toContain('### Task 001');
|
|
206
|
+
expect(prompt).toContain('## Status: SUCCESS');
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('should not include previous outcomes section when empty', () => {
|
|
210
|
+
const prompt = getExecutionPrompt(baseParams);
|
|
211
|
+
expect(prompt).not.toContain('Previous Task Outcomes');
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
describe('Retry Context', () => {
|
|
216
|
+
it('should not include retry context on first attempt', () => {
|
|
217
|
+
const params = {
|
|
218
|
+
...baseParams,
|
|
219
|
+
attemptNumber: 1,
|
|
220
|
+
previousOutcomeFile: '/path/to/outcome.md',
|
|
221
|
+
};
|
|
222
|
+
const prompt = getExecutionPrompt(params);
|
|
223
|
+
expect(prompt).not.toContain('Retry Context');
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('should not include retry context when attemptNumber is not provided', () => {
|
|
227
|
+
const prompt = getExecutionPrompt(baseParams);
|
|
228
|
+
expect(prompt).not.toContain('Retry Context');
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('should include retry context on second attempt with previous outcome file', () => {
|
|
232
|
+
const params = {
|
|
233
|
+
...baseParams,
|
|
234
|
+
attemptNumber: 2,
|
|
235
|
+
previousOutcomeFile: '/Users/test/RAF/005-task-naming-improvements/outcomes/001-enhance-identifier-resolution.md',
|
|
236
|
+
};
|
|
237
|
+
const prompt = getExecutionPrompt(params);
|
|
238
|
+
expect(prompt).toContain('## Retry Context');
|
|
239
|
+
expect(prompt).toContain('This is attempt 2');
|
|
240
|
+
expect(prompt).toContain('**Previous outcome file**: /Users/test/RAF/005-task-naming-improvements/outcomes/001-enhance-identifier-resolution.md');
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it('should include retry context on third attempt', () => {
|
|
244
|
+
const params = {
|
|
245
|
+
...baseParams,
|
|
246
|
+
attemptNumber: 3,
|
|
247
|
+
previousOutcomeFile: '/path/to/outcome.md',
|
|
248
|
+
};
|
|
249
|
+
const prompt = getExecutionPrompt(params);
|
|
250
|
+
expect(prompt).toContain('This is attempt 3');
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('should not include retry context on second attempt without previous outcome file', () => {
|
|
254
|
+
const params = {
|
|
255
|
+
...baseParams,
|
|
256
|
+
attemptNumber: 2,
|
|
257
|
+
previousOutcomeFile: undefined,
|
|
258
|
+
};
|
|
259
|
+
const prompt = getExecutionPrompt(params);
|
|
260
|
+
expect(prompt).not.toContain('Retry Context');
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('should instruct to read previous outcome file and avoid same mistakes', () => {
|
|
264
|
+
const params = {
|
|
265
|
+
...baseParams,
|
|
266
|
+
attemptNumber: 2,
|
|
267
|
+
previousOutcomeFile: '/path/to/outcome.md',
|
|
268
|
+
};
|
|
269
|
+
const prompt = getExecutionPrompt(params);
|
|
270
|
+
expect(prompt).toContain('Read the previous outcome file first');
|
|
271
|
+
expect(prompt).toContain('Understand what was attempted and why it failed');
|
|
272
|
+
expect(prompt).toContain('Account for the previous failure in your approach');
|
|
273
|
+
expect(prompt).toContain('Avoid making the same mistakes');
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
describe('Dependency Context', () => {
|
|
278
|
+
it('should not include dependency context when task has no dependencies', () => {
|
|
279
|
+
const prompt = getExecutionPrompt(baseParams);
|
|
280
|
+
expect(prompt).not.toContain('Dependency Context');
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('should not include dependency context when dependencyIds is empty', () => {
|
|
284
|
+
const params = {
|
|
285
|
+
...baseParams,
|
|
286
|
+
dependencyIds: [],
|
|
287
|
+
dependencyOutcomes: [],
|
|
288
|
+
};
|
|
289
|
+
const prompt = getExecutionPrompt(params);
|
|
290
|
+
expect(prompt).not.toContain('Dependency Context');
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it('should not include dependency context when dependencyOutcomes is empty', () => {
|
|
294
|
+
const params = {
|
|
295
|
+
...baseParams,
|
|
296
|
+
dependencyIds: ['001'],
|
|
297
|
+
dependencyOutcomes: [],
|
|
298
|
+
};
|
|
299
|
+
const prompt = getExecutionPrompt(params);
|
|
300
|
+
expect(prompt).not.toContain('Dependency Context');
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it('should include dependency context when task has dependencies with outcomes', () => {
|
|
304
|
+
const params = {
|
|
305
|
+
...baseParams,
|
|
306
|
+
taskId: '002',
|
|
307
|
+
taskNumber: 2,
|
|
308
|
+
dependencyIds: ['001'],
|
|
309
|
+
dependencyOutcomes: [
|
|
310
|
+
{ taskId: '001', content: '## Summary\n\nImplemented the base feature.\n\n<promise>COMPLETE</promise>' },
|
|
311
|
+
],
|
|
312
|
+
};
|
|
313
|
+
const prompt = getExecutionPrompt(params);
|
|
314
|
+
expect(prompt).toContain('## Dependency Context');
|
|
315
|
+
expect(prompt).toContain('**Dependencies**: 001');
|
|
316
|
+
expect(prompt).toContain('### Task 001');
|
|
317
|
+
expect(prompt).toContain('Implemented the base feature');
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it('should include multiple dependency outcomes', () => {
|
|
321
|
+
const params = {
|
|
322
|
+
...baseParams,
|
|
323
|
+
taskId: '003',
|
|
324
|
+
taskNumber: 3,
|
|
325
|
+
dependencyIds: ['001', '002'],
|
|
326
|
+
dependencyOutcomes: [
|
|
327
|
+
{ taskId: '001', content: '## Summary\n\nFirst task done.\n\n<promise>COMPLETE</promise>' },
|
|
328
|
+
{ taskId: '002', content: '## Summary\n\nSecond task done.\n\n<promise>COMPLETE</promise>' },
|
|
329
|
+
],
|
|
330
|
+
};
|
|
331
|
+
const prompt = getExecutionPrompt(params);
|
|
332
|
+
expect(prompt).toContain('**Dependencies**: 001, 002');
|
|
333
|
+
expect(prompt).toContain('### Task 001');
|
|
334
|
+
expect(prompt).toContain('First task done');
|
|
335
|
+
expect(prompt).toContain('### Task 002');
|
|
336
|
+
expect(prompt).toContain('Second task done');
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it('should explain purpose of dependency context', () => {
|
|
340
|
+
const params = {
|
|
341
|
+
...baseParams,
|
|
342
|
+
taskId: '002',
|
|
343
|
+
taskNumber: 2,
|
|
344
|
+
dependencyIds: ['001'],
|
|
345
|
+
dependencyOutcomes: [
|
|
346
|
+
{ taskId: '001', content: '## Summary\n\nDone.\n\n<promise>COMPLETE</promise>' },
|
|
347
|
+
],
|
|
348
|
+
};
|
|
349
|
+
const prompt = getExecutionPrompt(params);
|
|
350
|
+
expect(prompt).toContain('depends on the following completed tasks');
|
|
351
|
+
expect(prompt).toContain('Review their outcomes to understand what was accomplished');
|
|
352
|
+
expect(prompt).toContain('build upon their work');
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it('should place dependency context before previous outcomes section', () => {
|
|
356
|
+
const params = {
|
|
357
|
+
...baseParams,
|
|
358
|
+
taskId: '003',
|
|
359
|
+
taskNumber: 3,
|
|
360
|
+
previousOutcomes: [
|
|
361
|
+
{ taskId: '001', content: 'Previous outcome 1' },
|
|
362
|
+
{ taskId: '002', content: 'Previous outcome 2' },
|
|
363
|
+
],
|
|
364
|
+
dependencyIds: ['001'],
|
|
365
|
+
dependencyOutcomes: [
|
|
366
|
+
{ taskId: '001', content: '## Summary\n\nDependency work.\n\n<promise>COMPLETE</promise>' },
|
|
367
|
+
],
|
|
368
|
+
};
|
|
369
|
+
const prompt = getExecutionPrompt(params);
|
|
370
|
+
const depContextIndex = prompt.indexOf('## Dependency Context');
|
|
371
|
+
const prevOutcomesIndex = prompt.indexOf('## Previous Task Outcomes');
|
|
372
|
+
expect(depContextIndex).toBeGreaterThan(-1);
|
|
373
|
+
expect(prevOutcomesIndex).toBeGreaterThan(-1);
|
|
374
|
+
expect(depContextIndex).toBeLessThan(prevOutcomesIndex);
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
describe('summarizeOutcome', () => {
|
|
379
|
+
it('should return content as-is when under size limit', () => {
|
|
380
|
+
const content = '## Summary\n\nShort content.\n\n<promise>COMPLETE</promise>';
|
|
381
|
+
const result = summarizeOutcome(content);
|
|
382
|
+
expect(result).toBe(content);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
it('should extract Summary section when content is too long', () => {
|
|
386
|
+
const summary = 'This is the summary of what was done.';
|
|
387
|
+
const longContent = `## Summary\n\n${summary}\n\n## Details\n\n${'x'.repeat(5000)}\n\n<promise>COMPLETE</promise>`;
|
|
388
|
+
const result = summarizeOutcome(longContent);
|
|
389
|
+
expect(result).toContain(summary);
|
|
390
|
+
expect(result).toContain('[Outcome truncated for context size]');
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it('should truncate at reasonable break point when no Summary section', () => {
|
|
394
|
+
const longContent = 'x'.repeat(5000);
|
|
395
|
+
const result = summarizeOutcome(longContent);
|
|
396
|
+
expect(result.length).toBeLessThan(5000);
|
|
397
|
+
expect(result).toContain('[Outcome truncated for context size]');
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
it('should prefer newline as break point when truncating', () => {
|
|
401
|
+
const content = 'First line.\nSecond line.\n' + 'x'.repeat(5000);
|
|
402
|
+
const result = summarizeOutcome(content);
|
|
403
|
+
expect(result).toContain('[Outcome truncated for context size]');
|
|
404
|
+
});
|
|
405
|
+
});
|
|
406
|
+
});
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import {
|
|
2
|
+
detectProgrammaticFailure,
|
|
3
|
+
generateProgrammaticReport,
|
|
4
|
+
analyzeFailure,
|
|
5
|
+
type ProgrammaticFailureType,
|
|
6
|
+
} from '../../src/core/failure-analyzer.js';
|
|
7
|
+
|
|
8
|
+
describe('Failure Analyzer', () => {
|
|
9
|
+
describe('detectProgrammaticFailure', () => {
|
|
10
|
+
describe('context overflow detection', () => {
|
|
11
|
+
it('should detect "context length exceeded"', () => {
|
|
12
|
+
const output = 'Error: context length exceeded';
|
|
13
|
+
expect(detectProgrammaticFailure(output, '')).toBe('context_overflow');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should detect "token limit"', () => {
|
|
17
|
+
const output = 'The token limit has been reached';
|
|
18
|
+
expect(detectProgrammaticFailure(output, '')).toBe('context_overflow');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should detect "maximum context"', () => {
|
|
22
|
+
const output = 'Maximum context size reached';
|
|
23
|
+
expect(detectProgrammaticFailure(output, '')).toBe('context_overflow');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should detect "context window"', () => {
|
|
27
|
+
const output = 'Error: context window exceeded';
|
|
28
|
+
expect(detectProgrammaticFailure(output, '')).toBe('context_overflow');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should detect "too many tokens"', () => {
|
|
32
|
+
const output = 'Error: too many tokens in request';
|
|
33
|
+
expect(detectProgrammaticFailure(output, '')).toBe('context_overflow');
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe('rate limit detection', () => {
|
|
38
|
+
it('should detect "rate limit"', () => {
|
|
39
|
+
const output = 'rate limit exceeded';
|
|
40
|
+
expect(detectProgrammaticFailure(output, '')).toBe('rate_limit');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should detect "too many requests"', () => {
|
|
44
|
+
const output = 'Error: too many requests';
|
|
45
|
+
expect(detectProgrammaticFailure(output, '')).toBe('rate_limit');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should detect "429 too many requests"', () => {
|
|
49
|
+
const output = 'HTTP 429 too many requests';
|
|
50
|
+
expect(detectProgrammaticFailure(output, '')).toBe('rate_limit');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should detect "quota exceeded"', () => {
|
|
54
|
+
const output = 'quota exceeded for this billing period';
|
|
55
|
+
expect(detectProgrammaticFailure(output, '')).toBe('rate_limit');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should detect "throttled"', () => {
|
|
59
|
+
const output = 'Request throttled due to high load';
|
|
60
|
+
expect(detectProgrammaticFailure(output, '')).toBe('rate_limit');
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('API error detection', () => {
|
|
65
|
+
it('should detect "api error"', () => {
|
|
66
|
+
const output = 'API error occurred';
|
|
67
|
+
expect(detectProgrammaticFailure(output, '')).toBe('api_error');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should detect "internal server error"', () => {
|
|
71
|
+
const output = 'Internal Server Error';
|
|
72
|
+
expect(detectProgrammaticFailure(output, '')).toBe('api_error');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should detect "500 server error"', () => {
|
|
76
|
+
const output = 'HTTP 500 Internal Server Error';
|
|
77
|
+
expect(detectProgrammaticFailure(output, '')).toBe('api_error');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should detect "502 bad gateway"', () => {
|
|
81
|
+
const output = '502 Bad Gateway';
|
|
82
|
+
expect(detectProgrammaticFailure(output, '')).toBe('api_error');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should detect "503 service unavailable"', () => {
|
|
86
|
+
const output = '503 Service Unavailable';
|
|
87
|
+
expect(detectProgrammaticFailure(output, '')).toBe('api_error');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should detect "APIError"', () => {
|
|
91
|
+
const output = 'APIError: Something went wrong';
|
|
92
|
+
expect(detectProgrammaticFailure(output, '')).toBe('api_error');
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('timeout detection', () => {
|
|
97
|
+
it('should detect "timeout" in failure reason', () => {
|
|
98
|
+
expect(detectProgrammaticFailure('', 'Task timeout')).toBe('timeout');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should detect "timed out" in failure reason', () => {
|
|
102
|
+
expect(detectProgrammaticFailure('', 'Task timed out after 60 minutes')).toBe('timeout');
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe('non-programmatic failures', () => {
|
|
107
|
+
it('should return null for regular failures', () => {
|
|
108
|
+
const output = 'Error: Could not find file foo.txt';
|
|
109
|
+
expect(detectProgrammaticFailure(output, 'File not found')).toBeNull();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should return null for test failures', () => {
|
|
113
|
+
const output = 'FAILED: 3 tests failed';
|
|
114
|
+
expect(detectProgrammaticFailure(output, 'Tests failed')).toBeNull();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should return null for compilation errors', () => {
|
|
118
|
+
const output = 'error TS2304: Cannot find name "foo"';
|
|
119
|
+
expect(detectProgrammaticFailure(output, 'Compilation failed')).toBeNull();
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe('priority ordering', () => {
|
|
124
|
+
it('should prioritize context overflow over rate limit', () => {
|
|
125
|
+
const output = 'context length exceeded, rate limit warning';
|
|
126
|
+
expect(detectProgrammaticFailure(output, '')).toBe('context_overflow');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('should prioritize rate limit over api error', () => {
|
|
130
|
+
const output = 'API error: rate limit exceeded';
|
|
131
|
+
expect(detectProgrammaticFailure(output, '')).toBe('rate_limit');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe('generateProgrammaticReport', () => {
|
|
137
|
+
describe('api_error report', () => {
|
|
138
|
+
it('should generate API error report with correct structure', () => {
|
|
139
|
+
const report = generateProgrammaticReport('api_error', 'API error', 'error output');
|
|
140
|
+
|
|
141
|
+
expect(report).toContain('## Failure Reason');
|
|
142
|
+
expect(report).toContain('API error occurred');
|
|
143
|
+
expect(report).toContain('## Analysis');
|
|
144
|
+
expect(report).toContain('## Suggested Fix');
|
|
145
|
+
expect(report).toContain('## Relevant Output');
|
|
146
|
+
expect(report).toContain('<promise>FAILED</promise>');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('should include relevant output in code block', () => {
|
|
150
|
+
const report = generateProgrammaticReport('api_error', 'API error', 'some error message');
|
|
151
|
+
|
|
152
|
+
expect(report).toContain('```');
|
|
153
|
+
expect(report).toContain('some error message');
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('rate_limit report', () => {
|
|
158
|
+
it('should generate rate limit report with correct structure', () => {
|
|
159
|
+
const report = generateProgrammaticReport('rate_limit', 'Rate limited', 'output');
|
|
160
|
+
|
|
161
|
+
expect(report).toContain('## Failure Reason');
|
|
162
|
+
expect(report).toContain('Rate limit exceeded');
|
|
163
|
+
expect(report).toContain('## Analysis');
|
|
164
|
+
expect(report).toContain('## Suggested Fix');
|
|
165
|
+
expect(report).toContain('Wait 1-2 minutes');
|
|
166
|
+
expect(report).toContain('<promise>FAILED</promise>');
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe('timeout report', () => {
|
|
171
|
+
it('should generate timeout report with correct structure', () => {
|
|
172
|
+
const report = generateProgrammaticReport('timeout', 'Task timed out', 'output');
|
|
173
|
+
|
|
174
|
+
expect(report).toContain('## Failure Reason');
|
|
175
|
+
expect(report).toContain('timed out');
|
|
176
|
+
expect(report).toContain('## Analysis');
|
|
177
|
+
expect(report).toContain('## Suggested Fix');
|
|
178
|
+
expect(report).toContain('--timeout');
|
|
179
|
+
expect(report).toContain('<promise>FAILED</promise>');
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
describe('context_overflow report', () => {
|
|
184
|
+
it('should generate context overflow report with correct structure', () => {
|
|
185
|
+
const report = generateProgrammaticReport('context_overflow', 'Context exceeded', 'output');
|
|
186
|
+
|
|
187
|
+
expect(report).toContain('## Failure Reason');
|
|
188
|
+
expect(report).toContain('Context window exceeded');
|
|
189
|
+
expect(report).toContain('## Analysis');
|
|
190
|
+
expect(report).toContain('## Suggested Fix');
|
|
191
|
+
expect(report).toContain('smaller');
|
|
192
|
+
expect(report).toContain('<promise>FAILED</promise>');
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe('output truncation', () => {
|
|
197
|
+
it('should truncate long output', () => {
|
|
198
|
+
const longOutput = Array(100).fill('Line of output').join('\n');
|
|
199
|
+
const report = generateProgrammaticReport('api_error', 'Error', longOutput);
|
|
200
|
+
|
|
201
|
+
expect(report).toContain('...(truncated)');
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should not truncate short output', () => {
|
|
205
|
+
const shortOutput = 'Short error message';
|
|
206
|
+
const report = generateProgrammaticReport('api_error', 'Error', shortOutput);
|
|
207
|
+
|
|
208
|
+
expect(report).not.toContain('...(truncated)');
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
describe('analyzeFailure', () => {
|
|
214
|
+
describe('programmatic failures', () => {
|
|
215
|
+
it('should handle context overflow without API call', async () => {
|
|
216
|
+
const output = 'Error: context length exceeded';
|
|
217
|
+
const result = await analyzeFailure(output, 'Context overflow', '001');
|
|
218
|
+
|
|
219
|
+
expect(result).toContain('## Failure Reason');
|
|
220
|
+
expect(result).toContain('Context window exceeded');
|
|
221
|
+
expect(result).toContain('<promise>FAILED</promise>');
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('should handle rate limit without API call', async () => {
|
|
225
|
+
const output = 'rate limit exceeded';
|
|
226
|
+
const result = await analyzeFailure(output, 'Rate limited', '002');
|
|
227
|
+
|
|
228
|
+
expect(result).toContain('## Failure Reason');
|
|
229
|
+
expect(result).toContain('Rate limit exceeded');
|
|
230
|
+
expect(result).toContain('<promise>FAILED</promise>');
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('should handle timeout without API call', async () => {
|
|
234
|
+
const output = 'Task running...';
|
|
235
|
+
const result = await analyzeFailure(output, 'Task timed out', '003');
|
|
236
|
+
|
|
237
|
+
expect(result).toContain('## Failure Reason');
|
|
238
|
+
expect(result).toContain('timed out');
|
|
239
|
+
expect(result).toContain('<promise>FAILED</promise>');
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('should handle API error without API call', async () => {
|
|
243
|
+
const output = '500 Internal Server Error';
|
|
244
|
+
const result = await analyzeFailure(output, 'API failed', '004');
|
|
245
|
+
|
|
246
|
+
expect(result).toContain('## Failure Reason');
|
|
247
|
+
expect(result).toContain('API error');
|
|
248
|
+
expect(result).toContain('<promise>FAILED</promise>');
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
describe('all failure reports end with FAILED marker', () => {
|
|
253
|
+
const failureTypes: ProgrammaticFailureType[] = ['api_error', 'rate_limit', 'timeout', 'context_overflow'];
|
|
254
|
+
|
|
255
|
+
for (const type of failureTypes) {
|
|
256
|
+
it(`should end with <promise>FAILED</promise> for ${type}`, () => {
|
|
257
|
+
const report = generateProgrammaticReport(type, 'reason', 'output');
|
|
258
|
+
expect(report.trim().endsWith('<promise>FAILED</promise>')).toBe(true);
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
describe('report structure', () => {
|
|
264
|
+
it('should include all required sections for programmatic failures', async () => {
|
|
265
|
+
const result = await analyzeFailure('context length exceeded', 'Error', '001');
|
|
266
|
+
|
|
267
|
+
// Check all required sections are present
|
|
268
|
+
expect(result).toContain('## Failure Reason');
|
|
269
|
+
expect(result).toContain('## Analysis');
|
|
270
|
+
expect(result).toContain('## Suggested Fix');
|
|
271
|
+
expect(result).toContain('## Relevant Output');
|
|
272
|
+
expect(result).toContain('<promise>FAILED</promise>');
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
});
|