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,372 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Failure types that can be detected programmatically without using the API.
|
|
6
|
+
*/
|
|
7
|
+
export type ProgrammaticFailureType =
|
|
8
|
+
| 'api_error'
|
|
9
|
+
| 'rate_limit'
|
|
10
|
+
| 'timeout'
|
|
11
|
+
| 'context_overflow';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Result of analyzing task failure.
|
|
15
|
+
*/
|
|
16
|
+
export interface FailureAnalysisResult {
|
|
17
|
+
failureReason: string;
|
|
18
|
+
analysis: string;
|
|
19
|
+
suggestedFix: string;
|
|
20
|
+
relevantOutput: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Patterns for detecting programmatic failure types.
|
|
25
|
+
*/
|
|
26
|
+
const API_ERROR_PATTERNS = [
|
|
27
|
+
/api error/i,
|
|
28
|
+
/internal server error/i,
|
|
29
|
+
/service unavailable/i,
|
|
30
|
+
/bad gateway/i,
|
|
31
|
+
/500\s+(internal\s+)?server\s+error/i,
|
|
32
|
+
/502\s+bad\s+gateway/i,
|
|
33
|
+
/503\s+service\s+unavailable/i,
|
|
34
|
+
/504\s+gateway\s+timeout/i,
|
|
35
|
+
/APIError/i,
|
|
36
|
+
/API request failed/i,
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const RATE_LIMIT_PATTERNS = [
|
|
40
|
+
/rate limit/i,
|
|
41
|
+
/too many requests/i,
|
|
42
|
+
/429\s+too\s+many\s+requests/i,
|
|
43
|
+
/quota exceeded/i,
|
|
44
|
+
/request limit/i,
|
|
45
|
+
/throttl/i,
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const CONTEXT_OVERFLOW_PATTERNS = [
|
|
49
|
+
/context length exceeded/i,
|
|
50
|
+
/token limit/i,
|
|
51
|
+
/maximum context/i,
|
|
52
|
+
/context window/i,
|
|
53
|
+
/too many tokens/i,
|
|
54
|
+
/max.*tokens/i,
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Detect if the failure is a known programmatic failure type.
|
|
59
|
+
* Returns null if the failure type requires AI analysis.
|
|
60
|
+
*/
|
|
61
|
+
export function detectProgrammaticFailure(
|
|
62
|
+
output: string,
|
|
63
|
+
failureReason: string
|
|
64
|
+
): ProgrammaticFailureType | null {
|
|
65
|
+
const combined = `${output}\n${failureReason}`;
|
|
66
|
+
|
|
67
|
+
// Check for context overflow
|
|
68
|
+
for (const pattern of CONTEXT_OVERFLOW_PATTERNS) {
|
|
69
|
+
if (pattern.test(combined)) {
|
|
70
|
+
return 'context_overflow';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Check for rate limiting
|
|
75
|
+
for (const pattern of RATE_LIMIT_PATTERNS) {
|
|
76
|
+
if (pattern.test(combined)) {
|
|
77
|
+
return 'rate_limit';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Check for API errors
|
|
82
|
+
for (const pattern of API_ERROR_PATTERNS) {
|
|
83
|
+
if (pattern.test(combined)) {
|
|
84
|
+
return 'api_error';
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Check for timeout (usually passed in failureReason)
|
|
89
|
+
if (/timeout|timed out/i.test(failureReason)) {
|
|
90
|
+
return 'timeout';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Generate a programmatic failure report for known failure types.
|
|
98
|
+
*/
|
|
99
|
+
export function generateProgrammaticReport(
|
|
100
|
+
failureType: ProgrammaticFailureType,
|
|
101
|
+
_failureReason: string,
|
|
102
|
+
output: string
|
|
103
|
+
): string {
|
|
104
|
+
const relevantOutput = extractRelevantOutput(output, 50);
|
|
105
|
+
|
|
106
|
+
switch (failureType) {
|
|
107
|
+
case 'api_error':
|
|
108
|
+
return `## Failure Reason
|
|
109
|
+
API error occurred during task execution.
|
|
110
|
+
|
|
111
|
+
## Analysis
|
|
112
|
+
The Claude API returned an error response. This is typically a temporary issue with the API service.
|
|
113
|
+
|
|
114
|
+
## Suggested Fix
|
|
115
|
+
- Wait a few minutes and retry the task
|
|
116
|
+
- Check the Anthropic status page for any ongoing incidents
|
|
117
|
+
- If the issue persists, try running with a smaller context
|
|
118
|
+
|
|
119
|
+
## Relevant Output
|
|
120
|
+
\`\`\`
|
|
121
|
+
${relevantOutput}
|
|
122
|
+
\`\`\`
|
|
123
|
+
|
|
124
|
+
<promise>FAILED</promise>`;
|
|
125
|
+
|
|
126
|
+
case 'rate_limit':
|
|
127
|
+
return `## Failure Reason
|
|
128
|
+
Rate limit exceeded during task execution.
|
|
129
|
+
|
|
130
|
+
## Analysis
|
|
131
|
+
The API rate limit was reached. This typically happens when too many requests are made in a short period.
|
|
132
|
+
|
|
133
|
+
## Suggested Fix
|
|
134
|
+
- Wait 1-2 minutes before retrying
|
|
135
|
+
- If using parallel execution, reduce concurrency
|
|
136
|
+
- Consider upgrading your API tier for higher limits
|
|
137
|
+
|
|
138
|
+
## Relevant Output
|
|
139
|
+
\`\`\`
|
|
140
|
+
${relevantOutput}
|
|
141
|
+
\`\`\`
|
|
142
|
+
|
|
143
|
+
<promise>FAILED</promise>`;
|
|
144
|
+
|
|
145
|
+
case 'timeout':
|
|
146
|
+
return `## Failure Reason
|
|
147
|
+
Task execution timed out.
|
|
148
|
+
|
|
149
|
+
## Analysis
|
|
150
|
+
The task took longer than the configured timeout to complete. This could indicate:
|
|
151
|
+
- The task is too complex or large for a single execution
|
|
152
|
+
- Claude is stuck or making slow progress
|
|
153
|
+
- Network issues causing delays
|
|
154
|
+
|
|
155
|
+
## Suggested Fix
|
|
156
|
+
- Increase the timeout with \`--timeout <minutes>\`
|
|
157
|
+
- Break the task into smaller subtasks
|
|
158
|
+
- Check the logs for what Claude was doing before timeout
|
|
159
|
+
|
|
160
|
+
## Relevant Output
|
|
161
|
+
\`\`\`
|
|
162
|
+
${relevantOutput}
|
|
163
|
+
\`\`\`
|
|
164
|
+
|
|
165
|
+
<promise>FAILED</promise>`;
|
|
166
|
+
|
|
167
|
+
case 'context_overflow':
|
|
168
|
+
return `## Failure Reason
|
|
169
|
+
Context window exceeded during task execution.
|
|
170
|
+
|
|
171
|
+
## Analysis
|
|
172
|
+
The conversation context grew too large for Claude to process. This typically happens when:
|
|
173
|
+
- Too much code or output was included in the context
|
|
174
|
+
- The task involves very large files
|
|
175
|
+
- Multiple previous outcomes created a large context
|
|
176
|
+
|
|
177
|
+
## Suggested Fix
|
|
178
|
+
- Break the task into smaller, independent subtasks
|
|
179
|
+
- Reduce the amount of context passed to Claude
|
|
180
|
+
- Consider processing files in chunks
|
|
181
|
+
|
|
182
|
+
## Relevant Output
|
|
183
|
+
\`\`\`
|
|
184
|
+
${relevantOutput}
|
|
185
|
+
\`\`\`
|
|
186
|
+
|
|
187
|
+
<promise>FAILED</promise>`;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Extract the most relevant portion of output for the failure report.
|
|
193
|
+
*/
|
|
194
|
+
function extractRelevantOutput(output: string, maxLines: number): string {
|
|
195
|
+
// Remove ANSI codes
|
|
196
|
+
const cleanOutput = output.replace(/\x1b\[[0-9;]*m/g, '');
|
|
197
|
+
|
|
198
|
+
// Split into lines
|
|
199
|
+
const lines = cleanOutput.split('\n');
|
|
200
|
+
|
|
201
|
+
// If output is small enough, return all of it
|
|
202
|
+
if (lines.length <= maxLines) {
|
|
203
|
+
return cleanOutput.trim();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Otherwise, take the last N lines (most relevant for failures)
|
|
207
|
+
const lastLines = lines.slice(-maxLines);
|
|
208
|
+
return `...(truncated)\n${lastLines.join('\n').trim()}`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Get the path to Claude CLI.
|
|
213
|
+
*/
|
|
214
|
+
function getClaudePath(): string {
|
|
215
|
+
try {
|
|
216
|
+
return execSync('which claude', { encoding: 'utf-8' }).trim();
|
|
217
|
+
} catch {
|
|
218
|
+
throw new Error('Claude CLI not found. Please ensure it is installed and in your PATH.');
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Analyze a failure using Claude (Sonnet/Haiku) and generate a structured report.
|
|
224
|
+
* Uses a fast model for cost efficiency.
|
|
225
|
+
*/
|
|
226
|
+
export async function analyzeFailure(
|
|
227
|
+
output: string,
|
|
228
|
+
failureReason: string,
|
|
229
|
+
taskId: string,
|
|
230
|
+
timeoutMs: number = 60000
|
|
231
|
+
): Promise<string> {
|
|
232
|
+
// First check for programmatic failures
|
|
233
|
+
const programmaticType = detectProgrammaticFailure(output, failureReason);
|
|
234
|
+
if (programmaticType) {
|
|
235
|
+
return generateProgrammaticReport(programmaticType, failureReason, output);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// For other failures, use Claude to analyze
|
|
239
|
+
try {
|
|
240
|
+
const analysisResult = await callClaudeForAnalysis(output, failureReason, taskId, timeoutMs);
|
|
241
|
+
return analysisResult;
|
|
242
|
+
} catch (error) {
|
|
243
|
+
// If analysis fails, generate a basic fallback report
|
|
244
|
+
const relevantOutput = extractRelevantOutput(output, 50);
|
|
245
|
+
return `## Failure Reason
|
|
246
|
+
${failureReason}
|
|
247
|
+
|
|
248
|
+
## Analysis
|
|
249
|
+
Unable to perform automated analysis: ${error instanceof Error ? error.message : String(error)}
|
|
250
|
+
|
|
251
|
+
## Suggested Fix
|
|
252
|
+
Review the relevant output below and the task logs for more details.
|
|
253
|
+
|
|
254
|
+
## Relevant Output
|
|
255
|
+
\`\`\`
|
|
256
|
+
${relevantOutput}
|
|
257
|
+
\`\`\`
|
|
258
|
+
|
|
259
|
+
<promise>FAILED</promise>`;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Call Claude CLI to analyze the failure.
|
|
265
|
+
* Uses the print mode with a concise prompt.
|
|
266
|
+
*/
|
|
267
|
+
async function callClaudeForAnalysis(
|
|
268
|
+
output: string,
|
|
269
|
+
failureReason: string,
|
|
270
|
+
taskId: string,
|
|
271
|
+
timeoutMs: number
|
|
272
|
+
): Promise<string> {
|
|
273
|
+
const relevantOutput = extractRelevantOutput(output, 100);
|
|
274
|
+
|
|
275
|
+
const prompt = `Analyze this failed task execution and generate a brief failure report.
|
|
276
|
+
|
|
277
|
+
Task ID: ${taskId}
|
|
278
|
+
Initial Failure Reason: ${failureReason}
|
|
279
|
+
|
|
280
|
+
Execution Output (last 100 lines):
|
|
281
|
+
\`\`\`
|
|
282
|
+
${relevantOutput}
|
|
283
|
+
\`\`\`
|
|
284
|
+
|
|
285
|
+
Respond with ONLY a markdown report in this exact format:
|
|
286
|
+
|
|
287
|
+
## Failure Reason
|
|
288
|
+
[One-line description of what went wrong]
|
|
289
|
+
|
|
290
|
+
## Analysis
|
|
291
|
+
[2-3 sentences explaining why the failure occurred]
|
|
292
|
+
|
|
293
|
+
## Suggested Fix
|
|
294
|
+
[1-3 bullet points with actionable steps to resolve]
|
|
295
|
+
|
|
296
|
+
## Relevant Output
|
|
297
|
+
\`\`\`
|
|
298
|
+
[Key error messages or output that shows the failure]
|
|
299
|
+
\`\`\`
|
|
300
|
+
|
|
301
|
+
<promise>FAILED</promise>`;
|
|
302
|
+
|
|
303
|
+
return new Promise((resolve, reject) => {
|
|
304
|
+
let analysisOutput = '';
|
|
305
|
+
let stderr = '';
|
|
306
|
+
|
|
307
|
+
const claudePath = getClaudePath();
|
|
308
|
+
|
|
309
|
+
// Use haiku model for fast, cost-effective analysis
|
|
310
|
+
const proc = spawn(claudePath, [
|
|
311
|
+
'--model', 'haiku',
|
|
312
|
+
'--dangerously-skip-permissions',
|
|
313
|
+
'-p',
|
|
314
|
+
prompt,
|
|
315
|
+
], {
|
|
316
|
+
env: process.env,
|
|
317
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
const timeout = setTimeout(() => {
|
|
321
|
+
proc.kill('SIGTERM');
|
|
322
|
+
reject(new Error('Analysis timed out'));
|
|
323
|
+
}, timeoutMs);
|
|
324
|
+
|
|
325
|
+
proc.stdout.on('data', (data) => {
|
|
326
|
+
analysisOutput += data.toString();
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
proc.stderr.on('data', (data) => {
|
|
330
|
+
stderr += data.toString();
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
proc.on('close', (exitCode) => {
|
|
334
|
+
clearTimeout(timeout);
|
|
335
|
+
|
|
336
|
+
if (exitCode !== 0) {
|
|
337
|
+
reject(new Error(`Analysis failed with exit code ${exitCode}: ${stderr}`));
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Validate the output has the expected structure
|
|
342
|
+
if (!analysisOutput.includes('## Failure Reason') ||
|
|
343
|
+
!analysisOutput.includes('<promise>FAILED</promise>')) {
|
|
344
|
+
// If the output doesn't have the expected structure, wrap it
|
|
345
|
+
const fixedOutput = `## Failure Reason
|
|
346
|
+
${failureReason}
|
|
347
|
+
|
|
348
|
+
## Analysis
|
|
349
|
+
${analysisOutput.trim()}
|
|
350
|
+
|
|
351
|
+
## Suggested Fix
|
|
352
|
+
Review the task logs for more details.
|
|
353
|
+
|
|
354
|
+
## Relevant Output
|
|
355
|
+
\`\`\`
|
|
356
|
+
${extractRelevantOutput(output, 30)}
|
|
357
|
+
\`\`\`
|
|
358
|
+
|
|
359
|
+
<promise>FAILED</promise>`;
|
|
360
|
+
resolve(fixedOutput);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
resolve(analysisOutput.trim());
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
proc.on('error', (error) => {
|
|
368
|
+
clearTimeout(timeout);
|
|
369
|
+
reject(error);
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
}
|
package/src/core/git.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { logger } from '../utils/logger.js';
|
|
3
|
+
|
|
4
|
+
export interface GitStatus {
|
|
5
|
+
isRepo: boolean;
|
|
6
|
+
hasChanges: boolean;
|
|
7
|
+
branch: string | null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Check if we're in a git repository.
|
|
12
|
+
*/
|
|
13
|
+
export function isGitRepo(): boolean {
|
|
14
|
+
try {
|
|
15
|
+
execSync('git rev-parse --is-inside-work-tree', { encoding: 'utf-8', stdio: 'pipe' });
|
|
16
|
+
return true;
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Get current git status.
|
|
24
|
+
*/
|
|
25
|
+
export function getGitStatus(): GitStatus {
|
|
26
|
+
const status: GitStatus = {
|
|
27
|
+
isRepo: false,
|
|
28
|
+
hasChanges: false,
|
|
29
|
+
branch: null,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
execSync('git rev-parse --is-inside-work-tree', { encoding: 'utf-8', stdio: 'pipe' });
|
|
34
|
+
status.isRepo = true;
|
|
35
|
+
} catch {
|
|
36
|
+
return status;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const branchOutput = execSync('git branch --show-current', { encoding: 'utf-8', stdio: 'pipe' });
|
|
41
|
+
status.branch = branchOutput.trim() || null;
|
|
42
|
+
} catch {
|
|
43
|
+
// Might be in detached HEAD state
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const statusOutput = execSync('git status --porcelain', { encoding: 'utf-8', stdio: 'pipe' });
|
|
48
|
+
status.hasChanges = statusOutput.trim().length > 0;
|
|
49
|
+
} catch {
|
|
50
|
+
// Ignore errors
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return status;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Check if there are uncommitted changes.
|
|
58
|
+
*/
|
|
59
|
+
export function hasUncommittedChanges(): boolean {
|
|
60
|
+
try {
|
|
61
|
+
const status = execSync('git status --porcelain', { encoding: 'utf-8', stdio: 'pipe' });
|
|
62
|
+
return status.trim().length > 0;
|
|
63
|
+
} catch {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Parse git status --porcelain output into a list of file paths.
|
|
70
|
+
* Format: XY filename (where X is index status, Y is working tree status)
|
|
71
|
+
* Examples:
|
|
72
|
+
* M file.txt - modified, staged
|
|
73
|
+
* MM file.txt - modified, staged, then modified again
|
|
74
|
+
* M file.txt - modified, not staged
|
|
75
|
+
* A file.txt - added
|
|
76
|
+
* D file.txt - deleted
|
|
77
|
+
* ?? file.txt - untracked
|
|
78
|
+
* R old -> new - renamed
|
|
79
|
+
*/
|
|
80
|
+
export function parseGitStatus(output: string): string[] {
|
|
81
|
+
if (!output.trim()) {
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const files: string[] = [];
|
|
86
|
+
// Don't trim the entire output - leading spaces are significant in git porcelain format
|
|
87
|
+
// Only split by newlines, then handle each line
|
|
88
|
+
const lines = output.split('\n');
|
|
89
|
+
|
|
90
|
+
for (const line of lines) {
|
|
91
|
+
if (!line || line.length < 3) continue;
|
|
92
|
+
|
|
93
|
+
// The filename starts at position 3 (after XY and space)
|
|
94
|
+
let filePath = line.slice(3);
|
|
95
|
+
|
|
96
|
+
// Handle renamed files: "R old -> new" or "R old -> new"
|
|
97
|
+
if (line[0] === 'R' || line[1] === 'R') {
|
|
98
|
+
const arrowIndex = filePath.indexOf(' -> ');
|
|
99
|
+
if (arrowIndex !== -1) {
|
|
100
|
+
filePath = filePath.slice(arrowIndex + 4);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Handle copied files similarly
|
|
105
|
+
if (line[0] === 'C' || line[1] === 'C') {
|
|
106
|
+
const arrowIndex = filePath.indexOf(' -> ');
|
|
107
|
+
if (arrowIndex !== -1) {
|
|
108
|
+
filePath = filePath.slice(arrowIndex + 4);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Handle quoted paths (git escapes special characters)
|
|
113
|
+
if (filePath.startsWith('"') && filePath.endsWith('"')) {
|
|
114
|
+
filePath = filePath.slice(1, -1);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
files.push(filePath);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return files;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Get list of currently changed files (both staged and unstaged).
|
|
125
|
+
* Returns empty array if not in a git repo.
|
|
126
|
+
*/
|
|
127
|
+
export function getChangedFiles(): string[] {
|
|
128
|
+
if (!isGitRepo()) {
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
const output = execSync('git status --porcelain', { encoding: 'utf-8', stdio: 'pipe' });
|
|
134
|
+
return parseGitStatus(output);
|
|
135
|
+
} catch {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Stash uncommitted changes with a descriptive name.
|
|
142
|
+
* @param name - Name for the stash (e.g., "raf-001-task-3-failed")
|
|
143
|
+
* @returns true if stash was created, false otherwise
|
|
144
|
+
*/
|
|
145
|
+
export function stashChanges(name: string): boolean {
|
|
146
|
+
if (!isGitRepo()) {
|
|
147
|
+
logger.warn('Not in a git repository, skipping stash');
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!hasUncommittedChanges()) {
|
|
152
|
+
logger.debug('No uncommitted changes to stash');
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
execSync(`git stash push -m "${name.replace(/"/g, '\\"')}"`, {
|
|
158
|
+
encoding: 'utf-8',
|
|
159
|
+
stdio: 'pipe',
|
|
160
|
+
});
|
|
161
|
+
return true;
|
|
162
|
+
} catch (error) {
|
|
163
|
+
logger.error(`Failed to stash changes: ${error}`);
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
}
|